首页
社区
课程
招聘
5
[原创]windbg 常用调试命令总结
发表于: 2025-3-12 10:11 2484

[原创]windbg 常用调试命令总结

2025-3-12 10:11
2484

windbg 是 Microsoft 公司免费调试器调试集合中的 GUI 的调试器,支持 Source 和 Assembly 两种模式的调试。Windbg 不仅可以调试应用程序,还可以进行 Kernel Debug。结合 Microsoft 的 Symbol Server,可以获取系统符号文件,便于应用程序和内核的调试。Windbg 支持的平台包括 X86、IA64、AMD64。

那么在我们使用 windbg 的时候,虽然命令纷繁复杂,但是有一些常用的命令是我们需要掌握的,熟练的运用这些命令能给我们调试带来事半功倍的效果,因此我对常用命令进行了一个总结,方便查找。

至于其他更为复杂命令使用,我们可以通过查看官方提供的 windbg 命令手册:
https://learn.microsoft.com/zh-cn/windows-hardware/drivers/debuggercmds/commands

1.流程控制相关命令

g               // Go 让程序跑起来
p               // 单步步进(F10)
p 2             // 单步步进2次
pa 0x7c801b0b   // 单步布进执行到 7c801b0b 地址处停下
pc              // 单步步进执行到下一个函数调用处停下

q               // 结束调试会话(会结束进程,但不会退出 windbg)
qd              // 脱离调试会话(不会结束进程,也不会退出 windbg)

.restart        // 重启目标进程
.reboot         // 重启调试系统(内核调试中使用)

2.内存读写相关命令

db      // 按字节显示(1字节)
dw      // 按单字显示(2字节)
dd      // 按双字显示(4字节)
dq      // 按四字显示(8字节)
da      // 按 ASCll 字符显示(1字节)
du      // 按 UNICODE 字节显示(2字节)
df      // 按单精度浮点数显示(4字节)
dD      // 按双精度浮点数显示(8字节)

eb      // 按字节写入(1字节)
ew      // 按单字写入(2字节)
ed      // 按双字写入(4字节)
eq      // 按四字写入(8字节)
ea      // 按 ASCll 字符写入(1字节,不会自动在结尾填充 '\0' 字符)
eu      // 按 UNICODE 字符写入(2字节,不会自动在结尾填充 '\0' 字符)
ef      // 按单精度浮点数写入(4字节)
eD      // 按双精度浮点数写入(8字节)
eza     // 按 ASCll 字符写入(1字节,会自动在结尾填充 '\0' 字符)
ezu     // 按 UNICODE 字符写入(2字节,会自动在结尾填充 '\0' 字符)

!db     // 将物理地址按字节显示(1字节),其他内存操作命令同理

dds     // 按双字(4字节)显示给定范围内的内存内容(此内存被假定为符号表中的一系列地址,相应的符号也会显示)
dqs     // 按四字(8字节)显示给定范围内的内存内容(此内存被假定为符号表中的一系列地址,相应的符号也会显示)

dt _eprocess        // 查看 EPROCESS 结构体成员
dt _eprocess 0x510  // 从地址 0x510 处按照结构体 EPROCESS 对数据进行解析
dt ntdll!*          // 显示ntdll里的所有类型信息
dt ntdll!_peb*      // *是通配符;显示 ntdll 模块中所有peb打头的结构体名称;

r               // 显示所有寄存器信息及发生 core 所在的指令
r eax, gdtr     // 显示eax,gdtr寄存器信息
r eax=5, edx=6  // 对寄存器eax赋值为5,edx赋值为6

!pte 0x80b99000            // 查看当前进程(一般为系统进程)中虚拟地址的页表和页目录信息
!vtop 33a3f000 0x80b99000  // 查看指定页目录基址(cr3)中虚拟地址的页表和页目录信息

3.内存搜索相关命令

可以指定的查找模式有:
-b    // 字节(8位)
-w    // WORD(16位)
-d    // DWORD(32位)
-q    // QWORD(64位)

s -b fffff801`87b58a70 L100 cc c2    // 从地址处往后100个字节里查找字节序列为 cc c2 的地址
s -b fffff801`87b58a70 L-100 cc c2   // 从地址处往前查找
s -b fffff801`87b58a70 L100 'k' 'k'  // 查找字节序列的 ascall 码为 k k 的地址

s -d fffff801`87b58a70 L100 'H'      // 按照双字查找 ascall 码为 H 的地址,结果如下:
(fffff801`87b58a70 00000048 00000000 500c0163 00000000 H.......c..P....)

s -a fffff801`87b58a70 L100 "ntdll"  // 查找 ascall 字符串为 "ntdll" 的地址,结果如下:
(fffff801`87b58a70 6e 74 64 6c 6c 5c 6c 64-72 69 6e 69 74 2e 63 00 ntdll\ldrinit.c.)

4.断点相关命令

硬件断点(ba):break on access,又称为处理器断点、数据访问断点
参数:

  • e(执行):当 CPU 从指定地址检索指令时,会中断到调试器(和软件断点类似,但不需要向目标代码插入断点指令)。
  • r(读取/写入):当 CPU 读取或写入指定地址时,中断到调试器。
  • w(写入):当 CPU 写入指定地址时,中断到调试器。
  • i(I/O):(仅内核模式,仅基于 x86 的系统)访问指定地址处的 I/O 端口时,中断到调试器。
ba r4 0x00401200    // r4 表示在对指定地址开始的 4 字节内存区进行读写操作时中断
ba w4 0x00401200    // w4 表示在对指定地址开始的 4 字节内存区进行写操作时中断
ba i4 0x3f8      // 访问该地址数据时断下,该命令在所有串行端口上添加一个断点,其中包含从 0x3F8 到 0x3FB 的地址

软件断点(bp, bu, bm)
bp(设置软件断点):在指定地址处设置一个断点。如果调试器在设置断点时无法解析断点的地址表达式,则 bp 断点将自动转换为 bu 断点,且使用 bp 命令创建的断点在模块卸载后不再处于活动状态。
bu(设置未解析的断点):在指定地址设置延迟或未解析的断点。bu 命令是在断点地址的符号引用上设置的,并在解析具有引用的模块时激活。

bp main        // 在 main 函数开头设置一个软件断点
bp 0x7c801b00    // 在 7c801b00 地址处放置一个软件断点
bp /p EProcess    //(仅内核模式)对 EProcess 所对应的进程设置软件断点(其中所有线程都会设置)
bp /t EThread    //(仅内核模式)对 EThread 所对应的线程设置软件断点
bu 0x7c801b00    // 设置一个未解析的断点

其他断点命令

bl            // 列出所有断点
bc *          // 清除所有断点
be *          // 启用所有断点
bd *          // 禁用所有断点
bc 1 2 5      // 清除1号、2号、5号断点,其他命令同理

5.反汇编相关命令

u                      // 反汇编当前 eip 寄存器地址的后8条指令
u main.exe+0x10 L20    // 反汇编 main.exe+0x10 地址后20条指令
ub 000c135d L20        // 查看地址为000c135d指令前的20条指令内容
uf NtOpenProcess       // 反汇编 NtOpenProcess 函数
uf demo::add           // 反汇编demo类的add函数

6.堆栈相关命令

k       // 显示当前调用堆栈
kn      // 带栈编号显示当前调用堆栈
kb      // 打印出前3个函数参数的当前调用堆栈
kb 5    // 只显示最上的5层调用堆栈
kv      // 在kb的基础上增加了函数调用约定、FPO等信息
kp      // 显示每一层函数调用的完整参数,包括参数类型、名字、取值
kd      // 打印堆栈的地址

.frame         // 显示当前栈帧
.frame n       // 显示编号为n的栈帧(n为16进制数)
.frame /r n    // 显示编号n的栈帧(n为16进制数) 并显示寄存器变量
.frame /c n    // 设置编号n的栈帧为当前栈帧(n为16进制数)

dv             // 显示当前栈帧的参数和局部变量

7.进程线程相关命令

!process -1 1                    // 查看当前进程信息
!process 0n<进程PID> 0(e.g. !process 0n4 0)         // 获取 PID 为 4 的进程信息
!process 0 0 <进程名>(e.g. !process 0 0 x64.exe)    // 获取进程名为 x64 的进程信息
!process 86a7d030    // 显示 EPROCESS 结构地址为 0x86a7d030 的进程关键信息(包括所有线程)
!peb    // 显示当前进程的 peb 详细信息
!peb 7ffdf000    // 显示当前进程中位于 0x7ffdf000 处的 PEB 结构(先用 .process 命令切换到目标进程)
!Token e24d8510    // 查看当前进程中位于 0xe24d8510 处的 Token 结构(包含进程的很多与安全有关的信息)
.context    // 显示用户态当前进程的上下文/页目录基址(物理地址)
.process    // 显示当前进程 EPROCESS
.process /p /i <进程eprocess>    // 切换到目标进程的上下文
.process /p /r <进程eprocess>    // 切换到目标进程的上下文后重新加载用户模式符号(/r 与 .reload /user 效果相同)
.thread    // 显示当前的线程 ETHREAD
.thread 84018d78    // 切换到特定的线程上下文

8.模块相关命令

lm            // 列出所有模块对应的符号信息
lm u          // (仅内核模式)仅显示用户模式符号信息
lm k          // (仅内核模式)仅显示内核模式符号信息
ld *          // 为所有模块加载符号(只为当前进程)
ld kernel32   // 加载 kernel32.dll 的符号(只为当前进程)

9.符号相关命令

.sympath              // 查看当前符号查找路径
.sympath c:\symbols   // 将符号查找路径设为:c:\symbols
.sympath SRV*C:\ProgramData\dbg\sym*http://msdl.microsoft.com/download/symbols    // 指定符号路径为远程服务器
.sympath+ c:\symbols  // 将c:\symbols添加到符号查找路径集合中

.reload               // 为所有已加载模块载入符号信息(为所有进程)
.reload /f kernel32.dll    // 为指定模块加载符号信息(为所有进程)
.reload /f /v         // f:强制立即模式(不允许延迟载入)  v:详细模式
.reload /f @"c:\windows\System32\verifier.dll"   // 为指定模块加载符号信息

10.其他常用命令

ed kd_default_mask 0xffffffff    // 设置在 windbg 上输出调试信息

dg 10(dg cs)    // cs=0010,显示一个段选择子所指向的段描述符的详细信息
(                                P Si Gr Pr Lo
Sel    Base     Limit     Type    l ze an es ng Flags
---- -------- -------- ---------- - -- -- -- -- --------
0010 00000000 ffffffff Data RW Ac 0 Bg Pg P  Nl 00000c93
)

!pte    //

.formats 10    // 在当前线程和进程的上下文中计算表达式或符号,并将其以多个数字格式显示
(
Evaluate expression:
  Hex:     00000010
  Decimal: 16
  Octal:   00000000020
  Binary:  00000000 00000000 00000000 00010000
  Chars:   ....
  Time:    Thu Jan  1 08:00:16 1970
  Float:   low 2.24208e-044 high 0
  Double:  7.90505e-323
)

? 0y0000101110    // ? 命令计算并显示表达式的值,0y 表示后面跟着二进制
(Evaluate expression: 46 = 0000002e)
? 0t123    // 计算八进制
(Evaluate expression: 83 = 00000053)
? 123    // 计算十进制
(Evaluate expression: 291 = 00000123)
? 0x4d    // 计算十六进制
(Evaluate expression: 77 = 0000004d)

!idt -a    // 列出 IDT 中的所有项
!idt 3    // 显示中断向量表中 3 号向量对应的服务例程和地址

.thread    // 显示当前线程的 ETHREAD 结构地址
!thread 873e9500    // 以简洁的方式显示 873e9500 地址的 ETHREAD 结构
!teb    // 显示当前线程的 TEB 结构地址

!apc    // 显示系统中所有进程的所有 APC
!apc proc ffffc10f`8fe5a080    // 显示 EPROCESS 为 ffffc10f`8fe5a080 的进程的所有 APC

!pcr    // 获取当前 CPU 的 KPCR 结构地址
dt nt!_KPCR fffff803077dc000 -y IRQL    // 获取地址为 fffff803077dc000 的 KPCR 结构中的请求级别
dt ntdll!_Teb  0000003c`99f0e000 -y DbgSsReserved    // 以递归方式显示特定地址的 Teb 结构中的 DbgSsReserved 字段

!dpcs    // 获取当前 CPU 的 DPC 队列
dt _KDPC 0xffffe009aa42738    // 获取地址为 0xffffe009aa42738 的 DPC 队列

!alpc /lpp ffffc48d86b00640    // 列出 EPROCESS 为 ffffc48d86b00640 的进程的所有 LPC 端口
!alpc /p ffffc48d8895de20    // 观察指定地址 LPC 端口的详情
!alpc /m ffffa480730b6890    // 观察特定 LPC 端口中特定消息的详情

x nt!Dbg*    // 查看 nt 模块中以 Dbg 开头的所有函数

!handle 0    // 列出当前进程中所有句柄
!handle 句柄地址    // 查看句柄的类型
!hanlde 0 6 Mutant    // 只显示互斥类型的对象

!object 对象地址    // 查看对象类型 

ln eip    // 列出与 eip 值最近的符号

!address 0013073c    // 显示特定地址内存信息

[注意]看雪招聘,专注安全领域的专业人才平台!

收藏
免费 5
支持
分享
赞赏记录
参与人
雪币
留言
时间
_Smile`Melo
感谢你的贡献,论坛因你而更加精彩!
3天前
mb_nfpyhygl
这个讨论对我很有帮助,谢谢!
4天前
shishichen
为你点赞!
2025-3-21 06:42
木志本柯
+6
你的帖子非常有用,感谢分享!
2025-3-18 11:18
周旋久
非常支持你的观点!
2025-3-18 10:26
最新回复 (4)
雪    币: 4020
活跃值: (4282)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
2
分享一条命令:用cmd启动windbg.exe,命令行参数为-xe cpr   xxxxxx.exe,这样调试器会在xxxxxx.exe进程的ntdll.dll入口点执行前中断下来,可以调试ntdll.dll的初始化流程。
2025-3-19 10:24
1
雪    币: 79
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
3
fengyunabc 分享一条命令:用cmd启动windbg.exe,命令行参数为-xe cpr xxxxxx.exe,这样调试器会在xxxxxx.exe进程的ntdll.dll入口点执行前中断下来,可以调试ntdll ...
好的 我试试 感谢  涨知识了 哈哈
6天前
0
雪    币: 0
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
4
windbg如何查看内核调试的寄存器,怎么设置呢?
4天前
0
雪    币: 79
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
5
mb_nfpyhygl windbg如何查看内核调试的寄存器,怎么设置呢?
直接用 r 命令就可以了 
查看寄存器:r rax, rbx
修改寄存器:r rax=0
3天前
0
游客
登录 | 注册 方可回帖
返回

账号登录
验证码登录

忘记密码?
没有账号?立即免费注册