악성코드에 포함된 Shellcode를 보면 원하는 DLL를 로딩하기 위해 PEB(Process Environment Blcok)에서 DLL의 Base Address를 가져온다. 이 과정을 윈도우 XP와 7으로 나누어 살펴보자.


[윈도우 XP]

먼저 PEB의 구조를 그림으로 나타내면 아래와 같다. PEB 구조체의 LDR 멤버는 _PEB_LDR_DATA 구조체의 포인터이다. 그리고 _PEB_LDR_DATA 구조체에는 양방향 연결 리스트인 _LIST_ENTRY 타입의 InLoadOrderMoudleList, InMemoryOrderModuleList, InInitializationOrderModuleList라는 세 가지 멤버를 가지고 있다. 이 멈버들은 각각 _LDR_DATA_TABLE_ENTRY 구조체의 InLoadOrderLinks, InMemoryOrderLinks, InInitializationOrderLinks 멤버의 포인터이다. 바로 이 _LDR_DATA_TABE_ENTRY 구조체가 프로세스 정보와 프로세스에 로딩되는 DLL의 정보를 가지고 있고, 이 구조체를 이용하여 로딩되는 DLL의 Base Address를 직접 구할 수 있다. 즉, 프로세스에 로딩되는 DLL마다 _LDR_DATA_TABLE_ENTRY 구조체가 하나씩 생성되는데, 연결 방법이 세 가지인 것이다. 첫 번째 _LDR_DATA_TABLE_ENTRY는 해당 process의 정보를, 두 번째는 ntdll.dll의 정보, 세 번째는 kernel32.dll의 정보를 가지고 있다. 프로세스에 로딩되는 순서에 따라 연결 리스크가 형성되는 것 같다. 


주의해야 할 것은 InLoadOrderModuleLinks와 InMemoryOrderLinks는 순차적으로 연결되는 것에 반해, InInitializationOrderLinks는 그렇지 않다. _PEB_LDR_DATA.InInitializationOrderModuleList는  첫 번째 _LDR_DATA_TABLE_ENTRY가 아닌 두 번째 _LDR_DATA_TABLE_ENTRY의 InInitializationOrderLinks를 가리킨다. ntdll.dll은 kernel32.dll과 연결되지만, kernel32.dll은 그 다음 _LDR_DATA_TABLE_ENTRY가 아닌 다른(3번 건너띈) _LDR_DATA_TABLE_ENTRY와 연결된다. (이 부분은 해당 글에서 다루는 범위를 넘어서므로 설명하지 않는다.)




이번에는 실제 shellcode에서 kernel32.dll의 Base Address를 구하는 assembly를 보면 아래와 같다. FS:[30]으로 PEB의 주소를 구하고, _PEB.LDR과 PEB_LDR_DATA.InInitalizationOrderModuleList을 따라가서 ntdll의 _LDR_DATA_TABLE_ENTRY 구조체로 들어간다. 그리고 그 다음 _LDR_DATA_TABLE_ENTRY.DllBase 멤버에서 kernel32.dll의 Base Address를 가져온다.




위 과정을 WinDbg로 분석해 보면 아래와 같다. 첫 번째 _LDR_DATA_TABLE_ENTRY는 현재 process의 정보를 가지고 있고, 두 번째와 세 번째 _LDR_DATA_TABLE_ENTRY는 각각 ntdll.dll과 kernel32.dll의 정보를 가지고 있다. process의 _LDR_DATA_TABLE_ENTRY.InInitializationOrderLinks 멤버의 값은 0으로 다른 LDR과 연결되지 않는다.





[윈도우 7]

윈도우 7부터 kernelbase.dll이라는 새로운 dll이 추가되었다. 윈도우 7 이전에는 kernel32.dll 함수들이 ntdll.dll 함수를 호출하였지만, 윈도우 7부터는 kernel32.dll 함수는 kernelbase.dll 함수를 호출하고 kernelbase.dll 함수는 ntdll.dll의 함수를 호출한다. 따라서 _LDR_DATA_TABLE_ENTRY의 연결 리스트도 약간에 변화가 생겼다. 좀 더 자세하게 설명하기 위해 FLink와 BLink를 나눠서 그렸다.


ntdll.dll의 _LDR_DATA_TABLE_ENTRY.InInitializationOrderLinks가 kernel32.dll을 가리키는 것이 아니라 KERNELBA를 가리킨다. 그리고 KERNELBA는 kernel32.dll과 연결된다. 따라서 윈도우 7에서 위의 shellcode를 실행시키면 kernel32.dll의 Base Address가 아닌 KERNELBA의 Base Address를 가져온다.







Posted by Lim Jun Young

댓글을 달아 주세요