From d1a6c9be00d6b65d8b459ef8145dd03e47fe986b Mon Sep 17 00:00:00 2001 From: Matt Nadareski Date: Sat, 10 Dec 2022 17:31:41 -0800 Subject: [PATCH] Add header padding strings --- BurnOutSharp.Wrappers/PortableExecutable.cs | 32 +++++++++++++ BurnOutSharp/PackerType/UPX.cs | 50 +++++++++++++++------ BurnOutSharp/ProtectionType/Macrovision.cs | 33 +++----------- 3 files changed, 74 insertions(+), 41 deletions(-) diff --git a/BurnOutSharp.Wrappers/PortableExecutable.cs b/BurnOutSharp.Wrappers/PortableExecutable.cs index 748345c2..1757ce01 100644 --- a/BurnOutSharp.Wrappers/PortableExecutable.cs +++ b/BurnOutSharp.Wrappers/PortableExecutable.cs @@ -352,6 +352,33 @@ namespace BurnOutSharp.Wrappers } } + /// + /// Header padding strings, if they exist + /// + public List HeaderPaddingStrings + { + get + { + lock (_sourceDataLock) + { + // If we already have cached data, just use that immediately + if (_headerPaddingStrings != null) + return _headerPaddingStrings; + + // TODO: Don't scan the known header data as well + + // Populate the raw header padding data based on the source + uint headerStartAddress = Stub_NewExeHeaderAddr; + uint firstSectionAddress = SectionTable.Select(s => s.PointerToRawData).Where(s => s != 0).OrderBy(s => s).First(); + int headerLength = (int)(firstSectionAddress - headerStartAddress); + _headerPaddingStrings = ReadStringsFromDataSource((int)headerStartAddress, headerLength, charLimit: 3); + + // Cache and return the header padding data, even if null + return _headerPaddingStrings; + } + } + } + /// /// Overlay data, if it exists /// @@ -663,6 +690,11 @@ namespace BurnOutSharp.Wrappers /// private byte[] _headerPaddingData = null; + /// + /// Header padding data, if it exists + /// + private List _headerPaddingStrings = null; + /// /// Overlay data, if it exists /// diff --git a/BurnOutSharp/PackerType/UPX.cs b/BurnOutSharp/PackerType/UPX.cs index 2f6c53e1..670bd581 100644 --- a/BurnOutSharp/PackerType/UPX.cs +++ b/BurnOutSharp/PackerType/UPX.cs @@ -1,7 +1,9 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Text; +using System.Text.RegularExpressions; using BurnOutSharp.Interfaces; using BurnOutSharp.Matching; using BurnOutSharp.Wrappers; @@ -12,6 +14,10 @@ namespace BurnOutSharp.PackerType // https://raw.githubusercontent.com/wolfram77web/app-peid/master/userdb.txt public class UPX : IPortableExecutableCheck, IScannable { + private static readonly Regex _oldUpxVersionMatch = new Regex(@"\$Id: UPX (.*?) Copyright \(C\)", RegexOptions.Compiled); + + private static readonly Regex _upxVersionMatch = new Regex(@"^([0-9]\.[0-9]{2})$", RegexOptions.Compiled); + /// public string CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug) { @@ -20,22 +26,40 @@ namespace BurnOutSharp.PackerType if (sections == null) return null; - // Check header padding data - var headerPaddingData = pex.HeaderPaddingData; - if (headerPaddingData != null) + // Check header padding strings + if (pex.HeaderPaddingStrings.Any()) { - var matchers = new List + string match = pex.HeaderPaddingStrings.FirstOrDefault(s => s.Contains("UPX!")); + //if (match != null) + // return "UPX"; + + match = pex.HeaderPaddingStrings.FirstOrDefault(s => s.StartsWith("$Id: UPX")); + if (match != null) { - // UPX! - new ContentMatchSet(new byte?[] { 0x55, 0x50, 0x58, 0x21 }, GetVersion, "UPX"), + var regexMatch = _oldUpxVersionMatch.Match(match); + if (regexMatch.Success) + return $"UPX {regexMatch.Groups[1].Value}"; + else + return "UPX (Unknown Version)"; + } - // NOS - new ContentMatchSet(new byte?[] { 0x4E, 0x4F, 0x53, 0x20 }, GetVersion, "UPX (NOS Variant)"), - }; - - string match = MatchUtil.GetFirstMatch(file, headerPaddingData, matchers, includeDebug); - if (!string.IsNullOrEmpty(match)) - return match; + match = pex.HeaderPaddingStrings.FirstOrDefault(s => _upxVersionMatch.IsMatch(s)); + if (pex.HeaderPaddingStrings.Any(s => s == "UPX!" && match != null)) + { + var regexMatch = _upxVersionMatch.Match(match); + if (regexMatch.Success) + return $"UPX {regexMatch.Groups[1].Value}"; + else + return "UPX (Unknown Version)"; + } + else if (pex.HeaderPaddingStrings.Any(s => s == "NOS " && match != null)) + { + var regexMatch = _upxVersionMatch.Match(match); + if (regexMatch.Success) + return $"UPX (NOS Variant) {regexMatch.Groups[1].Value}"; + else + return "UPX (NOS Variant) (Unknown Version)"; + } } return null; diff --git a/BurnOutSharp/ProtectionType/Macrovision.cs b/BurnOutSharp/ProtectionType/Macrovision.cs index f85dbee0..6fe77315 100644 --- a/BurnOutSharp/ProtectionType/Macrovision.cs +++ b/BurnOutSharp/ProtectionType/Macrovision.cs @@ -66,7 +66,7 @@ namespace BurnOutSharp.ProtectionType List resultsList = new List(); // Check the header padding - string match = CheckSectionForProtection(file, includeDebug, pex.HeaderPaddingData); + string match = CheckSectionForProtection(file, includeDebug, pex.HeaderPaddingStrings, pex.HeaderPaddingData); if (!string.IsNullOrWhiteSpace(match)) { resultsList.Add(match); @@ -74,7 +74,7 @@ namespace BurnOutSharp.ProtectionType else { // Get the .data section, if it exists - match = CheckSectionForProtection(file, includeDebug, pex, ".data"); + match = CheckSectionForProtection(file, includeDebug, pex.GetFirstSectionStrings(".data"), pex.GetFirstSectionData(".data")); if (!string.IsNullOrWhiteSpace(match)) resultsList.Add(match); } @@ -184,39 +184,16 @@ namespace BurnOutSharp.ProtectionType return $"{version}.{subVersion:00}.{subsubVersion:000}"; } - private string CheckSectionForProtection(string file, bool includeDebug, byte[] sectionRaw) - { - // If we have null section data - if (sectionRaw == null) - return null; - - var matchers = new List - { - // BoG_ *90.0&!! Yy> - new ContentMatchSet(new byte?[] - { - 0x42, 0x6F, 0x47, 0x5F, 0x20, 0x2A, 0x39, 0x30, - 0x2E, 0x30, 0x26, 0x21, 0x21, 0x20, 0x20, 0x59, - 0x79, 0x3E - }, GetMacrovisionVersion, "SafeCast/SafeDisc"), - }; - - return MatchUtil.GetFirstMatch(file, sectionRaw, matchers, includeDebug); - } - - private string CheckSectionForProtection(string file, bool includeDebug, PortableExecutable pex, string sectionName) + private string CheckSectionForProtection(string file, bool includeDebug, List sectionStrings, byte[] sectionRaw) { // Get the section strings, if they exist - List strs = pex.GetFirstSectionStrings(sectionName); - if (strs == null) + if (sectionStrings == null) return null; // If we don't have the "BoG_" string - if (!strs.Any(s => s.Contains("BoG_ *90.0&!! Yy>"))) + if (!sectionStrings.Any(s => s.Contains("BoG_ *90.0&!! Yy>"))) return null; - byte[] sectionRaw = pex.GetFirstSectionData(sectionName); - // TODO: Add more checks to help differentiate between SafeDisc and SafeCast. var matchers = new List {