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 |