views:

77

answers:

3

Hi All,

I created a simple "Hello World" application in VS2005. It's a straight-forward console application; it only contains the following lines:

Console.WriteLine("Hello World");
Console.ReadLine();

When I tried to rebuild the same console application WITHOUT performing any changes (just press the rebuild button), I get a subtly different executable. (I generated a SHA-1 hash from both the 1st and 2nd generated executable, and it's different!)

Why is it different when there are no code changes? What actually changed? I used a hex editor to compare and only saw a couple different bytes.

I guess my ultimate question is, how can I know if an "assembly" really did change? (Of course without looking at File versions, file size, etc)

EDIT

So far, we've established that the difference lies in the PE header (timestamp and some debug data). Before I re-invent the wheel, is there an "assembly comparison" tool that ignores the PE header?

Thanks, Ian

+1  A: 

On the command line fc /b < oldfile > < newfile >

controlfreak123
Is this supposed to be an answer? At least provide some context.
Oded
haha sorry. I put some things in brackets and it thought they were html tags
controlfreak123
Comparing files a.exe and B.EXE00000088: 92 A400000770: F4 DD00000771: 62 2000000772: 7F CF00000773: A1 2400000774: 0B AA00000775: 5A 1600000776: 7A 9A00000777: 43 4100000778: B7 9D00000779: F3 390000077A: 22 C00000077B: 8D BF0000077C: 50 820000077D: 17 1D0000077E: 52 270000077F: D6 4A000008CC: 92 A4000008E8: 2A 8D000008E9: 6D 26000008EA: C2 21000008EB: F0 F4000008EC: 70 D4000008ED: 1E 98000008EE: 3F 76000008EF: 4B 4D000008F0: AC B7000008F1: 5A 0D000008F2: 75 9C000008F3: E0 3E000008F4: 4D 39000008F5: 83 8E000008F6: 6E 54000008F7: 1E 26000008F8: 02 01
Ian
That's a lot of bytes.
Ian
Hmm, that's more than I was expecting. To see what's actually changed, in a VS command prompt (or run `vsvars32`), run `dumpbin /all /rawdata:none` on both files and then windiff the output. The first one will be the timestamp and I'd guess one of the others will be the debug GUID but can't think what the third will be.
Rup
+6  A: 

The differences will be

  • the timestamp in the PE header
  • the GUID of the debug data, if present

(and maybe something more, as per the other output you've posted?) To see these, run dumpbin /all /rawdata:none on both assemblies in a VS command prompt.

To do this properly you'd have to write a comparison tool that understood this and ignored those bytes - or took copies of the executables, cleared the timestamp and GUID and then compared those versions. Or, at a pinch, you could use something like fc /b as controlfreak suggests and assume that if there are < 20 bytes different (4 for the timestamp, 16 for the GUID) then it's probably the same.

You may well get away with using an assembly with the timestamp cleared - AFAIK it's only used to cache exported symbol offsets in other DLLs if you hook that up - but it's probably safer to leave as is. If you actually need binary-identical assemblies I suggest you change your processes so you never clean-build unless you really need it.

Rup
In order to properly ignore those bytes, I need to know the location and range of those bytes right? Is there a documentation of some sort that I can read?
Ian
Here's the PE format documentation link from MSDN: http://www.microsoft.com/whdc/system/platform/firmware/PECOFF.mspx I meant the timestamp in the COFF header and the contents of the Debug Directory. However I'd be very surprised if tools to do this don't already exist - but I don't know of one, sorry.
Rup
Wow, you nailed it. It is the timestamp and some debug data!4C4953A4 time date stamp Fri Jul 23 16:32:36 20104C4953A4 cv 6D 000026E4 8E4 Format: RSDS, {F421268D-98D4-4D76-B70D-9C3E398E5426}, 1, C:\HelloWorld\HelloWorld\obj\x86\Debug\HelloWorld.pdb*using dumpbin /all /rawdata:none
Ian
+2  A: 

From a Visual Studio command prompt you can do a more elaborate comparison:

  • You could compare the PE header using the output of dumpbin:

    dumpbin /HEADERS assembly.dll
    
  • Or you could compare PE headers and the IL code embedded in the assembly using ildasm:

    ildasm /ALL /TEXT assembly1.dll > dump1.txt
    ildasm /ALL /TEXT assembly2.dll > dump2.txt
    fc dump1.txt dump2.txt        
    

    The /ALL option will dump the DOS and PE headers, the CLR header, assembly metadata and disassembled IL. However, it will not contain embedded resources. If your assmembly contains embedded resources you can use the /OUT option. This will create a separate file for each embedded resource that you can the compare using your favourite diff tool, e.g. WinMerge:

    ildasm /ALL /TEXT /OUT:folder1\dump.txt folder1\assembly.dll
    ildasm /ALL /TEXT /OUT:folder2\dump.txt folder2\assembly.dll
    
0xA3