WinDbg:使用.foreach中的几个标记来输入命令

时间:2013-12-11 09:52:01

标签: windbg

一些背景信息

最近我问a question并使用.foreach收到了很好的答案。 现在我有一个包含很多非常大的char []的转储。我做了

.logopen c:\mychararrays.log
!dumpheap -type System.Char[]
.logclose

我已经删除了所有人类可读的内容,例如摘要等。 现在该文件有很多行,包括对象地址,方法表和大小:

03d74c88 52b8b680  5570670
042c4cf8 52b8b680  5762890     
...
21a1d6e0 52b8b680  6010030

我已经使用过了

.foreach /ps 2 /f (chararray "c:\mychararrays.log") { !do ${chararray} }

转储.NET对象,但这不会转储char []的完整文本,只会转储前128个字符。 不幸的是,这些char []的开头总是一样的。

问题

我想做点什么

.foreach /f (chararray "c:\mychararrays.log") { du <token 1 of line>+8 L? 0n<token 3 of line> }

为每行打印完整的char []。默认情况下,WinDbg会将一行中的标记分开并逐个处理,因此该命令只有一个标记可供使用。

在Notepad ++中解决它

我已经通过在Notepad ++中进行正则表达式替换来解决这个问题。 我只是想知道是否有一个“原生”WinDbg解决方案。

Find: ([^ ]*) [^ ]*  ([^ ]*).*
Replace: du \1+8 L? 0n\2

然后将结果作为脚本运行:

$<c:\mychararrays.log

注意:这花了很长时间,所以我决定切换到

Find: ([^ ]*) [^ ]*  ([^ ]*).*
Replace: .writemem c:\s\1.txt \1+8 L? 0n\2

3 个答案:

答案 0 :(得分:1)

如果您知道最大大小,则可以将该大小指定为du,并且它将在第一个空终止符处停止打印。例如,如果我知道最大值为10,000,000,那么即使长度为320个字符,下面的内容也会正确打印:

0:000> du 00000000033495d8 +10 L?0n10000000
00000000`033495e8  "PermissionSetty.PermissionSeting"
00000000`03349628  "Permission, System.Drawing, Vers"
00000000`03349668  "ion=2.0.0.0, Culture=neutral, Pu"
00000000`033496a8  "blicKeyToken=b03f5f7f11d50a3a619"
00000000`033496e8  "34e0899AD9D5DCC1DD9AD23613210290"
00000000`03349728  "0B723CF980957FC4E177108FC607774F"
00000000`03349768  "29E8320E92EA05ECE4E821C0A5EFE8F1"
00000000`033497a8  "645C4C0C93C1AB99285D622CAA652C1D"
00000000`033497e8  "FAD63D745D6F2DE5F17E5EAF0FC4963D"
00000000`03349828  "261C8A12436518206DC093344D5AD293"
00000000`03349868  ""

这是空终结符00000000`03349868:

0:000> db 00000000`03349868 l2
00000000`03349868  00 00

所以尽管我给了du 1000万的范围,但它知道要停在第一个空终止符。

BTW这是64位进程的转储,这可能是我对char缓冲区的偏移量与你的不同的原因。

如果您绝对需要实际大小,那么我们可以将其作为对象地址的偏移量来抓取,这样您就不需要尝试将该值作为另一个标记来获取。但希望最大值适合你。

答案 1 :(得分:0)

尝试使用windbg pykd.codeplex.com的python扩展。使用python,您可以获得RE,灵活的脚本语言并快速解决您的问题

答案 2 :(得分:0)

尽管它不依赖于任何扩展名,等等,但这可能并不是您正在寻找的“本地”解决方案(5年前,我知道-我将发布为参考),但我相信您可以通过一些簿记和仔细的别名/伪注册管理来实现。

一般的想法是foreach循环的主块接收每个令牌,并记住并在所有用于主要处理的令牌被存储时使用它们。 >。以下脚本中的内容列出了当前目标中以“ ora *”开头的已加载模块,并列出了它们的起始地址和 size (单行/模块中不可用) lm输出):

ad /q startAddress;
ad /q endAddress;
r $t0=0;
.foreach /pS 8 (token {lmn m ora*}) {
    r $t0=@$t0 + 1;
    .if (@$t0 % 4 == 1) { as ${/v:startAddress} ${token}};
    .if (@$t0 % 4 == 2) { as ${/v:endAddress} ${token}};
    .if (@$t0 % 4 == 0) {.printf "${token}=%x,%x\n", ${startAddress}, ${endAddress} - ${startAddress}}; 
}

您可能已经猜到了,主要要求是每行中肯定有N个令牌(在我的示例中为4个)(或者如果可以将某个令牌标识为“标记”,也可以用来重置我用模运算完成的计数器)。也就是说,如果行的令牌数量不同(由于文件名中的空格等),这将无法解决。

单行复制粘贴:

ad /q startAddress; ad /q endAddress; r $t0=0; .foreach /pS 8 (token {lmn m ora*}) {r $t0=@$t0 + 1; .if (@$t0 % 4 == 1) { as ${/v:startAddress} ${token}}; .if (@$t0 % 4 == 2) { as ${/v:endAddress} ${token}}; .if (@$t0 % 4 == 0) {.printf "${token}=%x,%x\n", ${startAddress}, ${endAddress} - ${startAddress}}; }

还要注意,如果要处理的令牌是数字的,则使用伪寄存器而不是别名会使事情变得容易一些,因为您可以避免WinDbg的别名特质!即使我的令牌确实是数字的,我还是在这里使用别名来提供更通用的示例/模板。