在 WinDbg 命令中,如何引用与全局变量同名的寄存器?
In WinDbg commands, how can I refer to a register with the same name as a global variable?
假设我想使用 Windows:
的 WinDbg、cdb 或 ntsd 调试器来调试这个程序
/* test.c */
#include <stdio.h>
int rip = 42;
int main(void)
{
puts("Hello world!");
return (0);
}
我在 WinDbg 下为 AMD64 和 运行 编译程序。我在 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 是的,我真的打算读取寄存器?如果我想写那个寄存器怎么办?一定有一件简单的事情我在这里错过了。
如路过another question所述,您可以在寄存器名称前放置一个at符号(@
)以强制将其解释为寄存器或伪寄存器,绕过尝试将其解析为十六进制数或符号。
Registers and Pseudo-Registers in MASM Expressions
You can use registers and pseudo-registers within MASM expressions. You can add an at sign (@) before all registers and pseudo-registers. The at sign causes the debugger to access the value more quickly. This at sign is unnecessary for the most common x86-based registers. For other registers and pseudo-registers, we recommend that you add the at sign, but it is not actually required. If you omit the at sign for the less common registers, the debugger tries to parse the text as a hexadecimal number, then as a symbol, and finally as a register.
假设我想使用 Windows:
的 WinDbg、cdb 或 ntsd 调试器来调试这个程序/* test.c */
#include <stdio.h>
int rip = 42;
int main(void)
{
puts("Hello world!");
return (0);
}
我在 WinDbg 下为 AMD64 和 运行 编译程序。我在 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 是的,我真的打算读取寄存器?如果我想写那个寄存器怎么办?一定有一件简单的事情我在这里错过了。
如路过another question所述,您可以在寄存器名称前放置一个at符号(@
)以强制将其解释为寄存器或伪寄存器,绕过尝试将其解析为十六进制数或符号。
Registers and Pseudo-Registers in MASM Expressions
You can use registers and pseudo-registers within MASM expressions. You can add an at sign (@) before all registers and pseudo-registers. The at sign causes the debugger to access the value more quickly. This at sign is unnecessary for the most common x86-based registers. For other registers and pseudo-registers, we recommend that you add the at sign, but it is not actually required. If you omit the at sign for the less common registers, the debugger tries to parse the text as a hexadecimal number, then as a symbol, and finally as a register.