1. 命令系统概述
1.1 命令分类
WinDbg的命令系统非常丰富,主要分为以下几类:
标准命令
- 执行控制命令:g, t, p, gu等
- 断点命令:bp, bl, bc等
- 内存命令:d, e, s等
- 寄存器命令:r, rm等
- 符号命令:x, ln, uf等
元命令(Meta Commands)
以点号(.)开头的命令,用于控制调试器本身:
.help # 显示帮助
.reload # 重新加载符号
.sympath # 设置符号路径
.logopen # 打开日志文件
扩展命令(Extension Commands)
以感叹号(!)开头的命令,提供专门的分析功能:
!analyze # 自动分析
!heap # 堆分析
!handle # 句柄分析
!process # 进程分析
1.2 命令语法规则
基本语法
命令 [选项] [参数1] [参数2] ...
地址表示法
# 十六进制地址(默认)
0x401000
401000
# 符号地址
kernel32!CreateFileW
mymodule!MyFunction+0x10
# 寄存器间接寻址
@eax
@esp+4
poi(@esp)
数值表示法
# 十六进制(默认)
0x100
100
# 十进制
0n256
0t256
# 八进制
0o377
# 二进制
0y11111111
1.3 命令历史和编辑
命令历史
↑ / ↓ # 浏览命令历史
Ctrl+R # 搜索命令历史
!history # 显示命令历史
命令编辑
Ctrl+A # 移到行首
Ctrl+E # 移到行尾
Ctrl+K # 删除到行尾
Ctrl+U # 删除整行
2. 执行控制命令
2.1 基本执行控制
继续执行
g # 继续执行
g <地址> # 执行到指定地址
g @eip+5 # 执行到当前指令后5字节
单步执行
t # 单步执行(进入函数调用)
p # 单步执行(跳过函数调用)
tt # 执行到下一个分支指令
pt # 跳过到下一个分支指令
高级执行控制
gu # 执行到当前函数返回
gu <地址> # 执行到指定函数返回
pc # 执行到下一个call指令
tc # 执行到下一个call指令(进入)
ph # 执行到下一个分支指令
th # 执行到下一个分支指令(进入)
2.2 条件执行
条件断点
# 设置条件断点
bp kernel32!CreateFileW "j (@rcx != 0) 'g'; 'kb'"
# 如果rcx不为0则继续执行,否则显示堆栈
# 计数断点
bp /1 myfunction # 断点只触发一次
bp /5 myfunction # 断点触发5次后自动删除
条件执行示例
# 循环执行直到条件满足
.while (@eax < 0x100) { t; r eax }
# 条件分支执行
.if (@eax == 0) { .echo "EAX is zero" } .else { .echo "EAX is not zero" }
2.3 异常处理
异常控制
sxe av # 在访问违例时中断
sxi av # 忽略访问违例
sxd av # 在访问违例时显示信息但不中断
# 查看异常设置
sx # 显示所有异常设置
sx av # 显示访问违例设置
常见异常类型
av # 访问违例
bp # 断点异常
eh # C++异常
clr # .NET异常
ld # 模块加载
ud # 模块卸载
3. 断点管理
3.1 断点类型
软件断点
bp <地址> # 设置软件断点
bp kernel32!CreateFileW
bp mymodule!MyFunction+0x10
bp 0x401000
硬件断点
ba e 1 <地址> # 设置执行断点(1字节)
ba r 4 <地址> # 设置读取断点(4字节)
ba w 4 <地址> # 设置写入断点(4字节)
ba rw 8 <地址> # 设置读写断点(8字节)
数据断点示例
# 监视变量修改
ba w 4 mymodule!g_variable
# 监视内存区域访问
ba rw 0x100 0x401000
# 监视堆栈变量
ba w 4 @esp+0x10
3.2 断点管理命令
断点列表和状态
bl # 列出所有断点
bl <断点号> # 显示特定断点信息
断点控制
bc <断点号> # 清除断点
bc * # 清除所有断点
bd <断点号> # 禁用断点
be <断点号> # 启用断点
断点修改
# 修改断点命令
bs <断点号> "命令" # 设置断点触发时执行的命令
# 示例:断点触发时显示寄存器并继续
bs 0 "r; g"
3.3 高级断点技巧
符号断点
# 模块加载时设置断点
bu mymodule!MyFunction
# bu表示unresolved breakpoint,模块加载后自动解析
# 通配符断点
bm mymodule!My* # 匹配所有以My开头的函数
bm *!CreateFile* # 匹配所有模块中的CreateFile函数
条件断点高级用法
# 复杂条件断点
bp kernel32!CreateFileW ".if (poi(@esp+4) != 0) { .echo 'File:'; da poi(@esp+4); g } .else { kb }"
# 计数器断点
bp myfunction ".if (@$t0 < 5) { r $t0 = @$t0 + 1; g } .else { kb }"
4. 内存操作命令
4.1 内存显示命令
基本显示命令
d <地址> # 显示内存(十六进制+ASCII)
db <地址> # 显示字节
dw <地址> # 显示字(2字节)
dd <地址> # 显示双字(4字节)
dq <地址> # 显示四字(8字节)
df <地址> # 显示浮点数
字符串显示
da <地址> # 显示ASCII字符串
du <地址> # 显示Unicode字符串
dS <地址> # 智能字符串显示
显示选项
# 指定显示长度
dd 401000 L10 # 显示16个双字
da 401000 L20 # 显示32个字符
# 指定结束地址
dd 401000 401040 # 显示从401000到401040的内容
4.2 内存修改命令
基本修改命令
e <地址> <值> # 修改内存
eb 401000 90 # 修改字节为0x90
ew 401000 1234 # 修改字为0x1234
ed 401000 12345678 # 修改双字为0x12345678
eq 401000 123456789abcdef0 # 修改四字
字符串修改
ea 401000 "Hello" # 修改为ASCII字符串
eu 401000 "Hello" # 修改为Unicode字符串
批量修改
# 填充内存
f 401000 L100 90 # 用0x90填充256字节
f 401000 401100 cc # 用0xcc填充指定范围
4.3 内存搜索命令
搜索字节模式
s -b 401000 L1000 90 90 90 # 搜索字节序列
s -w 401000 L1000 1234 # 搜索字值
s -d 401000 L1000 12345678 # 搜索双字值
搜索字符串
s -a 401000 L1000 "Hello" # 搜索ASCII字符串
s -u 401000 L1000 "Hello" # 搜索Unicode字符串
高级搜索
# 搜索指针
s -q 401000 L1000 kernel32!CreateFileW
# 搜索模式
s -b 0 L?80000000 ff 25 ?? ?? ?? ?? # 搜索JMP指令模式
5. 寄存器操作
5.1 寄存器显示
基本寄存器显示
r # 显示所有通用寄存器
rm # 显示寄存器掩码格式
rf # 显示浮点寄存器
rx # 显示SSE寄存器
特定寄存器显示
r eax # 显示EAX寄存器
r eax,ebx,ecx # 显示多个寄存器
r @eax # 显示EAX的值(作为地址)
标志寄存器
r efl # 显示标志寄存器
.formats @efl # 显示标志寄存器的各种格式
5.2 寄存器修改
基本修改
r eax = 12345678 # 设置EAX为指定值
r eip = 401000 # 修改指令指针
r esp = @esp + 4 # 修改堆栈指针
标志位修改
r efl = @efl | 0x40 # 设置零标志位
r efl = @efl & ~0x1 # 清除进位标志位
5.3 伪寄存器
WinDbg提供了一些伪寄存器用于特殊用途:
自动伪寄存器
@$ip # 当前指令指针
@$sp # 当前堆栈指针
@$bp # 当前基址指针
@$ra # 返回地址
用户定义伪寄存器
r $t0 = 12345 # 设置临时寄存器$t0
r $t1 = @eax + @ebx # 计算并存储到$t1
# 在脚本中使用
.for (r $t0 = 0; @$t0 < 10; r $t0 = @$t0 + 1) { .echo @$t0 }
6. 符号和模块操作
6.1 符号查找
符号搜索
x *!CreateFile* # 搜索所有模块中的CreateFile符号
x kernel32!* # 列出kernel32模块的所有符号
x mymodule!My* # 搜索mymodule中以My开头的符号
地址到符号转换
ln 401000 # 查找地址对应的最近符号
ln @eip # 查找当前指令的符号
符号到地址转换
? kernel32!CreateFileW # 显示符号地址
dd kernel32!CreateFileW # 显示符号处的内存
6.2 模块信息
模块列表
lm # 列出所有加载的模块
lm o # 按加载顺序列出模块
lm v # 详细模块信息
lm m kernel32 # 显示特定模块信息
模块详细信息
!lmi kernel32 # 显示模块详细信息
!dh kernel32 # 显示模块头信息
!imports kernel32 # 显示导入表
!exports kernel32 # 显示导出表
6.3 函数分析
反汇编函数
uf kernel32!CreateFileW # 反汇编整个函数
uf /c kernel32!CreateFileW # 显示函数调用
uf /i kernel32!CreateFileW # 显示指令地址
函数参数分析
!analyze -f # 分析当前函数
.fnent @eip # 显示函数入口信息
.fnret # 显示函数返回信息
7. 调用堆栈分析
7.1 堆栈显示
基本堆栈命令
k # 显示调用堆栈
kb # 显示堆栈和参数
kp # 显示堆栈和完整参数
kv # 显示详细堆栈信息
堆栈选项
k 10 # 显示10层堆栈
kb L20 # 显示20层堆栈和参数
kn # 显示带编号的堆栈
7.2 堆栈帧操作
切换堆栈帧
.frame 0 # 切换到第0帧
.frame 2 # 切换到第2帧
.frame /r 1 # 切换到第1帧并显示寄存器
堆栈帧信息
.frame # 显示当前帧信息
dv # 显示当前帧的局部变量
dt # 显示类型信息
7.3 多线程堆栈
线程切换
~ # 显示所有线程
~0s # 切换到线程0
~*k # 显示所有线程的堆栈
~*kb # 显示所有线程的详细堆栈
线程状态
!runaway # 显示线程CPU使用情况
!locks # 显示锁信息
!cs # 显示临界区信息
8. 调试技巧和最佳实践
8.1 高效调试技巧
命令组合
# 设置断点并显示上下文
bp kernel32!CreateFileW "kv; da @rcx; g"
# 循环监视变量
.while (1) { dd mymodule!g_counter L1; .sleep 1000 }
# 条件日志
bp myfunction ".if (@eax > 100) { .logopen c:\debug.log; .echo 'Large value:'; r eax; .logclose }"
脚本自动化
# 创建调试脚本文件 debug.wds
.echo "Starting debug session"
.sympath srv*c:\symbols*https://msdl.microsoft.com/download/symbols
.reload
bp kernel32!CreateFileW
g
# 执行脚本
$$>< c:\debug.wds
8.2 性能调试技巧
性能计数器
!perfctr # 显示性能计数器
.time # 显示时间信息
!runaway 7 # 显示详细的线程时间信息
内存使用分析
!heap -s # 堆统计信息
!heap -stat -h 0 # 详细堆统计
!address # 虚拟内存使用情况
!vm # 虚拟内存统计
8.3 错误诊断技巧
自动分析
!analyze -v # 详细自动分析
!analyze -hang # 分析挂起问题
!analyze -f # 分析当前函数
异常分析
.exr -1 # 显示最后一个异常记录
.cxr # 显示上下文记录
!cppexr # 分析C++异常
8.4 调试会话管理
会话保存和恢复
.dump /ma c:\crash.dmp # 创建完整内存转储
.opendump c:\crash.dmp # 打开转储文件
.writemem c:\mem.bin 401000 401100 # 保存内存到文件
日志管理
.logopen c:\debug.log # 打开日志文件
.logappend c:\debug.log # 追加到日志文件
.logclose # 关闭日志文件
9. 常见问题和解决方案
9.1 符号问题
符号加载失败
# 检查符号路径
.sympath
# 强制重新加载符号
.reload /f
# 详细符号加载信息
!sym noisy
.reload
符号不匹配
# 检查模块版本
lm v m kernel32
# 验证符号
!chksym kernel32
# 手动加载符号
.reload /i kernel32
9.2 调试器连接问题
附加进程失败
# 检查进程权限
!process 0 0 notepad.exe
# 使用管理员权限
# 重新启动WinDbg as Administrator
# 检查防病毒软件干扰
内核调试连接问题
# 检查调试设置
bcdedit /debug on
bcdedit /dbgsettings
# 验证连接
.reboot
9.3 性能问题
调试器响应慢
# 禁用不必要的符号加载
.symopt +0x40
# 限制输出长度
.prefer_dml 0
# 使用本地符号缓存
.sympath cache*c:\symcache;srv*https://msdl.microsoft.com/download/symbols
内存使用过高
# 清理符号缓存
.reload /u
# 限制历史记录
!history -c
# 重启调试会话
小结
本章详细介绍了WinDbg的基本命令和调试技巧:
- 命令系统:掌握了标准命令、元命令和扩展命令的使用
- 执行控制:学习了程序执行控制和异常处理
- 断点管理:了解了各种断点类型和高级断点技巧
- 内存操作:掌握了内存显示、修改和搜索命令
- 寄存器操作:学习了寄存器查看和修改技巧
- 符号分析:了解了符号查找和模块分析方法
- 堆栈分析:掌握了调用堆栈和多线程调试
- 调试技巧:学习了高效调试和问题诊断方法
下一章将学习WinDbg的高级调试功能和专项分析技术。