使用C++ DLL挂钩x86程序指令后执行崩溃的问题排查求助
C++ DLL挂钩x86程序指令后执行崩溃的问题排查求助
看起来你的挂钩核心思路是通顺的,但程序崩溃大概率是栈/寄存器上下文被破坏导致的,我帮你梳理几个关键的问题点和修复方案:
1. 裸函数中的push esp/pop esp是致命错误
你的MyFun_Wrapper里的push esp和pop esp完全多余,而且会直接破坏栈结构:
- 执行
push esp时,esp已经因为之前的push ebx/push ecx等操作被修改,此时压栈的是当前的esp值 - 后续
pop esp会把esp强制恢复到这个被修改后的值,导致后面的pop ebp/pop edi等操作从错误的栈地址取值,直接造成栈不平衡,程序必然崩溃
解决方法:直接删掉push esp和pop esp这两行代码。
2. 通用寄存器的保存可以更可靠(避免遗漏)
你手动push/pop了多个寄存器,但x86平台有pushad/popad指令可以一次性保存/恢复所有8个通用寄存器(EAX、ECX、EDX、EBX、ESP、EBP、ESI、EDI),不仅代码更简洁,还能避免漏存寄存器的问题。
修改后的裸函数可以简化成这样:
extern "C" __declspec(dllexport) __declspec(naked) noinl void MyFun_Wrapper() { __asm { pushfd // 保存标志寄存器 pushad // 一次性保存所有通用寄存器 // 传递参数:原EAX和EDI(此时寄存器值还没被修改) push edi push eax call MyFun add esp, 8 // 清理栈上的两个参数 // MyFun的返回值已经在EAX里,不需要额外操作 popad // 恢复所有通用寄存器 // 执行原ADD指令的等效逻辑:用新EAX值更新结构体 add [edi + 0x194], eax popfd // 恢复标志寄存器 jmp jump_back // 跳回原程序继续执行 } }
3. 浮点数寄存器上下文的破坏(你提到了浮点数操作)
如果MyFun里用到了x87浮点数寄存器(比如fld/fstp等指令)或者SSE寄存器(xmm0-xmm7),这些寄存器的状态没有被保存,原程序后续执行时会因为浮点数上下文被篡改而崩溃。
解决方法:
用fxsave/fxrestore指令保存和恢复浮点数/SSE寄存器状态,需要注意缓冲区要按16字节对齐:
// 在DLL全局区域定义对齐的浮点数状态缓冲区 alignas(16) char fxsave_buf[512]; extern "C" __declspec(dllexport) __declspec(naked) noinl void MyFun_Wrapper() { __asm { pushfd pushad // 保存浮点数/SSE寄存器状态 lea eax, fxsave_buf fxsave [eax] push edi push eax call MyFun add esp, 8 // 恢复浮点数/SSE寄存器状态 lea eax, fxsave_buf fxrestore [eax] popad add [edi + 0x194], eax popfd jmp jump_back } }
4. 额外验证建议
按照上面的修改后,你还可以做两个验证:
- 确认
jump_back的地址是否正确:原ADD指令地址是base + 0x1a0d39,加6字节后正好是base + 0x1a0d3f,这部分你是对的,但要确保赋值的是虚拟地址而非相对偏移 - 用x64dbg等调试器挂到目标程序,在
MyFun_Wrapper的jmp jump_back处下断点,检查此时的ESP、EBP寄存器是否和进入包装器时一致(除了EAX被修改为自定义值)
按照这些步骤调整后,应该能解决崩溃问题。
内容来源于stack exchange
相关产品推荐
相关产品推荐

