From AppInit_DLLs To Injection
2011/09/28 07:04

다음의 윈도우즈 레지스트리에 DLL 파일의 경로를 입력하면, 이후 새로운 프로세스가 생성될 때마다 키값에 입력된 DLL 파일이 프로세스에 인젝션됩니다.
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Windows\AppInit_DLLsuser32.dll이 프로세스에 적재되면서 DllMain 함수에서 레지스트리 키값을 열람하고 DLL을 적재할거라고 생각할 수 있지만, 그렇지 않습니다. AppInit_DLLs의 DLL 파일은 시스템 DLL 파일들이 적재된 이후에 프로세스 초기화 과정에서 프로세스에 적재됩니다.

프로세스 초기화 과정 중에 gdi32.dll의 GdiDllInitialize 함수가 수행됩니다. 이 과정에서 운영체제는 이미 적재된 user32.dll의 ClientThreadSetup 콜백 함수를 호출합니다. [그림 2]와 같이 PEB(Process Environment Block)1의 KernelCallbackTable에 저장된 콜백 함수의 주소를 참조합니다.

바야흐로, 이 ClientThreadSetup 함수에서 AppInit_DLLs를 읽습니다. [그림 2]에서 볼 수 있듯이, 일반적으로 레지스트리를 조회할 때 쓰이는 RegOpenKey, RegQueryValue와 같은 API들이 쓰이지 않습니다. 여기서는 네이티브 함수를 바로 호출하는 ZwOpenKey2와 ZwQueryValueKey3 함수를 사용합니다. 그래서 디버거로 볼 때, 윈도우즈 API에 BP(Break Point)를 걸고 달려도 AppInit_DLLs를 조회하는 것을 잡을 수 없습니다. ZwQueryValueKey에 BP를 걸고 달려야 하죠. 인자로 넘어가는 Buffer에 키값이 저장되는데, 이 구조는 InfoClass에 따라서 변경됩니다. InfoClass가 2이면, KeyValuePartialInformation 구조체로 Buffer에 저장됩니다.
KeyValuePartialInformation 구조체의 정의는 다음과 같습니다.
typedef struct _KEY_VALUE_PARTIAL_INFORMATION {
ULONG TitleIndex;
ULONG Type;
ULONG DataLength;
UCHAR Data[1];
} KEY_VALUE_PARTIAL_INFORMATION, *PKEY_VALUE_PARTIAL_INFORMATION;구조체의 네 번째 요소인 Data[1]에 키값의 문자열이 저장됩니다. UCHAR Data[1]의 의미4는 길이가 정해지지 않은 데이터를 담기 위한 더미 변수입니다. KeyValuePartialInformation가 헤더이고, DataLength 값만큼 뒤에 바디가 붙는것이죠.

Buffer에 DLL 파일의 경로가 쓰여 있으면, LoadLibraryW로 프로세스에 적재합니다. 만약 값이 비어 있으면, LoadLibraryW를 호출하는 루틴을 건너뜁니다.

LoadLibraryW가 호출되는 시점에 DLL 파일이 프로세스에 적재됩니다. AppInit_DLLs를 이용한 DLL 인젝션은 인젝션이 이루어진 이후부터 실행되는 프로세스에 대하여 유효합니다. 레지스트리에 저장되는 값이기 때문에 윈도우즈가 재부팅되어도 유효합니다. 지금까지 보았듯이, 프로세스가 실행될 때마다 프로세스 초기화 과정 중에 인젝션이 되죠.
주석.
"0x02 Windows RCE" 분류의 다른 글
| 게임 매크로 Inventory A+ 분석 | 2012/02/15 |
| DumpFromOEP.py for Immunity Debugger | 2011/10/22 |
| Windows Debugging Intrenals: A to Z | 2011/08/28 |
| IsDebuggerPresent 그리고 패치 | 2011/07/04 |
| API Redirect on Themida | 2011/02/27 |
Trackback Address:http://hisjournal.net/blog/trackback/372