From 0c7001acf698cc31c93e9cbbcf87278b3569be93 Mon Sep 17 00:00:00 2001 From: Matt Nadareski Date: Mon, 7 Nov 2022 10:42:48 -0800 Subject: [PATCH] Add NE module-reference table parsing This also fixes a critical flaw in the resident-name table parsing since there is no defined size, just the point where the next table begins. --- BurnOutSharp.Builder/NewExecutable.cs | 113 ++++++++++++++++++++++---- 1 file changed, 98 insertions(+), 15 deletions(-) diff --git a/BurnOutSharp.Builder/NewExecutable.cs b/BurnOutSharp.Builder/NewExecutable.cs index 55cc6f2d..c78f2979 100644 --- a/BurnOutSharp.Builder/NewExecutable.cs +++ b/BurnOutSharp.Builder/NewExecutable.cs @@ -1,4 +1,5 @@ -using System.IO; +using System.Collections.Generic; +using System.IO; using System.Linq; using BurnOutSharp.Models.NewExecutable; @@ -103,7 +104,7 @@ namespace BurnOutSharp.Builder return executable; // Try to parse the resident-name table - var residentNameTable = ParseResidentNameTable(data, tableAddress, executableHeader.FileSegmentCount); + var residentNameTable = ParseResidentNameTable(data, tableAddress, executableHeader.ModuleReferenceTableOffset); if (residentNameTable == null) return null; @@ -112,6 +113,25 @@ namespace BurnOutSharp.Builder #endregion + #region Module-Reference Table + + // If the offset for the module-reference table doesn't exist + tableAddress = initialOffset + + (int)stub.Header.NewExeHeaderAddr + + executableHeader.ModuleReferenceTableOffset; + if (tableAddress >= data.Length) + return executable; + + // Try to parse the module-reference table + var moduleReferenceTable = ParseModuleReferenceTable(data, tableAddress, executableHeader.ModuleReferenceTableSize); + if (moduleReferenceTable == null) + return null; + + // Set the module-reference table + executable.ModuleReferenceTable = moduleReferenceTable; + + #endregion + // TODO: Complete NE parsing return executable; } @@ -261,23 +281,45 @@ namespace BurnOutSharp.Builder /// /// Byte array to parse /// Offset into the byte array - /// Number of resident-name table entries to read + /// First address not part of the resident-name table /// Filled resident-name table on success, null on error - private static ResidentNameTableEntry[] ParseResidentNameTable(byte[] data, int offset, int count) + private static ResidentNameTableEntry[] ParseResidentNameTable(byte[] data, int offset, ushort endOffset) { // TODO: Use marshalling here instead of building - var residentNameTable = new ResidentNameTableEntry[count]; + var residentNameTable = new List(); - for (int i = 0; i < count; i++) + while (offset < endOffset) { var entry = new ResidentNameTableEntry(); entry.Length = data.ReadByte(ref offset); entry.NameString = data.ReadBytes(ref offset, entry.Length); entry.OrdinalNumber = data.ReadUInt16(ref offset); - residentNameTable[i] = entry; + residentNameTable.Add(entry); } - return residentNameTable; + return residentNameTable.ToArray(); + } + + /// + /// Parse a byte array into a module-reference table + /// + /// Byte array to parse + /// Offset into the byte array + /// Number of module-reference table entries to read + /// Filled module-reference table on success, null on error + private static ModuleReferenceTableEntry[] ParseModuleReferenceTable(byte[] data, int offset, int count) + { + // TODO: Use marshalling here instead of building + var moduleReferenceTable = new ModuleReferenceTableEntry[count]; + + for (int i = 0; i < count; i++) + { + var entry = new ModuleReferenceTableEntry(); + entry.Offset = data.ReadUInt16(ref offset); + moduleReferenceTable[i] = entry; + } + + return moduleReferenceTable; } #endregion @@ -380,7 +422,7 @@ namespace BurnOutSharp.Builder // Try to parse the resident-name table data.Seek(tableAddress, SeekOrigin.Begin); - var residentNameTable = ParseResidentNameTable(data, executableHeader.FileSegmentCount); + var residentNameTable = ParseResidentNameTable(data, executableHeader.ModuleReferenceTableOffset); if (residentNameTable == null) return null; @@ -389,6 +431,26 @@ namespace BurnOutSharp.Builder #endregion + #region Module-Reference Table + + // If the offset for the module-reference table doesn't exist + tableAddress = initialOffset + + (int)stub.Header.NewExeHeaderAddr + + executableHeader.ModuleReferenceTableOffset; + if (tableAddress >= data.Length) + return executable; + + // Try to parse the module-reference table + data.Seek(tableAddress, SeekOrigin.Begin); + var moduleReferenceTable = ParseModuleReferenceTable(data, executableHeader.ModuleReferenceTableSize); + if (moduleReferenceTable == null) + return null; + + // Set the module-reference table + executable.ModuleReferenceTable = moduleReferenceTable; + + #endregion + // TODO: Complete NE parsing return executable; } @@ -535,23 +597,44 @@ namespace BurnOutSharp.Builder /// Parse a byte array into a resident-name table /// /// Stream to parse - /// Number of resident-name table entries to read + /// First address not part of the resident-name table /// Filled resident-name table on success, null on error - private static ResidentNameTableEntry[] ParseResidentNameTable(Stream data, int count) + private static ResidentNameTableEntry[] ParseResidentNameTable(Stream data, ushort endOffset) { // TODO: Use marshalling here instead of building - var residentNameTable = new ResidentNameTableEntry[count]; + var residentNameTable = new List(); - for (int i = 0; i < count; i++) + while (data.Position < endOffset) { var entry = new ResidentNameTableEntry(); entry.Length = data.ReadByteValue(); entry.NameString = data.ReadBytes(entry.Length); entry.OrdinalNumber = data.ReadUInt16(); - residentNameTable[i] = entry; + residentNameTable.Add(entry); } - return residentNameTable; + return residentNameTable.ToArray(); + } + + /// + /// Parse a byte array into a module-reference table + /// + /// Stream to parse + /// Number of module-reference table entries to read + /// Filled module-reference table on success, null on error + private static ModuleReferenceTableEntry[] ParseModuleReferenceTable(Stream data, int count) + { + // TODO: Use marshalling here instead of building + var moduleReferenceTable = new ModuleReferenceTableEntry[count]; + + for (int i = 0; i < count; i++) + { + var entry = new ModuleReferenceTableEntry(); + entry.Offset = data.ReadUInt16(); + moduleReferenceTable[i] = entry; + } + + return moduleReferenceTable; } #endregion