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