Windbg - !for_each_frame 可以用 .for、.do 或 .while 来模仿吗?
Windbg - can !for_each_frame be mimicked with a .for, .do or .while?
!for_each_frame
将遍历线程的每一帧,并允许您 运行 在一行中执行一个命令(甚至是一堆命令)。
有没有办法在 Windbg 脚本中做一个简单的循环,这样您就可以从当前线程的帧 00
开始,迭代到最后一帧,然后在每个帧中做任何您想做的事情在漂亮的多行、多步骤代码块中构建框架?
这段代码显然会迭代,但它永远不会停止,直到您执行 Debug - Break。即使 Windbg 开始报告也是如此 Cannot find frame 0xXX, previous scope unchanged
那么我如何才能检查我需要的条件?
.frame 0n0
.do
{
.f+
}
(1==1)
在 .do
开始之前,是否有一些我可以检索和存储的东西,或者我可以在条件中检查的一些内置线程令牌,或者一些会被 .f+
命中的错误条件,当它遍历到更高的帧时,我可以跳出来吗?
对于这样的脚本任务,我鼓励您查看对 JavaScript 的内置支持(尤其是 WinDbg 预览版)。总的来说,它使这样的任务比在调试器中使用了很长时间的 "command/dot scripting" 简单得多。下面的脚本显示了一个例子:
"use strict";
function invokeScript()
{
for (var frame of host.currentThread.Stack.Frames)
{
// Do whatever you want:
host.diagnostics.debugLog("I just found frame: ", frame, "\n");
}
}
您可以 运行 WinDbg Preview 中的此脚本,只需单击功能区上的 "execute" 按钮...或将其放入文件中,然后“.script运行 FullScriptPath.js".
如果它不支持某些东西让您退回到旧脚本,我们当然很乐意听取反馈。
0:000> dx @$curstack.Frames.Count()
@$curstack.Frames.Count() : 0x4
0:000> .cxr;r $t0 = 0;.do { .f+ ; r $t0 = @$t0+1 } (@$t0 < 4 )
Resetting default scope
01 0014fa14 770060a7 ntdll!LdrpInitializeProcess+0x11a9
02 0014fa64 77003659 ntdll!_LdrpInitialize+0x78
03 0014fa74 00000000 ntdll!LdrInitializeThunk+0x10
Cannot find frame 0x4, previous scope unchanged
03 0014fa74 00000000 ntdll!LdrInitializeThunk+0x10
根据 William Messmer 的评论,您可以将 dx 表达式分配给原始伪寄存器,前提是您将其用作 dx
我之前说你不能分配的评论是基于这种格式
这不起作用
.for( r $t0 = @$curstack.Frames.Count() ;......)
但这是陷阱
你可以使用
**dx @$t0 = @$curstack.Frames.Count()** and use the Pseudo Register inside any loop variables
被赋值的伪寄存器不会导致错误
尽管这似乎等同于创建一个用户变量
像 dx @$foo = @$curStack.Frames.Count()
看来我们不能将@$foo 用作循环变量
这里是基于测试的简单 poc
C:>cdb cdb
Microsoft (R) Windows 调试器版本 10.0.16299.15 X86
0:000> dx @$t1 = @$curstack.Frames.Count()
@$t1 = @$curstack.Frames.Count() : 0x4 [Type: unsigned __int64]
0:000> .for(dx @$t0 =0 ; @$t0 < @$t1 ; r $t0 = @$t0 +1 ) { .frame @$t0 }
@$t0 =0 : 0 [Type: int]
00 0012fad0 77000e00 ntdll!LdrpDoDebuggerBreak+0x2c
01 0012fc30 76fe60a7 ntdll!LdrpInitializeProcess+0x11a9
02 0012fc80 76fe3659 ntdll!_LdrpInitialize+0x78
03 0012fc90 00000000 ntdll!LdrInitializeThunk+0x10
0:000>.cxr; dx @$t0 =0;.do { .f+ ; r $t0 = @$t0+1 } (@$t0 < @$t1 )
Resetting default scope
@$t0 =0 : 0 [Type: int]
01 0012fc30 76fe60a7 ntdll!LdrpInitializeProcess+0x11a9
02 0012fc80 76fe3659 ntdll!_LdrpInitialize+0x78
03 0012fc90 00000000 ntdll!LdrInitializeThunk+0x10
Cannot find frame 0x4, previous scope unchanged
03 0012fc90 00000000 ntdll!LdrInitializeThunk+0x10
0:000>
0:001> .for(dx @$t0 =0 ; @$t0 < @$t1 ; r $t0 = @$t0 +1 ) { .echo "hi" ; ?? (@$t0 * 3.1415)}
@$t0 =0 : 0 [Type: int]
hi
double 0
hi
double 3.1415000000000001812
hi
double 6.2830000000000003624
hi
double 9.4245000000000000995
hi
double 12.566000000000000725
hi
double 15.70750000000000135
hi
double 18.849000000000000199
hi
double 21.990500000000000824
hi
double 25.13200000000000145
hi
double 28.273500000000002075
hi
double 31.4150000000000027
0:001>
需要 c++ 而不是 masm 来评估使用?它会出现语法错误
但是使常量 c++ 似乎评估
**0:001>.expr
当前表达式计算器:MASM - Microsoft Assembler 表达式
0:001> .for(dx @$t0 =0 ; @$t0 < @$t1 ; r $t0 = @$t0 +1 ) { .echo "hi" ; ? ( @$t0 * 3.1415 ) }**
@$t0 =0 : 0 [Type: int]
hi
Syntax error at '3.1415 ) '
0:001> .for(dx @$t0 =0 ; @$t0 < @$t1 ; r $t0 = @$t0 +1 ) { .echo "hi" ; ? ( @$t0 * @@c++(3.1415) ) }
@$t0 =0 : 0 [Type: int]
hi
Evaluate expression: 0 = 00000000
hi
Evaluate expression: 3 = 00000003
hi
Evaluate expression: 6 = 00000006
hi
Evaluate expression: 9 = 00000009
hi
Evaluate expression: 12 = 0000000c
hi
Evaluate expression: 15 = 0000000f
hi
Evaluate expression: 18 = 00000012
hi
Evaluate expression: 21 = 00000015
hi
Evaluate expression: 24 = 00000018
hi
Evaluate expression: 27 = 0000001b
hi
Evaluate expression: 30 = 0000001e
!for_each_frame
将遍历线程的每一帧,并允许您 运行 在一行中执行一个命令(甚至是一堆命令)。
有没有办法在 Windbg 脚本中做一个简单的循环,这样您就可以从当前线程的帧 00
开始,迭代到最后一帧,然后在每个帧中做任何您想做的事情在漂亮的多行、多步骤代码块中构建框架?
这段代码显然会迭代,但它永远不会停止,直到您执行 Debug - Break。即使 Windbg 开始报告也是如此 Cannot find frame 0xXX, previous scope unchanged
那么我如何才能检查我需要的条件?
.frame 0n0
.do
{
.f+
}
(1==1)
在 .do
开始之前,是否有一些我可以检索和存储的东西,或者我可以在条件中检查的一些内置线程令牌,或者一些会被 .f+
命中的错误条件,当它遍历到更高的帧时,我可以跳出来吗?
对于这样的脚本任务,我鼓励您查看对 JavaScript 的内置支持(尤其是 WinDbg 预览版)。总的来说,它使这样的任务比在调试器中使用了很长时间的 "command/dot scripting" 简单得多。下面的脚本显示了一个例子:
"use strict";
function invokeScript()
{
for (var frame of host.currentThread.Stack.Frames)
{
// Do whatever you want:
host.diagnostics.debugLog("I just found frame: ", frame, "\n");
}
}
您可以 运行 WinDbg Preview 中的此脚本,只需单击功能区上的 "execute" 按钮...或将其放入文件中,然后“.script运行 FullScriptPath.js".
如果它不支持某些东西让您退回到旧脚本,我们当然很乐意听取反馈。
0:000> dx @$curstack.Frames.Count()
@$curstack.Frames.Count() : 0x4
0:000> .cxr;r $t0 = 0;.do { .f+ ; r $t0 = @$t0+1 } (@$t0 < 4 )
Resetting default scope
01 0014fa14 770060a7 ntdll!LdrpInitializeProcess+0x11a9
02 0014fa64 77003659 ntdll!_LdrpInitialize+0x78
03 0014fa74 00000000 ntdll!LdrInitializeThunk+0x10
Cannot find frame 0x4, previous scope unchanged
03 0014fa74 00000000 ntdll!LdrInitializeThunk+0x10
根据 William Messmer 的评论,您可以将 dx 表达式分配给原始伪寄存器,前提是您将其用作 dx
我之前说你不能分配的评论是基于这种格式 这不起作用
.for( r $t0 = @$curstack.Frames.Count() ;......)
但这是陷阱
你可以使用
**dx @$t0 = @$curstack.Frames.Count()** and use the Pseudo Register inside any loop variables
被赋值的伪寄存器不会导致错误
尽管这似乎等同于创建一个用户变量
像 dx @$foo = @$curStack.Frames.Count()
看来我们不能将@$foo 用作循环变量
这里是基于测试的简单 poc
C:>cdb cdb
Microsoft (R) Windows 调试器版本 10.0.16299.15 X86
0:000> dx @$t1 = @$curstack.Frames.Count()
@$t1 = @$curstack.Frames.Count() : 0x4 [Type: unsigned __int64]
0:000> .for(dx @$t0 =0 ; @$t0 < @$t1 ; r $t0 = @$t0 +1 ) { .frame @$t0 }
@$t0 =0 : 0 [Type: int]
00 0012fad0 77000e00 ntdll!LdrpDoDebuggerBreak+0x2c
01 0012fc30 76fe60a7 ntdll!LdrpInitializeProcess+0x11a9
02 0012fc80 76fe3659 ntdll!_LdrpInitialize+0x78
03 0012fc90 00000000 ntdll!LdrInitializeThunk+0x10
0:000>.cxr; dx @$t0 =0;.do { .f+ ; r $t0 = @$t0+1 } (@$t0 < @$t1 )
Resetting default scope
@$t0 =0 : 0 [Type: int]
01 0012fc30 76fe60a7 ntdll!LdrpInitializeProcess+0x11a9
02 0012fc80 76fe3659 ntdll!_LdrpInitialize+0x78
03 0012fc90 00000000 ntdll!LdrInitializeThunk+0x10
Cannot find frame 0x4, previous scope unchanged
03 0012fc90 00000000 ntdll!LdrInitializeThunk+0x10
0:000>
0:001> .for(dx @$t0 =0 ; @$t0 < @$t1 ; r $t0 = @$t0 +1 ) { .echo "hi" ; ?? (@$t0 * 3.1415)}
@$t0 =0 : 0 [Type: int]
hi
double 0
hi
double 3.1415000000000001812
hi
double 6.2830000000000003624
hi
double 9.4245000000000000995
hi
double 12.566000000000000725
hi
double 15.70750000000000135
hi
double 18.849000000000000199
hi
double 21.990500000000000824
hi
double 25.13200000000000145
hi
double 28.273500000000002075
hi
double 31.4150000000000027
0:001>
需要 c++ 而不是 masm 来评估使用?它会出现语法错误
但是使常量 c++ 似乎评估
**0:001>.expr
当前表达式计算器:MASM - Microsoft Assembler 表达式
0:001> .for(dx @$t0 =0 ; @$t0 < @$t1 ; r $t0 = @$t0 +1 ) { .echo "hi" ; ? ( @$t0 * 3.1415 ) }**
@$t0 =0 : 0 [Type: int]
hi
Syntax error at '3.1415 ) '
0:001> .for(dx @$t0 =0 ; @$t0 < @$t1 ; r $t0 = @$t0 +1 ) { .echo "hi" ; ? ( @$t0 * @@c++(3.1415) ) }
@$t0 =0 : 0 [Type: int]
hi
Evaluate expression: 0 = 00000000
hi
Evaluate expression: 3 = 00000003
hi
Evaluate expression: 6 = 00000006
hi
Evaluate expression: 9 = 00000009
hi
Evaluate expression: 12 = 0000000c
hi
Evaluate expression: 15 = 0000000f
hi
Evaluate expression: 18 = 00000012
hi
Evaluate expression: 21 = 00000015
hi
Evaluate expression: 24 = 00000018
hi
Evaluate expression: 27 = 0000001b
hi
Evaluate expression: 30 = 0000001e