How can you change an age-mismatched PDB to match properly?

风流意气都作罢 提交于 2019-11-27 18:00:51

the windbg will not modify pdb's age - it only looks it up to match that of executable - the compiler does when it (re)generates executable and debug files.

now, based on the debuginfo.com article, it is not too difficult to arrive at the proper debug directory (of type codeview), match it against PDB7 signature and make modifications to either age or GUID inside an executable. why is that not an option?

i guess, you want to update pdb instead? i'm afraid, pdb is a proprietary format. there're multiple read-only APIs (dbghelp.dll and dia sdk), but as far as modifications go, you need to guess the details to be able to modify.

Or you could just use the suggestion here to have windbg ignore mismatched signatures and age:

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

... While by default it [windbg] also does not allow to load unmatched debug information, .symopt debugger command can change the default behaviour. After we have issued “.symopt+0x40” command, the debugger will happily accept and load unmatched PDB and DBG files.

Hope this helps.

Although as SamB said, in PDB(format 7, my test is based on VS2010 generated .exe and .pdb, and windbg 6.9.0003.113 X86) there's one extra reference to age, so totally there will be 3 ages to modify in PDB file. Unfortunately, SamB did not told us how to find the magic 3rd age, the stream 3? no! according to my test, I extract more than 100 pdb streams, I tried 02(if SamB is 0-indexed) and 03, both cannot find the age.

Fixing the other 2 ages is easy, as soon as you have a hex editor and windbg.

  • Find the GUID and age

using symchk to get the Signature(a GUID) of the your mismatched PDB file: symchk your.exe /v /s .

The typically output will contains:

[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
  • Fix the 2 easier ages

Search the last part of the of the GUID: 8BDC5152B6E0, because only the last part is byte-order-free from big-endian/little-endian issue, it's just exactly same as in pdb files. Be careful to search as raw hex value, to make it more accurate, you should verify the other values in the GUID(need to rever byte-order in X86)exactly matches. There will be exactly 2 GUIDs found inside the PDB file, the accompanying age is just before the first byte of the GUID. Modify it. That's it!

  • my brute way to find out the 3rd age.

    dump the hex number of your PDB file, one byte(2 hex numbers) per line. od -v -t x1 your.pdb | sed 's/^[0-9a-f]* //;s/ /\n/g' > age_offset.txt

    get the line number of every matched age, in my case it's 4 consecutive lines which has value 88 01 00 00, vim age_offset.txt :g/88\n01\n00\n00/s/^/\= (line('.') . ':')/

    This is a ex mode command, which should be support by a recent version of vim.

    :v/:/d

    This will delete all lines which does not contains ':', the remained lines are line numbers which is the offset of every matched age.

    :%s/:.*//

    This will trim :88 and leaving the offset alone.

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

    This command substract every number by 1, I do this because the line number in vim is 1-index, and the byte offset of every age should be 0-index to make the co-worker utility happy.

    :w

    save the file

    Now we get a text file with every line contains a decimal number representing an offset, from this offset, the following 4 bytes is candidate for your dreaming age.

    Next I'm trying to modify every potential age and then try to check it by symchk until it matches, every time only one offset will be patched.

    First of all, I will backup a PDB with the 2 ages(and GUID) be modified. Let's called it ori.pdb

    Here's the batch script to do the hard work:

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

Good lucky, I found the right place at 38th offset.

It's not the fastest way to try-error out the correct offset to patch, but it works for me, it's my prototype to make sure there's only 1 extra age to fix, otherwise, the possible combination is huge(I've 111 age candidate to try) and thus a try-error way is not pragmatic.

I think it's very easy to write an utility to do the same job in a faster way.

BTW: according to my test. chkmatch may report match while symchk and windbg vs think it mismatch.

windbg command !itoldyouso match while .reload /f your_module.exe still cannot match.

After the 3 ages being fixed, not only windbg but also visual studio can load the pdb files.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!