mirror of
https://github.com/SabreTools/BinaryObjectScanner.git
synced 2026-07-17 22:35:09 +00:00
Finalize resource reading
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user