Trampoline Code Hooking은 후킹할 함수의 첫 부분에 jmp 코드로 후킹 함수로 실행 흐름이 이동하도록 한다.
이 때 jmp 코드로 덮어진 부분은 저장해 두었다가 후킹 함수에서 원래 함수를 정상적으로 처리할 수 있도록 해준다.
아래에 실습할 MessageBox를 조작하는 방법은 아래와 같다.
1. 원본코드의 첫 5바이트에 hook 코드로 점프하도록 패치
2. hook코드로 넘어오면 원본코드 언훅 후 파라미터를 조작해서 호출
3. 다시 원본코드에 후킹 설치
#include "stdio.h" #include "wchar.h" #include "windows.h" #define DEF_USER32 "User32.dll" #define DEF_MBOX "MessageBoxA" typedef BOOL (WINAPI *PFMessageBox)(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType); // global variable BYTE g_pOrgBytes[5] = {0,}; BOOL hook_code(LPCSTR szDllName, LPCSTR szFuncName, PROC pfNew) { FARPROC pfOrg; DWORD dwOldProtect, dwAddress; BYTE pBuf[5] = {0xE9, 0, }; PBYTE pByte; // 후킹 대상 API 주소를 구한다 pfOrg = (FARPROC)GetProcAddress(GetModuleHandleA(szDllName), szFuncName); pByte = (PBYTE)pfOrg; // 만약 이미 후킹 되어 있다면 return FALSE if( pByte[0] == 0xE9 ) return FALSE; // 5 byte 패치를 위하여 메모리에 WRITE 속성 추가 VirtualProtect((LPVOID)pfOrg, 5, PAGE_EXECUTE_READWRITE, &dwOldProtect); // 기존 코드 (5 byte) 백업 memcpy(g_pOrgBytes, pfOrg, 5); // JMP 주소 계산 (E9 XXXX) // => XXXX = pfNew - pfOrg - 5 dwAddress = (DWORD)pfNew - (DWORD)pfOrg - 5; memcpy(&pBuf[1], &dwAddress, 4); // Hook - 5 byte 패치 (JMP XXXX) memcpy(pfOrg, pBuf, 5); // 메모리 속성 복원 VirtualProtect((LPVOID)pfOrg, 5, dwOldProtect, &dwOldProtect); return TRUE; } BOOL unhook_code(LPCSTR szDllName, LPCSTR szFuncName) { FARPROC pFunc; DWORD dwOldProtect; PBYTE pByte; // API 주소 구한다 pFunc = GetProcAddress(GetModuleHandleA(szDllName), szFuncName); pByte = (PBYTE)pFunc; // 만약 이미 언후킹 되어 있다면 return FALSE if( pByte[0] != 0xE9 ) return FALSE; // 원래 코드(5 byte)를 덮어쓰기 위해 메모리에 WRITE 속성 추가 VirtualProtect((LPVOID)pFunc, 5, PAGE_EXECUTE_READWRITE, &dwOldProtect); // Unhook memcpy(pFunc, g_pOrgBytes, 5); // 메모리 속성 복원 VirtualProtect((LPVOID)pFunc, 5, dwOldProtect, &dwOldProtect); return TRUE; } BOOL WINAPI MyMessageBox(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType) { char ChangeStr[20] = "Hello Hooking ~~!"; FARPROC pforg_mbox; DWORD return_val; // 작업 전에 unhook unhook_code(DEF_USER32, DEF_MBOX); pforg_mbox = GetProcAddress(GetModuleHandleA(DEF_USER32), DEF_MBOX); return_val = ((PFMessageBox)pforg_mbox)(hWnd, (LPCTSTR)ChangeStr, lpCaption, uType); hook_code(DEF_USER32, DEF_MBOX, (PROC)MyMessageBox); return return_val; } BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { switch( fdwReason ) { case DLL_PROCESS_ATTACH: hook_code(DEF_USER32, DEF_MBOX, (PROC)MyMessageBox); // MessageBoxA를 MyMessageBox로 jmp하도록 패치 break; case DLL_PROCESS_DETACH: unhook_code(DEF_USER32, DEF_MBOX); break; } return TRUE; }
위에서 만든 DLL을 인젝션 시켜주면 아래와 같이 후킹이 성공한 것을 확인할 수 있다.
디버거로 MessageBoxA를 따라 들어가보면 아래와 같이 "jmp 100110c3"으로 패치되어 후킹된 함수로 점프하는 것을 확인할 수 있다.
후킹 함수에서는 "Hello Hooking ~~!"으로 파라미터를 변경한 후 언훅된 MessageBox를 호출한다.
'Programming > Win_API' 카테고리의 다른 글
ANSI, WIDE, TCHAR 함수들 (0) | 2014.01.08 |
---|---|
실행 중인 Class, Caption, Process 이름 구하기 (0) | 2014.01.08 |
API Hooking - [2] DLL Injection + IAT (1) | 2013.11.24 |
API Hooking - [1] Debugger Attach + 0xCC (1) | 2013.11.23 |
API Hooking 정리 (0) | 2013.11.10 |