使用MS Detours挂钩函数后RAX寄存器值异常的问题
问题描述
正常未挂钩时,在EXE地址242685处断点,RAX寄存器包含游戏数据指针;但挂钩后在此处断点,RAX值为0。若将Objects_detour改为void*返回类型,RAX变为某个指针,但并非游戏数据指针。请问哪里操作错误?RAX值不应被改变才对?
相关代码与汇编
Hook代码
DetourTransactionBegin(); DetourUpdateThread(GetCurrentThread()); DetourAttach(&Objects_orig, Objects_detour); DetourTransactionCommit();
Detour函数
void Objects_detour(uint64_t a1, int a2, int a3) { return Objects_orig(a1,a2,a3); }
头文件定义
void Objects_detour(uint64_t a1, int a2, int a3); typedef void(*Objects_deb)(uint64_t a1, int a2, int a3); inline Objects_deb Objects_orig = nullptr;
原EXE汇编代码
.exe+24267F - CC - int 3 .exe+242680 - 44 89 44 24 18 - mov [rsp+18],r8d .exe+242685 - 89 54 24 10 - mov [rsp+10],edx
挂钩后的EXE汇编代码
.exe+24267F - CC - int 3 .exe+242680 - E9 F3DAFEBF - jmp 7FF766E50178 .exe+242685 - 89 54 24 10 - mov [rsp+10],edx
问题分析与解决
核心问题是你定义的函数签名和原函数不匹配。x64调用约定下,RAX寄存器专门用于存储函数返回值,未挂钩时RAX在断点处有有效数据指针,说明原函数绝对不是void类型。
错误原因:
- 你把原函数类型定义为
void(*Objects_deb)(...),hook函数也用void返回类型,编译器生成的代码会在函数返回时清空RAX,导致回到原断点处RAX值被修改为0。 - 改成
void*后结果不对,是因为你仍未匹配原函数的真实返回类型,或者没有正确传递原函数的返回值。
- 你把原函数类型定义为
修复步骤:
- 先确定原函数的正确返回类型:从RAX存储游戏数据指针的现象来看,原函数应该返回对应的数据结构指针(比如
uint64_t*或自定义结构体指针,需根据实际逻辑确认)。 - 同步修改头文件定义和hook函数的返回类型,确保和原函数完全一致,并且在hook中正确返回原函数的结果:
// 示例:假设原函数返回uint64_t类型指针,需根据实际情况调整 uint64_t* Objects_detour(uint64_t a1, int a2, int a3) { return Objects_orig(a1,a2,a3); } // 头文件同步修改 uint64_t* Objects_detour(uint64_t a1, int a2, int a3); typedef uint64_t*(*Objects_deb)(uint64_t a1, int a2, int a3); inline Objects_deb Objects_orig = nullptr; - 这样原函数的返回值会通过RAX正确传递,回到原断点处RAX的值就会和未挂钩时一致。
- 先确定原函数的正确返回类型:从RAX存储游戏数据指针的现象来看,原函数应该返回对应的数据结构指针(比如
另外要注意,x64调用约定中除了返回值,寄存器的保存规则也有要求——Detour本身会处理寄存器的保存,但如果函数签名错误,编译器生成的代码会破坏寄存器状态,直接导致返回后RAX不符合预期。
内容的提问来源于stack exchange,提问作者ayes l
相关产品推荐
相关产品推荐

