diff --git a/BurnOutSharp.Builder/PortableExecutable.cs b/BurnOutSharp.Builder/PortableExecutable.cs index e81e11ba..6f97ca5c 100644 --- a/BurnOutSharp.Builder/PortableExecutable.cs +++ b/BurnOutSharp.Builder/PortableExecutable.cs @@ -70,7 +70,7 @@ namespace BurnOutSharp.Builder #region Optional Header // Try to parse the optional header - var optionalHeader = ParseOptionalHeader(data, offset, coffFileHeader.SizeOfOptionalHeader); + var optionalHeader = ParseOptionalHeader(data, ref offset, coffFileHeader.SizeOfOptionalHeader); if (optionalHeader == null) return null; @@ -79,6 +79,18 @@ namespace BurnOutSharp.Builder #endregion + #region Section Table + + // Try to parse the section table + var sectionTable = ParseSectionTable(data, offset, coffFileHeader.NumberOfSections); + if (sectionTable == null) + return null; + + // Set the section table + executable.SectionTable = sectionTable; + + #endregion + // TODO: Finish implementing PE parsing return executable; } @@ -112,7 +124,7 @@ namespace BurnOutSharp.Builder /// Offset into the byte array /// Size of the optional header /// Filled optional header on success, null on error - private static OptionalHeader ParseOptionalHeader(byte[] data, int offset, int optionalSize) + private static OptionalHeader ParseOptionalHeader(byte[] data, ref int offset, int optionalSize) { int initialOffset = offset; @@ -141,6 +153,7 @@ namespace BurnOutSharp.Builder optionalHeader.ImageBase_PE32 = data.ReadUInt32(ref offset); else if (optionalHeader.Magic == OptionalHeaderMagicNumber.PE32Plus) optionalHeader.ImageBase_PE32Plus = data.ReadUInt64(ref offset); + optionalHeader.SectionAlignment = data.ReadUInt32(ref offset); optionalHeader.FileAlignment = data.ReadUInt32(ref offset); optionalHeader.MajorOperatingSystemVersion = data.ReadUInt16(ref offset); optionalHeader.MinorOperatingSystemVersion = data.ReadUInt16(ref offset); @@ -275,6 +288,47 @@ namespace BurnOutSharp.Builder return optionalHeader; } + /// + /// Parse a byte array into a section table + /// + /// Byte array to parse + /// Offset into the byte array + /// Number of section table entries to read + /// Filled section table on success, null on error + private static SectionHeader[] ParseSectionTable(byte[] data, int offset, int count) + { + // TODO: Use marshalling here instead of building + var sectionTable = new SectionHeader[count]; + + for (int i = 0; i < count; i++) + { + var entry = new SectionHeader(); + entry.Name = data.ReadBytes(ref offset, 8); + entry.VirtualSize = data.ReadUInt32(ref offset); + entry.VirtualAddress = data.ReadUInt32(ref offset); + entry.SizeOfRawData = data.ReadUInt32(ref offset); + entry.PointerToRawData = data.ReadUInt32(ref offset); + entry.PointerToRelocations = data.ReadUInt32(ref offset); + entry.PointerToLinenumbers = data.ReadUInt32(ref offset); + entry.NumberOfRelocations = data.ReadUInt16(ref offset); + entry.NumberOfLinenumbers = data.ReadUInt16(ref offset); + entry.Characteristics = (SectionFlags)data.ReadUInt32(ref offset); + entry.COFFRelocations = new COFFRelocation[entry.NumberOfRelocations]; + for (int j = 0; i < entry.NumberOfRelocations; j++) + { + // TODO: Seek to correct location and read data + } + entry.COFFLineNumbers = new COFFLineNumber[entry.NumberOfRelocations]; + for (int j = 0; i < entry.NumberOfRelocations; j++) + { + // TODO: Seek to correct location and read data + } + sectionTable[i] = entry; + } + + return sectionTable; + } + #endregion #region Stream Data @@ -349,6 +403,18 @@ namespace BurnOutSharp.Builder #endregion + #region Section Table + + // Try to parse the section table + var sectionTable = ParseSectionTable(data, coffFileHeader.NumberOfSections); + if (sectionTable == null) + return null; + + // Set the section table + executable.SectionTable = sectionTable; + + #endregion + // TODO: Finish implementing PE parsing return executable; } @@ -409,6 +475,7 @@ namespace BurnOutSharp.Builder optionalHeader.ImageBase_PE32 = data.ReadUInt32(); else if (optionalHeader.Magic == OptionalHeaderMagicNumber.PE32Plus) optionalHeader.ImageBase_PE32Plus = data.ReadUInt64(); + optionalHeader.SectionAlignment = data.ReadUInt32(); optionalHeader.FileAlignment = data.ReadUInt32(); optionalHeader.MajorOperatingSystemVersion = data.ReadUInt16(); optionalHeader.MinorOperatingSystemVersion = data.ReadUInt16(); @@ -543,6 +610,46 @@ namespace BurnOutSharp.Builder return optionalHeader; } + /// + /// Parse a Stream into a section table + /// + /// Stream to parse + /// Number of section table entries to read + /// Filled section table on success, null on error + private static SectionHeader[] ParseSectionTable(Stream data, int count) + { + // TODO: Use marshalling here instead of building + var sectionTable = new SectionHeader[count]; + + for (int i = 0; i < count; i++) + { + var entry = new SectionHeader(); + entry.Name = data.ReadBytes(8); + entry.VirtualSize = data.ReadUInt32(); + entry.VirtualAddress = data.ReadUInt32(); + entry.SizeOfRawData = data.ReadUInt32(); + entry.PointerToRawData = data.ReadUInt32(); + entry.PointerToRelocations = data.ReadUInt32(); + entry.PointerToLinenumbers = data.ReadUInt32(); + entry.NumberOfRelocations = data.ReadUInt16(); + entry.NumberOfLinenumbers = data.ReadUInt16(); + entry.Characteristics = (SectionFlags)data.ReadUInt32(); + entry.COFFRelocations = new COFFRelocation[entry.NumberOfRelocations]; + for (int j = 0; j < entry.NumberOfRelocations; j++) + { + // TODO: Seek to correct location and read data + } + entry.COFFLineNumbers = new COFFLineNumber[entry.NumberOfLinenumbers]; + for (int j = 0; j < entry.NumberOfLinenumbers; j++) + { + // TODO: Seek to correct location and read data + } + sectionTable[i] = entry; + } + + return sectionTable; + } + #endregion } } \ No newline at end of file diff --git a/ExecutableTest/Program.cs b/ExecutableTest/Program.cs index feba089a..bff03479 100644 --- a/ExecutableTest/Program.cs +++ b/ExecutableTest/Program.cs @@ -485,99 +485,127 @@ namespace ExecutableTest if (executable.OptionalHeader.ExportTable != null) { - Console.WriteLine(" Export Table (1)"); - Console.WriteLine($" Virtual address: {executable.OptionalHeader.ExportTable.VirtualAddress}"); - Console.WriteLine($" Size: {executable.OptionalHeader.ExportTable.Size}"); + Console.WriteLine(" Export Table (1)"); + Console.WriteLine($" Virtual address: {executable.OptionalHeader.ExportTable.VirtualAddress}"); + Console.WriteLine($" Size: {executable.OptionalHeader.ExportTable.Size}"); } if (executable.OptionalHeader.ImportTable != null) { - Console.WriteLine(" Import Table (2)"); - Console.WriteLine($" Virtual address: {executable.OptionalHeader.ImportTable.VirtualAddress}"); - Console.WriteLine($" Size: {executable.OptionalHeader.ImportTable.Size}"); + Console.WriteLine(" Import Table (2)"); + Console.WriteLine($" Virtual address: {executable.OptionalHeader.ImportTable.VirtualAddress}"); + Console.WriteLine($" Size: {executable.OptionalHeader.ImportTable.Size}"); } if (executable.OptionalHeader.ResourceTable != null) { - Console.WriteLine(" Resource Table (3)"); - Console.WriteLine($" Virtual address: {executable.OptionalHeader.ResourceTable.VirtualAddress}"); - Console.WriteLine($" Size: {executable.OptionalHeader.ResourceTable.Size}"); + Console.WriteLine(" Resource Table (3)"); + Console.WriteLine($" Virtual address: {executable.OptionalHeader.ResourceTable.VirtualAddress}"); + Console.WriteLine($" Size: {executable.OptionalHeader.ResourceTable.Size}"); } if (executable.OptionalHeader.ExceptionTable != null) { - Console.WriteLine(" Exception Table (4)"); - Console.WriteLine($" Virtual address: {executable.OptionalHeader.ExceptionTable.VirtualAddress}"); - Console.WriteLine($" Size: {executable.OptionalHeader.ExceptionTable.Size}"); + Console.WriteLine(" Exception Table (4)"); + Console.WriteLine($" Virtual address: {executable.OptionalHeader.ExceptionTable.VirtualAddress}"); + Console.WriteLine($" Size: {executable.OptionalHeader.ExceptionTable.Size}"); } if (executable.OptionalHeader.CertificateTable != null) { - Console.WriteLine(" Certificate Table (5)"); - Console.WriteLine($" Virtual address: {executable.OptionalHeader.CertificateTable.VirtualAddress}"); - Console.WriteLine($" Size: {executable.OptionalHeader.CertificateTable.Size}"); + Console.WriteLine(" Certificate Table (5)"); + Console.WriteLine($" Virtual address: {executable.OptionalHeader.CertificateTable.VirtualAddress}"); + Console.WriteLine($" Size: {executable.OptionalHeader.CertificateTable.Size}"); } if (executable.OptionalHeader.BaseRelocationTable != null) { - Console.WriteLine(" Base Relocation Table (6)"); - Console.WriteLine($" Virtual address: {executable.OptionalHeader.BaseRelocationTable.VirtualAddress}"); - Console.WriteLine($" Size: {executable.OptionalHeader.BaseRelocationTable.Size}"); + Console.WriteLine(" Base Relocation Table (6)"); + Console.WriteLine($" Virtual address: {executable.OptionalHeader.BaseRelocationTable.VirtualAddress}"); + Console.WriteLine($" Size: {executable.OptionalHeader.BaseRelocationTable.Size}"); } if (executable.OptionalHeader.Debug != null) { - Console.WriteLine(" Debug Table (7)"); - Console.WriteLine($" Virtual address: {executable.OptionalHeader.Debug.VirtualAddress}"); - Console.WriteLine($" Size: {executable.OptionalHeader.Debug.Size}"); + Console.WriteLine(" Debug Table (7)"); + Console.WriteLine($" Virtual address: {executable.OptionalHeader.Debug.VirtualAddress}"); + Console.WriteLine($" Size: {executable.OptionalHeader.Debug.Size}"); } if (executable.OptionalHeader.NumberOfRvaAndSizes >= 8) { - Console.WriteLine(" Architecture Table (8)"); - Console.WriteLine($" Virtual address: 0"); - Console.WriteLine($" Size: 0"); + Console.WriteLine(" Architecture Table (8)"); + Console.WriteLine($" Virtual address: 0"); + Console.WriteLine($" Size: 0"); } if (executable.OptionalHeader.GlobalPtr != null) { - Console.WriteLine(" Global Pointer Register (9)"); - Console.WriteLine($" Virtual address: {executable.OptionalHeader.GlobalPtr.VirtualAddress}"); - Console.WriteLine($" Size: {executable.OptionalHeader.GlobalPtr.Size}"); + Console.WriteLine(" Global Pointer Register (9)"); + Console.WriteLine($" Virtual address: {executable.OptionalHeader.GlobalPtr.VirtualAddress}"); + Console.WriteLine($" Size: {executable.OptionalHeader.GlobalPtr.Size}"); } if (executable.OptionalHeader.ThreadLocalStorageTable != null) { - Console.WriteLine(" Thread Local Storage (TLS) Table (10)"); - Console.WriteLine($" Virtual address: {executable.OptionalHeader.ThreadLocalStorageTable.VirtualAddress}"); - Console.WriteLine($" Size: {executable.OptionalHeader.ThreadLocalStorageTable.Size}"); + Console.WriteLine(" Thread Local Storage (TLS) Table (10)"); + Console.WriteLine($" Virtual address: {executable.OptionalHeader.ThreadLocalStorageTable.VirtualAddress}"); + Console.WriteLine($" Size: {executable.OptionalHeader.ThreadLocalStorageTable.Size}"); } if (executable.OptionalHeader.LoadConfigTable != null) { - Console.WriteLine(" Load Config Table (11)"); - Console.WriteLine($" Virtual address: {executable.OptionalHeader.LoadConfigTable.VirtualAddress}"); - Console.WriteLine($" Size: {executable.OptionalHeader.LoadConfigTable.Size}"); + Console.WriteLine(" Load Config Table (11)"); + Console.WriteLine($" Virtual address: {executable.OptionalHeader.LoadConfigTable.VirtualAddress}"); + Console.WriteLine($" Size: {executable.OptionalHeader.LoadConfigTable.Size}"); } if (executable.OptionalHeader.BoundImport != null) { - Console.WriteLine(" Bound Import Table (12)"); - Console.WriteLine($" Virtual address: {executable.OptionalHeader.BoundImport.VirtualAddress}"); - Console.WriteLine($" Size: {executable.OptionalHeader.BoundImport.Size}"); + Console.WriteLine(" Bound Import Table (12)"); + Console.WriteLine($" Virtual address: {executable.OptionalHeader.BoundImport.VirtualAddress}"); + Console.WriteLine($" Size: {executable.OptionalHeader.BoundImport.Size}"); } if (executable.OptionalHeader.ImportAddressTable != null) { - Console.WriteLine(" Import Address Table (13)"); - Console.WriteLine($" Virtual address: {executable.OptionalHeader.ImportAddressTable.VirtualAddress}"); - Console.WriteLine($" Size: {executable.OptionalHeader.ImportAddressTable.Size}"); + Console.WriteLine(" Import Address Table (13)"); + Console.WriteLine($" Virtual address: {executable.OptionalHeader.ImportAddressTable.VirtualAddress}"); + Console.WriteLine($" Size: {executable.OptionalHeader.ImportAddressTable.Size}"); } if (executable.OptionalHeader.DelayImportDescriptor != null) { - Console.WriteLine(" Delay Import Descriptior (14)"); - Console.WriteLine($" Virtual address: {executable.OptionalHeader.DelayImportDescriptor.VirtualAddress}"); - Console.WriteLine($" Size: {executable.OptionalHeader.DelayImportDescriptor.Size}"); + Console.WriteLine(" Delay Import Descriptior (14)"); + Console.WriteLine($" Virtual address: {executable.OptionalHeader.DelayImportDescriptor.VirtualAddress}"); + Console.WriteLine($" Size: {executable.OptionalHeader.DelayImportDescriptor.Size}"); } if (executable.OptionalHeader.CLRRuntimeHeader != null) { - Console.WriteLine(" CLR Runtime Header (15)"); - Console.WriteLine($" Virtual address: {executable.OptionalHeader.CLRRuntimeHeader.VirtualAddress}"); - Console.WriteLine($" Size: {executable.OptionalHeader.CLRRuntimeHeader.Size}"); + Console.WriteLine(" CLR Runtime Header (15)"); + Console.WriteLine($" Virtual address: {executable.OptionalHeader.CLRRuntimeHeader.VirtualAddress}"); + Console.WriteLine($" Size: {executable.OptionalHeader.CLRRuntimeHeader.Size}"); } if (executable.OptionalHeader.NumberOfRvaAndSizes >= 16) { - Console.WriteLine(" Reserved (16)"); - Console.WriteLine($" Virtual address: 0"); - Console.WriteLine($" Size: 0"); + Console.WriteLine(" Reserved (16)"); + Console.WriteLine($" Virtual address: 0"); + Console.WriteLine($" Size: 0"); + } + } + Console.WriteLine(); + + Console.WriteLine(" Section Table Information:"); + Console.WriteLine(" -------------------------"); + if (executable.COFFFileHeader.NumberOfSections == 0 || executable.SectionTable.Length == 0) + { + Console.WriteLine(" No section table items"); + } + else + { + for (int i = 0; i < executable.SectionTable.Length; i++) + { + var entry = executable.SectionTable[i]; + Console.WriteLine($" Segment Table Entry {i}"); + Console.WriteLine($" Name = {Encoding.UTF8.GetString(entry.Name)}"); + Console.WriteLine($" Virtual size = {entry.VirtualSize}"); + Console.WriteLine($" Virtual address = {entry.VirtualAddress}"); + Console.WriteLine($" Size of raw data = {entry.SizeOfRawData}"); + Console.WriteLine($" Pointer to raw data = {entry.PointerToRawData}"); + Console.WriteLine($" Pointer to relocations = {entry.PointerToRelocations}"); + Console.WriteLine($" Pointer to linenumbers = {entry.PointerToLinenumbers}"); + Console.WriteLine($" Number of relocations = {entry.NumberOfRelocations}"); + Console.WriteLine($" Number of linenumbers = {entry.NumberOfLinenumbers}"); + Console.WriteLine($" Characteristics = {entry.Characteristics}"); + // TODO: Add COFFRelocations + // TODO: Add COFFLineNumbers } } Console.WriteLine();