Determine whether .NET assemblies were built from the same source

丶灬走出姿态 提交于 2019-11-27 11:48:25

It's not too painful to use command-line tools to filter out MVID and date-time stamps from a text representation of the IL. Suppose file1.exe and file2.exe are built from the same sources:

c:\temp> ildasm /all /text file1.exe | find /v "Time-date stamp:" | find /v "MVID" > file1.txt

c:\temp> ildasm /all /text file2.exe | find /v "Time-date stamp:" | find /v "MVID" > file2.txt

c:\temp> fc file1.txt file2.txt

Comparing files file1.txt and FILE2.TXT

FC: no differences encountered

When comparing class libraries with ILDasm v4.0.319.1, it seems that image base is not initialized. To avoid mismatches, use a revised solution:

ildasm /all /text assembly.dll
| find /v "// Time-date stamp:"
| find /v "// MVID:"
| find /v "// Checksum:"
| find /v "// Image base:"
> assembly.dasm

Entry point (image base) is actually interesting information for executable assemblies, and will have to be verified carefully. Injecting a new image base is a common way to make a program do something entirely else. In my case, I am trying to verify consistency of multi-threaded builds, so it's safe to skip over the entry point.

A note on performance: I took an 8MB DLL that was built for AnyCPU, and ran ILDasm. Resulting file was 251MB in size and took several minutes to make. Roughly 32x the size was produced.

I have used the solution of Jerry Currry on .Net 4 assemblies and found out that there is now a third item that will vary on each build: Checksum. Isn't it surprising to find a checksum inside an assembly? I think that adding the checksum of a file inside that file will change the checksum...

Anyway, the modified command is:

ildasm /all /text "assembly.dll"
| find /v "// Time-date stamp:"
| find /v "// MVID:"
| find /v "// Checksum:"
> assembly.dasm

Note that I have also changed the search strings a bit by adding the slashes, in order to avoid unintentional matches. The lines of this command should be run together on the same line, split for readability. File names will need double quotes around them if they contain spaces.

There are a few ways to do this depending on the amount of work you're willing to do and the importance of performance and/or accuracy. One way as Eric J. pointed is to compare the assemblies in binary, excluding the parts that change on every compilation. This solution is easy and fast but could give you a lot of false negatives. One better way is to drill down by using reflection. If performance is critical you can start by comparing the types and if they match go to member definitions. After checking type and member definitions and if everything is equal to that point you can go further by examining the actual IL of each method by getting it through GetILAsByteArray method. Again you're going to find differences even if everything is the same but compiled with a little bit different flags or different version of the compiler. I'd say that the best solution is to use a continuous integration tools that tags the build with the changeset number of your source control (you are using one, right?).

A related article

you can use MonoCecil and give it a small modification to get the problem solved. I did it, you can read how over here: http://groups.google.com/group/mono-cecil/browse_thread/thread/6ab42df05daa3a/49e8b3b279850f13#49e8b3b279850f13

Regards Florian

You can use the Reflector Diff AddIn here.

Another solution to consider:

Source code information is stored when binaries are compiled in debug mode. Then you can check if pdb matches exe and if pdb lines matches source code.

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