如何更改年龄不匹配的PDB才能正确匹配?

pj4*_*533 29 windows symbols windbg symbol-server pdb-files

我们的夜间构建过程已经被打破了很长时间,因此它生成的PDB文件的年龄与相应的图像文件相差几个小时.我已经解决了这个问题.

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

我正在寻找一种方法来修改windbg用于标记pdb年龄的机制,并强制它匹配我的图像文件.实用程序ChkMatch执行类似的操作,但是对于pdb签名.开发人员在页面上声明"ChkMatch能够使可执行文件和PDB文件匹配,如果他们有不同的签名但年龄相同(有关PDB签名和年龄的更多信息,请参阅此文章).如果年龄不同,该工具无法生成文件匹配."

我看了一下hexeditor,甚至找到了与年龄相对应的东西,但它必须在内部拉出一些技巧,因为我无法让它工作.

有任何想法吗?

编辑:我不知道这是否有帮助,但在我的特殊情况下,年龄差异是由于不必要地重新连接dll引起的,这也会重新创建PDB文件.但是,我们的构建过程是存储原始dll(在重新链接之前),以及重新链接之后的pdb.我想过以某种方式手工重建这种情况.意思是,强制重新链接DLL,但在两种情况下都保存了pdb.然后我可以对这两个文件进行二进制比较,看看它们是如何变化的.也许运行某种自动执行此操作的修补软件?通过查看我的控制案例中究竟发生了哪些变化,或许我可以对我公司构建过程中保存的DLL和PDB做同样的事情?

编辑:我想出来!!!! 感谢第一个答案的评论之一,我查看了"未记载的Windows 2000 Secrets:A Programmers Cookbook"一书的pdf链接.作者详细介绍了pdb文件格式.正如我之前所说的那样,我已经将pdb加载到十六进制编辑器中,然后翻出一些看起来我的年龄/签名匹配,但它没有用.好吧,在使用W2k秘密书中的实用程序将pdb"爆炸"到包含的流中之后,我发现它们隐藏了对流3中年龄的另一个引用!!!!!!! 一旦我翻过那个,它在windbg中匹配.这太棒了!!!! 非常感谢....这里的符号服务器我来了!

dee*_*mok 10

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

现在,基于debuginfo.com文章,到达正确的调试目录(类型为codeview)并将其与PDB7签名匹配并对可执行文件中的age或GUID进行修改并不困难.为什么这不是一个选择?

我想,你想更新pdb吗?我担心,pdb是一种专有格式.有多个只读API(dbghelp.dll和dia sdk),但就修改而言,你需要猜测能够修改的细节.

  • 超过6年后,微软发布了PDB格式规范:https://github.com/Microsoft/microsoft-pdb. (5认同)

小智 8

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

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

...虽然默认情况下[windbg]也不允许加载不匹配的调试信息,.symopt debugger命令可以更改默认行为.在我们发出".symopt + 0x40"命令后,调试器将很乐意接受并加载不匹配的PDB和DBG文件.

希望这可以帮助.


zha*_*fei 5

虽然正如 SamB 所说,在 PDB(格式 7,我的测试基于 VS2010 生成的 .exe 和 .pdb,以及 windbg 6.9.0003.113 X86)有一个额外的年龄参考,所以在 PDB 文件中总共会有 3 个年龄要修改. 不幸的是,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
Run Code Online (Sandbox Code Playgroud)
  • 修复 2 个更容易的年龄

搜索 GUID 的最后一部分:8BDC5152B6E0,因为只有最后一部分是从 big-endian/little-endian 问题中无字节顺序的,它与 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/.*/\=(子匹配(0) - 1)/

    这个命令将每个数字减1,我这样做是因为vim中的行号是1-index,并且每个age的字节偏移量应该是0-index,以使同事实用程序满意。

    :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
Run Code Online (Sandbox Code Playgroud)

幸运的是,我在第 38 个偏移处找到了正确的位置。

这不是尝试错误修补正确偏移的最快方法,但它对我有用,这是我的原型,以确保只有 1 个额外的年龄需要修复,否则,可能的组合是巨大的(我有 111 岁的候选人尝试),因此尝试错误的方式是不实用的。

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

BTW:根据我的测试。chkmatch 可能会报告匹配,而 symchk 和 windbg vs 认为它​​不匹配。

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

3个时代修复后,不仅windbg,visual studio也可以加载pdb文件。