2023年1月

WinDbg的扩展,也可以叫插件。它用于实现针对特定调试目标的调试功能,用于扩展某一方面的调试功能。扩展的实现是通过扩展模块(DLL)实现的。Windbg本身已经包含了很多扩展命令,这些扩展为这Windbg调试器提供了强大的功能和灵活性。调试器扩展命令的使用与标准调试器命令非常相似。但是,虽然内置调试程序命令本身是调试程序二进制文件的一部分,但调试程序扩展命令是由与调试程序不同的DLL公开的。windbg可以添加扩展功能,用户可以自己实现一组功能并添加到windbg中,把包含扩展功能的dll文件放到windbg目录下的winext子目录 ,windbg就会自动加载扩展模块。这允许您编写新的调试器命令,这些命令是根据您的特定需求定制的。

加载调试器扩展DLL

有几种方法可以加载调试器扩展DLL,以及控制默认调试器扩展DLL和默认调试器扩展路径:

  • 在启动调试程序之前,使用\u nt \u debugger \u extension \u path环境变量设置扩展DLL的默认路径。这可以是多个目录路径,用分号分隔。
  • 使用.load(加载扩展dll)命令加载新的dll。
  • 使用.unload(卸载扩展dll)命令卸载dll。
  • 使用.unload all(卸载所有扩展DLL)命令卸载所有调试器扩展。
  • 启动调试器之前,使用-a命令行选项设置默认扩展dll。
  • 使用.extpath(设置扩展路径)命令设置扩展dll搜索路径。
  • 使用.set dll(设置默认扩展dll)命令设置默认扩展dll。
  • 使用.chain(list debugger extensions)命令以默认搜索顺序显示所有加载的调试器扩展模块。

 您也可以通过使用full加载扩展dll!第一次从该模块发出命令时使用module.extension语法。您使用的扩展DLL必须与目标计算机的操作系统匹配。随Windows软件包调试工具一起提供的扩展DLL都放置在安装目录的不同子目录中:

调试器命令窗口是windbg中的主要调试信息窗口。可以在此窗口中输入调试程序命令并查看命令输出。Windbg的命令窗口是我们进行调试时,主要打交道的窗口。界面如下

有很多的环境变量,主要分为常规环境变量和内核模式环境变量。下面分别列出。

常规环境变量

下表列出了可在用户模式和内核模式调试的环境变量。

变量含义

_NT_DEBUGGER_EXTENSION_PATH = Path

指定调试器将先搜索扩展 Dll 的路径。 路径可以包含驱动器号后, 接一个冒号 (:)。 用分号分隔多个目录 (;)。 有关详细信息,请参阅加载的调试器扩展 Dll

_NT_EXECUTABLE_IMAGE_PATH = Path

指定包含二进制可执行文件的路径。 路径可以包含驱动器号后, 接一个冒号 (:)。 用分号分隔多个目录 (;)。

_NT_SOURCE_PATH = Path

指定包含目标的源代码文件的路径。 路径可以包含驱动器号后, 接一个冒号 (:)。 用分号分隔多个目录 (;)。 有关详细信息,以及更改此路径的其他方法,请参阅源路径

_NT_SYMBOL_PATH = Path

指定包含符号文件的目录树的根。 路径可以包含驱动器号后, 接一个冒号 (:)。 用分号分隔多个目录 (;)。 有关详细信息,以及更改此路径的其他方法,请参阅符号路径

_NT_ALT_SYMBOL_PATH = Path

指定搜索之前 _NT_SYMBOL_PATH 替代符号路径。 这可用于保留符号文件的专用版本。 路径可以包含驱动器号后, 接一个冒号 (:)。 用分号分隔多个目录 (;)。 有关详细信息,请参阅符号路径

_NT_SYMBOL_PROXY =代理:端口

指定要由 SymSrv 的代理服务器。 有关详细信息,请参阅防火墙和代理服务器

_NT_DEBUG_HISTORY_SIZE = Number

可以在远程调试过程中访问的命令历史记录中指定命令的数。 命令的长度会有所不同,因为可用的行数可能不完全匹配有关详细信息,以及更改此数字的其他方法,请参阅使用调试器命令

_NT_DEBUG_LOG_FILE_OPEN = Filename

(CDB 和仅 KD)指定调试程序应向其发送输出的日志文件。

_NT_DEBUG_LOG_FILE_APPEND = Filename

(CDB 和仅 KD)指定调试器应将输出追加到日志文件。

_NT_EXPR_EVAL = {masm | c++}

指定默认表达式计算器。 如果masm指定,则将使用 MASM 表达式语法。 如果c + +指定,则C++将使用表达式语法。 默认值为 MASM 表达式语法。 请参阅评估表达式有关详细信息。

_NO_DEBUG_HEAP

指定调试堆不应使用用户模式调试。

DBGENG_NO_DEBUG_PRIVILEGE

可防止生成继承 SeDebugPrivilege 调试器的进程。

DBGENG_NO_BUGCHECK_ANALYSIS

防止自动检测错误分析。

DBGHELP_HOMEDIR

指定由 SymSrv 和 SrcSrv 默认下游 store 的根目录的路径。 路径可以包含驱动器号后, 接一个冒号 (:)。 用分号分隔多个目录 (;)。

SRCSRV_INI_FILE

指定的路径和名称使用的配置文件SrcSrv默认情况下,路径是有关 Windows 调试工具安装目录的 srcsrv 子目录和文件名称是 Srcsrv.ini。 请参阅源索引编制有关详细信息。

内核模式环境变量

下表列出了仅在内核模式调试中使用的环境变量。

变量含义

_NT_DEBUG_PORT = ComPort

指定要在内核连接中使用的 COM 端口。 有关详细信息,请参阅获取设置以便进行调试

_NT_DEBUG_BAUD_RATE = BaudRate

指定要使用通过 COM 端口连接的波特率。

_NT_DEBUG_BUS = 1394

指定将通过 1394年电缆连接进行内核调试。

_NT_DEBUG_1394_CHANNEL = 1394Channel

指定要用于 1394年内核连接的通道。

_NT_DEBUG_1394_SYMLINK = Protocol

指定要用于 1394年内核连接的连接协议。

KDQUIET =任何内容

如果定义 KDQUIET,则调试器将在中运行安静模式下静默模式都涉及到三个不同的效果:

1. 调试器不显示每次的扩展 DLL 加载或卸载的消息。

2. R (寄存器)命令不再要求其语法中一个等号。

3. 分解为目标计算机时,调试器将不会显示一条警告消息。

安静模式还可通过使用控制sq (设置安静模式下)命令。

_NT_DEBUG_CACHE_SIZE= 大小

指定最大内核调试缓存大小 (字节)。 此缓存保存主机计算机的串行连接从收到的数据。 默认值为 1,024,000。

_NT_DEBUG_OPTIONS = Option

指定以下两个值之一:

NOEXTWARNING 告知调试程序不要执行时找不到扩展命令输出一条警告。

NOVERSIONCHECK 告知调试器不自动检查调试器扩展的版本。

 

可以修改这些选项或通过使用显示因此 (设置内核选项) 命令。

_NT_KD_FILES = MapFile

指定驱动程序替换映射文件。 有关详细信息和控制驱动程序替换的其他方法,请参阅映射驱动程序文件

 

windbg是一个内核模式和用户模式调试器,包含在Windows调试工具中。在这里,提供个实践练习,帮助我们开始使用windbg作为用户模式调试器。

用WinDbg调试记事本

1、导航到安装目录,然后打开windbg.exe。

2、在“文件”菜单上,选择“打开可执行文件”。在“打开可执行文件”对话框中,导航到包含notepad.exe的文件夹(例如,C:\windows\system32)。输入notepad.exe作为“文件名”。单击“打开”。

3、在windbg窗口底部附近的命令行中,输入以下命令:.sympath srv*.

输出:

符号搜索路径告诉windbg在哪里查找符号(pdb)文件。调试器需要符号文件来获取有关代码模块(函数名、变量名等)的信息。
输入此命令,通知windbg执行符号文件的初始查找和加载:.reload

4、查看notepad.exe模块的符号

请输入以下命令:x notepad!*

注意:如果看不到任何输出,请输入.reload。要查看包含main的notepad.exe模块中的符号,请输入以下命令: x notepad!*main*

5、在记事本上设置断点notepad!WinMain,输入以下命令:bu notepad!WinMain

要验证是否设置了断点,请输入以下命令:bl

6、运行,请输入以下命令:g

记事本一直运行到winmain函数,然后中断到调试器。

要查看在记事本进程中加载的代码模块列表,请输入以下命令:lm

 

要查看堆栈跟踪,请输入以下命令:k

7、再次运行 g

8、要中断记事本执行,请从“调试”菜单中选择“中断”。

9、观察保存过程,要在zwwritefile处设置和验证断点,请输入以下命令:

bu ntdll!ZwWriteFile

bl

10、输入g重新开始运行记事本。在记事本窗口中,输入一些文本,然后从“文件”菜单中选择“保存”。当涉及zwCreateFile时,正在运行的代码将中断。输入k以查看堆栈跟踪。

在windbg窗口的命令行左侧,注意处理器和线程号。在本例中,当前处理器编号为0,当前线程编号为15。因此,我们正在查看线程151的堆栈跟踪(它恰好运行在处理器0上)。