악성코드 분석/Practical Malware Analysis 실습

[Practical Malware Analysis] Lab 05

sec_kero 2023. 5. 6. 18:07

IDA Pro만을 이용해 파일 Lab05-01.dll 내의 악성코드를 분석하라. 이 실습의 목적은 IDA Pro를 직접 다루는 데 있다. 이미 IDA Pro를 사용해 본 적이 있으면 다음 문제를 무시하고 악성코드 리버싱에 초점을 맞춰도 좋다.

 

질문)

1. DllMain의 주소는 무엇인가?

 

- dll 파일을 열면 보이는 지점이 바로 DllMain이다. 0x1000D02E

 

 

2. Imports 윈도우를 이용해 gethostbyname을 탐색해보자. 임포트 위치는 어디인가?

 

 

- imports 윈도우에서 이름을 검색할 수 있다. 0x100163CC

 

 

3. gethostbyname를 호출하는 함수는 몇 개 인가?

 

 

- 함수명을 누르고 ctrl+x를 누르면 xref(상호참조)를 볼 수 있다. 총 5개의 함수에서 9번 호출한다.

 

 

4. 0x10001757에 위치한 gethostbyname 호출을 보면 어떤 DNS 요청이 이뤄지는지 알 수 있는가?

 

 

- 0x10001757의 gethostbyname 함수는 off_10019040에 0x0D를 더한 값을 인자로 사용하는 것을 볼 수 있다. off_10019040을 따라가 보면 "[This is RD0]pic.praticalmalwareanalysis.com"이 보인다. 여기에 0x0D를 더한 위치부터는 "pics.praticalmalwareanalysis.com"이다. 해당 주소로 DNS 요청이 이뤄질 것이다.

 

 

5. 0x10001656에 있는 서브루틴에서 IDA Pro는 지역 변수 몇 개를 인지하고 있는가?

 

 

- 0x10001656으로 이동하면 지역변수는 음수(-) 값을 가진 변수들로 총 20개를 인지하고 있다. (필자는 free버전을 사용하고 있어서 20개로 인지하는 것으로 보이며, pro 버전은 23개를 인지한다고 한다.)

 

 

6. 0x10001656에 있는 서브루틴에서 IDA Pro는 파라미터 몇 개를 인지하고 있는가?

 

- 위 사진에서 양수(+) 값을 가진 것들이 파라미터가 되며, 여기서는 하나의 파라미터를 인지하고 있다.

 

 

7. Strings 윈도우를 이용해 디스어셈블리 내의 문자열 \cmd.exe /c를 찾아보자. 어디에 있는가?

 

 

- strings 윈도우에서 찾아본 결과 xdoors_d 영역의 0x10095B34에 위치하는 것을 알 수 있다.

 

 

8. \cmd.exe /c를 참조하는 코드 영역에서 무슨 일이 발생하는가?

 

 

- 우선 참조하는 위치를 ctrl+x를 눌러 확인했다. 0x100101D0에서 참조하는 걸 볼 수 있었다.

 

 

-  해당 함수 영역을 살펴보니 아래 사진의 문자열을 볼 수 있었고, 이 외에도 통신에 쓰이는 함수들(recv, send)이나 cmd 상에서 사용할 수 있는 명령어들(quit, exit, cd 등)을 볼 수 있었다. 이 점으로 보아 해당 코드 영역은 원격 쉘 세션 함수로 볼 수 있다. 

 

 

 

9. 같은 영역 0x100101C8에서 dword_1008E5C4는 경로를 지정하는 전역 변수로 보인다. 악성코드는 어떻게 dword_1008E5C4를 설정하는가?(힌트 : dword_1008E5C4의 상호 참조를 이용하라)

 

 

- 힌트를 참고해 상호참조를 확인해 보니 0x10001678에서 sub_10003695 함수의 실행 결과를 dword_1008E5C4로 설정하는 것으로 보인다. sub_10003695를 좀 더 확인해 보자.

 

 

- GetVersionExA 함수를 호출하는 것을 볼 수 있다. 해당 함수는 OS의 버전 정보를 가져온다(Windows 8.1부터는 다른 정보를 가져온다고 한다).

   하지만 여기서 최종적으로 eax를 결정짓는 건 아래쪽의 setz(=sete) al로, VersionInformation.dwPlatformID가 2인지 아닌지 비교해서 일치할 경우에 al을 1로 세팅한다.

 

 

- VersionInformation.dwPlatformID는 위의 운영체제에 해당되는 경우 2로 설정된다고 한다. 즉, 현재 프로그램이 실행되고 있는 운영체제의 정보를 파악해서 dword_1008E5C4를 설정함을 알 수 있다.

 

 

10. 0x1000FF58에서 서브루틴으로 수백 라인은 문자열을 비교하기 위한 일련의 memcmp 비교다. robotwork와 문자열 비교가 성공적으로 이뤄지면 무슨 일이 일어나는가?(memcmp가 0을 반환)

 

 

- 0x1000FF58의 서브루틴을 보다 보면 위의 지점에서 "robotwork"와 문자열을 비교하는 것을 볼 수 있다. 비교가 성공적으로 이루어질 경우, jnz short loc_10010468에 걸리지 않아서 빨간 선을 타고 간다.

 

 

- 그렇게 넘어간 지점에서 sub_100052A2를 호출한다. 해당 함수는 "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion"에서 WorkTime과 WorkTimes를 질의한다. 만약 해당 값이 0이 아닐 경우에는 이를 출력하고, sub_100038EE 함수를 호출해 socket에 전달한다.

 

 

11. PSLIST 익스포트는 무슨 역할을 하는가?

 

 

- Exports 윈도우를 살펴보면 PSLIST를 볼 수 있다. 해당 함수를 더블클릭하여 이동하자.

 

 

- PSLIST 초반에 sub_100036C3 함수를 호출한다. 해당 함수의 결과로 인해 분기가 나뉘는 것 같아 자세히 살펴보니, 해당 함수는 운영체제가 Windows 7, 2008, Vista라면 eax로 1을, 그 외의 운영체제(Windows 2000, XP, 2003) 일 경우에는 eax로 0을 반환한다 (해당 프로그램은 Windows 7이 최신 운영체제일 때 만들어졌나 보다).

 

- Windows 2000, XP, 2003일 경우에 밑의 세부 구문들을 거치게 되며 중간에 분기가 나뉘게 되고 다른 함수들을 호출하는데, 양 쪽 모두 CreateToolhelp32snapshot 함수를 실행한 다음 Process32First, Process32Next 함수들을 이용해서 프로세스들을 검색한다.

 

+) CreateToolhelp32snapshot : 프로세스에서 사용되는 힙, 모듈 및 스레드뿐만 아니라 지정된 프로세스의 스냅샷을 만듭니다. CreateToolhelp32Snapshot을 사용하여 시스템에서 현재 실행 중인 프로세스의 스냅샷을 만든 다음 Process32First  Process32Next를 사용하여 스냅샷에 기록된 목록을 안내합니다.

https://learn.microsoft.com/ko-kr/windows/win32/toolhelp/taking-a-snapshot-and-viewing-processes

 

   두 분기의 다른 점은 한쪽(왼쪽 경로)은 xinstall.dll 파일에 프로세스들을 기록하는 것만 하고, 다른 쪽(오른쪽 경로)은 이를 소켓으로 send까지 하는 것을 볼 수 있었다. 통신이 되는 상황인지 여부에 따라 다르게 실행되는 것으로 보인다.

 

- 요약하면 함수의 이름(PSLIST)에서 짐작할 수 있듯, 프로세스들의 리스트를 저장 및 전송까지 하는 함수로 보인다.

 

 

12. 그래프 모드를 이용해 sub_10004E79 상호 참조 그래프를 그려보자. 이 함수에 의해 호출될 수 있는 API 함수는 무엇인가? 해당 API 함수에만 기반을 두고 이 함수를 어떤 이름으로 변경하겠는가?

+) 책에서 문제 번역을 잘못해서 이를 수정했다. 의미가 조금 달라져도 해야 하는 분석이 달라지니 좀 짜증 난다.

 

- View -> Graphs -> User xrefs chart를 누르면 상호참조 그래프를 그릴 수 있다. 우리는 이 함수로부터 호출되는 API 함수들을 보는 게 목적이기 때문에 Starting direction 항목에서 "Cross Reference from"에만 체크를 해주면 아래의 그림을 볼 수 있다.

 

 

 

- 해당 함수에서 "GetSystemDefaultLangID", "send" 등을 호출하는 것을 보아 해당 시스템의 기본 설정 언어 정보를 얻어서 소켓으로 보내는 역할로 보인다. 해당 함수만을 보았을 때 함수 이름을 send_langID 정도로 정해두면 좋아 보인다.

 

 

13. DllMain이 직접 호출하는 윈도우 API 함수는 몇 개인가? 두 번째 깊이(depth of 2)에서 몇 개인가?

 

 

- 이 질문의 답변도 Graph를 그려서 확인해 보았다. DllMain이 직접 호출하는 윈도우 API 함수를 알기 위해 Recursion depth를 1로 설정하면 위의 그림처럼 나온다. 여기서 볼 수 있는 직접 호출하는 윈도우 API 함수는 총 4개(strncpy, _strnicmp, CreateThread, strlen)이다.

 

- 두 번째 깊이를 보기 위해서는 Recursion depth를 2로 설정하면 된다. 두 번째 깊이에서는 33개를 호출하는 것을 볼 수 있었다. (그래프가 더 커지고 한 번에 찍기 힘들어서 사진은 첨부하지 않는다)

 

 

14. 0x10001358에서 Sleep 호출이 존재한다. (sleep까지 수밀리초 값을 파라미터로 갖는 API 함수) 이 코드가 수행되면 프로그램이 얼마동안 sleep하는가?

 

 

- 해당 지점으로 넘어가면 Sleep 함수의 인자로 사용될 eax를 세팅하는 과정부터 볼 수 있다. off_10019020의 0x0D 지점부터 문자열을 읽어와서 atoi 함수를 거쳐 int 형으로 바꾼 값에 0x3E8(1000)을 곱한 값을 eax로 세팅하고 있다.

 

 

- off_10019020을 따라가 보면 "[This is CTI]30"이라는 문자열을 볼 수 있다. 이 문자열의 0x0D(13)번째 지점부터의 문자열은 "30"이다. 이 값이 atoi를 거치면 숫자 30이라는 값으로 바뀌고, 여기에 0x3E8(1000)을 곱하면 30,000을 가진다. 이 값을 Sleep의 인자로 사용하게 되면 30000ms(30s) 동안 프로그램이 sleep 하게 된다.

 

 

15. 0x10001701에서 소켓을 호출한다. 세 가지 파라미터는 무엇인가?

 

 

- 0x10001701로 넘어가면 위 사진과 같이 주석을 곁들여서 protocol로 6, type으로 1, af로 2라는 값을 인자로 사용하는 것을 볼 수 있다. 각 숫자가 의미하는 바는 아래의 주소로 들어가면 각각의 항목에서 찾을 수 있다.

https://learn.microsoft.com/ko-kr/windows/win32/api/winsock2/nf-winsock2-socket

 

 

16. 소켓과 IDA Pro에서 명명한 심볼 상수 기능을 이용해 이 파라미터를 좀 더 유용하게 할 수 있겠는가? 변경 후 파라미터는 무엇인가?

 

 

- 앞에서 함수의 이름을 바꿨듯이 IDA의 기능을 이용해 의미를 쉽게 파악할 수 있도록 표시할 수 있다. 각각의 숫자를 우클릭 -> Use standard symbolic constant를 눌러서 위의 주소에서 확인한 값을 찾아 아래의 사진과 같이 바꿔서 표현할 수 있다.

 

 

 

17. 명령어 옵코드 0xED의 사용법을 찾아보자. 이 명령어는 VMware 탐지를 수행하는 VMXh 매직 문자열로 사용한다. 이 악성코드는 이를 이용하고 있는가? VMware를 탐지하는 다른 증거가 있는가?

 

 

http://ref.x86asm.net/coder32.html
https://c9x.me/x86/html/file_module_x86_id_139.html

 

 

- 구글에서 0xED opcode를 검색해 보면 In eax, dx라는 명령어가 실행됨을 알 수 있다. 더 찾아보니 DX의 I/O port로부터 입력을 받아서 AX에 저장하는 명령어로 보인다. 이렇게만 보면 어떻게 사용되는 건지 도통 알 수가 없어서, IDA에서 해당 명령어를 찾아보자.

 

 

- Search 탭의 sequence of bytes를 눌러서 "ed"를 검색해서 찾아보았다.

 

 

- 해당 명령어를 눌러서 점프해 보니, 명령어 실행 전에 eax로 "VMX"라는 문자열을, edx로는 "VX"라는 문자열을 저장한 것을 볼 수 있었다. VMX, VX라는 문자열은 가상화를 의미하는 문자열이기도 하다.

 

+) 해당 명령어를 실행하는 함수(0x10006196)의 상호 참조 영역들을 살펴보니, 다음과 같이 가상머신 환경을 감지하는 데 사용되는 것으로 짐작된다. 자세한 내용은 17장에서 배울 수 있다고 한다.

 

 

18. 0x1001D988로 점프해보자. 무엇을 찾을 수 있는가?

 

 

- 0x1001D988로 점프를 해보면 위와 같이 의미를 알 수 없는 문자들이 나열된 것을 볼 수 있다.

 

 

19. IDA 파이썬 플러그인을 설치했다면(IDA Pro 상용버전에는 포함돼 있음) Lab05-01.py를 실행해보자. IDA 파이썬 스크립트는 이 책의 악성코드와 함께 제공한다.(커서가 0x1001D988에 위치해야 함) 스크립트 실행 후 무슨 일이 일어났는가?

 

 

- 질문에서 요구한대로 커서를 0x1001D988위에 위치시킨 후, 위 사진처럼 File -> Python file을 눌러 Lab05-01.py를 실행시킬 수 있다.

 

 

- 실행시킨 결과, 아까는 읽을 수 없던 문자들이 이제는 읽을 수 있는 문자들의 나열이 되었다.

 

 

20. 동일한 위치에 커서를 두고 이 데이터를 ASCII 문자열로 어떻게 변환할 수 있는가?

 

 

- 위의 문자열을 보기 좋게 ASCII 문자열로 변환하려면 우클릭 후 위처럼 문자열로 바꾸는 부분을 누르거나, 간단하게 단축키 "A"를 누르면 아래 사진처럼 보기 좋게 문자열로 변환해준다.

 

 

 

21. 문자 편집기로 스크립트를 열어보자. 어떻게 동작하는가?

 

 

- 스크립트는 위와 같이 짜여있는 것을 볼 수 있다. 화면에서 선택된 부분부터 +0x50 지점까지 바이트를 하나씩 읽어와 xor 0x55 암호화를 하는 방식으로 동작한다.