[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi, Pack = 1)] public struct COFFOptionalHeaderStandardFields { [FieldOffset(0x0)] [MarshalAs(UnmanagedType.U2)] public UInt16 Magic; [FieldOffset(0x2)] [MarshalAs(UnmanagedType.U1)] byte MajorLinkerVersion; [FieldOffset(0x3)] [MarshalAs(UnmanagedType.U1)] byte MinorLinkerVersion; [FieldOffset(0x4)] [MarshalAs(UnmanagedType.U4)] UInt32 SizeOfCode; [FieldOffset(0x8)] [MarshalAs(UnmanagedType.U4)] UInt32 SizeOfInitializedData; [FieldOffset(0xC)] [MarshalAs(UnmanagedType.U4)] UInt32 SizeOfUninitializedData; [FieldOffset(0x10)] [MarshalAs(UnmanagedType.U4)] UInt32 AddressOfEntryPoint; [FieldOffset(0x14)] [MarshalAs(UnmanagedType.U4)] UInt32 BaseOfCode; public override string ToString() { StringBuilder returnValue = new StringBuilder(); returnValue.AppendFormat("Magic: 0x{0:X}", Magic); returnValue.AppendLine(); returnValue.AppendFormat("Magic (decoded): {0}", DecodeMagic(Magic)); returnValue.AppendLine(); returnValue.AppendFormat("MajorLinkerVersion: {0}", MajorLinkerVersion); returnValue.AppendLine(); returnValue.AppendFormat("MinorLinkerVersion: {0}", MinorLinkerVersion); returnValue.AppendLine(); returnValue.AppendFormat("SizeOfCode: {0}", SizeOfCode); returnValue.AppendLine(); returnValue.AppendFormat("SizeOfInitializedData: {0}", SizeOfInitializedData); returnValue.AppendLine(); returnValue.AppendFormat("SizeOfUninitializedData: {0}", SizeOfUninitializedData); returnValue.AppendLine(); returnValue.AppendFormat("AddressOfEntryPoint: 0x{0:X}", AddressOfEntryPoint); returnValue.AppendLine(); returnValue.AppendFormat("BaseOfCode: 0x{0:X}", BaseOfCode); returnValue.AppendLine(); return returnValue.ToString(); } private string DecodeMagic(ushort magic) { string returnValue = string.Empty; switch (magic) { case 0x10b: returnValue = "PE32"; break; case 0x20b: returnValue = "PE32+"; break; default: returnValue = "Undefined"; break; } return returnValue; } }
Once we read them in, we can determine if we need to pull in the BaseOfCode and which sizes and offsets to use for the Windows-Specific fields. I am going to cheat a little bit and stash the BaseOfCode with the PE32 Windows-Specific fields rather than pulling it in separately. The only problem with pulling these fields out separately is that the offsets in the struct won't match up with nicely with the documentation. It isn't a big deal really, but anything that adds cognitive overhead is to be avoided when possible. Wait though, I am already deviating pretty heavily because I am giving my offsets in hex rather than decimal. Nevermind.
The struct for the PE32 Windows-Specific fields section is quite long, so I have included it as a separate page. I built a PE32+ Windows-Specific struct, but will leave it out here since we aren't going to be using it for any of our examples. The output now is an impressive length and is:
Signature: MZ? OffsetToPEHeader: 80 PE Signature: PE MachineType: 0x14C MachineType (decoded): IMAGE_FILE_MACHINE_I386 NumberOfSections: 3 TimeDateStamp: 0x58475109 PointerToSymbolTable: 0x0 NumberOfSymbols: 0 SizeOfOptionalHeader: 224 Characteristics: 0x102 Characteristics (decoded): IMAGE_FILE_EXECUTABLE_IMAGE,IMAGE_FILE_32BIT_MACHINE Magic: 0x10B Magic (decoded): PE32 MajorLinkerVersion: 8 MinorLinkerVersion: 0 SizeOfCode: 1024 SizeOfInitializedData: 1536 SizeOfUninitializedData: 0 AddressOfEntryPoint: 0x23AE BaseOfCode: 0x2000 BaseOfData: 0x4000 ImageBase: 0x400000 SectionAlignment: 0x2000 FileAlignment: 0x200 MajorOperatingSystemVersion: 4 MinorOperatingSystemVersion: 0 MajorImageVersion: 0 MinorImageVersion: 0 MajorSubsystemVersion: 4 MinorSubsystemVersion: 0 Win32VersionValue: 0 SizeOfImage: 32768 SizeOfHeaders: 512 CheckSum: 0x0 Subsystem: 0x3 Subsystem (decoded): IMAGE_SUBSYSTEM_WINDOWS_CUI DllCharacteristics: 0x8540 DllCharacteristics (decoded): IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE,IMAGE_DLLCHA RACTERISTICS_NX_COMPAT,IMAGE_DLLCHARACTERISTICS_ NO_SEH,IMAGE_DLLCHARACTERISTICS _TERMINAL_SERVER_AWARE SizeOfStackReserve: 1048576 SizeOfStackCommit: 4096 SizeOfHeapReserve: 1048576 SizeOfHeapCommit: 4096 LoaderFlags: 0x0 NumberOfRvaAndSizes: 0x10 Press return to exit
This is looking good so far. Almost caught up with the Dissection articles. We should sync up by the end of the week and I will run them in parallel after that.
Keep your code clean!