单步调试驱动
驱动的调试不能直接在本机上进行,而是要放在虚拟机(或其它设备)中。这是因为在内核模式下,一个断点的触发将会停下整个系统而不只是单个进程。
在前面的文章里,使用了DbgPrint函数来进行日志的输出,但这种方法不能进行单步调试。下面介绍两种调试方法。
基于Visual Studio的调试方法
参数配置前准备
在第一篇文章的末尾指出需要准备一台虚拟机,现在就能够派上用场了。
说明:在Vmware中,使用NAT模式,虚拟机可以直接跟物理机通信。
我这里的配置如下:
说明 | 版本 | IP | 虚拟机版本 |
调试机器 (本机) | Windows 10 x64 1903 | 192.168.109.1 | NULL |
被调试机器 (虚拟机) | Windows 11 x64 21H2 | 192.168.109.128 | Vmware 17 |
最初我在虚拟机里装Windows 11只是为了测试其它的程序,这里也懒得重新装了,直接用Windows11测试。
建议还是选择同版本系统进行测试,以免影响驱动运行及测试。
如果在本机ping虚拟机,发现ping不通,应该是防火墙的问题
可以关闭虚拟机防火墙,如下
关闭后就可以ping得通了。
参数配置
接下来我们在虚拟机中进行配置:
以管理员运行命令提示符,完成以下操作
说明:bcdedit用于修改启动配置数据存储,这里不做详细介绍,感兴趣的可以参考以下链接
1、开启调试模式
1 bcdedit /debug on
参数 /debug: 启用或禁用指定启动项的内核调试程序
参数 on: 启用内核调试
2、配置调试模式参数
1 bcdedit /dbgsettings net hostip:192.168.109.1 port:50000
参数/dbgsettings:设置或显示系统的全局调试程序设置
参数 net :使用网络进行调试的连接方式,
参数 hostip:调试机器的IP,即上面表格中列出的192.168.109.1
参数 port:表示所使用网络的端口,这里使用的50000(建议范围是49152至65535,这样能最大程度的避免与已使用的端口有冲突)
命令执行成功后,会输出一个Key,这个Key会在Visual Studio中配置时用到,需要保留下来
切换到调试机器,打开Visual Studio,在工具栏中选择Configure target devices,如下所示
如果未在工具栏中找到这个按钮,可以在工具栏右键,钩选Driver,就可以看到Driver工具栏
在Configure Devices界面,选择添加新设备(Add New Device)
输入设备名称及hostname(或IP),这里我们直接使用被调试机器的IP:192.168.109.128
Provisioning Options这里选择Manual configure debuggers and do not provision(手动配置被调试机器以及手动分发驱动文件)
单击下一步,在这里配置端口、Key、及IP
说明:端口要保持跟前面在被调试机器中设置的一致,即50000。Key就是前面生成的Key。IP是被调试机器的IP
单击下一步,可以看到如下界面
此时已经完成了Visual Studio中的全部配置。
在代码中添加断点函数
在上一篇文章中,我们创建了一个基本的驱动程序,代码如下:
1 #include<ntddk.h> 2 3 VOID DriverUnload(PDRIVER_OBJECT DriverObject) 4 { 5 if (DriverObject != NULL) 6 { 7 DbgPrint("Driver Unload...Driver Object Address: %p\n", DriverObject); 8 } 9 10 return; 11 } 12 13 extern "C" NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) 14 { 15 KdBreakPoint(); 16 DbgPrint("Hello World\n"); 17 18 if (RegistryPath != NULL) 19 { 20 DbgPrint("Driver RegistryPath: %wZ\n", RegistryPath); 21 } 22 23 if (DriverObject != NULL) 24 { 25 DbgPrint("Driver Object Address: %p\n", DriverObject); 26 DriverObject->DriverUnload = DriverUnload; 27 } 28 29 KeBugCheckEx(INVALID_DATA_ACCESS_TRAP, NULL, NULL, NULL, NULL); 30 31 //return STATUS_FAILED_DRIVER_ENTRY; 32 }
开始调试前,首先修改一下MyFirstDriver驱动的入口函数,在DriverEntry入口函数中加入一个断点KdBreakPoint(),这样当MyFirstDriver运行的时候,就会在DriverEntry触发这个断点而停止下来。
说明:KdBreakPoint只对Debug版的驱动有效,如果需要对Release版本的驱动放置断点代码,请使用DbgBreakPoint。
编译通过后,将.sys文件复制到被调试机器中。
开始调试
在Visual Studio中,选择附加到进程
连接类型选择Windows Kernel Mode Debugger
连接目标选择前面创建的设备,即DriverTestVM
单击附加按钮后,Visual Studio会弹出 “Debugger Immediate Window”,窗口输出内容如下
这表示当前调试器使用网络连接方式,正在等待被连接。
此时我们切换到被调试机器 ,将系统重启,让被调试机器的调试设置生效。
在重启过程中,被调试机器会主动连接设置的50000端口,连接成功后,界面会输出以下内容
我们按照上一篇文章中的步骤,在被调试机中运行驱动,可以看到Visual Studio就中断在了KdBreakPoint()函数处,此时可以进行单步调试。
说明:可以使用VMWare的挂起功能,这次就可以不用每次都去设置禁用驱动程序强制签名 。
基于WinDbg的调试方法
说明:WinDbg是Windows开发经常用到的一个调试工具,包括用户层和内核层,在后面会进行详细的介绍
在WDK安装时,会自动安装WinDbg,路径为%programfiles(x86)%\Windows Kits\10\Debuggers\x64
使用WinDbg调试时,以串口(COM口)作为连接介质
参数配置
切换到被调试机,以管理员打开cmd,执行以下操作
1、开启调试模式
1 bcdedit /debug on
参数 /debug: 启用或禁用指定启动项的内核调试程序
参数 on: 启用内核调试
2、配置调试模式参数
1 bcdedit /dbgsettings serial baudrate:115200 debugport:2
参数/dbgsettings:设置或显示系统的全局调试程序设置
参数serial:表示使用串口作为连接介质
参数baudrate:表示串口使用的波特率,这里使用的是115200
参数debugport:表示 用来调试的串口号,这里表示 使用串口2作为连接介质
配置完成后,关闭被调试机,在Vmware的配置中,新增加一个串口设备
串口配置如下:
设备连接使用命名管道,名字为\\.\pipe\com_2
Windbg启动参数配置
切换到调试机,打开WinDbg的安装路径"%programfiles(x86)%\Windows Kits\10\Debuggers\x64\windbg.exe",将WinDbg发送到桌面快捷方式。
在快捷方式上右键-》属性-》快捷方式-》目标
在路径的后面填入如下参数(注意,-b前需要加入一个空格)
1 -b -k com:pipe,port=\\.\pipe\com_2,resets=0
如下所示
开始调试
切换到调试机,双击桌面的WinDbg快捷方式,WinDbg启动后会连接\\.\pipe\com_2管道,如下所示
此时我们将被调试机重启,可以看到WinDbg已经连接上被调试机,输出 如下所示
说明:可能由于我的被调试机是Windows11,所以运行WinDbg后,不能直接连接上,需要重启才能连接。而且重启后,需要在WinDbg中按下F5才能正常开机,不然会卡在开机界面。
我们按照上一篇文章中的步骤,在被调试机中运行驱动 ,WinDbg中断在了KdBreakPoint()函数处,此时可以进行单步调试。