악성코드 하나를 분석하던 중, 아주 흔하면서도 지금까지 짜증나게 만들었던 루틴이 하나 등장했습니다.
단순하게 LoadLibrary와 GetProcAddress를 통해 모듈 핸들과 함수 주소를 가져오고, 이를 전역변수에 대입하여 다른 코드들에서 사용하는 것으로 IAT에 자신이 사용하는 함수명을 표시하지 않게 하는 흔한 기법이지만, 몇가지 문제점이 있었습니다.
[그림 1. 첫번째 문제]
첫째, 양이 많았습니다. 한 함수 내에서 40개가 넘어가는 함수들의 주소를 가져오는데, 이는 다음 문제점과 더해 미친듯한 시너지를 발휘합니다.
[그림 2. 두번째 문제]
둘째, 변수명이 스택에 저장되어있습니다. 바이트 단위로 할당되어있기 때문에 보통이라면 이걸 전부 아스키 문자로 바꿔서 하나하나 읽고 무슨 함수인지를 파악해야 합니다. 함수가 엄청나게 많다 보니 1500바이트가 넘어가는 양입니다.
[그림 3. 세번째 문제]
셋째, 변수 값이 암호화되어있습니다. 정확히는 0x08이라는 고정된 값으로 XOR되어있는 것이지만, 어쨌든 그냥 봐서는 어떤 함수인지 알기가 힘듭니다. 셋중 하나라도 문제가 없었으면 그냥 복사해서 파이썬 스크립트로 복호화하거나 해서 하나하나 네이밍해줬겠지만, 도저히 그럴 양이 아니었습니다.
여기에서 잠시 현자타임이 왔고, 이걸 어떻게 해결할까 하다가 지금까지 너무 무식하게 분석해왔다는 생각이 들어서 IDAPython을 이용하여 자동 스크립트를 짜기로 결심했습니다.
[그림 04. 스크립트 동작 전]
작성한 스크립트를 돌리기 전의 모습입니다.
[그림 05. 스크립트 로그]
스크립트를 동작시키면 IDAPython 콘솔창에 로그가 남습니다.
[그림 06. 스크립트 동작 후]
스크립트를 동작한 후 새로고침해주면 위와 같이 GetProcAddress를 이용하여 대입한 값들이 네이밍됩니다. 예전 BoB 4기에서 잠깐 한 적이 있기는 했는데 사실 기억에는 전혀 남아있지 않아서 혼자 여기저기 검색하면서 조잡하게 짰습니다.
이 스크립트에는 아직 개선할 점이 몇 가지 있습니다.
- GetProcAddress의 결과를 전역변수가 아닌 지역변수나 Struct의 멤버변수같은것에 대입하는 경우는 네이밍이 되지 않습니다.
- 특정 함수 내에 커서를 둔 채로 실행해야 하며, 해당 함수 내에서의 GetProcAddress에 대해서만 네이밍을 진행합니다.
- GetProcAddress함수의 주소를 직접 구해서 RenameGetProcAddrVars 함수에 인자로 넣어야 합니다.
스크립트를 사용하면서 나중에 조금씩 업데이트해갈텐데, 그러면서 하나씩 해결해갈 예정입니다.
소스코드 및 정리한 내용은 아래에 있습니다.
IDAPythonUtils.py
소스코드 내에서 사용한 idaapi의 함수들은 다음과 같습니다.
※ ea라는 용어는 Effective Address의 약자로, 주소값을 의미합니다.
'Reversing' 카테고리의 다른 글
디버깅 중인 프로세스 덤프하기 (0) | 2019.05.08 |
---|---|
IDA에서 타입 추가 로드하기 (0) | 2018.09.21 |
IsDebuggerPresent와 바이너리 패치 (0) | 2017.05.24 |
64비트 Windows에서 32비트 악성코드 분석 시 유의할 점 (0) | 2017.01.04 |
[ARM] Reversing.kr HateIntel 분석 (0) | 2016.04.22 |