WinDBG 是在 windows 平台下,强大的用户态和内核态调试工具,相比较于 Visual Studio 它是一个轻量级的调试工具,所谓轻量级指的是它的安装文件大小较小,但是其调试功能,却比VS更为强大,WinDBG由于是微软的产品所以能够调试Windows系统的内核,另外一个用途是可以用来分析dump数据,本笔记用于记录WinDBG内核调试的配置过程,并附有常用命令的使用方法。

1.首先需要安装VmWare虚拟机,并自行安装好Windows系统,虚拟机关闭状态下添加一个管道虚拟串口,此处需要删除打印机,否则串口之间冲突。

操作步骤:​​编辑虚拟机设置​​ -> ​​添加​​ -> ​​串行端口​​ -> ​​完成​​ -> 并配置以下参数 参数配置:​​使用命名管道​​ -> ​​\\.\pipe\com_1​​ -> ​​该端是服务器,另一端是应用程序​​ -> ​​轮询时主动放弃CPU​​->​​确定​

WinDBG 配置内核双机调试_Windows 驱动开发

2.开启虚拟机中的Windows7系统,然后以管理员身份运行CMD命令行,输入​​bcdedit​​命令,可以查看到系统的当前启动项,如果是新的系统,则只会有一个 ​​{current}​​ 的启动项。

WinDBG 配置内核双机调试_Windows 驱动开发_02

3.接着我们连续执行下方的三条命令,依次建立启动项,并激活调试模式。

# windows 7 配置
bcdedit /copy {current} /d "Windwos7"
bcdedit /debug ON
bcdedit /bootdebug ON
bcdedit /timeout 10

# windows 10 配置
bcdedit /set testsigning on
bcdedit -debug on
bcdedit /bootdebug on

bcdedit /set "{current}" bootmenupolicy Legacy // 修改启动方式为Legacy
bcdedit /dbgsettings SERIAL DEBUGPORT:1 BAUDRATE:115200 // 设置串口1为调试端口波特率为115200
bcdedit /copy "{current}" /d "Debug" // 将当前配置复制到Debug启动配置

bcdedit /enum // 记录下debug下的标识符
bcdedit /debug "{<新建的启动配置的标识符>}" on // 打开调试开关

WinDBG 配置内核双机调试_Windows 驱动开发_03

4.最后查看一下当前调试配置选项,执行命令 ​​bcdedit /dbgsettings​​,显示出使用的第一个串口,波特率为115200bps,保持默认不需要修改。

WinDBG 配置内核双机调试_windows系统_04

5.配置完成后,重新启动系统,在开机的时候选择​​Windows7 [启用调试程序]​​则系统会黑屏,说明已经正常进入调试模式了。

WinDBG 配置内核双机调试_加载_05

6.接着回到物理机上面,我们在命令行中切换到WinDBG的根目录下,并执行以下命令,即可连接虚拟机串口进行调试了。 执行命令 ​​Windbg.exe -b -k com:port=\\.\pipe\com_1,baud=115200,pipe​​ 如下图,已经成功连接上了。

WinDBG 配置内核双机调试_加载_06

7.为了方便调试,可以通过【File菜单】加载一下符号文件,也可以按下【Ctrl+S】并输入。 输入命令 ​​srv*c:\symbols*http://msdl.microsoft.com/download/symbols​​ 自动下载符号保存到C盘下。

WinDBG 配置内核双机调试_加载_07

到此为止,我们的内核调试环境已经配置并能够独立工作了,接下来,我们将手动编译一个简单的驱动文件,并通过WinDBG对其进行调试分析。

1.首先我们需要编写一个简单的驱动程序,由于我们的驱动程序比较的简单,所以我们只能够从DriverEntry驱动开始执行之前下一个断点,此处我们可以通过内联汇编的方式手动加入一个断点,其最终代码如下所示。

#include <ntifs.h>

// 绕过签名检测
void BypassCheckSign(PDRIVER_OBJECT pDriverObj)
{
//STRUCT FOR WIN64
typedef struct _LDR_DATA // 24 elements, 0xE0 bytes (sizeof)
{
struct _LIST_ENTRY InLoadOrderLinks; // 2 elements, 0x10 bytes (sizeof)
struct _LIST_ENTRY InMemoryOrderLinks; // 2 elements, 0x10 bytes (sizeof)
struct _LIST_ENTRY InInitializationOrderLinks; // 2 elements, 0x10 bytes (sizeof)
VOID* DllBase;
VOID* EntryPoint;
ULONG32 SizeOfImage;
UINT8 _PADDING0_[0x4];
struct _UNICODE_STRING FullDllName; // 3 elements, 0x10 bytes (sizeof)
struct _UNICODE_STRING BaseDllName; // 3 elements, 0x10 bytes (sizeof)
ULONG32 Flags;
}LDR_DATA, *PLDR_DATA;
PLDR_DATA ldr;
ldr = (PLDR_DATA)(pDriverObj->DriverSection);
ldr->Flags |= 0x20;
}

NTSTATUS DriverDefaultHandle(PDEVICE_OBJECT pDevObj, PIRP pIrp)
{
NTSTATUS status = STATUS_SUCCESS;
pIrp->IoStatus.Status = status;
pIrp->IoStatus.Information = 0;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);

return status;
}

VOID UnDriver(PDRIVER_OBJECT driver)
{
DbgPrint("驱动已卸载 \n");
}

NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{
// 绕过签名
BypassCheckSign(Driver);

// 初始化默认派遣函数
NTSTATUS status = STATUS_SUCCESS;
Driver->DriverUnload = UnDriver;
for (ULONG i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)
{
Driver->MajorFunction[i] = DriverDefaultHandle;
}

// 设置断点
DbgBreakPoint();
// KdBreakPoint();
// __debugbreak();

DbgPrint("驱动已加载 \n");
Driver->DriverUnload = UnDriver;
return STATUS_SUCCESS;
}

2.现在我们启动Windows7系统,并通过上面的方法使之与WinDBG联机,当WinDBG断下时,手动添加符号文件。

按下 ​​Ctrl +S​​ 加入以下符号文件,最后的路径是你驱动编译所在路径。 .sympath SRVc:\mySymbols​http://msdl.microsoft.com/download/symbols​

上方步骤总结起来如下:

windbg.exe -b -k com:port=\\.\pipe\com_1,baud=115200,pipe
.sympath SRV*c:\mySymbols*http://msdl.microsoft.com/download/symbols
.reload
ed nt!Kd_SXS_Mask 0
ed nt!Kd_FUSION_Mask 0
u KiSystemServiceUser

WinDBG 配置内核双机调试_启动项_08

添加符号完成以后,在命令窗口输入g并按下回车键,过程中可能需要按下多次g键,使Windows系统正常加载并运行。

WinDBG 配置内核双机调试_Windows 驱动开发_09

当Windows系统加载完成以后,拖入我们的驱动文件​​wdk.sys​​,并通过驱动加载工具加载运行,此时Windows系统会卡死,回到WinDBG中发现已经可以进行源码调试了哈。

WinDBG 配置内核双机调试_启动项_10