From ba4c56997a174ce381437f3e9a1063d13986c02a Mon Sep 17 00:00:00 2001 From: Matt Nadareski Date: Tue, 15 Mar 2022 10:15:05 -0700 Subject: [PATCH] Add Relocation section skeleton --- .../PE/Entries/BaseRelocationBlock.cs | 48 +++++++++++++++++ .../Microsoft/PE/PortableExecutable.cs | 40 +++++++++++---- .../Microsoft/PE/Sections/DebugSection.cs | 1 - .../PE/Sections/RelocationSection.cs | 51 +++++++++++++++++++ 4 files changed, 130 insertions(+), 10 deletions(-) create mode 100644 BurnOutSharp/ExecutableType/Microsoft/PE/Entries/BaseRelocationBlock.cs create mode 100644 BurnOutSharp/ExecutableType/Microsoft/PE/Sections/RelocationSection.cs diff --git a/BurnOutSharp/ExecutableType/Microsoft/PE/Entries/BaseRelocationBlock.cs b/BurnOutSharp/ExecutableType/Microsoft/PE/Entries/BaseRelocationBlock.cs new file mode 100644 index 00000000..fea04df5 --- /dev/null +++ b/BurnOutSharp/ExecutableType/Microsoft/PE/Entries/BaseRelocationBlock.cs @@ -0,0 +1,48 @@ +using System.IO; +using BurnOutSharp.Tools; + +namespace BurnOutSharp.ExecutableType.Microsoft.PE.Entries +{ + /// + /// The base relocation table is divided into blocks. + /// Each block represents the base relocations for a 4K page. + /// Each block must start on a 32-bit boundary. + /// + /// https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#base-relocation-block + public class BaseRelocationBlock + { + /// + /// The image base plus the page RVA is added to each offset to create the VA where the base relocation must be applied. + /// + public uint PageRVA; + + /// + /// The total number of bytes in the base relocation block, including the Page RVA and Block Size fields and the Type/Offset fields that follow. + /// + public uint BlockSize; + + public static BaseRelocationBlock Deserialize(Stream stream) + { + var brb = new BaseRelocationBlock(); + + brb.PageRVA = stream.ReadUInt32(); + brb.BlockSize = stream.ReadUInt32(); + + // TODO: Read in the type/offset field entries + + return brb; + } + + public static BaseRelocationBlock Deserialize(byte[] content, ref int offset) + { + var brb = new BaseRelocationBlock(); + + brb.PageRVA = content.ReadUInt32(ref offset); + brb.BlockSize = content.ReadUInt32(ref offset); + + // TODO: Read in the type/offset field entries + + return brb; + } + } +} \ No newline at end of file diff --git a/BurnOutSharp/ExecutableType/Microsoft/PE/PortableExecutable.cs b/BurnOutSharp/ExecutableType/Microsoft/PE/PortableExecutable.cs index 8db4d59a..55acc224 100644 --- a/BurnOutSharp/ExecutableType/Microsoft/PE/PortableExecutable.cs +++ b/BurnOutSharp/ExecutableType/Microsoft/PE/PortableExecutable.cs @@ -89,6 +89,12 @@ namespace BurnOutSharp.ExecutableType.Microsoft.PE /// public ImportDataSection ImportTable; + /// + /// The base relocation table contains entries for all base relocations in the image. + /// The Base Relocation Table field in the optional header data directories gives the number of bytes in the base relocation table. + /// + public RelocationSection RelocationTable; + /// /// Resources are indexed by a multiple-level binary-sorted tree structure. /// The general design can incorporate 2**31 levels. @@ -110,7 +116,7 @@ namespace BurnOutSharp.ExecutableType.Microsoft.PE // X - .edata *1 protection Export tables // X - .idata *1 protection Import tables // X - .rdata 11 protections Read-only initialized data - // - .rsrc *1 protection Resource directory [Mostly taken care of, last protection needs research] + // - .rsrc *1 protection Resource directory [TODO: Mostly taken care of, last protection needs research] // X - .text 6 protections Executable code (free format) // Y - .tls *1 protection Thread-local storage (object only) // @@ -120,7 +126,11 @@ namespace BurnOutSharp.ExecutableType.Microsoft.PE // X - .grand *1 protection CD-Cops / DVD-Cops // X - .init *1 protection SolidShield // - .pec2 *1 protection PE Compact [Unconfirmed] + // - .NOS0 *1 protection UPX (NOS Variant) + // - .NOS1 *1 protection UPX (NOS Variant) // X - .txt2 *1 protection SafeDisc + // - .UPX0 *1 protection UPX + // - .UPX1 *1 protection UPX // // Here is a list of non-standard sections whose data is not read by various protections: // - .brick 1 protection StarForce @@ -131,15 +141,11 @@ namespace BurnOutSharp.ExecutableType.Microsoft.PE // - .ldr 1 protection 3PLock // - .ldt 1 protection 3PLock // - .nicode 1 protection Armadillo - // - .NOS0 1 protection UPX (NOS Variant) [Used as endpoint] - // - .NOS1 1 protection UPX (NOS Variant) [Used as endpoint] // - .pec1 1 protection PE Compact // - .securom 1 protection SecuROM // - .sforce 1 protection StarForce // - stxt371 1 protection SafeDisc // - stxt774 1 protection SafeDisc - // - .UPX0 1 protection UPX [Used as endpoint] - // - .UPX1 1 protection UPX [Used as endpoint] // - .vob.pcd 1 protection VOB ProtectCD // - _winzip_ 1 protection WinZip SFX // - XPROT 1 protection JoWood @@ -266,6 +272,14 @@ namespace BurnOutSharp.ExecutableType.Microsoft.PE // this.ImportTable = ImportDataSection.Deserialize(stream, this.OptionalHeader.Magic == OptionalHeaderType.PE32Plus, hintCount: 0); // } + // // Relocation Section + // var table = this.GetLastSection(".reloc", true); + // if (table != null && table.VirtualSize > 0) + // { + // stream.Seek((int)table.PointerToRawData, SeekOrigin.Begin); + // this.RelocationTable = RelocationSection.Deserialize(stream); + // } + // Resource Table var table = this.GetLastSection(".rsrc", true); if (table != null && table.VirtualSize > 0) @@ -362,7 +376,15 @@ namespace BurnOutSharp.ExecutableType.Microsoft.PE // if (table != null && table.VirtualSize > 0) // { // int tableAddress = (int)table.PointerToRawData; - // this.ImportTable = ImportDataSection.Deserialize(content, tableAddress, this.OptionalHeader.Magic == OptionalHeaderType.PE32Plus, hintCount: 0); + // this.ImportTable = ImportDataSection.Deserialize(content, ref tableAddress, this.OptionalHeader.Magic == OptionalHeaderType.PE32Plus, hintCount: 0); + // } + + // // Relocation Section + // var table = this.GetLastSection(".reloc", true); + // if (table != null && table.VirtualSize > 0) + // { + // int tableAddress = (int)table.PointerToRawData; + // this.RelocationTable = RelocationSection.Deserialize(content, ref tableAddress); // } // Resource Table @@ -420,13 +442,13 @@ namespace BurnOutSharp.ExecutableType.Microsoft.PE if (sectionNames == null) return false; - // If we're checking exactly, return only exact matches (with nulls trimmed) + // If we're checking exactly, return only exact matches if (exact) - return sectionNames.Any(n => n.Trim('\0').Equals(sectionName)); + return sectionNames.Any(n => n.Equals(sectionName)); // Otherwise, check if section name starts with the value else - return sectionNames.Any(n => n.Trim('\0').StartsWith(sectionName)); + return sectionNames.Any(n => n.StartsWith(sectionName)); } /// diff --git a/BurnOutSharp/ExecutableType/Microsoft/PE/Sections/DebugSection.cs b/BurnOutSharp/ExecutableType/Microsoft/PE/Sections/DebugSection.cs index 92e105c7..f63bef74 100644 --- a/BurnOutSharp/ExecutableType/Microsoft/PE/Sections/DebugSection.cs +++ b/BurnOutSharp/ExecutableType/Microsoft/PE/Sections/DebugSection.cs @@ -1,5 +1,4 @@ using System.IO; -using BurnOutSharp.ExecutableType.Microsoft.PE.Headers; using BurnOutSharp.ExecutableType.Microsoft.PE.Tables; namespace BurnOutSharp.ExecutableType.Microsoft.PE.Sections diff --git a/BurnOutSharp/ExecutableType/Microsoft/PE/Sections/RelocationSection.cs b/BurnOutSharp/ExecutableType/Microsoft/PE/Sections/RelocationSection.cs new file mode 100644 index 00000000..bd7e82b6 --- /dev/null +++ b/BurnOutSharp/ExecutableType/Microsoft/PE/Sections/RelocationSection.cs @@ -0,0 +1,51 @@ +using System.IO; +using BurnOutSharp.ExecutableType.Microsoft.PE.Entries; + +namespace BurnOutSharp.ExecutableType.Microsoft.PE.Sections +{ + /// + /// The base relocation table contains entries for all base relocations in the image. + /// The Base Relocation Table field in the optional header data directories gives the number of bytes in the base relocation table. + /// The base relocation table is divided into blocks. + /// Each block represents the base relocations for a 4K page. + /// Each block must start on a 32-bit boundary. + /// + /// https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#the-reloc-section-image-only + public class RelocationSection + { + /// + /// The base relocation table is divided into blocks. + /// + public BaseRelocationBlock[] BaseRelocationTable; + + public static RelocationSection Deserialize(Stream stream, int blockCount) + { + long originalPosition = stream.Position; + + var rs = new RelocationSection(); + rs.BaseRelocationTable = new BaseRelocationBlock[blockCount]; + for (int i = 0; i < blockCount; i++) + { + rs.BaseRelocationTable[i] = BaseRelocationBlock.Deserialize(stream); + } + + stream.Seek(originalPosition, SeekOrigin.Begin); + return rs; + } + + public static RelocationSection Deserialize(byte[] content, ref int offset, int blockCount) + { + int originalPosition = offset; + + var rs = new RelocationSection(); + rs.BaseRelocationTable = new BaseRelocationBlock[blockCount]; + for (int i = 0; i < blockCount; i++) + { + rs.BaseRelocationTable[i] = BaseRelocationBlock.Deserialize(content, ref offset); + } + + offset = originalPosition; + return rs; + } + } +} \ No newline at end of file