命令标记
命令分隔符
- 用于分隔单行上的多个命令
块分隔符
- 圆括号
1 |
? (1 + 2) * 3 |
- 一对大括号 (
{ }
) 用于包围调试器命令程序中的语句块
1 2 3 |
.if (@eax == 0) { .echo "EAX is zero"; } .else { .echo "EAX is not zero"; } .for (r $t0 = 0; @$t0 < 5; r $t0 = @$t0 + 1) { .echo @$t0; } |
- 方括号
- 用于访问数组元素或表示寄存器或内存位置
1 |
dd [eax] |
别名解释器
- 用户别名(以
$
开头)- 用户别名只能在当前调试会话中使用
- 例如:
$myalias
- 全局别名(以
$$
开头)- 全局别名在所有调试会话中可用
- 例如:
$$myglobalalias
- 定义用户别名:
1 |
as $myalias .echo "Hello, World!" |
- 定义全局别名:
- 使用
as /g
命令定义全局别名
- 使用
1 |
as /g $$myglobalalias .echo "Hello, Global World!" |
- 使用
al
命令显示所有当前定义的别名
1 |
al |
- 使用
ad
命令删除别名
1 2 |
ad $myalias ad /g $$myglobalalias |
- 直接输入别名名称即可执行定义的命令
1 |
$myalias |
- 直接输入全局别名名称即可执行定义的命令
1 |
$$myglobalalias |
- 高级用法:别名与表达式结合
- 可以将别名与表达式结合使用,以简化复杂的调试任务
1 2 |
as $showregs r $showregs |
- 高级用法:嵌套别名
- 可以嵌套使用,即一个别名可以引用另一个别名
1 2 3 |
as $alias1 .echo "This is alias1" as $alias2 $alias1 $alias2 |
注释说明符
- 使用
;
符号添加单行注释
1 |
.echo "This is a command"; This is a comment |
WinDbg
本身不直接支持块注释,但你可以使用多个单行注释来实现类似的效果
1 2 |
; This is a multi-line comment ; that spans multiple lines |
.block
- 在
WinDbg
中,.block
命令用于创建一个代码块,该代码块中的命令会被作为一个整体执行- 这对于在条件语句、循环和宏定义中组合多条命令特别有用
1 2 3 4 5 6 7 8 9 10 11 12 13 |
.if (@eax == 0) { .block { .echo "EAX is zero"; r eax=1; .echo "EAX has been set to 1"; } } .else { .block { .echo "EAX is not zero"; r eax=0; .echo "EAX has been set to 0"; } } |
.break
- 在
WinDbg
中,.break
命令用于中断当前的调试会话,使调试器进入命令模式- 这通常用于调试过程中需要临时停止程序的执行以检查状态或修改内存和寄存器
.catch
- 在
WinDbg
中,.catch
命令用于设置异常捕获点- 当指定的异常发生时,调试器会捕获并停止在异常发生的地方
- 这对于调试特定类型的异常或错误非常有用
- 捕获访问冲突异常(异常代码为
0xC0000005
),可以使用以下命令:
1 |
.catch 0xC0000005 |
- 捕获所有异常,可以使用以下命令:
1 |
.catch -1 |
- 查看当前设置的捕获点
1 |
.catch |
- 删除对访问冲突异常的捕获点:
1 |
.catch -d 0xC0000005 |
- 删除所有捕获点
1 |
.catch -d -1 |
- 高级用法
- 可以在特定线程中设置异常捕获点,以便更精细地控制调试过程
- 切换到线程
3
,~3s
- 设置对访问冲突异常的捕获点
.catch 0xC0000005
- 运行程序
g
.continue
- 在
WinDbg
中,.continue
命令用于继续执行调试目标- 这与
g
(go
)命令类似,但通常用于处理器命令执行之后的特定情况,比如在脚本或异常处理的上下文中 - 与
g
命令的区别
g
(go
):继续执行程序,通常用于手动中断后或设置断点后继续执行
.continue
:主要用于脚本和异常处理的上下文中,继续执行程序
- 这与
- 在调试过程中,设置了断点或中断程序执行后,可以使用
.continue
继续执行程序:
1 2 |
.break .continue |
- 调试异常时,可以使用
.catch
捕获异常,然后在处理完异常后使用.continue
继续执行程序 - 在调试脚本中,可以使用
.continue
命令来控制程序执行的流程
1 2 3 4 5 6 7 8 9 10 11 12 13 |
.block { .echo "Setting a breakpoint at 0x12345678"; bp 0x12345678; .echo "Running the program"; g; .echo "Breakpoint hit, checking context"; r; .echo "Continuing execution"; .continue; } |
- 高级用法
- 可以在条件语句中使用
.continue
命令
- 可以在条件语句中使用
1 2 3 4 5 6 |
.if (@eax == 0) { .echo "EAX is zero, continuing execution"; .continue; } .else { .echo "EAX is not zero, doing something else"; } |
.do
- 在
WinDbg
中,.do
命令是一种控制流命令,用于执行一个代码块,直到指定的条件为假
1 |
.do { Commands } .while (Condition) |
- 使用
.do
命令输出一个变量的值,直到该变量的值大于或等于10
1 2 3 4 5 |
r $t0 = 0 .do { .echo "Current value of \$t0 is: @$t0"; r $t0 = @$t0 + 1; } .while (@$t0 < 10) |
- 使用
.do
命令不断检查寄存器的值,直到特定寄存器(例如eax
)的值变为0
1 2 3 4 |
.do { .echo "Current value of EAX is: @eax"; g; } .while (@eax != 0) |
- 使用
.do
命令在调试过程中输出内存地址的内容,直到该地址的内容为特定值
1 2 3 4 5 |
r $t1 = 0x12345678 .do { dd @$t1 L1; g; } .while (@$t1 != 0xDEADBEEF) |
.else
- 根据
eax
寄存器的值执行不同的命令
1 2 3 4 5 |
.if (@eax == 0) { .echo "EAX is zero"; } .else { .echo "EAX is not zero"; } |
- 处理更复杂的条件逻辑
1 2 3 4 5 6 7 8 9 |
.if (@eax == 0) { .echo "EAX is zero"; } .else { .if (@ebx == 1) { .echo "EBX is one"; } .else { .echo "EBX is not one"; } } |
- 在调试脚本中使用条件语句执行不同的操作
1 2 3 4 5 6 7 |
.if (@eax > 100) { .echo "EAX is greater than 100"; r eax=0; } .else { .echo "EAX is 100 or less"; r eax=@eax + 10; } |
.elsif
- 根据
eax
寄存器的值执行不同的命令
1 2 3 4 5 6 7 8 9 |
.if (@eax == 0) { .echo "EAX is zero"; } .elsif (@eax == 1) { .echo "EAX is one"; } .elsif (@eax == 2) { .echo "EAX is two"; } .else { .echo "EAX is greater than two"; } |
- 使用嵌套的条件语句处理更复杂的条件
1 2 3 4 5 6 7 8 9 |
.if (@eax == 0) { .echo "EAX is zero"; } .elsif (@ebx == 1) { .echo "EBX is one"; } .elsif (@ecx == 2) { .echo "ECX is two"; } .else { .echo "None of the conditions are met"; } |
- 在调试脚本中使用条件语句执行不同的操作
1 2 3 4 5 6 7 8 9 10 |
.if (@eax > 100) { .echo "EAX is greater than 100"; r eax=0; } .elsif (@eax > 50) { .echo "EAX is greater than 50 but less than or equal to 100"; r eax=@eax + 10; } .else { .echo "EAX is 50 or less"; r eax=@eax + 20; } |
.for
- 输出一个变量的值,直到该变量的值大于或等于
10
1 |
.for (r $i = 0; @$i < 10; r $i = @$i + 1) { .echo "Current value of \$i is: @$i"; } |
- 检查一段内存区域的内容,直到找到特定值
1 2 3 |
.for (r $addr = 0x1000; dwo(@$addr) != 0xDEADBEEF; r $addr = @$addr + 4) { .echo "Current value at @$addr is: " dwo(@$addr); } |
.foreach
- 使用
.foreach
命令迭代一段内存地址,并显示每个地址的内容
1 2 3 |
.foreach (addr { .shell -ci "!address -summary" grep "region" | awk "{print \$2}" }) { dd @$addr L1; } |
- 使用
.foreach
命令迭代加载的模块,并显示每个模块的信息
1 2 3 |
.foreach (module { lm }) { .printf "Module: %s\n", @$module; } |
- 使用
.foreach
命令迭代进程的线程,并显示每个线程的堆栈信息
1 2 3 4 |
.foreach (thread { ~* }) { .printf "Thread: %s\n", @$thread; ~@$thread k; } |
.if
- 根据
eax
寄存器的值执行不同的命令
1 2 3 4 5 |
.if (@eax == 0) { .echo "EAX is zero"; } .else { .echo "EAX is not zero"; } |
.leave
- 在
WinDbg
中,.leave
命令用于在循环或块结构中提前退出- 这类似于许多编程语言中的
break
语句,允许你在满足某些条件时提前终止循环或块执行
- 这类似于许多编程语言中的
- 假设你有一个循环,想在某个条件满足时提前退出:
1 2 3 4 5 6 7 |
.for (r $i = 0; @$i < 10; r $i = @$i + 1) { .if (@$i == 5) { .echo "Leaving the loop at iteration @$i"; .leave; } .echo "Iteration: @$i"; } |
- 可以在
.while
循环中使用.leave
提前退出循环:
1 2 3 4 5 6 7 8 9 |
r $i = 0 .while (@$i < 10) { .if (@$i == 5) { .echo "Leaving the loop at iteration @$i"; .leave; } .echo "Iteration: @$i"; r $i = @$i + 1; } |
- 还可以在
.block
块中使用.leave
提前退出块执行:
1 2 3 4 5 6 7 8 |
.block { .echo "Entering block"; .if (1) { .echo "Condition met, leaving block"; .leave; } .echo "This will not be printed"; } |
.printf
- 在
WinDbg
中,.printf
命令用于格式化输出文本和变量值 - 常见格式
%d
:十进制整数%u
:无符号十进制整数%x
:小写十六进制整数%X
:大写十六进制整数%s
:字符串%c
:字符%p
:指针(十六进制表示)%f
:浮点数
- 输出一个整数和一个字符串
1 2 |
.printf "The value of EAX is %d\n", @eax .printf "Hello, %s!\n", "World" |
- 输出多个变量的值,包括十进制和十六进制格式
1 |
.printf "EAX: %d, EBX: %x, ECX: %X\n", @eax, @ebx, @ecx |
- 输出内存地址及其对应的内容
1 2 3 |
r $addr = 0x12345678 dd $addr L1 .printf "Memory at address %p: %x\n", @$addr, dwo(@$addr) |
.while
- 在
WinDbg
中,.while
命令用于创建一个循环结构,允许你根据条件表达式反复执行一组命令,直到条件表达式为假 - 在循环体中使用条件分支语句处理不同的情况
1 2 3 4 5 6 7 8 9 |
r $i = 0 .while (@$i < 5) { .if (@$i % 2 == 0) { .echo "Iteration @$i is even"; } .else { .echo "Iteration @$i is odd"; } r $i = @$i + 1; } |
命令
enter
- 重复键入的最后一个命令
运行脚本文件
$<
- 用于运行一个脚本文件,并将脚本文件中的命令作为调试器命令来执行
1 |
$< [ScriptFileName] |
$><
- 用于运行一个脚本文件,并将脚本文件中的命令输出到一个新的文件
1 |
$>< myscript.txt output.txt |
$$<
- 用于运行一个脚本文件,该脚本文件可以包含调试器命令和注释。注释以
$
开头
- 用于运行一个脚本文件,该脚本文件可以包含调试器命令和注释。注释以
1 |
$$< myscript.txt |
$><$
- 用于将当前输出重定向到一个文件,同时执行一个脚本文件
- 这个命令结合了
$<
和>
的功能
1 |
$><$ myscript.txt output.txt |
$a ><
- 用于将当前的输出附加到一个文件,并运行一个脚本文件
1 |
$a>< myscript.txt output.txt |
命令帮助
?
计算表达式
?
1 |
? (2 + 3) * 4 |
计算C++表达式
1 |
?? 2 + 3 |
系统状态
设置当前系统
进程状态
设置当前进程
线程状态
线程特定命令
冻结线程
解冻线程
挂起线程
恢复线程
设置当前线程
更改当前处理器
汇编
删除别名
断言处理
列出别名
设置别名
访问时中断
断点清除
断点禁用
断点启用
断点列表
设置断点
断点重新编号
更新断点命令
更新条件断点
比较内存
显示内存
显示引用的内存
显示单词和符号
显示选择器
显示链接的列表
显示字符串
显示类型
显示类型-扩展的调试器对象模型信息
显示局部变量
显示调试器对象模型表达式
输入值
填充内存
转到
从条件断点继续
转到已处理的异常
转到未处理的异常
向上
从端口输入
执行if-else
显示堆栈回溯
设置源选项
加载符号
列出已加载的模块
列出最接近的符号
列出源行
列出当前源
启动源编辑器
加载或卸载源文件
设置源行数目
移动内存
设置数字基
输出端口
步进
步进到地址
步进到下一个调用
步进到下一个call或return
步进到下一个分支指令
步进到下一个return
退出
退出和分离
寄存器
读取msr
寄存器掩码
搜索内存
设置内核调试选项
设置安静模式
设置符号后缀
设置异常
跟踪
跟踪到地址
跟踪到下一个分支
跟踪到下一个调用
跟踪到下一个call或return
跟踪到下一个分支指令
跟踪到下一个return
取消汇编
取消汇编函数
从物理内存取消汇编
取消汇编实际模式BIOS
取消汇编x86 BIOS
显示调试器命令行
显示调试器版本
显示目标计算机版本
写入MSR
跟踪和监视数据
检查符号
执行while
元命令
常规扩展命令
内核模式扩展命令
用户模式扩展命令
专业扩展命令
本文为原创文章,版权归Aet所有,欢迎分享本文,转载请保留出处!
你可能也喜欢
- ♥ Bkwin一12/01
- ♥ Windows 核心编程 _ 进程五06/30
- ♥ COM组件_303/07
- ♥ Windows 核心编程 _ 进程二06/19
- ♥ Dump分析:堆内存泄露03/29
- ♥ Dump分析:空指针访问二,重复释放堆内存二03/30