이번에는 IAT Hooking으로 실행흐름에서 제어권을 가져오고 DLL Injection으로 원하는 동작을 하는 코드를 실행시키는 방법으로 실습해보겠다.
대상 프로그램은 "API Hooking - [1] Debugger Attach + 0xCC" 에서 실습한 MessageBox를 띄워주는 프로그램을 가지고 동일하게 "Hello World" 문자열을 "Hello Hooking" 문자열로 띄워지도록 후킹을 해보겠다.
IAT 후킹 코드는 아래의 IAT에 접근하는 방법을 보면 이해하기 쉬울 것이다.
IMAGE_DIRECTORY_ENTRY_IMPORT
|-------------------|
| VirtualAddress |
|-------------------|
| Size |
|-------------------|
VirtualAddress + ImageBase가 IMAGE_IMPORT_DESCRIPTOR의 가상주소를 가진다.
IMAGE_IMPORT_DESCRIPTOR (임포트 테이블)
|----------------------|
| OriginalFirstThunk | -> INT(IMPORT_NAME_TABLE) 주소
|----------------------|
| TimeDateStamp |
|----------------------|
| ForwarderChain |
|----------------------|
| Name | -> DLL name 주소
|----------------------|
| FirstThunk | -> IAT(IMPORT_ADDRESS_TABLE) 주소
|----------------------|
1. IID테이블의 Name으로 DLL을 먼저 탐색한다.
2. 검색한 DLL의 IID테이블에서 FirstThunk를 탐색하여 후킹할 API의 주소를 탐색한다.
3. 이전 과정에서 구한 IAT 영역을 후킹한다.
[실습 소스]
#include "stdio.h" #include "wchar.h" #include "windows.h" typedef BOOL (WINAPI *PFMessageBox)(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType); FARPROC g_pOriginFunc = NULL; BOOL WINAPI MyMessageBox(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType) { char ChangeStr[20] = "Hello Hooking ~~!"; return ((PFMessageBox)g_pOriginFunc)(hWnd, (LPCTSTR)ChangeStr, lpCaption, uType); } BOOL Change_iat(LPCSTR szDllName, PROC pfnOrg, PROC pfnNew) { HMODULE hMod; LPCSTR szLibName; PIMAGE_IMPORT_DESCRIPTOR pImportDesc; PIMAGE_THUNK_DATA pThunk; DWORD dwOldProtect, dwRVA; PBYTE pAddr; hMod = GetModuleHandle(NULL); pAddr = (PBYTE)hMod; //IMAGE_DOS_HEADER pAddr += *((DWORD*)&pAddr[0x3C]); //[e_lfanew] -> IMAGE_NT_HEADERS dwRVA = *((DWORD*)&pAddr[0x80]); //IMAGE_IMPORT_DESCRIPTOR Table의 RVA pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)hMod+dwRVA); //IMAGE_IMPORT_DESCRIPTOR Table의 VA //pImportDesc는 IMAGE_IMPORT_DESCRIPTOR임. -> [OriginalFirstThunk, TimeDateStamp, ForwarderChain, Name, FirstThunk] /* (1). 후킹할 API함수가 있는 DLL이름을 비교하여 찾는다. (2). 후킹할 API함수의 주소와 IAT에 있는 주소가 일치한 곳을 구한다. (3). (2)에서 얻은 IAT 부분을 후킹함수로 바꿔준다. */ for(; pImportDesc->Name; pImportDesc++) { szLibName = (LPCSTR)((DWORD)hMod + pImportDesc->Name); //(1). DLL을 찾기 if( !stricmp(szLibName, szDllName) ) //stricmp : 대소문자 구분없이 비교 { pThunk = (PIMAGE_THUNK_DATA)((DWORD)hMod + pImportDesc->FirstThunk); //IAT의 시작부분을 가리킴. //(2) API함수가 있는 IAT부분 찾기 for(; pThunk->u1.Function; pThunk++) { if( pThunk->u1.Function == (DWORD)pfnOrg) //후킹할 API의 IAT 영역을 찾음 { VirtualProtect((LPVOID)&pThunk->u1.Function, 4, PAGE_EXECUTE_READWRITE, &dwOldProtect); // 메모리 속성 변경 pThunk->u1.Function = (DWORD)pfnNew; // IAT 후킹 VirtualProtect((LPVOID)&pThunk->u1.Function, 4, dwOldProtect, &dwOldProtect); // 메모리 속성 복원 return TRUE; } } } } return FALSE; } BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { switch( fdwReason ) { case DLL_PROCESS_ATTACH: g_pOriginFunc = GetProcAddress(GetModuleHandle(L"User32.dll"), "MessageBoxA"); Change_iat("User32.dll", g_pOriginFunc, (PROC)MyMessageBox); // IAT상에 있는 "1번째 인자의 주소"를 "2번째 인자의 주소"로 변경 break; case DLL_PROCESS_DETACH: Change_iat("User32.dll", (PROC)MyMessageBox, g_pOriginFunc); break; } return TRUE; }
DLL Injection은 http://reversecore.com/에서 받은 Inject.exe프로그램을 사용한다.
프로그램 사용은 InjectDll.exe <pid> <dll_path>와 같이 해준다. 그럼 위에서 만든 IAT 후킹하는 DLL파일을 인젝션 시키면
원하는 대로 후킹이 수행되어 "Hello Hooking"으로 조작시킬 수 있다.
Ollydbg로 MessageBox를 Call하는 부분을 비교해 보면 아래와 같다.
[ 원래의 API Call ]
[ 후킹되서 조작된 API Call ]
'Programming > Win_API' 카테고리의 다른 글
실행 중인 Class, Caption, Process 이름 구하기 (0) | 2014.01.08 |
---|---|
API Hooking - [3] DLL Injection + Trampoline Code Hooking (0) | 2013.12.07 |
API Hooking - [1] Debugger Attach + 0xCC (1) | 2013.11.23 |
API Hooking 정리 (0) | 2013.11.10 |
쓰레드 - 타이머기반 동기화 (0) | 2013.01.03 |