Buy Me a Coffee

Buy Me a Coffee!

Friday, January 6, 2017

Dissecting C# Executables: Part 4

Ok, in Part 3 we just finished the COFF Header and now we move on to the COFF Optional Header.

The COFF Optional Header is not a fixed size, so we use the information from the previous section to determine the size.  All three images had the same SizeOfOptionalHeader data, 0x00E0 or 244 bytes.  We start just where we left off, in the second half of the 00000090 row which are different for each of the binary files under investigation:

MS Command Line, .NET 2.0:
00000090   00 00 00 00 E0 00 02 01  0B 01 08 00 00 04 00 00   ····à···········

VS 2015, .NET 2.0
00000090   00 00 00 00 E0 00 22 00  0B 01 30 00 00 08 00 00   ····à·"···0·····

Xamarin Studio, .NET 2.0
00000090   00 00 00 00 E0 00 02 01  0B 01 08 00 00 06 00 00   ····à···········

The first data halfword (two bytes) is the PE Format, and all three are the same 0x0B 0x01 or 0x010B which we look up in the table given in the super Microsoft Portable Executable and Common ObjectFile Format Specification: Revision 10:

Magic number
PE format
0x10b
PE32
0x20b
PE32+
So we have a PE32 format for all three files.  The next part depends on what type of image.  Since we are looking at a PE32 image, the offset to the standard fields is 0, so the next halfword is the start of them.  Here are the standard fields from the MS COFF doc:

Offset
Size
Field
Description
  0
2
Magic
The unsigned integer that identifies the state of the image file. The most common number is 0x10B, which identifies it as a normal executable file. 0x107 identifies it as a ROM image, and 0x20B identifies it as a PE32+ executable.
  2
1
MajorLinkerVersion
The linker major version number.
  3
1
MinorLinkerVersion
The linker minor version number.
  4
4
SizeOfCode
The size of the code (text) section, or the sum of all code sections if there are multiple sections.
  8
4
SizeOfInitializedData
The size of the initialized data section, or the sum of all such sections if there are multiple data sections.
12
4
SizeOfUninitializedData
The size of the uninitialized data section (BSS), or the sum of all such sections if there are multiple BSS sections.
16
4
AddressOfEntryPoint
The address of the entry point relative to the image base when the executable file is loaded into memory. For program images, this is the starting address. For device drivers, this is the address of the initialization function. An entry point is optional for DLLs. When no entry point is present, this field must be zero.
20
4
BaseOfCode
The address that is relative to the image base of the beginning-of-code section when it is loaded into memory.

So, the next byte after the Magic field is the MajorLinkerVersion which is 0x08 for both the MS Command Line and the Xamarin Studio versions and 0x30 for the VS 2015 version.  The MinorLinkerVersion is 0x00 for all three.  What this means, is that the linker used is definitely different between the VS 2015 file and the other two.  We don't know for sure that the two with the same version numbers used the same linker (and they probably didn't), but we know they didn't use the same one as VS 2015.  Does it matter?  It shouldn't, but linkers are code and code almost always has bugs of some type.

Next, to finish out the line we have the SizeOfCode which differs in all three.  Not entirely surprising, I guess, but the Program of all three decompile to the same IL in JustDecompile.  The differences must be around the edges.  Something to look into in another post.  For now, let's finish up the section by moving to the next line from the file:

MS Command Line, .NET 2.0:
000000A0   00 06 00 00 00 00 00 00  AE 23 00 00 00 20 00 00   ········r#··· ··

VS 2015, .NET 2.0
000000A0   00 0A 00 00 00 00 00 00  AA 27 00 00 00 20 00 00   ········ª'··· ··

Xamarin Studio, .NET 2.0
000000A0   00 06 00 00 00 00 00 00  FE 24 00 00 00 20 00 00   ········_$··· ··

As you can see, they all differ.  The next word (4 bytes) is the SizeOfInitializedData which is the same for the Command Line and Xamarin.  We will need to look back on this when we get to those sections of the files.  Next we have the SizeOfUnitializedData which is 0 for all three.  Next, we have the AddressOfEntryPoint which is different for all three, not surprising given the previous size differences we found.  The last word on this line is the BaseOfCode which is the same for all three.

We need the first word from the next line to finish out the section with the BaseOfData:
Offset
Size
Field
Description
24
4
BaseOfData
The address that is relative to the image base of the beginning-of-data section when it is loaded into memory.

which is only found in the PE32 image type.  All three are the same, so I will just end by showing the line from the Command line version:

MS Command Line, .NET 2.0:
000000B0   00 40 00 00 00 00 40 00  00 20 00 00 00 02 00 00   ·@····@·· ······

Till next time, happy digging!