From 1027956892b09cbeeccca80907000881efc6a585 Mon Sep 17 00:00:00 2001 From: Matt Nadareski Date: Fri, 30 Dec 2022 09:09:42 -0800 Subject: [PATCH] Lock section names, scan for hidden resources --- BurnOutSharp.Builders/PortableExecutable.cs | 34 +++++++++++++++++++-- BurnOutSharp.Wrappers/PortableExecutable.cs | 33 +++++++++++--------- 2 files changed, 50 insertions(+), 17 deletions(-) diff --git a/BurnOutSharp.Builders/PortableExecutable.cs b/BurnOutSharp.Builders/PortableExecutable.cs index 2908b4fc..d34a116b 100644 --- a/BurnOutSharp.Builders/PortableExecutable.cs +++ b/BurnOutSharp.Builders/PortableExecutable.cs @@ -300,7 +300,7 @@ namespace BurnOutSharp.Builders // Try to parse the resource directory table data.Seek(resourceTableAddress, SeekOrigin.Begin); - var resourceDirectoryTable = ParseResourceDirectoryTable(data, data.Position, executable.SectionTable); + var resourceDirectoryTable = ParseResourceDirectoryTable(data, data.Position, executable.SectionTable, optionalHeader.ResourceTable.Size, true); if (resourceDirectoryTable == null) return null; @@ -1195,8 +1195,10 @@ namespace BurnOutSharp.Builders /// Stream to parse /// Initial offset to use in address comparisons /// Section table to use for virtual address translation + /// Indicates the size of the section, only used for top-level + /// Indicates if this is the top level or not /// Filled resource directory table on success, null on error - private static ResourceDirectoryTable ParseResourceDirectoryTable(Stream data, long initialOffset, SectionHeader[] sections) + private static ResourceDirectoryTable ParseResourceDirectoryTable(Stream data, long initialOffset, SectionHeader[] sections, uint size = 0, bool topLevel = false) { // TODO: Use marshalling here instead of building var resourceDirectoryTable = new ResourceDirectoryTable(); @@ -1287,6 +1289,34 @@ namespace BurnOutSharp.Builders } } + // If we are not at the top level + if (!topLevel) + return resourceDirectoryTable; + + // Align to the 1024-byte boundary + while (data.Position - initialOffset < size && data.Position % 1024 != 0) + _ = data.ReadByteValue(); + + // If we have not used up the full size, parse the remaining chunk as a single resource + if (data.Position - initialOffset < size) + { + Array.Resize(ref resourceDirectoryTable.Entries, totalEntryCount + 1); + int length = (int)(data.Position - initialOffset); + + resourceDirectoryTable.Entries[totalEntryCount] = new ResourceDirectoryEntry + { + Name = new ResourceDirectoryString { UnicodeString = Encoding.ASCII.GetBytes("HIDDEN RESOURCE") }, + IntegerID = uint.MaxValue, + DataEntryOffset = (uint)data.Position, + DataEntry = new ResourceDataEntry + { + Size = (uint)length, + Data = data.ReadBytes(length), + Codepage = (uint)Encoding.Unicode.CodePage, + }, + }; + } + return resourceDirectoryTable; } diff --git a/BurnOutSharp.Wrappers/PortableExecutable.cs b/BurnOutSharp.Wrappers/PortableExecutable.cs index 15d2fbff..b02af082 100644 --- a/BurnOutSharp.Wrappers/PortableExecutable.cs +++ b/BurnOutSharp.Wrappers/PortableExecutable.cs @@ -563,23 +563,26 @@ namespace BurnOutSharp.Wrappers { get { - // Use the cached data if possible - if (_sectionNames != null) - return _sectionNames; - - // Otherwise, build and return the cached array - _sectionNames = new string[_executable.SectionTable.Length]; - for (int i = 0; i < _sectionNames.Length; i++) + lock (_sourceDataLock) { - var section = _executable.SectionTable[i]; + // Use the cached data if possible + if (_sectionNames != null) + return _sectionNames; - // TODO: Handle long section names with leading `/` - byte[] sectionNameBytes = section.Name; - string sectionNameString = Encoding.UTF8.GetString(sectionNameBytes).TrimEnd('\0'); - _sectionNames[i] = sectionNameString; + // Otherwise, build and return the cached array + _sectionNames = new string[_executable.SectionTable.Length]; + for (int i = 0; i < _sectionNames.Length; i++) + { + var section = _executable.SectionTable[i]; + + // TODO: Handle long section names with leading `/` + byte[] sectionNameBytes = section.Name; + string sectionNameString = Encoding.UTF8.GetString(sectionNameBytes).TrimEnd('\0'); + _sectionNames[i] = sectionNameString; + } + + return _sectionNames; } - - return _sectionNames; } } @@ -3117,7 +3120,7 @@ namespace BurnOutSharp.Wrappers /// private void ParseResourceDirectoryTable(Models.PortableExecutable.ResourceDirectoryTable table, List types) { - int totalEntries = table.NumberOfNameEntries + table.NumberOfIDEntries; + int totalEntries = table?.Entries?.Length ?? 0; for (int i = 0; i < totalEntries; i++) { var entry = table.Entries[i];