You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

x64 detour开发中rsp/rbp/r15寄存器异常变化问题排查

问题根因

你的寄存器值根本没有发生异常变化,问题出在转储代码的偏移量写错,导致后续写入的flags值覆盖了之前存储的r15、rsp、rbp的转储结果,你读到的第一次转储的三个寄存器值是被污染的错误值,不是真实的寄存器状态。

具体错误点

你代码里所有寄存器转储的偏移都加了0x前缀表示十六进制,唯独两次存储flags的偏移漏写了0x:

  • 第一次存flags你写的是mov [rax+100], rcx,这里的100是十进制值,对应地址偏移0x64,但你实际想写的应该是十六进制偏移0x100(和第二次存flags的0x108位置对应)。
  • 第二次存flags你写的是mov [rax+108], rcx,这里的108也是十进制值,对应地址偏移0x6C,你实际想写的是十六进制偏移0x108。

污染过程复现

你设置的转储内存起始地址是0x1C122560000,第一次转储寄存器时的内存布局是:

  • 偏移0x60~0x67:存储r15的8字节值
  • 偏移0x68~0x6F:存储rsp的8字节值
  • 偏移0x70~0x77:存储rbp的8字节值
  1. 你第一次存flags时,往偏移0x64写入了8字节的flags值(你的测试里flags为0),写入范围覆盖0x64~0x6B:
    • 覆盖了r15存储区的高4字节(0x64~0x67)为0,导致读出来的r15_1是被篡改后的值
    • 覆盖了rsp存储区的低4字节(0x68~0x6B)为0,导致读出来的rsp_1是被篡改后的值
  2. 你的push/pop序列是完全对等的,14次push对应14次pop,执行完后所有寄存器(包括r15、rsp、rbp)都恢复到了push前的真实状态,没有任何修改。
  3. 你第二次转储寄存器时,从偏移0x78开始写入,所有寄存器的存储偏移都正确,没有发生覆盖,所以读到的r15_2、rsp_2、rbp_2都是真实值。
  4. 你第二次存flags时,往偏移0x6C写入8字节0,写入范围覆盖0x6C`0x73`,刚好覆盖了第一次转储的rbp存储区的低4字节(`0x70`0x73)为0,导致读出来的rbp_1是被篡改后的值。
    这也完美解释了为什么只有r15、rsp、rbp三个值“异常”,其余寄存器的存储位置都在0x60之前,不会被两次错误偏移的flags写入影响,所以两次读到的值完全一致。
对你现有方案的修正建议
  • 首先修正转储代码的数制错误:把两次存flags的偏移改成十六进制,即mov [rax+0x100], rcx和mov [rax+0x108], rcx,修正后再读转储结果就会发现三个寄存器值前后完全一致。
  • 你的push/pop保存寄存器的思路本身是可行的,但必须把detour函数声明为裸函数(MSVC下用__declspec(naked)修饰),否则编译器会自动在你写的汇编前插入函数序言(prolog)、末尾插入函数尾声(epilog),自动修改rsp、rbp和非易失寄存器(r12~r15、rbx、rdi、rsi),你写的汇编不会是detour入口第一时间执行的代码,最后直接ret也会导致执行流错误。
  • 如果你要在detour逻辑中修改rsp、rbp,也需要把这两个寄存器加入push/pop的保存序列,测试时空逻辑不修改这两个寄存器的话可以不用额外保存。

内容的提问来源于stack exchange,提问作者QuestionCurioused

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.02 23:57:19