需求
想修改 API 的返回结果。举个例子,想把前文提到的 Windows Release 信息改为 “0618”。

分析
从技术角度看,需求就是在 RegQueryValueExW 返回时,改 lpData 指向的内存。
1 | LSTATUS RegQueryValueExW( |
lpData 为第 5 个参数,根据《x64 软件约定》,它位于栈。具体来说,断点时,rip 处于 call 指令执行完毕的时间点,这时调用方的返回地址已经被压入栈里,所以此时的栈顶为返回地址。按照内存地址递增方向,返回地址后面就是 6 个参数。
实现
- 按照前文方法,断到 DisplayVersion 的读取:
1 | DisplayVersion |
- 用
dq rsp L7显示返回地址和 6 个参数:
1 | 0:000> dq rsp L7 |
其中,00000268`e4a96d10 对应 lpData,000000d7`e975e820 对于 lpcbData。
- 可选地,查看 lpcbData 指向的值,发现它是 0x100:
1 | 0:000> dd 000000d7`e975e820 L1 |
- 输入 gu 运行到函数返回,再查看 lpData 的内容:
1 | 0:000> gu |
- 用 eu 指令修改 lpData 的内容:
1 | eu 00000268`e4a96d10 "0618" |
- 输入 g,再继续运行,即可大功告成。
埋前文的坑
- 前文“实现”节的第 5 步,
bm KERNELBASE!RegQueryValueExW断不下来?
您可能是在 Windows 10 下实践才遇到这个问题。可以用 x KERNELBASE!RegQueryValueExW* 看看是不是有多个。一般来说,即使有多个,无银第八哥也能都断,用 bl 可以看到多个都被加入。万一多个函数的类型不一样,可能就只加了一个 void 类型的,可以直接用地址指定另外类型的(没有被添加的)。
Windows 11 是这样:
1 | 0:000> x KERNELBASE!RegQueryValueExW* |
Windows 10 可能是这样:
1 | 0:000> x kernelbase!RegQueryValueExW* |
KERNELBASE!RegQueryValueExW返回后的指令怪怪的?
1 | 0:000> gu |
前一条的 call qword ptr [shcore!_imp_RegQueryValueExW (00007ffc2e5e5c90)]` 指令是 7 字节的,如果为了对齐也不应该补 5 字节呀。
1 | 0:000> u 00007ffc`2e53e6b6 |
看!后面的指令是从 00007ffc`2e53e6c2 开始的,也没有对齐。所以,如果不是为了对齐,那就可能是为了方便调试时在函数返回时加 int 3 了。如果有新的答案,将在本系列后续文章分享。













