你怎么能改变一个年龄不匹配的PDB来正确匹配?

我们每晚的构build过程被打破了很长一段时间,这样它生成的PDB文件的年龄与相应的图像文件相差几个小时。 我已经解决了这个问题。

不过,我想开始使用符号服务器,但不能由于必须使用这些年龄不匹配的pdb文件。 我使用windbg中的.symopt + 0x40方法解决了这个问题。 这意味着我必须手工组织我所有的pdb文件,经过多年的发布,这些都是相加的。

我正在寻找一种方法来修改windbg用来标记pdb年龄的机制,并强制它匹配我的图像文件。 实用程序ChkMatch做了类似的事情,但对于pdb签名。 开发人员在页面上指出:“如果ChkMatch具有不同的签名但是年龄相同,ChkMatch能够使可执行文件和PDB文件匹配(有关PDB签名和年龄的更多信息,请参阅本文)。如果年龄不同,工具无法制作文件匹配“。

我看了一个六合彩的人,甚至发现了与年龄相对应的东西,但是它必须在内部扯些更多的伎俩,因为我不能使它工作。

有任何想法吗?

编辑 :我不知道这是否有帮助,但在我的特殊情况下,年龄差异是由于不必要地重新链接dll的,这将重新创buildPDB文件。 但是,我们的构build过程是将原始dll(在重新链接之前)和重新链接之后的pdb进行存储。 我想到了手工重现这种情况。 意思是强制在DLL上重新链接,但是在两种情况下都要保存pdb。 然后我可以做两个文件的二进制比较,看看他们如何改变。 也许运行某种修补软件,自动执行此操作? 通过查看我的控件情况究竟发生了什么变化,也许我可以对我公司构build过程中保存的DLL和PDB执行相同的操作?

编辑 :我想出来了! 感谢第一个答复的评论之一,我查了一下这本书“无证Windows 2000秘密:程序员食谱”的pdf的链接。 作者详细介绍了pdb文件格式。 正如我之前所说的,我已经把pdb加载到了一个hex编辑器中,并翻转了一些表示我做了年龄/签名匹配的东西,但是它没有起作用。 那么,在使用W2k机密书中的实用程序将pdb“爆炸”到包含的stream中之后,我发现他们隐藏了另一个在stream3中对年龄的引用!!!!!!! 一旦我翻转那一个,它在windbg匹配。 这是巨大的! 非常感谢你….符号服务器在这里我来了!

Solutions Collecting From Web of "你怎么能改变一个年龄不匹配的PDB来正确匹配?"

windbg不会修改pdb的年龄 – 它只是查找它与可执行文件相匹配 – 编译器在(重新)生成可执行文件和调试文件时执行的操作。

现在,基于debuginfo.com文章,到达适当的调试目录(类型代码视图)并不难,将其与PDB7签名进行匹配,并在可执行文件内对年龄或GUID进行修改。 为什么这不是一个选择?

我想,你想更新pdb呢? 恐怕,pdb是专有格式。 有多个只读API(dbghelp.dll和dia sdk),但只要修改,您需要猜测的细节,以便能够修改。

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

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

…虽然默认情况下它[windbg]也不允许加载不匹配的调试信息,.symopt debugger命令可以改变默认的行为。 在发出“.symopt + 0x40”命令后,调试器将高兴地接受并加载不匹配的PDB和DBG文件。

希望这可以帮助。

虽然正如SamB所说,在PDB(格式7,我的测试是基于VS2010生成的.exe和.pdb,以及windbg 6.9.0003.113 X86),还有一个额外的年龄参考,所以总共会有3个年龄修改PDB文件。 不幸的是,SamB没有告诉我们如何找到神奇的第三个年龄,流3? 没有! 根据我的测试,我提取了100多个pdb流,我尝试了02(如果SamB是0索引的)和03,都找不到年龄。

只要你有一个十六进制编辑器和windbg,修复其他2个年龄是很容易的。

  • 找到GUID和年龄

使用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 
  • 修复2个更容易的年龄

搜索GUID的最后一部分:8BDC5152B6E0,因为只有最后一部分是从big-endian / little-endian问题的字节顺序,它只是在pdb文件中完全相同。 小心搜索原始十六进制值,使其更加准确,你应该验证GUID中的其他值(需要在X86中反转字节顺序)完全匹配。 在PDB文件里面将会有两个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-index,并且每个年龄段的字节偏移量应该是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 vs认为它不匹配。

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

三年后,不仅windbg,而且视觉工作室可以加载pdb文件。