【发布时间】:2016-06-09 05:17:12
【问题描述】:
假设我想使用 Windows 的 WinDbg、cdb 或 ntsd 调试器来调试这个程序:
/* test.c */
#include <stdio.h>
int rip = 42;
int main(void)
{
puts("Hello world!");
return (0);
}
我为 AMD64 编译程序并在 WinDbg 下运行它。我在 main() 处设置了一个断点,当断点命中时,我想检查 RIP 寄存器(程序计数器)的值,以及该值周围的内存(如果该值被视为指针)。
我可以用r rip 直接查看寄存器的值,但是当我尝试查看该地址周围的内存时,WinDbg 会显示一个不同的地址!在读取了 test.pdb 中的符号后,WinDbg 发现 rip 是在 C 代码中声明的全局变量,并向我展示了 &rip 周围的内存。
0:000> bu test!main
0:000> g
Breakpoint 0 hit
test!main:
00007ff6`de1868d0 4883ec28 sub rsp,28h
0:000> r rip
rip=00007ff6de1868d0
0:000> db rip
00007ff6`de1f2000 2a 00 00 00 ff ff ff ff-01 00 00 00 00 00 00 00 *...............
00007ff6`de1f2010 01 00 00 00 02 00 00 00-ff ff ff ff ff ff ff ff ................
00007ff6`de1f2020 00 00 00 00 00 00 00 00-43 46 92 e5 1b df 00 00 ........CF......
00007ff6`de1f2030 bc b9 6d 1a e4 20 ff ff-00 00 00 00 00 00 00 00 ..m.. ..........
00007ff6`de1f2040 00 01 00 00 00 00 00 00-ca b0 1e de f6 7f 00 00 ................
00007ff6`de1f2050 00 00 00 00 00 80 00 00-00 00 00 00 00 80 00 00 ................
00007ff6`de1f2060 d0 66 fc c2 f2 01 03 00-ab 90 ec 5e 22 c0 b2 44 .f.........^"..D
00007ff6`de1f2070 a5 dd fd 71 6a 22 2a 15-00 00 00 00 00 00 00 00 ...qj"*.........
0:000> ? rip
Evaluate expression: 140698265264128 = 00007ff6`de1f2000
0:000> ? dwo(rip)
Evaluate expression: 42 = 00000000`0000002a
这确实很烦人,但只要我意识到这一点,手动读取这样的数据就不是问题了。但是如果我想使用寄存器值,例如在调试器脚本中,那么没有简单的解决方法:
0:000> bu test!main ".if (dwo(rip) == 0n42) { .echo Whoops! I don't want to get here! }"
0:000> g
Whoops! I don't want to get here!
test!main:
00007ff6`de1868d0 4883ec28 sub rsp,28h
这个问题,程序中的符号隐藏了寄存器名称,这对我来说真的很困难。这打破了一个实际场景:
- 我想在 CreateFileW() 上设置断点,这是一个非常常用的 Windows API 函数。
- 由于我只关心一个特定文件,因此我想检查在 RCX 寄存器中传递的文件名,并继续通过断点,除非文件名与我想要的文件匹配。
- 但是我不能写这个条件,因为程序中的另一个模块定义了一个符号
foobar!rcx,而我在断点上执行的命令中对rcx的任何引用都引用了那个全局变量!李>
那么我如何告诉 WinDbg 是的,我真的打算读取寄存器?如果我想写那个寄存器怎么办?我这里一定有一个简单的东西。
【问题讨论】:
-
if dwo(@rip) == xx 做其他事情 if qwo (@rcx) != foobar!rcx 做其他事情 .else gotosleep() @rcx = 注册 rcx 而 foobar!rcx或者只是 rcx 是一个全局的