Windbg 条件断点未按预期工作,我的语法是否正确?

Windbg conditional break point not working as expected, is my syntax correct?

我正在尝试学习如何在 windbg 中设置条件断点,我的程序名为 ConsoleApplication7,如下所示:

int main()
{
    int r1 = 0;
    r1 += 1;
    r1 = 3;
    return 0;
}

我用VC编译这个程序。然后在 windbg 中,我设置 "Symbol path" 和 "Source path",在 windbg 中打开 ConsoleApplication7.exe,windbg 运行并打开 .cpp 文件。

在 windbg 里面我设置了一个条件断点,我希望程序应该在 "r1=3".

bp consoleapplication7!main "j (poi(r1)>2) ''; 'gc'"

但是当我按下"g"时,windbg并没有说"Hit breakpoint",只是打印出寄存器信息。 运行 "g" 3次后,程序终止,如下所示:

0:000> bp consoleapplication7!main "j (poi(r1)>2) ''; 'gc'"
*** WARNING: Unable to verify checksum for ConsoleApplication7.exe
0:000> bl
 0 e 01251380     0001 (0001)  0:**** ConsoleApplication7!main "j (poi(r1)>2) ''; 'gc'"
0:000> g
eax=00718918 ebx=7efde000 ecx=0071b880 edx=00000001 esi=00000000 edi=00000000
eip=01251380 esp=002afeb4 ebp=002aff00 iopl=0         nv up ei pl nz na po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000202
ConsoleApplication7!main:
01251380 55              push    ebp
0:000> g
eax=00000000 ebx=00000000 ecx=00000000 edx=00000000 esi=77c02100 edi=77c020c0
eip=77b1fcd2 esp=002afe18 ebp=002afe34 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
ntdll!NtTerminateProcess+0x12:
77b1fcd2 83c404          add     esp,4
0:000> g
       ^ No runnable debuggees error in 'g'

其他命令如ba、bp在程序中运行良好,只是条件断点不行。

我的条件语句是否正确?为什么它不起作用?

我尝试了 Dono 回答中的建议,但它显示了另一个问题

0:000> bp ConsoleApplication7!main+0x3e "j (poi(r1) > 2) ''; 'gc'"
0:000> bl
 0 e 008e143e     0001 (0001)  0:**** ConsoleApplication7!main+0x3e "j (poi(r1) > 2) ''; 'gc'"
0:000> g
(4458.4840): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000000 ebx=7efde000 ecx=d3392f75 edx=00000001 esi=00000000 edi=00000000
eip=cccccccc esp=0046f82c ebp=cccccccc iopl=0         nv up ei pl nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010206
cccccccc ??              ???

似乎这个条件断点导致异常? 谢谢!

我也尝试了Blabb的建议,不幸的是,它没有用:

0:000> t "$$>a< c:\autostep.txt"
Couldn't resolve error at 'r1) == 3 ) { dv } .else { t "$$>a< c:\autostep.txt" } '
eax=00000001 ebx=7efde000 ecx=00000000 edx=00000001 esi=00000000 edi=001dfcb0
eip=013b13c0 esp=001dfbac ebp=001dfcb0 iopl=0         nv up ei pl nz na po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000202
ConsoleApplication7!f:
013b13c0 55              push    ebp

好像C++风格的命令不起作用,所以我把它改成了MASM风格

j (poi(r1)==3)''; 't "$$>a< c:\autostep.txt"'

另存为 c:\autostep.txt 然后我重新启动 windbg 以重新加载它。

0:000> t "$$>a< c:\autostep.txt"
eax=00000000 ebx=00000000 ecx=bc260000 edx=0015dc38 esi=fffffffe edi=00000000
eip=77ba0e15 esp=0042f804 ebp=0042f830 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000244
ntdll!LdrpDoDebuggerBreak+0x2d:
77ba0e15 8975fc          mov     dword ptr [ebp-4],esi ss:002b:0042f82c=00000000
0:000> g
eax=00000000 ebx=00000000 ecx=00000000 edx=00000000 esi=77c02100 edi=77c020c0
eip=77b1fcd2 esp=0042fb94 ebp=0042fbb0 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
ntdll!NtTerminateProcess+0x12:
77b1fcd2 83c404          add     esp,4

这一次,它没有语法问题,但它并没有像我预期的那样 break/stop。我错过了什么吗?

谢谢。

你的命令意思是:在main函数开始时无条件中断。然后,如果 r1 > 2,什么都不做;否则,继续。

请注意,bp 获取一个地址并在其上中断。因为您有符号 (PDB),所以您可以将符号 "consoleapplication7!main" 转换为地址。这指向函数的开始,r1 甚至还没有被初始化,所以它不可能 > 2,除了随机垃圾值。

所以首先你需要在一个更合理的位置休息。有多种方法可以做到这一点。您可以 "unscramble" 汇编代码 uf consoleapplication7!main 并确定要中断的偏移地址。类似于 bp ConsoleApplication7!main+0x35 "j (poi(r1) > 2) ''; 'gc'"。这可能有点困难。一种更简单的方法是指定行号,例如 bp `driver.cpp:6` "j (poi(r1) > 2) ''; 'gc'",假设您的主要函数位于名为 driver.cpp.

的文件中

此外,您需要注意您的应用程序是为调试模式还是发布模式编译的。在发布模式下,您的大部分主要功能都可以优化掉,因为 r1 的值可以在编译时预先计算。这自然会影响偏移量。

最后,除非您习惯使用 j 来表示 "if",否则我建议使用更现代的 .if (condition) { commands } .else { commands } 语法。虽然他们做同样的事情,但后者更具可读性。

有关详细信息,请参阅 here

首先你应该知道你的程序将被优化到 xor eax,eax ; ret

除非您在调试模式下编译并使用 /Od 开关明确禁用优化

(我假设您正在调试模式下使用视觉怪物项目来处理这个问题)

其次,您应该知道调试器不知道您的 r1 r2 或其他什么,除非存在符号信息和事件,那么您应该知道有两个表达式计算器 MASM 和 C++,默认情况下 windbg 使用 MASM

? poi(r1) == MASM evaluation 
?? r1 == c++ evaluation    

否则调试器只理解 cpu 理解的变量,如 BYTE , WORD , DWORD , QWORD .... etc 和地址

当您设置条件断点时,如 bp xxxxxmodule!yyyyysymbol "condition" 条件仅在指定的地址上计算,不在下面 所以你的情况只在主要

上进行了评估

你应该更进一步,评估每一步的条件,直到你遇到一个匹配项

编译后的代码和反汇编的 main() 代码将如下所示

0:000> .dml_flow steptest!main .
                              <No previous node>                    


          STEPTEST!main (013e6aa0):
          e:\test\steptest\steptest.cpp
          2     013e6aa0 push    ebp                                
          2     013e6aa1 mov     ebp,esp                            
          2     013e6aa3 push    ecx                                
          3     013e6aa4 mov     dword ptr [ebp-4],0                
          4     013e6aab mov     eax,dword ptr [ebp-4]              
          4     013e6aae add     eax,1                              
          4     013e6ab1 mov     dword ptr [ebp-4],eax              
          5     013e6ab4 mov     dword ptr [ebp-4],3                
          6     013e6abb xor     eax,eax                            
          7     013e6abd mov     esp,ebp                            
          7     013e6abf pop     ebp                                
          7     013e6ac0 ret                                        


                                <No next node>                      
0:000> lsa .
     1: int main()
     2: {
     3:     int r1 = 0;
>    4:     r1 += 1;
     5:     r1 = 3;
     6:     return 0;
     7: }

所以你的条件只能在第 6 行或地址 013e6abb xor eax, eax

的汇编中为真

您设置了一个 conditional bp on 013e6aa0 并且仅在该地址评估条件

你需要找到一种方法直到 013e6abb

那是你应该

step <evaluate> if match stop else repeat step and evaluate until match occurs 

为此,将以下行放入名为 autostep.txt 的文件中,并将其保存到 c:\

脚本说明

如果 c++ 表达式 r1 等于 3,则显示 locals else 步骤并再次通过 运行 此脚本重新评估(因此此脚本将在每个指令序列上执行,直到找到匹配项)

.if ( @@c++(r1) == 3 ) { dv } .else { t "$$>a< c:\autostep.txt" } 

现在在 windbg 中打开 exe 并执行

bp xxxxmod!main
g
t "$$>a< c:\autostep.txt"

当 r1 为 3 时,windbg 将中断

E:\test\STEPTEST>cdb -c "g steptest!main" STEPTEST.exe

0:000> cdb: Reading initial command 'g steptest!main'

STEPTEST!main:
013e6aa0 55              push    ebp
0:000> t "$$>a< c:\autostep.txt"
             r1 = 0n3

013e6abb 33c0            xor     eax,eax
0:000> ?? r1
int 0n3
0:000> ? poi(r1)
Evaluate expression: 3 = 00000003
0:000> ? &main ; ? &@eip
Evaluate expression: 20867744 = 013e6aa0
Evaluate expression: 20867771 = 013e6abb
0:000>

您可以在 cmd.exe

中调用脚本
cat c:\autostep.txt
.if ( @@c++(r1) == 3 ) { dv } .else { t "$$>a< c:\autostep.txt" }

cdb -c "g steptest!main;$$>a< c:\autostep.txt"  STEPTEST.exe

0:000> cdb: Reading initial command 'g steptest!main;$$>a< c:\autostep.txt'

             r1 = 0n3

eax=00000001 ebx=7ffd6000 ecx=a4894de4 edx=00000001 esi=00a2dd04 edi=00a2dd08
eip=009d6abb esp=0019f8d0 ebp=0019f8d4 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
STEPTEST!main+0x1b:
009d6abb 33c0            xor     eax,eax
0:000>