你如何将年龄不匹配的PDB文件进行更正?

35
我们的夜间构建过程长期存在问题,导致生成的PDB文件与相应的映像文件的时间差几个小时。我已经解决了这个问题。
然而,我想开始使用符号服务器,但由于必须使用这些年龄不匹配的pdb文件,所以无法使用。我通过在windbg中使用.symopt +0x40方法来解决此问题。这意味着我必须手动组织所有的pdb文件,并且在多年的发布之后,这会累加起来。
我正在寻找一种修改windbg用于标记pdb年龄的机制并强制其与我的映像文件匹配的方法。工具ChkMatch执行类似操作,但是针对pdb签名。开发人员在页面上指出“如果可执行文件和PDB文件具有不同的签名但相同的年龄(请参见本文了解有关PDB签名和年龄的更多信息),则ChkMatch能够使它们匹配。如果年龄不同,则该工具无法使文件匹配。”
我查看了十六进制编辑器中的内容,甚至找到了看起来对应于年龄的位,但它必须在内部进行一些额外的技巧,因为我无法使其正常工作。
有什么想法吗?

编辑: 我不知道这是否有帮助,但在我的情况下,年龄差异是由于不必要地重新链接dll文件造成的,这也会重新创建PDB文件。然而,我们的构建过程存储了原始的dll(在重新链接之前)和重新链接后的pdb。我考虑通过手动重新创建这种情况来实现。也就是说,强制对DLL进行重新链接,但在两种情况下都保存PDB。然后,我可以对比这两个文件的二进制内容以查看它们如何改变。也许运行一些自动执行此操作的修补软件?通过查看控制情况中确切发生了什么,也许我可以对公司构建过程中保存的DLL和PDB进行相同的操作?

编辑: 我找到了答案!!!感谢第一个答案中的一个评论,我查看了一本名为“Undocumented Windows 2000 Secrets: A Programmers Cookbook”的书的pdf版本。作者详细介绍了pdb文件格式。正如我之前所说,我已经将pdb加载到十六进制编辑器中,并翻转了一些位,看起来我使年龄/签名匹配了,但它没有起作用。好吧,在使用W2k秘密书中的实用程序将pdb“爆炸”为包含的流之后,我发现它们在第3个流中隐藏了另一个年龄引用!!!一旦我也翻转了那个,它就在windbg中匹配了。这太重要了!!!非常感谢...符号服务器,我来了!

4个回答

12

windbg不会修改pdb的age - 它只查找符合可执行文件的年龄 - 编译器在重新生成可执行文件和调试文件时进行修改。

现在,根据debuginfo.com网站的文章,很容易确定正确的调试目录(类型为codeview),将其与PDB7签名进行匹配,并修改可执行文件中的年龄或GUID。为什么不选择这个选项呢?

我猜想,您希望更新pdb文件?恐怕,pdb是一种专有格式。虽然有多个只读API(dbghelp.dll和dia sdk),但就修改而言,您需要猜测细节才能进行修改。


更改签名并不难。但是年龄是不同的。我明确表示我想要更新pdb。类似于chkmatch的工作方式。 - pj4533
不错的网站!我正在查看那本书……也许它会让我走上正确的轨道。如果我想出了什么,我会回报的。 - pj4533
你太棒了!感谢你推荐那个网站,我已经弄明白了! - pj4533
6
6年后,微软发布了PDB格式规范:https://github.com/Microsoft/microsoft-pdb。 - codekaizen
@pj4533 有没有可能将没有调试信息的 DLL 与稍后构建的 PDB 匹配,如果可以,该如何操作? - waterd

12

或者你可以使用这里的建议,让windbg忽略不匹配的签名和年龄:

http://www.debuginfo.com/articles/debuginfomatch.html

...默认情况下,windbg也不允许加载不匹配的调试信息,但.symopt调试器命令可以更改默认行为。在我们发出“.symopt+0x40”命令之后,调试器将愉快地接受并加载不匹配的PDB和DBG文件。

希望这有帮助。


5
尽管像SamB所说,在PDB(格式7,我的测试基于VS2010生成的.exe和.pdb以及windbg 6.9.0003.113 X86)中有一个额外的age引用,所以在PDB文件中总共有3个age需要修改。不幸的是,SamB没有告诉我们如何找到第三个age,stream 3?不!根据我的测试,我提取了100多个pdb流,我尝试了02(如果SamB是0索引)和03,都找不到该age。
修复其他2个age很容易,只要您有一个十六进制编辑器和windbg。
  • 查找GUID和age

使用symchk获取您的不匹配的PDB文件的签名(GUID): symchk your.exe /v /s .

通常的输出将包含:

[SYMCHK] ------------------------------------
SymbolCheckVersion  0x00000002
Result              0x00010001
DbgFilename         CPP_Snippet.dbg
DbgTimeDateStamp    0x00000000
DbgSizeOfImage      0x00000000
DbgChecksum         0x00000000
PdbFilename         E:\zrf\C_CPP\CPP_Snippet.pdb
PdbSignature        {6D8D99B0-E96B-4093-9D97-8BDC5152B6E0}
PdbDbiAge           0x00000188
  • 修复两个较易的年龄

搜索GUID的最后一部分:8BDC5152B6E0,因为只有最后一部分不受大端/小端问题影响,与pdb文件完全相同。要注意以原始十六进制值进行搜索,为了更准确,您应该验证GUID中的其他值(需要在X86中反转字节顺序)是否完全匹配。在PDB文件内将找到正好2个GUID,附带的年龄就在GUID的第一个字节之前。修改它。就这样!

  • 我发现第三个年龄的粗暴方法。

    倒出PDB文件的十六进制数,每行一个字节(2个十六进制数)。 od -v -t x1 your.pdb | sed 's/^[0-9a-f]* //;s/ /\n/g' > age_offset.txt

    获取每个匹配年龄的行号,在我的情况下,连续4行的值为88 01 00 00, vim age_offset.txt :g/88\n01\n00\n00/s/^/\= (line('.') . ':')/

    这是一个ex模式命令,应该由最近版本的vim支持。

    :v/:/d

    这将删除所有不包含“:”的行,剩余的行是每个匹配年龄的偏移量。

    :%s/:.*//

    这将修剪:88并保留偏移量。

    :%s/.*/\=(submatch(0) - 1)/

    此命令通过1减去每个数字,我这样做是因为vim中的行号是1索引,并且每个年龄的字节偏移应该是0索引,以使共同工具满意。

    :w

    保存文件

    现在我们得到一个文本文件,每行包含表示偏移量的十进制数,从这个偏移量开始,以下4个字节是潜在的年龄。

    接下来,我尝试修改每个潜在的年龄,然后尝试通过symchk进行检查,直到它匹配为止,每次只会修补一个偏移量。

    首先,我将备份带有2个年龄(和GUID)被修改的PDB。让我们称之为ori.pdb

    这是批处理脚本来完成艰苦的工作:

for /F usebackq %%i in (`type age_offset.txt`) DO (
  copy /y ori.pdb CPP_Snippet.pdb
  @rem dd if=ori.pdb bs=1c count=4 skip=%%i | xxd -g1 | grep "88 01 00 00" || echo "Bad data at %%i" && goto exit
  dd if=pdb_age.dat of=CPP_Snippet.pdb bs=1c count=4 seek=%%i conv=notrunc
  symchk CPP_Snippet.exe /s . && echo "Found it at offset %%i" && goto exit
  )
:exit

好运,我在第38个偏移量找到了正确的位置。

这不是尝试错误找到正确补丁偏移量的最快方法,但对我来说有效,这是我的原型,以确保只有一个额外的年龄需要修复,否则可能的组合很多(我有111个年龄候选人要尝试),因此尝试错误的方式并不实用。

我认为很容易编写一个实用程序以更快的方式完成相同的工作。

顺便说一下:根据我的测试结果,chkmatch可能会报告匹配,而symchk和windbg则认为它们不匹配。

windbg命令!itoldyouso匹配,而.reload /f your_module.exe仍然无法匹配。

在修复了3个年龄之后,不仅windbg,而且visual studio也可以加载pdb文件。


还不知道它是否有效...我需要将年龄2改为1,字节序列02000000似乎更常见。有18845个可能的位置。 :) 仍在等待脚本完成。 - Oskar Berggren
对我不起作用(VS 2013-v120工具集)。我花了3或4天时间创建了一个调用ChkMatch.exe的工具,然后使用CDB获取PDB年龄,接着像你一样暴力破解日期。我已经逐一替换了我的PDB中所有9546个可能的年龄(在每个年龄之后调用Symchk),但没有找到匹配项。 - Violet Giraffe

1
使用symopt命令启用SYMOPT_LOAD_ANYTHING
.symopt+ 0x40

来自文档

该符号选项降低了符号处理程序匹配符号时的挑剔程度。

所有调试器默认情况下都未开启此选项。一旦调试器运行,可以使用.symopt+0x40.symopt-0x40 命令打开或关闭此选项。

DBH默认情况下也未开启此选项。一旦DBH运行,可以使用symopt +40symopt -40命令打开或关闭此选项。

更多信息请参见http://ntcoder.com/bab/2012/03/06/how-to-force-symbol-loading-in-windbg/


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接