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

问题描述 投票:2回答:3

一些背景信息

最近我问过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
windbg
3个回答
0
投票

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


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万的范围,但它知道要停在第一个空终止符。

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

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


0
投票

虽然它不依赖于任何扩展等,但这可能不是您所寻找的“原生”解决方案(5年多以前,我知道 - 我只是张贴供参考),但我相信你的意思之后可以通过一点点簿记和小心别名/ psudo-register管理来实现。

一般的想法是foreach循环的主要块接收每个令牌,并记住它们并在存储用于主要处理的所有令牌时使用它们。以下脚本中的某些内容列出了当前目标中以“ora *”开头的已加载模块,并列出了它们的起始地址和大小(在单行/模块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个)(或者如果某个令牌可以被识别为“标记”),这也可能用于重置计数器I已完成模数运算)。也就是说,如果行具有不同数量的标记(由于文件名中的空格等),则无法使用变通方法。

单行复制粘贴:

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的别名特性!尽管我的令牌确实是数字的,但我在这里使用了别名来提供更通用的示例/模板。

© www.soinside.com 2019 - 2024. All rights reserved.