Finalize resource reading

This commit is contained in:
Matt Nadareski
2021-09-09 16:05:17 -07:00
parent dc9a581e1c
commit af79b00bd6
5 changed files with 94 additions and 53 deletions

View File

@@ -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
/// </summary>
public uint OffsetToData;
/// <summary>
/// A unit of resource data in the Resource Data area.
/// </summary>
public byte[] Data;
/// <summary>
/// A unit of resource data in the Resource Data area.
/// </summary>
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);
}
}
}
/// <summary>
/// The size, in bytes, of the resource data that is pointed to by the Data RVA field.
/// </summary>
@@ -32,7 +64,7 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Entries
/// </summary>
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<byte>(content, realOffsetToData, (int)rde.Size).ToArray();
return rde;
}
}

View File

@@ -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
/// </summary>
public ResourceDataEntry DataEntry;
private bool NameFieldIsIntegerId = false;
/// <summary>
/// Another resource directory table (the next level down).
/// </summary>
public ResourceDirectoryTable Subdirectory;
/// <summary>
/// Determine if an entry has a name or integer identifier
@@ -60,47 +65,44 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Entries
/// </summary>
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

View File

@@ -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);
}
}
}

View File

@@ -22,24 +22,24 @@ namespace BurnOutSharp.ExecutableType.Microsoft.Sections
/// </summary>
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;

View File

@@ -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;