第39章 WinDbg
本文最后更新于:2022年5月27日 下午
第39章 WinDbg
WinDbg是Windows平台下用户模式和内核模式调试工具,它是一个轻量级的调试工具,但是功能十分强大。本章将学习有关WinDbg调试工具的知识(参考图39-1 )。
39.1 WinDbg
WinDbg是微软发布的一款免费调试工具,支持用户模式调试与内核模式调试,是一种“全天候”的调试器,但主要还是应用于内核调试。各位可以访问以下网址下载WinDbg调试器。
http://www.microsoft.com/whdc/devtools/debugging/default.mspx
本章讲解的是64位的WinDbg,它与32位版本在用户界面结构、命令组成上基本没有什么差别
39.1.1 WinDbg 的特征
WinDbg默认运行在CUI(Console User Interface,控制台用户界面)环境下,用户主要通过键盘而非鼠标来操作。要适应这种方式需要花费相当长的时间,可一旦熟悉起来就会非常方便。对于习惯了OllyDbg与IDAPro等GUI环境的朋友来说,初次接触WinDbg时会感到非常陌生、非常不方便(它们的差别就像Windows用户第一次接触Linux的终端用户环境时的感觉一样)。WinDbg中也提供大量快捷键,以及额外的窗口(反汇编、内存、寄存器、栈等),所以也可以使用类似OllyDbg形态的方式调试(当然,与OllyDbg、IDA Pro的GUI相比还差很远)。
39.1.2运行 WinDbg
符号
符号(Symbol)指的是调试信息文件(*.pdb)。使用Visual C++编译程序时,除了生成PE文件外,还会一起生成*.pdb(Program Data Base,程序数据库)文件,该文件包含PE文件的各种调试信息(变量/函数名、函数地址、源代码行等)。为了帮助理解,各位可以比较图39-2和图39-3。
虽然是相同的PE文件,但是符号文件的有无决定了反汇编代码的可读性。有符号文件时调试更方便快捷。但是通常只有程序的编写者才有符号文件,且一般不会对外发布。所以我们的调试工作大部分是在没有符号文件的情形下进行的。
安装符号文件
微软公开了Windows OS系统库的符号文件。在WinDbg中设置好符号的位置后,调试应用程序或驱动程序时会相当方便(因为拥有了系统库的调试信息)。在WinDbg菜单栏中依次选择File-Symbol File path菜单,弹岀对话框。像图39-4这样输入符号路径,需要时WinDbg会自动下载与OS相匹配的符号文件。
39.1.3 内核调试
WinDbg的特征之一就是可以进行内核调试(Kernel Debugging )。使用WinDbg进行内核调试时,一般要使用2台PC(调试器调试者),调试前需要通过Null Modem、1394、USB、Direct LAN Cable等将2台PC连接起来。近来,使用虚拟机(Virtual Machine)技术可以在同一台PC上同时运行调试器与被调试者,这被称为本地内核调试(Local Kernel Debugging ),即在运行WinDbg的PC上调试它(从Windows XP起支持该调试功能)。调试器的许多功能在这种调试方式下都受到限制,但是用来查看一些简单的信息还是非常方便的。
调试普通应用程序时,调试器与被调试者都在同一台PC中运行,但内核调试不同。内核调试中,被调试者为系统内核,即OS本身,所以OS系统自身会暂停。因此,调试内核时一般需要使用2台物理PC。以前SofllCE调试器可以完美地支持本地内核调试,受到广泛欢迎,但是由于它已经停止开发,不再有版本更新,所以调试内核时只好使用WinDbg调试器。关于内核调试的内容已经超出了本书的讨论范围,在此不再深入探讨。下面学习使用WinDbg调试器调试64位应用程序及查看PEB/TEB等系统结构体。
下面使用WinDbg的本地内核调试功能简单分析一下系统行为。为了进行本地内核调试,首先要把系统修改为调试模式。在控制台窗口输入bcdedit指令,查看当前系统状态,如图39-5所示。
在最后一行可以看到1个debug项目,其值为No,即“非调试模式”。使用以下命令修改该项的值,转换为调试模式,如图39-6所示
重启系统后进人内核调试模式,此时本地内核调试功能变为可用(再次使用bcdedit指令确认)。运行WinDbg调试器,在菜单栏中依次选择File-Kernel Debug菜单(快捷键Ctrl+K ),弹出Kernel Debugging对话框,如图39-7所示。
选择Local选项卡,然后单击“确定”按钮。一段时间后弹出WinDbg行初始画面,如图39-8所示。
首先岀现的是基于控制台的用户界面(看上去包含各种强大功能)。初始运行画面中显示的是基本的系统信息以及内核基址,该地址为ntoskrnl.exe文件的装载地址。Ntoskml.exe其实是驱动程序文件,指的是Windows内核本身。从技术上说,Windows内核实体是Ntoskml.exe驱动程序文件的内存装载映像。接下来输入简单指令,查看ntoskral!ZwCreateFile() API的实际代码,如图39-9所示。
ZwCreateFile() API的代码相当简单,它将服务编号(52)设置到EAX寄存器,然后跳转到KiServicelnternal()函数(函数的参数在寄存器与栈中)。其实,大部分ZwXXX系列函数都是由这种结构构成的。可以继续跟踪KiServicelnternal()API查看更详细的代码。查看系统内核代码如此方便,但是若想正式调试系统内核,应当釆用PC to PC或虚拟机方式连接。
39.1.4 WinDbg基本指令
下面简单整理WinDbg基本指令,调试64位应用程序或系统内核时会经常使用它们(更详细的说明请参考WinDbg帮助手册),如表39-1所示
指令 | 说明 | 应用 |
---|---|---|
u | Unassemble | u:显示下一条指令 |
u address:显示地址之后的指令 | ||
u L10:显示10行指令 | ||
ub:显示上一条指令 | ||
t | Trace(F11) | Step Into |
p | Pass(F10) | Step Over |
g | Go(Run) | g:运行 |
g address:运行到地址处 | ||
d | Dump | d address:显示地址内容 |
db address:byte | ||
dd address:dword | ||
dq address:qword | ||
r | Register | r:显示寄存器 |
r register:仅显示指定寄存器 | ||
bp | Break Point | bp:设置断点 |
bl:显示断点列表 | ||
bc:BP Clear(删除断点) | ||
lm | Loaded Module | Im:显示被调试进程中加载的模块 |
dt | Display Type | dt struct name:显示结构体成员 |
dt struct name address:映射地址到结构体并显示 | ||
!dh | Display PE Header | !dh loaded address:PE Viewer |
WinDbg支持的指令超过数十种,且各种指令的使用方法灵活多样。希望各位反复练习使用WinDbg调试器,直到能够熟练进行各种调试。