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,因为
- 不容易get the opcode from an ASM statement
- 您可能只想在
!address
中搜索 PAGE_EXECUTE
- WinDbg 脚本通常含糊不清且不易维护
你的查询不清楚你想做这样的事情吗
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
的组合
假设您想在 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 糟糕透顶的脚本语言来做到这一点并不意味着我们应该.
我打算在进程转储中的特定内存区域中搜索操作码。
我想在搜索的时候有一些条件
喜欢: $$><<>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,因为
- 不容易get the opcode from an ASM statement
- 您可能只想在
!address
中搜索PAGE_EXECUTE
- WinDbg 脚本通常含糊不清且不易维护
你的查询不清楚你想做这样的事情吗
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
假设您想在 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 糟糕透顶的脚本语言来做到这一点并不意味着我们应该.