背景
项目组出现过比较有意思的情况:在同一台持续集成服务器,从同一个SVN上取指定版本的代码进行打包,但生成的两个版本有差异,即有DLL不相同导致运行结果不正确。经过定位,推测可能是update代码的过程中出现了异常,没有获取到期望的代码。
因此,CI工程师需要一种方法能够对DLL,EXE等二进制文件进行比对,以验证其正确性。但是即使用普通二进制比较工具(BeyondCompare)进行比较,发现总是有几个字节不相同。于是向我求助。
过程
我曾看过windows的PE文件结构,依稀记得里边会有几个字节存放TimeStamp和CheckSum,所以会有这么几个字节的差异。为避免误人子弟,特找来微软的定义看看:
1 | typedef struct _IMAGE_NT_HEADERS { |
其中FileHeader的定义是,第三个变量就是时间戳,表示文件的创建时间。
1 | typedef struct _IMAGE_FILE_HEADER { |
再来看看所谓的可选头OptionalHeader,其实一点都不可选,里边藏了好多东西,其中的CheckSum也会导致DLL差异。
1 | typedef struct _IMAGE_OPTIONAL_HEADER { |
去除TimeStamp
既然时间戳确实存在,那么只能想办法在比较的时候忽略时间戳,或是在比较之前去除之。秉承一贯不重复造轮子的作风,先google一下是否有解决方案。
BinDiff
微软大力推荐的BinDiff,可惜找了一大圈都没找到下载源,网上另有说法是BinDiff属于商用软件,license很贵。只能放弃,另寻他法。
dumpbin /rawdata
VS2010自带了将PE文件导出的工具Dumpbin,据说可以将PE文件导出来。需要注意的是,不能直接在CMD里输入dumpbin
,会提示找不到某个DLL,必须在开始菜单-VS2010-Tools-prompt里打开。区别在于tools里会先调用一个bat环境变量。
用法
1 | dumpbin /rawdata 1.dll 1.txt |
用BeyondCompare比较1.txt和2.txt,发现差异还是在TimeStamp处,看来此法不通。
dumpbin /disasm
查看dumpbin命令
/ALL /ARCHIVEMEMBERS /CLRHEADER /DEPENDENTS /DIRECTIVES /DISASM[:{BYTES|NOBYTES}] /ERRORREPORT:{NONE|PROMPT|QUEUE|SEND} /EXPORTS /FPO /HEADERS /IMPORTS[:文件名] /LINENUMBERS /LINKERMEMBER[:{1|2}] /LOADCONFIG /OUT:文件名 /PDATA /PDBPATH[:VERBOSE] /RANGE:vaMin[,vaMax] /RAWDATA[:{NONE|1|2|4|8}[,#]] /RELOCATIONS /SECTION:名称 /SUMMARY /SYMBOLS /TLS /UNWINDINFO
其中有个disasm,看着像反汇编。如果能把PE反汇编出来,应该就能把TimeStamp去掉。
1 | dumpbin /disasm 1.dll 1.txt |
比较1.txt和2.txt果然一致。
后续
需要写一个bat,输入参数为两个文件夹的路径,将这两个文件夹内的PE文件都反汇编出来,然后一一进行比较,输出有差异的文件名。
本博客欢迎转发,但请保留原作者信息
github:codejuan
博客地址:http://blog.decbug.com/