diff --git a/BurnOutSharp.Builder/PortableExecutable.cs b/BurnOutSharp.Builder/PortableExecutable.cs index b64bfd39..470e07ca 100644 --- a/BurnOutSharp.Builder/PortableExecutable.cs +++ b/BurnOutSharp.Builder/PortableExecutable.cs @@ -67,6 +67,18 @@ namespace BurnOutSharp.Builder #endregion + #region Optional Header + + // Try to parse the optional header + var optionalHeader = ParseOptionalHeader(data, offset, coffFileHeader.SizeOfOptionalHeader); + if (optionalHeader == null) + return null; + + // Set the optional header + executable.OptionalHeader = optionalHeader; + + #endregion + // TODO: Implement PE parsing return null; } @@ -93,6 +105,176 @@ namespace BurnOutSharp.Builder return fileHeader; } + /// + /// Parse a byte array into an optional header + /// + /// Byte array to parse + /// 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) + { + int initialOffset = offset; + + // TODO: Use marshalling here instead of building + var optionalHeader = new OptionalHeader(); + + #region Standard Fields + + optionalHeader.Magic = (OptionalHeaderMagicNumber)data.ReadUInt16(ref offset); + optionalHeader.MajorLinkerVersion = data.ReadByte(ref offset); + optionalHeader.MinorLinkerVersion = data.ReadByte(ref offset); + optionalHeader.SizeOfCode = data.ReadUInt32(ref offset); + optionalHeader.SizeOfInitializedData = data.ReadUInt32(ref offset); + optionalHeader.SizeOfUninitializedData = data.ReadUInt32(ref offset); + optionalHeader.AddressOfEntryPoint = data.ReadUInt32(ref offset); + optionalHeader.BaseOfCode = data.ReadUInt32(ref offset); + + if (optionalHeader.Magic == OptionalHeaderMagicNumber.PE32) + optionalHeader.BaseOfData = data.ReadUInt32(ref offset); + + #endregion + + #region Windows-Specific Fields + + if (optionalHeader.Magic == OptionalHeaderMagicNumber.PE32) + optionalHeader.ImageBase_PE32 = data.ReadUInt32(ref offset); + else if (optionalHeader.Magic == OptionalHeaderMagicNumber.PE32Plus) + optionalHeader.ImageBase_PE32Plus = data.ReadUInt64(ref offset); + optionalHeader.FileAlignment = data.ReadUInt32(ref offset); + optionalHeader.MajorOperatingSystemVersion = data.ReadUInt16(ref offset); + optionalHeader.MinorOperatingSystemVersion = data.ReadUInt16(ref offset); + optionalHeader.MajorImageVersion = data.ReadUInt16(ref offset); + optionalHeader.MinorImageVersion = data.ReadUInt16(ref offset); + optionalHeader.MajorSubsystemVersion = data.ReadUInt16(ref offset); + optionalHeader.MinorSubsystemVersion = data.ReadUInt16(ref offset); + optionalHeader.Win32VersionValue = data.ReadUInt32(ref offset); + optionalHeader.SizeOfImage = data.ReadUInt32(ref offset); + optionalHeader.SizeOfHeaders = data.ReadUInt32(ref offset); + optionalHeader.CheckSum = data.ReadUInt32(ref offset); + optionalHeader.Subsystem = (WindowsSubsystem)data.ReadUInt16(ref offset); + optionalHeader.DllCharacteristics = (DllCharacteristics)data.ReadUInt16(ref offset); + if (optionalHeader.Magic == OptionalHeaderMagicNumber.PE32) + optionalHeader.SizeOfStackReserve_PE32 = data.ReadUInt32(ref offset); + else if (optionalHeader.Magic == OptionalHeaderMagicNumber.PE32Plus) + optionalHeader.SizeOfStackReserve_PE32Plus = data.ReadUInt64(ref offset); + if (optionalHeader.Magic == OptionalHeaderMagicNumber.PE32) + optionalHeader.SizeOfStackCommit_PE32 = data.ReadUInt32(ref offset); + else if (optionalHeader.Magic == OptionalHeaderMagicNumber.PE32Plus) + optionalHeader.SizeOfStackCommit_PE32Plus = data.ReadUInt64(ref offset); + if (optionalHeader.Magic == OptionalHeaderMagicNumber.PE32) + optionalHeader.SizeOfHeapReserve_PE32 = data.ReadUInt32(ref offset); + else if (optionalHeader.Magic == OptionalHeaderMagicNumber.PE32Plus) + optionalHeader.SizeOfHeapReserve_PE32Plus = data.ReadUInt64(ref offset); + if (optionalHeader.Magic == OptionalHeaderMagicNumber.PE32) + optionalHeader.SizeOfHeapCommit_PE32 = data.ReadUInt32(ref offset); + else if (optionalHeader.Magic == OptionalHeaderMagicNumber.PE32Plus) + optionalHeader.SizeOfHeapCommit_PE32Plus = data.ReadUInt64(ref offset); + optionalHeader.LoaderFlags = data.ReadUInt32(ref offset); + optionalHeader.NumberOfRvaAndSizes = data.ReadUInt32(ref offset); + + #endregion + + #region Data Directories + + if (offset - initialOffset < optionalSize) + { + optionalHeader.ExportTable = new DataDirectory(); + optionalHeader.ExportTable.VirtualAddress = data.ReadUInt32(ref offset); + optionalHeader.ExportTable.Size = data.ReadUInt32(ref offset); + } + if (offset - initialOffset < optionalSize) + { + optionalHeader.ImportTable = new DataDirectory(); + optionalHeader.ImportTable.VirtualAddress = data.ReadUInt32(ref offset); + optionalHeader.ImportTable.Size = data.ReadUInt32(ref offset); + } + if (offset - initialOffset < optionalSize) + { + optionalHeader.ResourceTable = new DataDirectory(); + optionalHeader.ResourceTable.VirtualAddress = data.ReadUInt32(ref offset); + optionalHeader.ResourceTable.Size = data.ReadUInt32(ref offset); + } + if (offset - initialOffset < optionalSize) + { + optionalHeader.ExceptionTable = new DataDirectory(); + optionalHeader.ExceptionTable.VirtualAddress = data.ReadUInt32(ref offset); + optionalHeader.ExceptionTable.Size = data.ReadUInt32(ref offset); + } + if (offset - initialOffset < optionalSize) + { + optionalHeader.CertificateTable = new DataDirectory(); + optionalHeader.CertificateTable.VirtualAddress = data.ReadUInt32(ref offset); + optionalHeader.CertificateTable.Size = data.ReadUInt32(ref offset); + } + if (offset - initialOffset < optionalSize) + { + optionalHeader.BaseRelocationTable = new DataDirectory(); + optionalHeader.BaseRelocationTable.VirtualAddress = data.ReadUInt32(ref offset); + optionalHeader.BaseRelocationTable.Size = data.ReadUInt32(ref offset); + } + if (offset - initialOffset < optionalSize) + { + optionalHeader.Debug = new DataDirectory(); + optionalHeader.Debug.VirtualAddress = data.ReadUInt32(ref offset); + optionalHeader.Debug.Size = data.ReadUInt32(ref offset); + } + if (offset - initialOffset < optionalSize) + { + optionalHeader.Architecture = data.ReadUInt64(ref offset); + } + if (offset - initialOffset < optionalSize) + { + optionalHeader.GlobalPtr = new DataDirectory(); + optionalHeader.GlobalPtr.VirtualAddress = data.ReadUInt32(ref offset); + optionalHeader.GlobalPtr.Size = data.ReadUInt32(ref offset); + } + if (offset - initialOffset < optionalSize) + { + optionalHeader.TLSTable = new DataDirectory(); + optionalHeader.TLSTable.VirtualAddress = data.ReadUInt32(ref offset); + optionalHeader.TLSTable.Size = data.ReadUInt32(ref offset); + } + if (offset - initialOffset < optionalSize) + { + optionalHeader.LoadConfigTable = new DataDirectory(); + optionalHeader.LoadConfigTable.VirtualAddress = data.ReadUInt32(ref offset); + optionalHeader.LoadConfigTable.Size = data.ReadUInt32(ref offset); + } + if (offset - initialOffset < optionalSize) + { + optionalHeader.BoundImport = new DataDirectory(); + optionalHeader.BoundImport.VirtualAddress = data.ReadUInt32(ref offset); + optionalHeader.BoundImport.Size = data.ReadUInt32(ref offset); + } + if (offset - initialOffset < optionalSize) + { + optionalHeader.IAT = new DataDirectory(); + optionalHeader.IAT.VirtualAddress = data.ReadUInt32(ref offset); + optionalHeader.IAT.Size = data.ReadUInt32(ref offset); + } + if (offset - initialOffset < optionalSize) + { + optionalHeader.DelayImportDescriptor = new DataDirectory(); + optionalHeader.DelayImportDescriptor.VirtualAddress = data.ReadUInt32(ref offset); + optionalHeader.DelayImportDescriptor.Size = data.ReadUInt32(ref offset); + } + if (offset - initialOffset < optionalSize) + { + optionalHeader.CLRRuntimeHeader = new DataDirectory(); + optionalHeader.CLRRuntimeHeader.VirtualAddress = data.ReadUInt32(ref offset); + optionalHeader.CLRRuntimeHeader.Size = data.ReadUInt32(ref offset); + } + if (offset - initialOffset < optionalSize) + { + optionalHeader.Reserved = data.ReadUInt64(ref offset); + } + + #endregion + + return optionalHeader; + } + #endregion #region Stream Data @@ -155,6 +337,18 @@ namespace BurnOutSharp.Builder #endregion + #region Optional Header + + // Try to parse the optional header + var optionalHeader = ParseOptionalHeader(data, coffFileHeader.SizeOfOptionalHeader); + if (optionalHeader == null) + return null; + + // Set the optional header + executable.OptionalHeader = optionalHeader; + + #endregion + // TODO: Implement PE parsing return null; } @@ -180,6 +374,175 @@ namespace BurnOutSharp.Builder return fileHeader; } + /// + /// Parse a Stream into an optional header + /// + /// Stream to parse + /// Size of the optional header + /// Filled optional header on success, null on error + private static OptionalHeader ParseOptionalHeader(Stream data, int optionalSize) + { + long initialOffset = data.Position; + + // TODO: Use marshalling here instead of building + var optionalHeader = new OptionalHeader(); + + #region Standard Fields + + optionalHeader.Magic = (OptionalHeaderMagicNumber)data.ReadUInt16(); + optionalHeader.MajorLinkerVersion = data.ReadByteValue(); + optionalHeader.MinorLinkerVersion = data.ReadByteValue(); + optionalHeader.SizeOfCode = data.ReadUInt32(); + optionalHeader.SizeOfInitializedData = data.ReadUInt32(); + optionalHeader.SizeOfUninitializedData = data.ReadUInt32(); + optionalHeader.AddressOfEntryPoint = data.ReadUInt32(); + optionalHeader.BaseOfCode = data.ReadUInt32(); + + if (optionalHeader.Magic == OptionalHeaderMagicNumber.PE32) + optionalHeader.BaseOfData = data.ReadUInt32(); + + #endregion + + #region Windows-Specific Fields + + if (optionalHeader.Magic == OptionalHeaderMagicNumber.PE32) + optionalHeader.ImageBase_PE32 = data.ReadUInt32(); + else if (optionalHeader.Magic == OptionalHeaderMagicNumber.PE32Plus) + optionalHeader.ImageBase_PE32Plus = data.ReadUInt64(); + optionalHeader.FileAlignment = data.ReadUInt32(); + optionalHeader.MajorOperatingSystemVersion = data.ReadUInt16(); + optionalHeader.MinorOperatingSystemVersion = data.ReadUInt16(); + optionalHeader.MajorImageVersion = data.ReadUInt16(); + optionalHeader.MinorImageVersion = data.ReadUInt16(); + optionalHeader.MajorSubsystemVersion = data.ReadUInt16(); + optionalHeader.MinorSubsystemVersion = data.ReadUInt16(); + optionalHeader.Win32VersionValue = data.ReadUInt32(); + optionalHeader.SizeOfImage = data.ReadUInt32(); + optionalHeader.SizeOfHeaders = data.ReadUInt32(); + optionalHeader.CheckSum = data.ReadUInt32(); + optionalHeader.Subsystem = (WindowsSubsystem)data.ReadUInt16(); + optionalHeader.DllCharacteristics = (DllCharacteristics)data.ReadUInt16(); + if (optionalHeader.Magic == OptionalHeaderMagicNumber.PE32) + optionalHeader.SizeOfStackReserve_PE32 = data.ReadUInt32(); + else if (optionalHeader.Magic == OptionalHeaderMagicNumber.PE32Plus) + optionalHeader.SizeOfStackReserve_PE32Plus = data.ReadUInt64(); + if (optionalHeader.Magic == OptionalHeaderMagicNumber.PE32) + optionalHeader.SizeOfStackCommit_PE32 = data.ReadUInt32(); + else if (optionalHeader.Magic == OptionalHeaderMagicNumber.PE32Plus) + optionalHeader.SizeOfStackCommit_PE32Plus = data.ReadUInt64(); + if (optionalHeader.Magic == OptionalHeaderMagicNumber.PE32) + optionalHeader.SizeOfHeapReserve_PE32 = data.ReadUInt32(); + else if (optionalHeader.Magic == OptionalHeaderMagicNumber.PE32Plus) + optionalHeader.SizeOfHeapReserve_PE32Plus = data.ReadUInt64(); + if (optionalHeader.Magic == OptionalHeaderMagicNumber.PE32) + optionalHeader.SizeOfHeapCommit_PE32 = data.ReadUInt32(); + else if (optionalHeader.Magic == OptionalHeaderMagicNumber.PE32Plus) + optionalHeader.SizeOfHeapCommit_PE32Plus = data.ReadUInt64(); + optionalHeader.LoaderFlags = data.ReadUInt32(); + optionalHeader.NumberOfRvaAndSizes = data.ReadUInt32(); + + #endregion + + #region Data Directories + + if (data.Position - initialOffset < optionalSize) + { + optionalHeader.ExportTable = new DataDirectory(); + optionalHeader.ExportTable.VirtualAddress = data.ReadUInt32(); + optionalHeader.ExportTable.Size = data.ReadUInt32(); + } + if (data.Position - initialOffset < optionalSize) + { + optionalHeader.ImportTable = new DataDirectory(); + optionalHeader.ImportTable.VirtualAddress = data.ReadUInt32(); + optionalHeader.ImportTable.Size = data.ReadUInt32(); + } + if (data.Position - initialOffset < optionalSize) + { + optionalHeader.ResourceTable = new DataDirectory(); + optionalHeader.ResourceTable.VirtualAddress = data.ReadUInt32(); + optionalHeader.ResourceTable.Size = data.ReadUInt32(); + } + if (data.Position - initialOffset < optionalSize) + { + optionalHeader.ExceptionTable = new DataDirectory(); + optionalHeader.ExceptionTable.VirtualAddress = data.ReadUInt32(); + optionalHeader.ExceptionTable.Size = data.ReadUInt32(); + } + if (data.Position - initialOffset < optionalSize) + { + optionalHeader.CertificateTable = new DataDirectory(); + optionalHeader.CertificateTable.VirtualAddress = data.ReadUInt32(); + optionalHeader.CertificateTable.Size = data.ReadUInt32(); + } + if (data.Position - initialOffset < optionalSize) + { + optionalHeader.BaseRelocationTable = new DataDirectory(); + optionalHeader.BaseRelocationTable.VirtualAddress = data.ReadUInt32(); + optionalHeader.BaseRelocationTable.Size = data.ReadUInt32(); + } + if (data.Position - initialOffset < optionalSize) + { + optionalHeader.Debug = new DataDirectory(); + optionalHeader.Debug.VirtualAddress = data.ReadUInt32(); + optionalHeader.Debug.Size = data.ReadUInt32(); + } + if (data.Position - initialOffset < optionalSize) + { + optionalHeader.Architecture = data.ReadUInt64(); + } + if (data.Position - initialOffset < optionalSize) + { + optionalHeader.GlobalPtr = new DataDirectory(); + optionalHeader.GlobalPtr.VirtualAddress = data.ReadUInt32(); + optionalHeader.GlobalPtr.Size = data.ReadUInt32(); + } + if (data.Position - initialOffset < optionalSize) + { + optionalHeader.TLSTable = new DataDirectory(); + optionalHeader.TLSTable.VirtualAddress = data.ReadUInt32(); + optionalHeader.TLSTable.Size = data.ReadUInt32(); + } + if (data.Position - initialOffset < optionalSize) + { + optionalHeader.LoadConfigTable = new DataDirectory(); + optionalHeader.LoadConfigTable.VirtualAddress = data.ReadUInt32(); + optionalHeader.LoadConfigTable.Size = data.ReadUInt32(); + } + if (data.Position - initialOffset < optionalSize) + { + optionalHeader.BoundImport = new DataDirectory(); + optionalHeader.BoundImport.VirtualAddress = data.ReadUInt32(); + optionalHeader.BoundImport.Size = data.ReadUInt32(); + } + if (data.Position - initialOffset < optionalSize) + { + optionalHeader.IAT = new DataDirectory(); + optionalHeader.IAT.VirtualAddress = data.ReadUInt32(); + optionalHeader.IAT.Size = data.ReadUInt32(); + } + if (data.Position - initialOffset < optionalSize) + { + optionalHeader.DelayImportDescriptor = new DataDirectory(); + optionalHeader.DelayImportDescriptor.VirtualAddress = data.ReadUInt32(); + optionalHeader.DelayImportDescriptor.Size = data.ReadUInt32(); + } + if (data.Position - initialOffset < optionalSize) + { + optionalHeader.CLRRuntimeHeader = new DataDirectory(); + optionalHeader.CLRRuntimeHeader.VirtualAddress = data.ReadUInt32(); + optionalHeader.CLRRuntimeHeader.Size = data.ReadUInt32(); + } + if (data.Position - initialOffset < optionalSize) + { + optionalHeader.Reserved = data.ReadUInt64(); + } + + #endregion + + return optionalHeader; + } + #endregion } } \ No newline at end of file