Add header padding strings

This commit is contained in:
Matt Nadareski
2022-12-10 17:31:41 -08:00
parent 3c3fd1be50
commit d1a6c9be00
3 changed files with 74 additions and 41 deletions

View File

@@ -352,6 +352,33 @@ namespace BurnOutSharp.Wrappers
}
}
/// <summary>
/// Header padding strings, if they exist
/// </summary>
public List<string> 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;
}
}
}
/// <summary>
/// Overlay data, if it exists
/// </summary>
@@ -663,6 +690,11 @@ namespace BurnOutSharp.Wrappers
/// </summary>
private byte[] _headerPaddingData = null;
/// <summary>
/// Header padding data, if it exists
/// </summary>
private List<string> _headerPaddingStrings = null;
/// <summary>
/// Overlay data, if it exists
/// </summary>

View File

@@ -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);
/// <inheritdoc/>
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<ContentMatchSet>
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;

View File

@@ -66,7 +66,7 @@ namespace BurnOutSharp.ProtectionType
List<string> resultsList = new List<string>();
// 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<ContentMatchSet>
{
// 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<string> sectionStrings, byte[] sectionRaw)
{
// Get the section strings, if they exist
List<string> 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<ContentMatchSet>
{