From 4ad7c604434d947553c4920f0b2d8ddf689d40e7 Mon Sep 17 00:00:00 2001 From: Matt Nadareski Date: Sat, 10 Dec 2022 20:10:25 -0800 Subject: [PATCH] Add overlay string finding --- BurnOutSharp.Wrappers/PortableExecutable.cs | 81 ++++++++++++++++++++- BurnOutSharp.Wrappers/WrapperBase.cs | 4 + BurnOutSharp/ProtectionType/ActiveMARK.cs | 13 +--- BurnOutSharp/ProtectionType/AlphaROM.cs | 15 +--- BurnOutSharp/ProtectionType/SecuROM.cs | 25 +++---- 5 files changed, 98 insertions(+), 40 deletions(-) diff --git a/BurnOutSharp.Wrappers/PortableExecutable.cs b/BurnOutSharp.Wrappers/PortableExecutable.cs index 1757ce01..c0a36fcf 100644 --- a/BurnOutSharp.Wrappers/PortableExecutable.cs +++ b/BurnOutSharp.Wrappers/PortableExecutable.cs @@ -383,7 +383,7 @@ namespace BurnOutSharp.Wrappers /// Overlay data, if it exists /// /// - public byte[] Overlay + public byte[] OverlayData { get { @@ -451,6 +451,77 @@ namespace BurnOutSharp.Wrappers } } + /// + /// Overlay strings, if they exist + /// + public List OverlayStrings + { + get + { + lock (_sourceDataLock) + { + // Use the cached data if possible + if (_overlayStrings != null) + return _overlayStrings; + + // Get the end of the file, if possible + int endOfFile = GetEndOfFile(); + if (endOfFile == -1) + return null; + + // If we have certificate data, use that as the end + if (OH_CertificateTable != null) + { + var certificateTable = _executable.OptionalHeader.CertificateTable; + int certificateTableAddress = (int)certificateTable.VirtualAddress.ConvertVirtualAddress(_executable.SectionTable); + if (certificateTableAddress != 0 && certificateTableAddress < endOfFile) + endOfFile = certificateTableAddress; + } + + // Search through all sections and find the furthest a section goes + int endOfSectionData = -1; + foreach (var section in _executable.SectionTable) + { + // If we have an invalid section address + int sectionAddress = (int)section.VirtualAddress.ConvertVirtualAddress(_executable.SectionTable); + if (sectionAddress == 0) + continue; + + // If we have an invalid section size + if (section.SizeOfRawData == 0 && section.VirtualSize == 0) + continue; + + // Get the real section size + int sectionSize; + if (section.SizeOfRawData < section.VirtualSize) + sectionSize = (int)section.VirtualSize; + else + sectionSize = (int)section.SizeOfRawData; + + // Compare and set the end of section data + if (sectionAddress + sectionSize > endOfSectionData) + endOfSectionData = sectionAddress + sectionSize; + } + + // If we didn't find the end of section data + if (endOfSectionData <= 0) + return null; + + // If we're at the end of the file, cache an empty list + if (endOfSectionData >= endOfFile) + { + _overlayStrings = new List(); + return _overlayStrings; + } + + // Otherwise, cache and return the strings + int overlayLength = endOfFile - endOfSectionData; + _overlayStrings = ReadStringsFromDataSource(endOfSectionData, overlayLength, charLimit: 3); + return _overlayStrings; + } + } + } + /// /// Sanitized section names /// @@ -691,16 +762,20 @@ namespace BurnOutSharp.Wrappers private byte[] _headerPaddingData = null; /// - /// Header padding data, if it exists + /// Header padding strings, if they exist /// private List _headerPaddingStrings = null; /// /// Overlay data, if it exists /// - /// TODO: Add overlay string data private byte[] _overlayData = null; + /// + /// Overlay strings, if they exist + /// + private List _overlayStrings = null; + /// /// Stub executable data, if it exists /// diff --git a/BurnOutSharp.Wrappers/WrapperBase.cs b/BurnOutSharp.Wrappers/WrapperBase.cs index 4f7bd4fc..d49af4a5 100644 --- a/BurnOutSharp.Wrappers/WrapperBase.cs +++ b/BurnOutSharp.Wrappers/WrapperBase.cs @@ -189,6 +189,10 @@ namespace BurnOutSharp.Wrappers // Check for Unicode strings while (sourceDataIndex < sourceData.Length) { + // Unicode characters are always 2 bytes + if (sourceDataIndex == sourceData.Length - 1) + break; + ushort ch = BitConverter.ToUInt16(sourceData, sourceDataIndex); // If we have a null terminator or "invalid" character diff --git a/BurnOutSharp/ProtectionType/ActiveMARK.cs b/BurnOutSharp/ProtectionType/ActiveMARK.cs index b9122ac9..71f82e3d 100644 --- a/BurnOutSharp/ProtectionType/ActiveMARK.cs +++ b/BurnOutSharp/ProtectionType/ActiveMARK.cs @@ -55,17 +55,10 @@ namespace BurnOutSharp.ProtectionType // TODO: Add entry point checks from https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt // Get the overlay data, if it exists - if (pex.Overlay != null) + if (pex.OverlayStrings != null) { - var matchers = new List - { - // (char)0x00 + TMSAMVOH - new ContentMatchSet(new byte?[] { 0x00, 0x54, 0x4D, 0x53, 0x41, 0x4D, 0x56, 0x4F, 0x48, }, "ActiveMARK"), - }; - - string match = MatchUtil.GetFirstMatch(file, pex.Overlay, matchers, includeDebug); - if (!string.IsNullOrWhiteSpace(match)) - return match; + if (pex.OverlayStrings.Any(s => s.Contains("TMSAMVOH"))) + return "ActiveMARK"; } // Get the last .bss section strings, if they exist diff --git a/BurnOutSharp/ProtectionType/AlphaROM.cs b/BurnOutSharp/ProtectionType/AlphaROM.cs index 185033fd..553a8717 100644 --- a/BurnOutSharp/ProtectionType/AlphaROM.cs +++ b/BurnOutSharp/ProtectionType/AlphaROM.cs @@ -75,18 +75,11 @@ namespace BurnOutSharp.ProtectionType } // Get the overlay data, if it exists - if (pex.Overlay != null) + if (pex.OverlayStrings != null) { - var matchers = new List - { - // Found in Redump entry 84122. - // SETTEC0000 - new ContentMatchSet(new byte?[] { 0x53, 0x45, 0x54, 0x54, 0x45, 0x43, 0x30, 0x30, 0x30, 0x30 }, "Alpha-ROM"), - }; - - string match = MatchUtil.GetFirstMatch(file, pex.Overlay, matchers, includeDebug); - if (!string.IsNullOrWhiteSpace(match)) - return match; + // Found in Redump entry 84122. + if (pex.OverlayStrings.Any(s => s.Contains("SETTEC0000"))) + return "Alpha-ROM"; } return null; diff --git a/BurnOutSharp/ProtectionType/SecuROM.cs b/BurnOutSharp/ProtectionType/SecuROM.cs index f51cb7bc..3f9a0709 100644 --- a/BurnOutSharp/ProtectionType/SecuROM.cs +++ b/BurnOutSharp/ProtectionType/SecuROM.cs @@ -53,17 +53,10 @@ namespace BurnOutSharp.ProtectionType return $"SecuROM SLL Protected (for SecuROM v8.x)"; // Search after the last section - if (pex.Overlay != null) + if (pex.OverlayStrings != null) { - var matchers = new List - { - // AddD + (char)0x03 + (char)0x00 + (char)0x00 + (char)0x00) - new ContentMatchSet(new byte?[] { 0x41, 0x64, 0x64, 0x44, 0x03, 0x00, 0x00, 0x00 }, GetV4Version, "SecuROM"), - }; - - string match = MatchUtil.GetFirstMatch(file, pex.Overlay, matchers, includeDebug); - if (!string.IsNullOrWhiteSpace(match)) - return match; + if (pex.OverlayStrings.Any(s => s == "AddD")) + return $"SecuROM {GetV4Version(pex)}"; } // Get the sections 5+, if they exist (example names: .fmqyrx, .vcltz, .iywiak) @@ -161,19 +154,19 @@ namespace BurnOutSharp.ProtectionType return MatchUtil.GetFirstMatch(path, matchers, any: true); } - public static string GetV4Version(string file, byte[] fileContent, List positions) + private static string GetV4Version(PortableExecutable pex) { - int index = positions[0] + 8; // Begin reading after "AddD" - char version = (char)fileContent[index]; + int index = 8; // Begin reading after "AddD" + char version = (char)pex.OverlayData[index]; index += 2; - string subVersion = Encoding.ASCII.GetString(fileContent, index, 2); + string subVersion = Encoding.ASCII.GetString(pex.OverlayData, index, 2); index += 3; - string subSubVersion = Encoding.ASCII.GetString(fileContent, index, 2); + string subSubVersion = Encoding.ASCII.GetString(pex.OverlayData, index, 2); index += 3; - string subSubSubVersion = Encoding.ASCII.GetString(fileContent, index, 4); + string subSubSubVersion = Encoding.ASCII.GetString(pex.OverlayData, index, 4); if (!char.IsNumber(version)) return "(very old, v3 or less)";