尽管像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。
使用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文件。