Windbg 命令的每个结果作为脚本中的参数

Windbg command's each result as parameter in script

我打算在进程转储中的特定内存区域中搜索操作码。

我想在搜索的时候有一些条件

喜欢: $$><<>script.wds #call 00400000 L? 01000000

for(00400000 ~ 01000000)
{
    // this condition is if argument's opcode which is address is not in this area 
   .if(arg1's opcode !in 00400000 ~ 01000000)
      .print arg1
}

我不太确定我是否理解你的需求,但我认为它类似于以下内容。

使用伪寄存器创建一个执行您想要的操作的脚本,例如

.for(r @$t2=@$t0; @$t2<@$t1; r @$t2=@$t2+1) {.printf "%d, ", @$t2}

在伪寄存器中设置"parameters"

0:000> r @$t0 = 0x4
0:000> r @$t1 = 0x10

然后运行脚本:

0:000> $$>< script.wds
4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,

考虑到整个任务,我不建议在普通 WinDbg 中这样做,而是使用一些更高级别的抽象,例如 PyKD,因为

你的查询不清楚你想做这样的事情吗

0:000> .shell -ci ".echo"  type c:\foo.txt
# ${$arg1} ${$arg2} ${$arg3}.shell: Process exited

运行 上面的脚本通过提供三个参数你可以搜索 您提供范围内的任何指令 参数 1 是调用,所以我想搜索调用说明 arg 2 是一个表达式,因此 windbg 将被评估为类似 0x12340000 的地址 arg 3 也是一个计算大小的表达式 结果如下

0:000> $$>a< c:\foo.txt call windbg L900
windbg+0x1009:
01341009 e8340170e8      call    e9a41142
windbg+0x10b5:
013410b5 e834010000      call    windbg+0x11ee (013411ee)
windbg+0x1171:
01341171 e8000060e8      call    e9941176

您可以使用 #, .foreach and $spat.

的组合

假设您想在 notepad!WinMain 中找到前几个 call 操作码。你可以这样做:

0:000> .foreach (addr {# call notepad!WinMain L20}) { .if ($spat("addr", "notepad!*:")) {.echo addr} }
notepad!WinMain+0xa:
notepad!WinMain+0x19:
notepad!WinMain+0x20:
notepad!WinMain+0x33:
notepad!WinMain+0x39:
notepad!WinMain+0x45:

现在开始解释。

# call notepad!WinMain L20 在指定范围的反汇编中搜索字符串 "call"。这是输出:

0:000> # call notepad!WinMain L20
notepad!WinMain+0xa:
01002940 ff1514110001    call    dword ptr [notepad!_imp__GetCommandLineW (01001114)]
notepad!WinMain+0x19:
0100294f ff151c120001    call    dword ptr [notepad!_imp__GetSystemMetrics (0100121c)]
notepad!WinMain+0x20:
01002956 ff1510110001    call    dword ptr [notepad!_imp__GetProcAddress (01001110)]
notepad!WinMain+0x33:
01002969 ffd0            call    eax
notepad!WinMain+0x39:
0100296f e874f2ffff      call    notepad!SkipProgramName (01001be8)
notepad!WinMain+0x45:
0100297b e8e51b0000      call    notepad!NPInit (01004565)

.foreach (var {cmd}) {commands} 执行 cmd,在空格处拆分输出,并为每个命令执行一次 {commands}它用“var”获得的标记被替换为该标记。

如果没有 .if,我们会得到这样的结果:

0:000> .foreach (addr {# call notepad!WinMain L20}) {.echo addr}
notepad!WinMain+0xa:
01002940
ff1514110001
call
dword
ptr
[notepad!_imp__GetCommandLineW
(01001114)]
notepad!WinMain+0x19:
0100294f
ff151c120001
call
dword
ptr
[notepad!_imp__GetSystemMetrics
 .
 .
 .

最后我们添加 .if 来检查我们的令牌是否以“notepad!”开头并以“:结尾”。请注意,我们必须在最后测试冒号。否则我们可能会得到“notepad!SkipProgramName”和“notepad!NPInit”。即使测试“notepad!WinMain*”也是不够的,因为它可能是本地跳转的目标。


现在,如果您想将此地址传递给任何命令,则必须去掉 addr 别名 .foreach 命令末尾的冒号创建。我不确定是否有办法做到这一点,所以我们做了最后一招。每次我们找到符合模式的 addr 时,我们都会设置一个标志,并在每次迭代中检查该标志。如果升起标志,我们将使用当前令牌。由于 # 的输出形式为

Symbol:
address opcode_byte opcode_mnemonic argument ...

与我们的模式匹配的符号后面的标记是一个干净的地址。

例如,下面的命令为找到的每个 call 反汇编两个操作码:

0:000> .foreach (addr {# call notepad!WinMain L20}) { .if (@$t0==1) { u addr L2; r @$t0=0;}; .if ($spat("addr", "notepad!*:")) { r @$t0 = 1} }
notepad!WinMain+0xa:
01002940 ff1514110001    call    dword ptr [notepad!_imp__GetCommandLineW (01001114)]
01002946 68d8130001      push    offset notepad!`string' (010013d8)
notepad!WinMain+0x19:
0100294f ff151c120001    call    dword ptr [notepad!_imp__GetSystemMetrics (0100121c)]
01002955 50              push    eax
notepad!WinMain+0x20:
01002956 ff1510110001    call    dword ptr [notepad!_imp__GetProcAddress (01001110)]
0100295c 33f6            xor     esi,esi
notepad!WinMain+0x33:
01002969 ffd0            call    eax
0100296b ff7514          push    dword ptr [ebp+14h]
notepad!WinMain+0x39:
0100296f e874f2ffff      call    notepad!SkipProgramName (01001be8)
01002974 50              push    eax
notepad!WinMain+0x45:
0100297b e8e51b0000      call    notepad!NPInit (01004565)
01002980 85c0            test    eax,eax

(伪寄存器$t0是标志。)

现在,在这场恐怖事件结束后,如果你想更进一步,我会加入 Thomas in suggesting you use PyKd

我们可以使用 WinDbg 糟糕透顶的脚本语言来做到这一点并不意味着我们应该.