C/C++Windows黑客编程系列——InlineHook实现
InlineHook
#include <stdio.h>
#include <windows.h>
// 保存原函数机器指令
BYTE originalApiByte[20] = {0,};
// 自定义新函数执行流程
int WINAPI newMessageBoxA(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType) {
// 为调用原API,这里需要进行脱钩
unHookApiMessageBoxA();
// 命令行程序没有引入user32,所以使用LoadLibrary
HMODULE hDll = LoadLibrary("user32.dll");
if (NULL == hDll) {
return FALSE;
}
// 获取函数的导出地址
FARPROC oldMessageBoxA = GetProcAddress(hDll, "MessageBoxA");
if (NULL == oldMessageBoxA) {
return FALSE;
}
int iRet = (int) oldMessageBoxA(hWnd, "i am nobody", "who are you?", MB_YESNO);
// 再进行hook,方便下次钩取
hookApiMessageBoxA();
return iRet;
}
// Unhook Api
BOOL unHookApiMessageBoxA() {
// 获取 user32.dll模块加载基址
HMODULE hDll = LoadLibrary("user32.dll");
if (NULL == hDll) {
return FALSE;
}
// 获取函数的导出地址
PVOID oldMessageBoxA = GetProcAddress(hDll, "MessageBoxA");
if (NULL == oldMessageBoxA) {
return FALSE;
}
// 计算写入的前几字节数据, 32位下5字节, 64位下12字节
# ifndef _WIN64
DWORD dwNewDataSize = 5;
# else
DWORD dwNewDataSize = 12;
# endif
// 设置页面的保护属性为 可读、可写、可执行
DWORD dwOldProtect = 0;
VirtualProtect(oldMessageBoxA, dwNewDataSize, PAGE_EXECUTE_READWRITE, &dwOldProtect);
// 恢复数据
memcpy(oldMessageBoxA, originalApiByte, dwNewDataSize);
// 还原页面保护属性
VirtualProtect(oldMessageBoxA, dwNewDataSize, dwOldProtect, &dwOldProtect);
return TRUE;
}
BOOL hookApiMessageBoxA() {
// 获取user32.dll模块加载基址
HMODULE hDll = LoadLibrary("user32.dll");
if (NULL == hDll) {
return FALSE;
}
// 获取MessageBoxA函数的导出地址
PVOID oldMessageBoxA = GetProcAddress(hDll, "MessageBoxA");
if (NULL == oldMessageBoxA) {
return FALSE;
}
// 计算写入的前几字节数据, 32位下5字节, 64位下12字节
# ifndef _WIN64
/*
32位汇编代码:jmp funcAddress(4字节函数指针)
机器码指令:e9 funcAddress(跳转偏移)
addr1 --> jmp funcAddress指令的下一条指令的地址,即eip的值
addr2 --> 跳转地址的值,即新函数指针所在地址的值
跳转偏移计算公式: offset = addr2 - addr1 - 5
*/
BYTE pNewData[5] = {0xe9, 0, 0, 0, 0};
DWORD dwNewDataSize = 5;
DWORD dwOffset = 0;
// 计算跳转偏移,32位系统jmp funAddress对应的机器指令本身占用5个字节
dwOffset = (DWORD)NewMessageBoxA - ((DWORD)oldMessageBoxA + 5);
RtlCopyMemory(&pNewData[1], &dwOffset, sizeof(dwOffset));
# else
/*
64位汇编代码:mov rax, funcAddress(真实函数地址,如:0x1122334455667788)
jmp rax
机器码指令:48 b8 funcAddress(0x1122334455667788)
ff e0
*/
BYTE pNewData[12] = {0x48, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xe0};
DWORD dwNewDataSize = 12;
ULONGLONG ullNewFuncAddr = (ULONGLONG) newMessageBoxA;
RtlCopyMemory(&pNewData[2], &ullNewFuncAddr, sizeof(ullNewFuncAddr));
# endif
// 设置页面的保护属性为 可读、可写、可执行
DWORD dwOldProtect = 0;
VirtualProtect(oldMessageBoxA, dwNewDataSize, PAGE_EXECUTE_READWRITE, &dwOldProtect);
// 保存原始数据
RtlCopyMemory(originalApiByte, oldMessageBoxA, dwNewDataSize);
// 开始修改 MessageBoxA 函数的前几字节数据, 实现 Inline Hook API
RtlCopyMemory(oldMessageBoxA, pNewData, dwNewDataSize);
// 还原页面保护属性
VirtualProtect(oldMessageBoxA, dwNewDataSize, dwOldProtect, &dwOldProtect);
return TRUE;
}
int main() {
MessageBoxA(NULL, "before hook", "tips", MB_OK);
hookApiMessageBoxA();
MessageBoxA(NULL, "after hook", "tips", MB_OK);
unHookApiMessageBoxA();
MessageBoxA(NULL, "after unhook", "tips", MB_OK);
}
二、效果
本作品采用《CC 协议》,转载必须注明作者和本文链接