Windows调试⼯具⼊门—windebug
⼀、 引⼦
Debugging Tools for Windows是微软发布的⼀套⽤于软件调试的⼯具包(后⾯如果没有指明,那么我会使⽤WinDbg来作为这⼀套调试⼯具的简称)。我第⼀次接触是在三年前的⼀个内核驱动项⽬,由于进⾏了IDT中键盘⿏标中断的Hook,使⽤Softice调试时造成会造成影响,只得使⽤WinDbg通过串⼝进⾏双机调试。⾃此之后这个Windows平台下最为强⼤的调试⼯具⼀直是开发过程中的必备。这⾥我毫不掩饰的说“最强”,可能很多通过逆向⼯作⽽接触调试的朋友不会认同,但是我相信随着对WinDbg了解的加深,以及对这套⼯具在软件开发中应⽤的了解,他们也会和我有⼀样的观点。
⼀直以来,软件调试技术在软件开发者中都没有得到⾜够的普及和重视,互联⽹上能到的系统描述的资料也较少。随着国内软件⾏业整体的发展和进步,这些技术慢慢开始得到推⼴。2008年出版的有关调试的数据⽐以往都要多。我有幸拜读了Raymond的《软件调试》,以及熊⼒的《Windows⽤户态程序⾼效排错》,获益良多。 这⼏年的⼯作中也积累了⼀些关于Windows调试⼯具的知识,希望能够将这些东西进⾏⼀些分享。因此,利⽤⼏个⽉空闲时间翻译了WinDbg⽂档中上半部调试器配置、使⽤和命令介绍的内容,同时准备写⼀些关于WinDbg调试⼯具的初级⽂章。希望能够为对调试技术感兴趣⽽⼜苦于没有资料的朋友提供⼀些帮助。
特别感谢我的前同事⼩喂。虽然他第⼀条串⼝线还是我焊的,但是他对于WinDbg的使⽤和了解程度很快就超过了我。在相当长时间的共事和讨论中,让我学到了很多。
⼆、 Windows调试⼯具的简介和组成
WinDbg是专门为Windows NT系列操作系统设计的调试器,最早是作为Windows NT 3.1的⼯具发布的。其后也⼀直跟随NT操作系统的发展⽽不断发展完善。如果⽤⼀句话来概括,可以说WinDbg是为了软件开发⽽存在的调试⼯具。软件包中的调试器和⼩⼯具的各种功能都是为了配合软件的开发⽽设计的,并且覆盖到了Windows平台下各种不同类型项⽬的调试(传统的SDK或MFC应⽤程序、.NET平台应⽤、COM应⽤、软硬件驱动程序等等)。
Windows调试⼯具包中的调试器包括WinDbg、KD、CDB和NTSD。其中, KD⽤于内核调试;CDB和NTSD⽤于⽤户态调试,在功能和使⽤上⼏乎完全⼀致;WinDbg是内核调试器和⽤户态调试器的综合体,由于功能完善并且具有图形界⾯,所以是最常⽤的⼯具。它们能够在x86、Itanium和x64机器上的所有NT平台操作系统中运⾏。
另外,⼯具包中还有⼀些⼩⼯具,下⾯是常⽤的⼏个:
KDbgCtrl:⽤于控制和配置内核调试的⼀些参数。例如是否只有当发⽣异常时才会启⽤内核调试、设置DbgPrint缓冲区⼤⼩、如何处理⽤户模式异常等等。
ADPlus:这是⼀个VB脚本,可以为⼀个或多个进程⾃动创建内存dump。
SymStore:⽤于创建符号存储。当需要创建⾃⼰的符号存储时就要⽤到它了。
SymProxy:⽤于在⽹络中创建单独的HTTP符号服务器,以供所有调试器使⽤。该⼯具特别适合企业级应⽤的环境,可以将多个符号存储通过单⼀的接⼊点提供使⽤。
DbgSrv、KdSrv、:⽤于远程调试。
GFlags:⽤于编辑Global Flags。
UMDH:⽤于对⽤户模式堆分配的情况进⾏转储和分析。
USBView:这是WinDbg 6.10.3版本才加⼊到软件包中的⼯具,可以查看当前连接到系统中的USB设备信息。
另外,Application Verifier虽然没有包含在软件包中,但是也是⼀个⾮常强⼤的⼯具。可以对程序运⾏时的很多状态进⾏监控,以发现⼀些普通调试难以到的错误。下⾯是Application Verifier配置界⾯的⼀个截图:
在C/C++选项卡中设置如下:
程序代码如下:
#include "stdafx.h"
#include <stdio.h>
int main(int argc, char* argv[])
{
printf( "TestDebug1.cpp");
return 0;
}
编译之后,将Release⽬录下的TestDebug1.pdb剪切到其他⽬录下(如果没有这样做,由于编译出来的程序中包含了符号⽂件路径,调试器可以直接使⽤exe中的信息到pdb⽂件,⽽不需要设置路径)。在map⽂件中可以看到像下⾯这样的内容:
0001:00000000 _main 00401000 f TestDebug1.obj
说明main函数位于401000地址处。
通过WinDbg的File->Open Executeable菜单打开,可以在调试器命令窗⼝中看到下⾯的内容:
可以看到,调试器⾃动中断下来的位置并不是程序⼊⼝点,这是由WinDbg实现造成的,这⾥先不管它。
调试器命令窗⼝中可以看到,我们还没有设置符号路径,所以WinDbg⽬前还不到的任何符号⽂件。如果想在main函数下断,这时就不能使⽤符号,⽽只能直接使⽤main的地址。
使⽤命令bp 00401000在main函数设置断点,然后F5执⾏就可以中断到main的⼊⼝处了。断点设置和基本操作我们将在后⾯介绍。可以在反汇编窗⼝中看到这样的内容:
由于没有加载任何符号,所以我们看到的都是⼀堆反汇编代码和地址。在上⼀篇中已经介绍过,WinDbg不像OllyDbg这些调试器⼀样拥有强⼤的反汇编分析能⼒,所以仅仅靠这些看起来⼀团乱⿇的反汇编代码,调试⼯作是很难开展下去的。
符号路径的设置
要想在WinDbg中看到程序中的符号,必须通过命令或者WinDbg菜单设置符号路径。如果还设置了Microsoft公共符号存储的话,我们不但能够看到⾃⼰程序中的符号,还能够看到Windows平台代码中的符号,这对于调试会提供很好的帮助。
所谓符号路径,就是包含了程序符号信息的符号⽂件所在的⽬录路径。通常我们接触到的符号⽂件都是以pdb作为后缀名的。项⽬如果在项⽬设置的Link选项中选中了⽣成调试信息的话(如上图中的Generate debug info),那么可以在Debug或者Release⽬录中到它的符号⽂件TestDebug1.pdb。
我们通过WinDbg的File->Symbol File Path…菜单,或者命令.sympath设置符号路径为TestDebug1.pdb所在的⽬录。例如刚才我把⽣成的pdb⽂件移动到桌⾯上了,所以在我的机器上就设置为:
完成之后在命令窗⼝输⼊.reload命令,我们可以看到反汇编窗⼝的内容发⽣改变:
这⾥就已经可以看到中的函数、变量名这样的符号了。⽽我们也可以通过bp main这样的命令直接使⽤符号来操作调试器。
另外,在Local、Watch等窗⼝中也可以直接使⽤符号名查看到变量的值、在Call Stack窗⼝中可以看到函数名,等等。
源码路径的设置
通过上⾯的设置,我们可以对程序进⾏符号化调试。如果拥有程序的代码,还可以通过设置源码路径来进⾏源码级调试。
继续上⾯的⼯作,我们通过WinDbg的File->Source File Path…菜单或者.srcpath命令设置源代码保存的路径,⽐如我的机器上是这样:
确定之后,如果当前指令指针在源⽂件的代码范围内,就会⾃动跳出源⽂件窗⼝。如果没有跳出,那么可以通过File->Open Source File…菜单⼿动打开源⽂件。由于刚才设置的断点还没有删除,所以在源码窗⼝也能⼝看到设断的⾏被⾼亮了
之后就基本上可以完全通过源码窗⼝进⾏设置断点、查看变量、跟踪代码等操作。⽐只有符号的时候⽅便了很多。
windows开发平台可执⾏映像路径的设置
可执⾏映像路径⼀般在调试dump⽂件时才⽤得上。需要将这个路径设置成要调试的exe、dll、sys等可执⾏⽂件的路径。可以通过File->Image File Path…菜单或者.exepath命令设置。
使⽤微软公共符号存储
除了使⽤⾃⼰程序的符号之外,调试时还可以使⽤微软提供的Windows系统代码的符号。这需要修改⼀下我们设置的符号路径。最⽅便的办法是使⽤.symfix命令。
现在我们来看⼀下kernel32.dll中的代码,在反汇编窗⼝的Offset栏中填⼊kernel32!OpenProcess,在我的机器上代码如下:
注意位于764e8ccf处的那个call,现在只能看到调⽤了kernel32某个偏移处的地址。
使⽤命令.symfix+ d:\Symbols命令,注意加号要紧靠前⾯的⽂本。d:\Symbols是⽤来保存下载的符号⽂件的⽬录,可以修改成⾃⼰需要的路径。再来打开符号路径窗⼝,我们可以看到调试器⾃动添加了⼀些内容:
⾃⼰在源码路径中加⼊这些新的内容也可以实现相同的效果。详细的原理请参考WinDbg帮助⽂档关于符号服务器设置的部分内容。
接下来再次使⽤.reload命令重新加载符号,第⼀次使⽤到的符号⽂件会从⽹上⾃动下载下来,所以可能有时候会等待⼀会。完成之后,可以看到反汇编窗⼝中出现了新的符号内容:
764e8cd8处指令中可以看到这是调⽤了kernel32导⼊的函数NtOpenProcess。
微软提供的Windows符号是我们研究Windows实现的必备利器。⾸先,符号化的名字有助于调试过程中的记忆和对各种信息的识别;其次,通过名字就常常可以猜测出来函数或变量的作⽤,很⼤的⽅便调试。在各种调试应⽤中,都强烈建议添加微软公共符号的引⽤。
设置环境变量
上⾯介绍的各种路径都可以通过环境变量来进⾏设置。将⼀些常⽤的路径保存在环境变量中,就可以避免每次在新的⼯作空间中进⾏调试时都要重新设置的⿇烦。另外,Visual Studio 2008也共享⼀些环
境变量的设置,这样在使⽤IDE调试的时候也能⽅便的查看到各种符号了。常⽤的有下⾯⼏个:
环境变量 作⽤
_NT_SOURCE_PATH = Path 指定包含调试⽬标的源代码的路径。Path可以包含后跟⼀个冒号(:)的驱动器符。⽤分号分隔多个⽬录(;)。_NT_SYMBOL_PATH = Path 指定包含符号⽂件的⽬录树的根⽬录。Path可以包含后跟⼀个冒号(:)的驱动器符。⽤分号分隔多个⽬录(;)。
_NT_EXECUTABLE_IMAGE_PATH = Path 指定包含⼆进制可执⾏⽂件的路径。Path可以包含后跟⼀个冒号(:)的驱动器符。⽤分号分隔多个⽬录(;)。
_NT_DEBUG_LOG_FILE_OPEN = Filename (仅CDB和KD) 指定调试器⽤来记录输出的⽇志⽂件。
_NT_DEBUG_LOG_FILE_APPEND = Filename (仅CDB和KD) 指定调试器⽤来添加输出的⽇志⽂件。新的内容每次会添加到这个⽂件末尾,⽽不是覆盖整个⽂件。
如果设置了符号路径的环境变量的话,可能在初期使⽤VS 2008调试MFC这样的有较多导⼊库的程序时会下载很多符号⽂件,使得启动调试的速度变慢。不过经过⼀段时间,⼤部分需要的符号都缓存到本地之后速度就会快起来。
⼆、 配置⽇志⽂件
进⾏调试时,有时候调试器命令窗⼝会变得很杂乱,所以常常想⽤.cls命令清空它。但是这样会⽆法再看到之前调试过程中输出的结果。另外,有时候想保存下整个调试过程的详细记录以备后⾯“回味”。这时,就需要⽤到⽇志⽂件了。可以将调试器命令窗⼝中出现过的所有内容都⾃动记录到⽇志⽂件中。
创建⽇志⽂件:
· (仅CDB 和KD) 启动调试器之前,设置_NT_DEBUG_LOG_FILE_OPEN环境变量。
· 启动调试器时,使⽤-logo 命令⾏选项。 如-logo d:\
· 使⽤.logopen命令。如.logopen /t d:\
· (仅WinDbg) 使⽤Edit->Open/Close Log File菜单命令。
将⽇志添加到已有的⽂件末尾:
· (仅CDB 和KD) 启动调试器之前,设置_NT_DEBUG_LOG_FILE_APPEND环境变量。
· 启动调试器时,使⽤-loga命令⾏选项。如-loga d:\
· 使⽤.logappend命令。 如. logappend/t d:\
· (仅WinDbg) 使⽤Edit->Open/Close Log File菜单命令,然后选择Append。
关闭⽇志⽂件:
· 使⽤.logclose命令
· (仅WinDbg) 使⽤Edit->Open/Close Log File菜单命令,然后选择Close Open Log File。
五、 设置⼯作空间
⼯作空间(Workspace)是⽤来保存WinDbg中⼯作环境的⼯具。例如习惯的窗⼝布局⽅式、符号路径、异常处理的设置等等,都可以通过⼯作空间保存下来,在下次调试的时候就不⽤再次设置了。
相关的设置都可以通过WinDbg菜单来完成,有下⾯⼏个:
Open Workspace:这⾥只能打开⾃⼰通过SaveAs保存的⼯作空间。
Save Workspace:按默认的⽅式保存当前的⼯作空间。下次再打开相同的调试⽬标时,就会⾃动打开这个Workspace。
Save Workspace As:可以⾃⼰设置⼯作空间的名字,这样就能通过Open Workspace来⼿动打开。
Clear Workspace:可以选择保存⼯作空间时要保存哪些设置。
Delete Workspace:删除当前保存的⼯作空间。这⾥可以查看到所有默认保存和另存为的⼯作空间,⽤来进⾏清理是很⽅便的。
Save Worlspace in File和Open Workspace in File:将⼯作空间保存到⽂件或者从⽂件打开。可以把⾃⼰的⼯作空间保存下来,这样通过U盘之类的就能在多台机器之间⽅便的使⽤相同的设置了。
在没有调试⽬标的时候调整WinDbg的窗⼝布局等等设置的话,会保存为默认的⼯作空间。下⼀次打开新⽬标的时候,就会使⽤这个设置。通常我们可以设定⼀个默认的⼯作空间,然后为各个单独的任务保存另外的设置。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论