diff --git a/BurnOutSharp/ExecutableType/Microsoft/Entries/ResourceDataEntry.cs b/BurnOutSharp/ExecutableType/Microsoft/Entries/ResourceDataEntry.cs index 6f48d750..67d395db 100644 --- a/BurnOutSharp/ExecutableType/Microsoft/Entries/ResourceDataEntry.cs +++ b/BurnOutSharp/ExecutableType/Microsoft/Entries/ResourceDataEntry.cs @@ -1,6 +1,9 @@ using System; using System.IO; +using System.Linq; using System.Runtime.InteropServices; +using System.Text; +using BurnOutSharp.ExecutableType.Microsoft.Headers; using BurnOutSharp.Tools; namespace BurnOutSharp.ExecutableType.Microsoft.Entries @@ -16,6 +19,35 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Entries /// public uint OffsetToData; + /// + /// A unit of resource data in the Resource Data area. + /// + public byte[] Data; + + /// + /// A unit of resource data in the Resource Data area. + /// + public string EncodedData + { + get + { + int codePage = (int)CodePage; + if (Data == null || codePage < 0) + return string.Empty; + + try + { + Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); + return Encoding.GetEncoding(codePage).GetString(Data); + } + catch (Exception ex) + { + return Encoding.ASCII.GetString(Data); + } + + } + } + /// /// The size, in bytes, of the resource data that is pointed to by the Data RVA field. /// @@ -32,7 +64,7 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Entries /// public uint Reserved; - public static ResourceDataEntry Deserialize(Stream stream) + public static ResourceDataEntry Deserialize(Stream stream, SectionHeader[] sections) { var rde = new ResourceDataEntry(); @@ -41,10 +73,19 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Entries rde.CodePage = stream.ReadUInt32(); rde.Reserved = stream.ReadUInt32(); + int realOffsetToData = (int)PortableExecutable.ConvertVirtualAddress(rde.OffsetToData, sections); + if (realOffsetToData > -1 && realOffsetToData < stream.Length) + { + long lastPosition = stream.Position; + stream.Seek(realOffsetToData, SeekOrigin.Begin); + rde.Data = stream.ReadBytes((int)rde.Size); + stream.Seek(lastPosition, SeekOrigin.Begin); + } + return rde; } - public static ResourceDataEntry Deserialize(byte[] content, int offset) + public static ResourceDataEntry Deserialize(byte[] content, int offset, SectionHeader[] sections) { var rde = new ResourceDataEntry(); @@ -53,6 +94,10 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Entries rde.CodePage = BitConverter.ToUInt32(content, offset); offset += 4; rde.Reserved = BitConverter.ToUInt32(content, offset); offset += 4; + int realOffsetToData = (int)PortableExecutable.ConvertVirtualAddress(rde.OffsetToData, sections); + if (realOffsetToData > -1 && realOffsetToData < content.Length) + rde.Data = new ArraySegment(content, realOffsetToData, (int)rde.Size).ToArray(); + return rde; } } diff --git a/BurnOutSharp/ExecutableType/Microsoft/Entries/ResourceDirectoryTableEntry.cs b/BurnOutSharp/ExecutableType/Microsoft/Entries/ResourceDirectoryTableEntry.cs index e7c80eef..af450330 100644 --- a/BurnOutSharp/ExecutableType/Microsoft/Entries/ResourceDirectoryTableEntry.cs +++ b/BurnOutSharp/ExecutableType/Microsoft/Entries/ResourceDirectoryTableEntry.cs @@ -1,5 +1,7 @@ using System; using System.IO; +using BurnOutSharp.ExecutableType.Microsoft.Headers; +using BurnOutSharp.ExecutableType.Microsoft.Tables; using BurnOutSharp.Tools; namespace BurnOutSharp.ExecutableType.Microsoft.Entries @@ -48,7 +50,10 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Entries /// public ResourceDataEntry DataEntry; - private bool NameFieldIsIntegerId = false; + /// + /// Another resource directory table (the next level down). + /// + public ResourceDirectoryTable Subdirectory; /// /// Determine if an entry has a name or integer identifier @@ -60,47 +65,44 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Entries /// public bool IsResourceDataEntry() => (DataEntryOffset & (1 << 31)) == 0; - public static ResourceDirectoryTableEntry Deserialize(Stream stream, long sectionStart) + public static ResourceDirectoryTableEntry Deserialize(Stream stream, long sectionStart, SectionHeader[] sections) { var rdte = new ResourceDirectoryTableEntry(); rdte.IntegerId = stream.ReadUInt32(); if (!rdte.IsIntegerIDEntry()) { - long lastPosition = stream.Position; int nameAddress = (int)(rdte.NameOffset + sectionStart); if (nameAddress >= 0 && nameAddress < stream.Length) { - try - { - stream.Seek(nameAddress, SeekOrigin.Begin); - rdte.Name = ResourceDirectoryString.Deserialize(stream); - } - catch { } - finally - { - stream.Seek(lastPosition, SeekOrigin.Begin); - } + long lastPosition = stream.Position; + stream.Seek(nameAddress, SeekOrigin.Begin); + rdte.Name = ResourceDirectoryString.Deserialize(stream); + stream.Seek(lastPosition, SeekOrigin.Begin); } } rdte.DataEntryOffset = stream.ReadUInt32(); if (rdte.IsResourceDataEntry()) { - long lastPosition = stream.Position; int dataEntryAddress = (int)(rdte.DataEntryOffset + sectionStart); if (dataEntryAddress > 0 && dataEntryAddress < stream.Length) { - try - { - stream.Seek(dataEntryAddress, SeekOrigin.Begin); - rdte.DataEntry = ResourceDataEntry.Deserialize(stream); - } - catch { } - finally - { - stream.Seek(lastPosition, SeekOrigin.Begin); - } + long lastPosition = stream.Position; + stream.Seek(dataEntryAddress, SeekOrigin.Begin); + rdte.DataEntry = ResourceDataEntry.Deserialize(stream, sections); + stream.Seek(lastPosition, SeekOrigin.Begin); + } + } + else + { + int subdirectoryAddress = (int)(rdte.SubdirectoryOffset + sectionStart); + if (subdirectoryAddress > 0 && subdirectoryAddress < stream.Length) + { + long lastPosition = stream.Position; + stream.Seek(subdirectoryAddress, SeekOrigin.Begin); + rdte.Subdirectory = ResourceDirectoryTable.Deserialize(stream, sectionStart, sections); + stream.Seek(lastPosition, SeekOrigin.Begin); } } @@ -109,7 +111,7 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Entries return rdte; } - public static ResourceDirectoryTableEntry Deserialize(byte[] content, int offset, long sectionStart) + public static ResourceDirectoryTableEntry Deserialize(byte[] content, int offset, long sectionStart, SectionHeader[] sections) { var rdte = new ResourceDirectoryTableEntry(); @@ -118,13 +120,7 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Entries { int nameAddress = (int)(rdte.NameOffset + sectionStart); if (nameAddress >= 0 && nameAddress < content.Length) - { - try - { - rdte.Name = ResourceDirectoryString.Deserialize(content, nameAddress); - } - catch { } - } + rdte.Name = ResourceDirectoryString.Deserialize(content, nameAddress); } rdte.DataEntryOffset = BitConverter.ToUInt32(content, offset); offset += 4; @@ -132,13 +128,13 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Entries { int dataEntryAddress = (int)(rdte.DataEntryOffset + sectionStart); if (dataEntryAddress > 0 && dataEntryAddress < content.Length) - { - try - { - rdte.DataEntry = ResourceDataEntry.Deserialize(content, dataEntryAddress); - } - catch { } - } + rdte.DataEntry = ResourceDataEntry.Deserialize(content, dataEntryAddress, sections); + } + else + { + int subdirectoryAddress = (int)(rdte.SubdirectoryOffset + sectionStart); + if (subdirectoryAddress > 0 && subdirectoryAddress < content.Length) + rdte.Subdirectory = ResourceDirectoryTable.Deserialize(content, subdirectoryAddress, sectionStart, sections); } // TODO: Add parsing for further directory table entries in the tree diff --git a/BurnOutSharp/ExecutableType/Microsoft/PortableExecutable.cs b/BurnOutSharp/ExecutableType/Microsoft/PortableExecutable.cs index 7a63a5a5..d6cee7da 100644 --- a/BurnOutSharp/ExecutableType/Microsoft/PortableExecutable.cs +++ b/BurnOutSharp/ExecutableType/Microsoft/PortableExecutable.cs @@ -216,7 +216,7 @@ namespace BurnOutSharp.ExecutableType.Microsoft { int tableAddress = (int)ConvertVirtualAddress(table.VirtualAddress, pex.SectionTable); stream.Seek(tableAddress, SeekOrigin.Begin); - pex.ResourceSection = ResourceSection.Deserialize(stream); + pex.ResourceSection = ResourceSection.Deserialize(stream, pex.SectionTable); } } catch (Exception ex) @@ -285,7 +285,7 @@ namespace BurnOutSharp.ExecutableType.Microsoft if (table != null && table.VirtualSize > 0) { int tableAddress = (int)ConvertVirtualAddress(table.VirtualAddress, pex.SectionTable); - pex.ResourceSection = ResourceSection.Deserialize(content, tableAddress); + pex.ResourceSection = ResourceSection.Deserialize(content, tableAddress, pex.SectionTable); } } } diff --git a/BurnOutSharp/ExecutableType/Microsoft/Sections/ResourceSection.cs b/BurnOutSharp/ExecutableType/Microsoft/Sections/ResourceSection.cs index cfea6738..eee13b54 100644 --- a/BurnOutSharp/ExecutableType/Microsoft/Sections/ResourceSection.cs +++ b/BurnOutSharp/ExecutableType/Microsoft/Sections/ResourceSection.cs @@ -22,24 +22,24 @@ 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(); long sectionStart = stream.Position; - rs.ResourceDirectoryTable = ResourceDirectoryTable.Deserialize(stream, sectionStart); + rs.ResourceDirectoryTable = ResourceDirectoryTable.Deserialize(stream, sectionStart, 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 { long sectionStart = offset; - rs.ResourceDirectoryTable = ResourceDirectoryTable.Deserialize(content, offset, sectionStart); offset += Marshal.SizeOf(rs.ResourceDirectoryTable); + rs.ResourceDirectoryTable = ResourceDirectoryTable.Deserialize(content, offset, sectionStart, 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 3110ff61..aa82fd0c 100644 --- a/BurnOutSharp/ExecutableType/Microsoft/Tables/ResourceDirectoryTable.cs +++ b/BurnOutSharp/ExecutableType/Microsoft/Tables/ResourceDirectoryTable.cs @@ -68,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, long sectionStart) + public static ResourceDirectoryTable Deserialize(Stream stream, long sectionStart, SectionHeader[] sections) { var rdt = new ResourceDirectoryTable(); @@ -82,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, sectionStart); + rdt.NamedEntries[i] = ResourceDirectoryTableEntry.Deserialize(stream, sectionStart, sections); } rdt.IdEntries = new ResourceDirectoryTableEntry[rdt.NumberOfIdEntries]; for (int i = 0; i < rdt.NumberOfIdEntries; i++) { - rdt.IdEntries[i] = ResourceDirectoryTableEntry.Deserialize(stream, sectionStart); + rdt.IdEntries[i] = ResourceDirectoryTableEntry.Deserialize(stream, sectionStart, sections); } return rdt; } - public static ResourceDirectoryTable Deserialize(byte[] content, int offset, long sectionStart) + public static ResourceDirectoryTable Deserialize(byte[] content, int offset, long sectionStart, SectionHeader[] sections) { var rdt = new ResourceDirectoryTable(); @@ -108,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, sectionStart); offset += 8; + rdt.NamedEntries[i] = ResourceDirectoryTableEntry.Deserialize(content, offset, sectionStart, sections); offset += 8; } rdt.IdEntries = new ResourceDirectoryTableEntry[rdt.NumberOfIdEntries]; for (int i = 0; i < rdt.NumberOfIdEntries; i++) { - rdt.IdEntries[i] = ResourceDirectoryTableEntry.Deserialize(content, offset, sectionStart); offset += 8; + rdt.IdEntries[i] = ResourceDirectoryTableEntry.Deserialize(content, offset, sectionStart, sections); offset += 8; } return rdt;