Windows API钩子实现异常:Hook后未触发目标消息框求助
Windows API钩子异常问题排查与修复
问题核心分析
你的代码存在两个致命错误,直接导致钩子安装后程序崩溃:
- 相对偏移量计算错误:
rOffset = (DWORD *)(dst-src);这行把偏移量数值强制转成指针,后续复制的是指针地址而非偏移量本身,生成的跳转指令地址完全非法,触发内存访问违规。 - 未修改内存页保护属性:DLL代码段默认是只读+执行权限,直接调用
WriteProcessMemory写入会触发系统内存保护机制,导致程序直接终止。
修复后的完整钩子代码
#include <windows.h> // 全局变量:保存原始指令字节与被Hook函数地址 BYTE originalBytes[5] = {0}; LPVOID hookedAddress = nullptr; // 定义被Hook函数的类型 typedef void (*CatFunc)(const char*); CatFunc catFunc = nullptr; // Hook触发后的自定义函数 void myFunc(const char* msg) { MessageBoxA(NULL, "Hook触发!", "提示", MB_OK); // 恢复原始指令,调用原函数 WriteProcessMemory(GetCurrentProcess(), hookedAddress, originalBytes, 5, NULL); catFunc(msg); // 重新安装Hook,保证后续调用仍能触发 setMySuperHook(); } void setMySuperHook() { HINSTANCE hLib; VOID* myFuncAddress; DWORD rOffset; DWORD src; DWORD dst; BYTE patch[5] = {0}; // 第一次调用时初始化函数地址与原始指令 if (!hookedAddress) { hLib = LoadLibraryA("pet.dll"); hookedAddress = GetProcAddress(hLib, "Cat"); catFunc = (CatFunc)hookedAddress; ReadProcessMemory(GetCurrentProcess(), hookedAddress, originalBytes, 5, NULL); } myFuncAddress = &myFunc; // 计算E9跳转的相对偏移:目标地址 - (源地址 + 5) src = (DWORD)hookedAddress + 5; dst = (DWORD)myFuncAddress; rOffset = dst - src; // 构造跳转指令:0xE9是相对跳转操作码,后面跟4字节偏移 patch[0] = 0xE9; memcpy(patch + 1, &rOffset, 4); // 修改内存页权限为可写,避免写入失败 DWORD oldProtect; VirtualProtect(hookedAddress, 5, PAGE_EXECUTE_READWRITE, &oldProtect); // 写入跳转指令 WriteProcessMemory(GetCurrentProcess(), hookedAddress, patch, 5, NULL); // 恢复内存页原权限 VirtualProtect(hookedAddress, 5, oldProtect, &oldProtect); } int main() { // 加载DLL并获取原始函数地址 HINSTANCE hLib = LoadLibraryA("pet.dll"); catFunc = (CatFunc)GetProcAddress(hLib, "Cat"); // 调用原始Cat函数 catFunc("meow-meow"); // 安装Hook setMySuperHook(); // 调用Hook后的Cat函数 catFunc("meow-meow"); FreeLibrary(hLib); return 0; }
关键修复点说明
- 偏移量计算修正:直接用
rOffset = dst - src;计算合法的相对偏移,将数值本身复制到跳转指令中,而非指针地址。 - 内存权限处理:通过
VirtualProtect临时修改目标内存页为可写,写入完成后恢复原权限,绕过系统内存保护。 - Hook生命周期维护:在自定义函数中先恢复原始指令调用原函数,再重新安装Hook,确保后续调用仍能触发钩子逻辑。
x64dbg调试查错步骤
- 附加进程:打开x64dbg,点击
File->Attach选择你的程序进程。 - 设置断点:在命令框输入
bp pet.dll!Cat,回车设置Cat函数的断点。 - 运行追踪:点击
Run按钮,程序会在调用Cat函数时暂停,查看函数开头的5字节内容,确认是否写入了0xE9开头的跳转指令。 - 崩溃定位:若程序崩溃,x64dbg会自动暂停,查看
Call Stack窗口可定位崩溃位置,检查内存地址是否合法、指令是否被正确写入。
常见疑问解答
- 为什么用5字节?:x86架构下
E9相对跳转指令是1字节操作码+4字节偏移,刚好覆盖多数函数开头的单字节指令(如push ebp),基础场景下足够使用。 - 为何之前正常现在异常?:可能是编译环境切换(Debug/Release)、DLL文件更新导致函数开头指令变化,或是系统内存保护机制触发条件改变。
内容的提问来源于stack exchange,提问作者movies netflix
相关产品推荐
相关产品推荐

