天天看点

5min学会WinDBG条件断点1.前言2.WinDBG断点3.WinDBG条件断点

1.前言

       很多时候我们可以使用Spy++查看某个窗口的消息,但是有一定的局限性。

       以编辑控件为例,我们打开Spy++截获应用程序的EM_GETTEXTRANGE消息,却只能看到TEXTRANGE结构的指针值,看不到结构的内容。

5min学会WinDBG条件断点1.前言2.WinDBG断点3.WinDBG条件断点

        如果想要详细查看消息的WPARAM和LPARAM参数,Spy++是无能为力的。

        但是可以通过WinDBG的条件断点却可以轻松实现。

        我们先从最简单的WinDBG断点开始,将断点打在USER32!SendMessage函数上,就可以看到应用程序传递了什么参数。

2.WinDBG断点

       首先,设置符号路径(假设放在本地的目录E:\symbols):

SRV*E:\symbols*http://msdl.microsoft.com/download/symbols
           

       然后,将WinDBG调试器附加到目标进程并且中断程序。

       接着,就可以打断点了。

bp USER32!SendMessageW

bp USER32!SendMessageA
           

        打完断点之后,继续执行程序。

g
           

       触发应用程序发送Windows消息,例如可以将鼠标移动到程序客户区将发送WM_MouseMOVE消息。输入以下命令,可以看到函数调用堆栈和传入的参数。

kvn
dd esp
           

        整体效果如下图所示:

5min学会WinDBG条件断点1.前言2.WinDBG断点3.WinDBG条件断点

       可以看到 'kvn' 命令输出的 '00'行,第二个值 '0a09c81'是函数返回地址,第三个值开始就是函数参数。结合SendMessage的定义可以知道‘0022065c’为窗口句柄,‘00000229’为消息值。

       根据'dd esp'输出结果,可以看到,esp+4开始从左到右依次就是SendMessage的4个参数

       现在万事具备,如何加上条件呢?

3.WinDBG条件断点

       我们先来最简单的。在断点命中时,输出一句'Hello SendMessage'

       重新定义断点:

bp USER32!SendMessageW " .printf \"Hello SendMessage\t\" "
           

       这样定义断点的意义就是,断点命中时,执行后面的WinDBG脚本。怎么样?是不是超简单。

       运行程序:

g
           

       触发应用程序发送Windows消息之后,可以得到以下结果:

5min学会WinDBG条件断点1.前言2.WinDBG断点3.WinDBG条件断点

      可以看到,确实输出了'Hello SendMessage’,并且执行中断在了'User32!SendMessageW'。

       接着,我们来尝试筛选消息EM_GETTEXTRANGE。由2可以,esp+4就是窗口句柄,esp+8就是消息值。

       重新定义断点:

bp USER32!SendMessageW ".if(poi(esp+8) == 0x44B) {.printf \"EM_GETTEXTRANGE\n\"} .else {gc}"
           

       脚本的意义是,执行一个if-else语句。当消息值为EM_GETTEXTRANGE时,打印文本,否则从断点继续执行。具体来讲,poi的含义跟C/C++的解引用是类似的。

       执行程序:

g
           

       触发应用程序发送EM_GETTEXTRANGE消息,可得到结果如下:

5min学会WinDBG条件断点1.前言2.WinDBG断点3.WinDBG条件断点

       可以看到,指定的文本确实输出了,程序也中断了。说明应用程序确实发送了EM_GETTEXTRANGE消息。那么怎么查看这条消息的参数呢?

       如果想要更复杂的功能,我们通常就会使用脚本文件来达到这个目的了,谁也不想在一行上写完所有代码逻辑。WinDBG里也是支持这种功能的,我们可以指定命中断点时,执行指定的脚本文件。

       中断程序,重新定义断点,假设脚本文件在'D:\script.txt':

bp USER32!SendMessageW "$$>< D:\script.txt"
           

       再次继续执行程序

g
           

       触发应用程序发送EM_GETTEXTRANGE后,可以得到如下执行结果:

5min学会WinDBG条件断点1.前言2.WinDBG断点3.WinDBG条件断点

       可以看到,我们输出了更多的信息,把 EM_GETTEXTRANGE的LPARAM参数指向的TEXTRANGE结构都打印出来了。下面给出脚本。

$$ put MessageID into presudo register t0
r $t0 = poi(esp + 8)

$$ put pointer to TEXTRANGE Structure into presudo register t1
r $t1 = poi(esp + 0x10)

.if($t0 == 0x44B) {
    .printf "\nEM_GETTEXTRANGE\n"
    .printf "TEXTRANGE Structure:\nchrg.cpMin = %d\nchrg.cpMax = %d\nlpstrText = 0x%x\n", poi($t1), poi($t1 + 4), poi($t1 + 8)

    gu
    du poi($t1 +8)
    .printf "\n"
    gc
    
} .else {
    gc
}
           

       其中:

       '$$'开始的行是注释

       r $t0 = poi(esp + 8)则是定义了伪寄存器

       当我们得到指定消息时,先打印参数情况,然后调用gu命令让SendMessageW继续执行后返回,这样我们就可以得到正确的结果。就保存在TEXTRANGE结构的lpstrText里。

       怎么样,是不是非常简单。5min立马就学会了WinDBG条件断点。