1、课程目标
- 理解内核调试的基本概念和原理
- 掌握VMware虚拟机双机调试配置
- 学会使用WinDbg进行内核调试
- 熟悉常用内核调试命令
2、名词解释
| 术语 |
解释 |
| Ring0 |
CPU最高特权级,内核模式运行级别 |
| Ring3 |
用户模式运行级别 |
| KD |
Kernel Debugger,内核调试器 |
| 双机调试 |
使用两台机器进行内核调试的方式 |
| 串口调试 |
通过COM口进行调试通信 |
| 命名管道调试 |
VMware通过命名管道模拟串口 |
3、使用工具
| 工具 |
用途 |
| VMware Workstation |
虚拟化平台 |
| WinDbg |
内核调试器 |
| VirtualKD |
加速虚拟机调试 |
| bcdedit |
配置启动选项 |
4、技术原理
4.1、双机调试架构
┌─────────────────────────────────────────────────────────────┐
│ 双机调试架构 │
│ │
│ 主机(Host) 虚拟机(Guest) │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ WinDbg │ │ 被调试系统 │ │
│ │ (Debugger) │←─────────────→│ (Debugee) │ │
│ └──────────────┘ 命名管道 └──────────────┘ │
│ ↑ \\.\pipe\ 调试引擎内置 │
│ │ com_1 于Windows内核 │
│ 调试符号(.pdb) │
│ 源代码 │
└─────────────────────────────────────────────────────────────┘
4.2、调试通信方式对比
| 方式 |
速度 |
配置难度 |
适用场景 |
| 串口(COM) |
慢 |
简单 |
物理双机 |
| 1394火线 |
快 |
中等 |
物理双机 |
| USB 3.0 |
快 |
中等 |
物理双机 |
| 命名管道 |
中等 |
简单 |
VMware |
| 网络调试 |
快 |
复杂 |
远程调试 |
5、配置步骤
5.1、步骤1:VMware虚拟机配置
1. 关闭虚拟机
2. 编辑虚拟机设置 → 添加 → 串行端口
3. 选择"输出到命名管道"
4. 配置:
- 命名管道:\\.\pipe\com_1
- 连接:该端是服务器
- 另一端:应用程序
5. 在.vmx文件中添加(可选,加速):
serial0.present = "TRUE"
serial0.fileType = "pipe"
serial0.fileName = "\\.\pipe\com_1"
serial0.tryNoRxLoss = "TRUE"
serial0.pipe.endPoint = "server"
5.2、步骤2:被调试系统配置
:: 以管理员权限运行
:: 开启调试模式
bcdedit /debug on
:: 设置调试类型为串口
bcdedit /dbgsettings serial debugport:1 baudrate:115200
:: 禁用驱动签名(开发测试)
bcdedit /set testsigning on
:: 查看当前配置
bcdedit /dbgsettings
:: 重启生效
shutdown /r /t 0
5.3、步骤3:WinDbg连接配置
1. 启动WinDbg(以管理员权限)
2. File → Kernel Debug(Ctrl+K)
3. 选择COM选项卡
4. 配置:
- Baud Rate: 115200
- Port: \\.\pipe\com_1
- 勾选 Pipe
- 勾选 Reconnect
5. 点击OK开始连接
6. 启动虚拟机,WinDbg自动连接
6、代码实现
6.1、示例1:WinDbg常用命令
# ==================== 基础命令 ====================
# 中断执行
Ctrl+Break
# 继续执行
g
# 单步步入
t
# 单步步过
p
# 查看寄存器
r
# 查看调用栈
k
kb # 带参数
kv # 详细信息
kp # 显示完整参数
# ==================== 内存操作 ====================
# 显示内存(字节)
db <address> L<length>
# 显示内存(双字)
dd <address>
# 显示内存(四字)
dq <address>
# 显示内存(ASCII字符串)
da <address>
# 显示内存(Unicode字符串)
du <address>
# 修改内存
eb <address> <value> # 写字节
ed <address> <value> # 写双字
# 搜索内存
s -b <start> L<length> <pattern>
s -a <start> L<length> "string"
# ==================== 断点命令 ====================
# 设置断点
bp <address>
bp <module>!<function>
bp nt!NtCreateFile
# 条件断点
bp nt!NtOpenProcess ".if (@rcx == 0x1234) {} .else {gc}"
# 硬件断点(写入)
ba w4 <address>
# 硬件断点(执行)
ba e1 <address>
# 列出断点
bl
# 删除断点
bc <id>
bc * # 删除所有
# 禁用/启用断点
bd <id>
be <id>
# ==================== 符号和模块 ====================
# 重新加载符号
.reload
# 加载指定模块符号
.reload /f <module>
# 设置符号路径
.sympath srv*c:\symbols*https://msdl.microsoft.com/download/symbols
# 查看模块列表
lm
# 查看模块详情
lm v m <module>
# 查看符号
x <module>!<pattern>
x nt!Nt*
# ==================== 进程线程 ====================
# 列出进程
!process 0 0
# 查看指定进程详情
!process <EPROCESS> 7
# 切换进程上下文
.process /i <EPROCESS>
# 列出线程
!thread
# 查看线程详情
!thread <ETHREAD>
# ==================== 系统信息 ====================
# 查看系统版本
vertarget
# 查看KPCR
!pcr
# 查看IDT
!idt
# 查看GDT
!gdt
# 查看系统调用表
dps nt!KiServiceTable L<count>
6.2、示例2:调试脚本
// debug_script.txt - WinDbg调试脚本
// 设置符号路径
.sympath srv*c:\symbols*https://msdl.microsoft.com/download/symbols
// 加载内核符号
.reload /f nt
// 开启详细输出
!sym noisy
// 设置常用断点
bp nt!NtCreateFile
bp nt!NtOpenProcess
bp nt!NtReadVirtualMemory
bp nt!NtWriteVirtualMemory
// 设置日志断点(不中断)
bp nt!NtCreateFile ".printf \"NtCreateFile called\\n\"; gc"
// 运行脚本: $$><debug_script.txt
6.3、示例3:VirtualKD加速调试
:: VirtualKD 安装步骤
:: 1. 下载VirtualKD-Redux
:: https://github.com/4d61726b/VirtualKD-Redux
:: 2. 在虚拟机中运行target\vminstall.exe
:: 3. 选择安装调试引导项
:: 4. 重启虚拟机
:: 5. 在主机运行vmmon64.exe
:: 6. 启动虚拟机,选择VirtualKD启动项
:: 7. vmmon自动启动WinDbg并连接
:: 速度对比:
:: - 原生串口:~115200 bps
:: - VirtualKD:~150 MB/s(提升1000倍)
6.4、示例4:网络调试配置
:: Windows 8及以上支持网络调试
:: 被调试机配置
bcdedit /debug on
bcdedit /dbgsettings net hostip:192.168.1.100 port:50000
:: 会显示一个Key,需要记录
:: Key=1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16
:: WinDbg连接
:: File → Kernel Debug → NET
:: Port: 50000
:: Key: <上面生成的Key>
6.5、示例5:常用调试场景
// ==================== 场景1:分析蓝屏 ====================
// 加载dump文件
File → Open Crash Dump
// 自动分析
!analyze -v
// 查看崩溃调用栈
.trap <trap_frame>
kv
// ==================== 场景2:驱动调试 ====================
// 在驱动入口设断点
bu MyDriver!DriverEntry
// 查看驱动对象
!drvobj MyDriver
// 查看设备对象
!devobj <DEVICE_OBJECT>
// ==================== 场景3:查找隐藏进程 ====================
// 遍历活动进程链表
!process 0 0
// 获取PsActiveProcessHead
? nt!PsActiveProcessHead
// 手动遍历
dt nt!_EPROCESS <address> ActiveProcessLinks
// ==================== 场景4:SSDT分析 ====================
// 获取SSDT基址
dps nt!KiServiceTable L100
// 查看特定服务号
dps nt!KiServiceTable+8*<index> L1
// 检测HOOK
!chkimg nt -d
7、课后作业
- 配置VMware+WinDbg双机调试环境
- 安装VirtualKD并验证调试速度提升
- 练习使用WinDbg查看进程、线程、模块信息
- 编写一个调试脚本自动设置常用断点
8、扩展阅读
- WinDbg官方文档
- Windows Internals
- Advanced Windows Debugging (Mario Hewardt)