From b4ab969f888c8a6647f519a3575f4e145f543a44 Mon Sep 17 00:00:00 2001 From: Matt Nadareski Date: Fri, 27 Aug 2021 10:38:42 -0700 Subject: [PATCH] Reorganize and create Resource-related things --- .../Microsoft/Entries/ResourceDataEntry.cs | 59 +++++++++++++++++ .../Entries/ResourceDirectoryTableEntry.cs | 64 +++++++++++++++---- .../Microsoft/IMAGE_RESOURCE_DATA_ENTRY.cs | 39 ----------- .../IMAGE_RESOURCE_DIRECTORY_ENTRY.cs | 35 ---------- .../Microsoft/PortableExecutable.cs | 38 ++++++++--- .../Microsoft/Sections/ResourceSection.cs | 9 +-- .../Tables/ResourceDirectoryTable.cs | 13 ++-- 7 files changed, 151 insertions(+), 106 deletions(-) create mode 100644 BurnOutSharp/ExecutableType/Microsoft/Entries/ResourceDataEntry.cs delete mode 100644 BurnOutSharp/ExecutableType/Microsoft/IMAGE_RESOURCE_DATA_ENTRY.cs delete mode 100644 BurnOutSharp/ExecutableType/Microsoft/IMAGE_RESOURCE_DIRECTORY_ENTRY.cs diff --git a/BurnOutSharp/ExecutableType/Microsoft/Entries/ResourceDataEntry.cs b/BurnOutSharp/ExecutableType/Microsoft/Entries/ResourceDataEntry.cs new file mode 100644 index 00000000..6f48d750 --- /dev/null +++ b/BurnOutSharp/ExecutableType/Microsoft/Entries/ResourceDataEntry.cs @@ -0,0 +1,59 @@ +using System; +using System.IO; +using System.Runtime.InteropServices; +using BurnOutSharp.Tools; + +namespace BurnOutSharp.ExecutableType.Microsoft.Entries +{ + /// + /// Each Resource Data entry describes an actual unit of raw data in the Resource Data area. + /// + [StructLayout(LayoutKind.Sequential)] + internal class ResourceDataEntry + { + /// + /// The address of a unit of resource data in the Resource Data area. + /// + public uint OffsetToData; + + /// + /// The size, in bytes, of the resource data that is pointed to by the Data RVA field. + /// + public uint Size; + + /// + /// The code page that is used to decode code point values within the resource data. + /// Typically, the code page would be the Unicode code page. + /// + public uint CodePage; + + /// + /// Reserved, must be 0. + /// + public uint Reserved; + + public static ResourceDataEntry Deserialize(Stream stream) + { + var rde = new ResourceDataEntry(); + + rde.OffsetToData = stream.ReadUInt32(); + rde.Size = stream.ReadUInt32(); + rde.CodePage = stream.ReadUInt32(); + rde.Reserved = stream.ReadUInt32(); + + return rde; + } + + public static ResourceDataEntry Deserialize(byte[] content, int offset) + { + var rde = new ResourceDataEntry(); + + rde.OffsetToData = BitConverter.ToUInt32(content, offset); offset += 4; + rde.Size = BitConverter.ToUInt32(content, offset); offset += 4; + rde.CodePage = BitConverter.ToUInt32(content, offset); offset += 4; + rde.Reserved = BitConverter.ToUInt32(content, offset); offset += 4; + + return rde; + } + } +} \ No newline at end of file diff --git a/BurnOutSharp/ExecutableType/Microsoft/Entries/ResourceDirectoryTableEntry.cs b/BurnOutSharp/ExecutableType/Microsoft/Entries/ResourceDirectoryTableEntry.cs index 92971263..d850f70f 100644 --- a/BurnOutSharp/ExecutableType/Microsoft/Entries/ResourceDirectoryTableEntry.cs +++ b/BurnOutSharp/ExecutableType/Microsoft/Entries/ResourceDirectoryTableEntry.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using BurnOutSharp.ExecutableType.Microsoft.Headers; using BurnOutSharp.Tools; namespace BurnOutSharp.ExecutableType.Microsoft.Entries @@ -18,8 +19,6 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Entries /// https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#resource-directory-entries internal class ResourceDirectoryTableEntry { - #region Name Entry - /// /// The offset of a string that gives the Type, Name, or Language ID entry, depending on level of table. /// @@ -40,31 +39,70 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Entries /// public uint SubdirectoryOffset => DataEntryOffset; - #endregion + /// + /// Resource Data entry (a leaf). + /// + public ResourceDataEntry DataEntry; /// /// Determine if an entry represents a leaf or another directory table /// public bool IsResourceDataEntry() => (DataEntryOffset & (1 << 31)) == 0; - public static ResourceDirectoryTableEntry Deserialize(Stream stream) + public static ResourceDirectoryTableEntry Deserialize(Stream stream, SectionHeader[] sections) { - var idte = new ResourceDirectoryTableEntry(); + var rdte = new ResourceDirectoryTableEntry(); - idte.NameOffset = stream.ReadUInt32(); - idte.DataEntryOffset = stream.ReadUInt32(); + rdte.NameOffset = stream.ReadUInt32(); + rdte.DataEntryOffset = stream.ReadUInt32(); - return idte; + // Read in the data if we have a leaf + if (rdte.IsResourceDataEntry()) + { + long lastPosition = stream.Position; + try + { + int dataEntryAddress = (int)EVORE.ConvertVirtualAddress(rdte.DataEntryOffset, sections); + if (dataEntryAddress > 0) + { + stream.Seek(dataEntryAddress, SeekOrigin.Begin); + rdte.DataEntry = ResourceDataEntry.Deserialize(stream); + } + } + catch { } + finally + { + stream.Seek(lastPosition, SeekOrigin.Begin); + } + } + + // TODO: Add parsing for further directory table entries in the tree + + return rdte; } - public static ResourceDirectoryTableEntry Deserialize(byte[] content, int offset) + public static ResourceDirectoryTableEntry Deserialize(byte[] content, int offset, SectionHeader[] sections) { - var idte = new ResourceDirectoryTableEntry(); + var rdte = new ResourceDirectoryTableEntry(); - idte.NameOffset = BitConverter.ToUInt32(content, offset); offset += 4; - idte.DataEntryOffset = BitConverter.ToUInt32(content, offset); offset += 4; + rdte.NameOffset = BitConverter.ToUInt32(content, offset); offset += 4; + rdte.DataEntryOffset = BitConverter.ToUInt32(content, offset); offset += 4; - return idte; + // Read in the data if we have a leaf + if (rdte.IsResourceDataEntry()) + { + try + { + int dataEntryAddress = (int)EVORE.ConvertVirtualAddress(rdte.DataEntryOffset, sections); + if (dataEntryAddress > 0) + rdte.DataEntry = ResourceDataEntry.Deserialize(content, dataEntryAddress); + } + catch { } + } + + // TODO: Add parsing for further directory table entries in the tree + + return rdte; } } } \ No newline at end of file diff --git a/BurnOutSharp/ExecutableType/Microsoft/IMAGE_RESOURCE_DATA_ENTRY.cs b/BurnOutSharp/ExecutableType/Microsoft/IMAGE_RESOURCE_DATA_ENTRY.cs deleted file mode 100644 index 5f17f779..00000000 --- a/BurnOutSharp/ExecutableType/Microsoft/IMAGE_RESOURCE_DATA_ENTRY.cs +++ /dev/null @@ -1,39 +0,0 @@ -/* - * NEWEXE.H (C) Copyright Microsoft Corp 1984-1987 - * - * Data structure definitions for the OS/2 & Windows - * executable file format. - * - * Modified by IVS on 24-Jan-1991 for Resource DeCompiler - * (C) Copyright IVS 1991 - * - * http://csn.ul.ie/~caolan/pub/winresdump/winresdump/newexe.h - */ - -using System.IO; -using System.Runtime.InteropServices; -using BurnOutSharp.Tools; - -namespace BurnOutSharp.ExecutableType.Microsoft -{ - [StructLayout(LayoutKind.Sequential)] - internal class IMAGE_RESOURCE_DATA_ENTRY - { - public uint OffsetToData; - public uint Size; - public uint CodePage; - public uint Reserved; - - public static IMAGE_RESOURCE_DATA_ENTRY Deserialize(Stream stream) - { - var irde = new IMAGE_RESOURCE_DATA_ENTRY(); - - irde.OffsetToData = stream.ReadUInt32(); - irde.Size = stream.ReadUInt32(); - irde.CodePage = stream.ReadUInt32(); - irde.Reserved = stream.ReadUInt32(); - - return irde; - } - } -} \ No newline at end of file diff --git a/BurnOutSharp/ExecutableType/Microsoft/IMAGE_RESOURCE_DIRECTORY_ENTRY.cs b/BurnOutSharp/ExecutableType/Microsoft/IMAGE_RESOURCE_DIRECTORY_ENTRY.cs deleted file mode 100644 index 37b20382..00000000 --- a/BurnOutSharp/ExecutableType/Microsoft/IMAGE_RESOURCE_DIRECTORY_ENTRY.cs +++ /dev/null @@ -1,35 +0,0 @@ -/* - * NEWEXE.H (C) Copyright Microsoft Corp 1984-1987 - * - * Data structure definitions for the OS/2 & Windows - * executable file format. - * - * Modified by IVS on 24-Jan-1991 for Resource DeCompiler - * (C) Copyright IVS 1991 - * - * http://csn.ul.ie/~caolan/pub/winresdump/winresdump/newexe.h - */ - -using System.IO; -using System.Runtime.InteropServices; -using BurnOutSharp.Tools; - -namespace BurnOutSharp.ExecutableType.Microsoft -{ - [StructLayout(LayoutKind.Sequential)] - internal class IMAGE_RESOURCE_DIRECTORY_ENTRY - { - public uint Name; - public uint OffsetToData; - - public static IMAGE_RESOURCE_DIRECTORY_ENTRY Deserialize(Stream stream) - { - var irde = new IMAGE_RESOURCE_DIRECTORY_ENTRY(); - - irde.Name = stream.ReadUInt32(); - irde.OffsetToData = stream.ReadUInt32(); - - return irde; - } - } -} \ No newline at end of file diff --git a/BurnOutSharp/ExecutableType/Microsoft/PortableExecutable.cs b/BurnOutSharp/ExecutableType/Microsoft/PortableExecutable.cs index b73b3aa1..b1beaf31 100644 --- a/BurnOutSharp/ExecutableType/Microsoft/PortableExecutable.cs +++ b/BurnOutSharp/ExecutableType/Microsoft/PortableExecutable.cs @@ -2,6 +2,7 @@ using System.IO; using System.Runtime.InteropServices; using BurnOutSharp.ExecutableType.Microsoft.Headers; using BurnOutSharp.ExecutableType.Microsoft.Sections; +using BurnOutSharp.Tools; namespace BurnOutSharp.ExecutableType.Microsoft { @@ -92,7 +93,7 @@ namespace BurnOutSharp.ExecutableType.Microsoft pex.SectionTable[i] = SectionHeader.Deserialize(stream); } - // TODO: Uncomment these when all directories are understod and implemented + // TODO: Uncomment these as the directories are understod and implemented // // Export Table // var table = pex.SectionTable[(byte)ImageDirectory.IMAGE_DIRECTORY_ENTRY_EXPORT]; // if (table.VirtualSize > 0) @@ -103,16 +104,26 @@ namespace BurnOutSharp.ExecutableType.Microsoft // } // // Import Table - // table = pex.SectionHeaders[(byte)ImageDirectory.IMAGE_DIRECTORY_ENTRY_IMPORT]; + // table = pex.SectionTable[(byte)ImageDirectory.IMAGE_DIRECTORY_ENTRY_IMPORT]; // if (table.VirtualSize > 0) // { - // int tableAddress = (int)EVORE.ConvertVirtualAddress(table.VirtualAddress, pex.SectionHeaders); + // int tableAddress = (int)EVORE.ConvertVirtualAddress(table.VirtualAddress, pex.SectionTable); // stream.Seek(tableAddress, SeekOrigin.Begin); // pex.ImportTable = ImportDataSection.Deserialize(stream, pex.OptionalHeader.Magic == OptionalHeaderType.PE32Plus, hintCount: 0); // TODO: Figure out where this count comes from // } + + // // Resource Table + // var table = pex.SectionTable[(byte)ImageDirectory.IMAGE_DIRECTORY_ENTRY_RESOURCE]; + // if (table.VirtualSize > 0) + // { + // int tableAddress = (int)EVORE.ConvertVirtualAddress(table.VirtualAddress, pex.SectionTable); + // stream.Seek(tableAddress, SeekOrigin.Begin); + // pex.ResourceSection = ResourceSection.Deserialize(stream, pex.SectionTable); + // } } - catch + catch (System.Exception ex) { + System.Console.WriteLine($"Errored out on a file: {ex}"); return null; } @@ -140,7 +151,7 @@ namespace BurnOutSharp.ExecutableType.Microsoft pex.SectionTable[i] = SectionHeader.Deserialize(content, offset); offset += 40; } - // TODO: Uncomment these when all directories are understod and implemented + // TODO: Uncomment these as the directories are understod and implemented // // Export Table // var table = pex.SectionTable[(byte)ImageDirectory.IMAGE_DIRECTORY_ENTRY_EXPORT]; // if (table.VirtualSize > 0) @@ -150,16 +161,25 @@ namespace BurnOutSharp.ExecutableType.Microsoft // } // // Import Table - // table = pex.SectionHeaders[(byte)ImageDirectory.IMAGE_DIRECTORY_ENTRY_IMPORT]; + // table = pex.SectionTable[(byte)ImageDirectory.IMAGE_DIRECTORY_ENTRY_IMPORT]; // if (table.VirtualSize > 0) // { - // int tableAddress = (int)EVORE.ConvertVirtualAddress(table.VirtualAddress, pex.SectionHeaders); - // pex.ImportTable = ImportDataSection.Deserialize(content, tableAddress, pex.OptionalHeader.Magic == OptionalHeaderType.PE32Plus, hintCount: 0); offset += Marshal.SizeOf(pex.ImportTable); // TODO: Figure out where this count comes from + // int tableAddress = (int)EVORE.ConvertVirtualAddress(table.VirtualAddress, pex.SectionTable); + // pex.ImportTable = ImportDataSection.Deserialize(content, tableAddress, pex.OptionalHeader.Magic == OptionalHeaderType.PE32Plus, hintCount: 0); + // } + + // // Resource Table + // var table = pex.SectionTable[(byte)ImageDirectory.IMAGE_DIRECTORY_ENTRY_RESOURCE]; + // if (table.VirtualSize > 0) + // { + // int tableAddress = (int)EVORE.ConvertVirtualAddress(table.VirtualAddress, pex.SectionTable); + // pex.ResourceSection = ResourceSection.Deserialize(content, tableAddress, pex.SectionTable); // } } } - catch + catch (System.Exception ex) { + System.Console.WriteLine($"Errored out on a file: {ex}"); return null; } diff --git a/BurnOutSharp/ExecutableType/Microsoft/Sections/ResourceSection.cs b/BurnOutSharp/ExecutableType/Microsoft/Sections/ResourceSection.cs index 95744587..134bada8 100644 --- a/BurnOutSharp/ExecutableType/Microsoft/Sections/ResourceSection.cs +++ b/BurnOutSharp/ExecutableType/Microsoft/Sections/ResourceSection.cs @@ -1,5 +1,6 @@ using System.IO; using System.Runtime.InteropServices; +using BurnOutSharp.ExecutableType.Microsoft.Headers; using BurnOutSharp.ExecutableType.Microsoft.Tables; namespace BurnOutSharp.ExecutableType.Microsoft.Sections @@ -21,22 +22,22 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Sections /// public ResourceDirectoryTable ResourceDirectoryTable; - public static ResourceSection Deserialize(Stream stream) + public static ResourceSection Deserialize(Stream stream, SectionHeader[] sections) { var rs = new ResourceSection(); - rs.ResourceDirectoryTable = ResourceDirectoryTable.Deserialize(stream); + rs.ResourceDirectoryTable = ResourceDirectoryTable.Deserialize(stream, sections); return rs; } - public static ResourceSection Deserialize(byte[] content, int offset) + public static ResourceSection Deserialize(byte[] content, int offset, SectionHeader[] sections) { var rs = new ResourceSection(); unsafe { - rs.ResourceDirectoryTable = ResourceDirectoryTable.Deserialize(content, offset); offset += Marshal.SizeOf(rs.ResourceDirectoryTable); + rs.ResourceDirectoryTable = ResourceDirectoryTable.Deserialize(content, offset, sections); offset += Marshal.SizeOf(rs.ResourceDirectoryTable); } return rs; diff --git a/BurnOutSharp/ExecutableType/Microsoft/Tables/ResourceDirectoryTable.cs b/BurnOutSharp/ExecutableType/Microsoft/Tables/ResourceDirectoryTable.cs index 2ff99503..411e261b 100644 --- a/BurnOutSharp/ExecutableType/Microsoft/Tables/ResourceDirectoryTable.cs +++ b/BurnOutSharp/ExecutableType/Microsoft/Tables/ResourceDirectoryTable.cs @@ -2,6 +2,7 @@ using System; using System.IO; using System.Runtime.InteropServices; using BurnOutSharp.ExecutableType.Microsoft.Entries; +using BurnOutSharp.ExecutableType.Microsoft.Headers; using BurnOutSharp.Tools; namespace BurnOutSharp.ExecutableType.Microsoft.Tables @@ -67,7 +68,7 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Tables // TODO: Determine how to store or reference the resource directory strings // that immediately follow the last directory entry but before the data - public static ResourceDirectoryTable Deserialize(Stream stream) + public static ResourceDirectoryTable Deserialize(Stream stream, SectionHeader[] sections) { var rdt = new ResourceDirectoryTable(); @@ -81,19 +82,19 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Tables rdt.NamedEntries = new ResourceDirectoryTableEntry[rdt.NumberOfNamedEntries]; for (int i = 0; i < rdt.NumberOfNamedEntries; i++) { - rdt.NamedEntries[i] = ResourceDirectoryTableEntry.Deserialize(stream); + rdt.NamedEntries[i] = ResourceDirectoryTableEntry.Deserialize(stream, sections); } rdt.IdEntries = new ResourceDirectoryTableEntry[rdt.NumberOfIdEntries]; for (int i = 0; i < rdt.NumberOfIdEntries; i++) { - rdt.IdEntries[i] = ResourceDirectoryTableEntry.Deserialize(stream); + rdt.IdEntries[i] = ResourceDirectoryTableEntry.Deserialize(stream, sections); } return rdt; } - public static ResourceDirectoryTable Deserialize(byte[] content, int offset) + public static ResourceDirectoryTable Deserialize(byte[] content, int offset, SectionHeader[] sections) { var rdt = new ResourceDirectoryTable(); @@ -107,13 +108,13 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Tables rdt.NamedEntries = new ResourceDirectoryTableEntry[rdt.NumberOfNamedEntries]; for (int i = 0; i < rdt.NumberOfNamedEntries; i++) { - rdt.NamedEntries[i] = ResourceDirectoryTableEntry.Deserialize(content, offset); offset += 8; + rdt.NamedEntries[i] = ResourceDirectoryTableEntry.Deserialize(content, offset, sections); offset += 8; } rdt.IdEntries = new ResourceDirectoryTableEntry[rdt.NumberOfIdEntries]; for (int i = 0; i < rdt.NumberOfIdEntries; i++) { - rdt.IdEntries[i] = ResourceDirectoryTableEntry.Deserialize(content, offset); offset += 8; + rdt.IdEntries[i] = ResourceDirectoryTableEntry.Deserialize(content, offset, sections); offset += 8; } return rdt;