Inline Hook也是光听说过没练过,今天自己动手还是遇到了不少问题,主要是替换后的函数如何调用原函数和平衡其调用堆栈。Demo里没有实现如何先执行被Inline Hook覆盖的代码后跳转到原函数的流程,以后实现后补充。
#include <Windows.h>
#include <tchar.h>
//////////////////////////////////////////////////////////////////////////
// Inline Hook
#define JMP_CODE_SIZE 5
#pragma warning(push)
#pragma warning(disable:4311)
BOOL InlineHook(void* lpOldFunction, void* lpNewFunction)
{
BOOL bRet = FALSE;
byte btCode[JMP_CODE_SIZE] = {0xE9}; // 5字节相对跳转指令
do
{
if(NULL == lpOldFunction || NULL == lpNewFunction)
{
break;
}
DWORD* pdwAddr = (DWORD*)&btCode[1];
*pdwAddr = (DWORD)lpNewFunction – (DWORD)lpOldFunction – JMP_CODE_SIZE; // 计算相对跳转地址
DWORD dwProtect = 0;
if(VirtualProtect(lpOldFunction, JMP_CODE_SIZE, PAGE_READWRITE, &dwProtect))
{
memcpy(lpOldFunction, btCode, JMP_CODE_SIZE);
VirtualProtect(lpOldFunction, JMP_CODE_SIZE, dwProtect, &dwProtect);
bRet = TRUE;
}
} while (0);
return bRet;
}
#pragma warning(pop)
// 用于恢复Inline Hook
void* g_lpMessageBoxA = NULL;
byte g_btCode[JMP_CODE_SIZE] = {0};
//////////////////////////////////////////////////////////////////////////
// 真正实现MessageBoxA, MyMessageBoxA只是一个马甲
int WINAPI InternalMessageBoxA(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType)
{
MessageBoxW(NULL, L”In MyMessageBoxA”, L”InlineHook”, MB_OK);
// 还原Inline Hook
DWORD dwProtect = 0;
if(VirtualProtect(g_lpMessageBoxA, JMP_CODE_SIZE, PAGE_READWRITE, &dwProtect))
{
memcpy(g_lpMessageBoxA, g_btCode, JMP_CODE_SIZE);
VirtualProtect(g_lpMessageBoxA, JMP_CODE_SIZE, dwProtect, &dwProtect);
}
// 调回真正的MessageBoxA
return MessageBoxA(hWnd, lpText, lpCaption, uType);
}
//////////////////////////////////////////////////////////////////////////
// Inline Hook用MyMessageBoxA替换MessageBoxA
// 编译器生成代码时会在函数前后增加一些堆栈平衡的代码, 导致直接ret 10h堆栈并不会平衡
// 因此需要使用_declspec(naked)修饰, 但函数内需要自己控制寄存器
_declspec(naked) int WINAPI MyMessageBoxA(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType)
{
// 堆栈平衡
_asm
{
push ebp
mov ebp, esp
push dword ptr[ebp+0x14]
push dword ptr[ebp+0x10]
push dword ptr[ebp+0xC]
push dword ptr[ebp+0x8]
call InternalMessageBoxA
pop ebp
ret 10h ; 由于没有jmp回被Inline Hook的函数, 因此需要平衡堆栈.
}
}
int _tmain(int argc, TCHAR* argv[])
{
HMODULE hLib = LoadLibrary(_T(“user32.dll”));
if(hLib != NULL)
{
g_lpMessageBoxA = GetProcAddress(hLib, “MessageBoxA”);
memcpy(g_btCode, g_lpMessageBoxA, JMP_CODE_SIZE); // 保存即将覆盖的5字节代码
InlineHook(g_lpMessageBoxA, MyMessageBoxA); // Inline Hook MessageBoxA到MyMessageBoxA
MessageBoxA(NULL, “Real MessageBoxA”, “InlineHook”, MB_OK);
FreeLibrary(hLib);
}
return 0;
}