mirror of
https://github.com/SabreTools/BinaryObjectScanner.git
synced 2026-07-15 21:35:01 +00:00
Better split matching code, fix UPX name
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
using System.Diagnostics.Eventing.Reader;
|
||||
|
||||
namespace BurnOutSharp.Matching
|
||||
{
|
||||
/// <summary>
|
||||
@@ -26,5 +28,66 @@ namespace BurnOutSharp.Matching
|
||||
Start = start;
|
||||
End = end;
|
||||
}
|
||||
|
||||
#region Matching
|
||||
|
||||
/// <summary>
|
||||
/// Get if this match can be found in a stack
|
||||
/// </summary>
|
||||
/// <param name="stack">Array to search for the given content</param>
|
||||
/// <param name="reverse">True to search from the end of the array, false from the start</param>
|
||||
public (bool, int) Match(byte[] stack, bool reverse = false)
|
||||
{
|
||||
// If either array is null or empty, we can't do anything
|
||||
if (stack == null || stack.Length == 0 || Needle == null || Needle.Length == 0)
|
||||
return (false, -1);
|
||||
|
||||
// If the needle array is larger than the stack array, it can't be contained within
|
||||
if (Needle.Length > stack.Length)
|
||||
return (false, -1);
|
||||
|
||||
// If start or end are not set properly, set them to defaults
|
||||
if (Start < 0)
|
||||
Start = 0;
|
||||
if (End < 0)
|
||||
End = stack.Length - Needle.Length;
|
||||
|
||||
for (int i = reverse ? End : Start; reverse ? i > Start : i < End; i += reverse ? -1 : 1)
|
||||
{
|
||||
if (EqualAt(stack, i))
|
||||
return (true, i);
|
||||
}
|
||||
|
||||
return (false, -1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get if a stack at a certain index is equal to a needle
|
||||
/// </summary>
|
||||
/// <param name="stack">Array to search for the given content</param>
|
||||
/// <param name="index">Starting index to check equality</param>
|
||||
private bool EqualAt(byte[] stack, int index)
|
||||
{
|
||||
// If the index is invalid, we can't do anything
|
||||
if (index < 0)
|
||||
return false;
|
||||
|
||||
// If we're too close to the end of the stack, return false
|
||||
if (Needle.Length >= stack.Length - index)
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < Needle.Length; i++)
|
||||
{
|
||||
// A null value is a wildcard
|
||||
if (Needle[i] == null)
|
||||
continue;
|
||||
else if (stack[i + index] != Needle[i])
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
105
BurnOutSharp/Matching/MatchUtil.cs
Normal file
105
BurnOutSharp/Matching/MatchUtil.cs
Normal file
@@ -0,0 +1,105 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace BurnOutSharp.Matching
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper class for content matching
|
||||
/// </summary>
|
||||
internal static class MatchUtil
|
||||
{
|
||||
/// <summary>
|
||||
/// Get all content matches for a given list of matchers
|
||||
/// </summary>
|
||||
/// <param name="file">File to check for matches</param>
|
||||
/// <param name="fileContent">Byte array representing the file contents</param>
|
||||
/// <param name="matchers">Enumerable of matchers to be run on the file</param>
|
||||
/// <param name="includePosition">True to include positional data, false otherwise</param>
|
||||
/// <returns>List of strings representing the matched protections, null or empty otherwise</returns>
|
||||
public static List<string> GetAllContentMatches(
|
||||
string file,
|
||||
byte[] fileContent,
|
||||
IEnumerable<Matcher> matchers,
|
||||
bool includePosition = false)
|
||||
{
|
||||
return FindAllContentMatches(file, fileContent, matchers, includePosition, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get first content match for a given list of matchers
|
||||
/// </summary>
|
||||
/// <param name="file">File to check for matches</param>
|
||||
/// <param name="fileContent">Byte array representing the file contents</param>
|
||||
/// <param name="matchers">Enumerable of matchers to be run on the file</param>
|
||||
/// <param name="includePosition">True to include positional data, false otherwise</param>
|
||||
/// <returns>String representing the matched protection, null otherwise</returns>
|
||||
public static string GetFirstContentMatch(
|
||||
string file,
|
||||
byte[] fileContent,
|
||||
IEnumerable<Matcher> matchers,
|
||||
bool includePosition = false)
|
||||
{
|
||||
var contentMatches = FindAllContentMatches(file, fileContent, matchers, includePosition, true);
|
||||
if (contentMatches == null || !contentMatches.Any())
|
||||
return null;
|
||||
|
||||
return contentMatches.First();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the required set of content matches on a per Matcher basis
|
||||
/// </summary>
|
||||
/// <param name="file">File to check for matches</param>
|
||||
/// <param name="fileContent">Byte array representing the file contents</param>
|
||||
/// <param name="matchers">Enumerable of matchers to be run on the file</param>
|
||||
/// <param name="includePosition">True to include positional data, false otherwise</param>
|
||||
/// <param name="stopAfterFirst">True to stop after the first match, false otherwise</param>
|
||||
/// <returns>List of strings representing the matched protections, null or empty otherwise</returns>
|
||||
private static List<string> FindAllContentMatches(
|
||||
string file,
|
||||
byte[] fileContent,
|
||||
IEnumerable<Matcher> matchers,
|
||||
bool includePosition,
|
||||
bool stopAfterFirst)
|
||||
{
|
||||
// If there's no mappings, we can't match
|
||||
if (matchers == null || !matchers.Any())
|
||||
return null;
|
||||
|
||||
// Initialize the list of matched protections
|
||||
List<string> matchedProtections = new List<string>();
|
||||
|
||||
// Loop through and try everything otherwise
|
||||
foreach (var matcher in matchers)
|
||||
{
|
||||
// Determine if the matcher passes
|
||||
(bool passes, List<int> positions) = matcher.MatchesAll(fileContent);
|
||||
if (!passes)
|
||||
continue;
|
||||
|
||||
// Format the list of all positions found
|
||||
string positionsString = string.Join(", ", positions);
|
||||
|
||||
// If we there is no version method, just return the protection name
|
||||
if (matcher.GetVersion == null)
|
||||
{
|
||||
matchedProtections.Add((matcher.ProtectionName ?? "Unknown Protection") + (includePosition ? $" (Index {positionsString})" : string.Empty));
|
||||
}
|
||||
|
||||
// Otherwise, invoke the version method
|
||||
// TODO: Pass all positions to the version finding method
|
||||
else
|
||||
{
|
||||
string version = matcher.GetVersion(file, fileContent, positions[0]) ?? "Unknown Version";
|
||||
matchedProtections.Add($"{matcher.ProtectionName ?? "Unknown Protection"} {version}" + (includePosition ? $" (Index {positionsString})" : string.Empty));
|
||||
}
|
||||
|
||||
// If we're stopping after the first protection, bail out here
|
||||
if (stopAfterFirst)
|
||||
return matchedProtections;
|
||||
}
|
||||
|
||||
return matchedProtections;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -55,5 +55,36 @@ namespace BurnOutSharp.Matching
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Matching
|
||||
|
||||
/// <summary>
|
||||
/// Determine wheter all content matches pass
|
||||
/// </summary>
|
||||
/// <param name="fileContent">Byte array representing the file contents</param>
|
||||
/// <returns>Tuole of passing status and matching positions</returns>
|
||||
public (bool, List<int>) MatchesAll(byte[] fileContent)
|
||||
{
|
||||
// If no content matches are defined, we fail out
|
||||
if (ContentMatches == null || !ContentMatches.Any())
|
||||
return (false, null);
|
||||
|
||||
// Initialize the position list
|
||||
List<int> positions = new List<int>();
|
||||
|
||||
// Loop through all content matches and make sure all pass
|
||||
foreach (var contentMatch in ContentMatches)
|
||||
{
|
||||
(bool match, int position) = contentMatch.Match(fileContent);
|
||||
if (!match)
|
||||
return (false, null);
|
||||
else
|
||||
positions.Add(position);
|
||||
}
|
||||
|
||||
return (true, positions);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -22,7 +22,7 @@ namespace BurnOutSharp.PackerType
|
||||
}, "Caphyon Advanced Installer"),
|
||||
};
|
||||
|
||||
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
return MatchUtil.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace BurnOutSharp.PackerType
|
||||
new Matcher(new byte?[] { 0x41, 0x52, 0x4D, 0x44, 0x45, 0x42, 0x55, 0x47 }, "Armadillo"),
|
||||
};
|
||||
|
||||
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
return MatchUtil.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace BurnOutSharp.PackerType
|
||||
}, end: 200), "CExe"),
|
||||
};
|
||||
|
||||
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
return MatchUtil.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace BurnOutSharp.PackerType
|
||||
}, "EXE Stealth"),
|
||||
};
|
||||
|
||||
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
return MatchUtil.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace BurnOutSharp.PackerType
|
||||
"Inno Setup"),
|
||||
};
|
||||
|
||||
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
return MatchUtil.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace BurnOutSharp.PackerType
|
||||
}, "NSIS"),
|
||||
};
|
||||
|
||||
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
return MatchUtil.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
}
|
||||
|
||||
public static string GetVersion(string file, byte[] fileContent, int index)
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace BurnOutSharp.PackerType
|
||||
}, "PE Compact 2"),
|
||||
};
|
||||
|
||||
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
return MatchUtil.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
}
|
||||
|
||||
public static string GetVersion(string file, byte[] fileContent, int position)
|
||||
|
||||
@@ -44,7 +44,7 @@ namespace BurnOutSharp.PackerType
|
||||
// }, GetVersion, "Setup Factory"),
|
||||
};
|
||||
|
||||
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
return MatchUtil.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace BurnOutSharp.PackerType
|
||||
var matchers = new List<Matcher>
|
||||
{
|
||||
// UPX!
|
||||
new Matcher(new byte?[] { 0x55, 0x50, 0x58, 0x21 }, GetVersion, "Inno Setup"),
|
||||
new Matcher(new byte?[] { 0x55, 0x50, 0x58, 0x21 }, GetVersion, "UPX"),
|
||||
|
||||
// NOS
|
||||
new Matcher(new byte?[] { 0x4E, 0x4F, 0x53, 0x20 }, GetVersion, "UPX (NOS Variant)"),
|
||||
@@ -42,7 +42,7 @@ namespace BurnOutSharp.PackerType
|
||||
),
|
||||
};
|
||||
|
||||
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
return MatchUtil.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
}
|
||||
|
||||
public static string GetVersion(string file, byte[] fileContent, int index)
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace BurnOutSharp.PackerType
|
||||
}, "WinRAR SFX"),
|
||||
};
|
||||
|
||||
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
return MatchUtil.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
}
|
||||
|
||||
public Dictionary<string, List<string>> Scan(Scanner scanner, string file)
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace BurnOutSharp.PackerType
|
||||
new Matcher(new byte?[] { 0x5F, 0x77, 0x69, 0x6E, 0x7A, 0x69, 0x70, 0x5F }, GetVersion, "WinZip SFX"),
|
||||
};
|
||||
|
||||
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
return MatchUtil.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace BurnOutSharp.PackerType
|
||||
new Matcher(new byte?[] { 0x57, 0x69, 0x73, 0x65, 0x4D, 0x61, 0x69, 0x6E }, "Wise Installation Wizard Module"),
|
||||
};
|
||||
|
||||
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
return MatchUtil.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace BurnOutSharp.PackerType
|
||||
}, "dotFuscator"),
|
||||
};
|
||||
|
||||
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
return MatchUtil.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace BurnOutSharp.ProtectionType
|
||||
}, "ActiveMARK 5"),
|
||||
};
|
||||
|
||||
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
return MatchUtil.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace BurnOutSharp.ProtectionType
|
||||
new Matcher(new byte?[] { 0x53, 0x45, 0x54, 0x54, 0x45, 0x43 }, "Alpha-ROM"),
|
||||
};
|
||||
|
||||
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
return MatchUtil.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace BurnOutSharp.ProtectionType
|
||||
new Matcher(new byte?[] { 0x43, 0x44, 0x43, 0x68, 0x65, 0x63, 0x6B }, "Executable-Based CD Check"),
|
||||
};
|
||||
|
||||
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
return MatchUtil.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
}
|
||||
|
||||
// These content checks are too broad to be useful
|
||||
@@ -45,7 +45,7 @@ namespace BurnOutSharp.ProtectionType
|
||||
}, "Executable-Based CD Check"),
|
||||
};
|
||||
|
||||
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
return MatchUtil.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace BurnOutSharp.ProtectionType
|
||||
new Matcher(new byte?[] { 0x2E, 0x67, 0x72, 0x61, 0x6E, 0x64, 0x00 }, "CD-Cops"),
|
||||
};
|
||||
|
||||
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
return MatchUtil.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace BurnOutSharp.ProtectionType
|
||||
}, "CD-Lock"),
|
||||
};
|
||||
|
||||
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
return MatchUtil.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace BurnOutSharp.ProtectionType
|
||||
new Matcher(new byte?[] { 0x7E, 0x30, 0x30, 0x31, 0x37, 0x2E, 0x74, 0x6D, 0x70 }, "CDSHiELD SE"),
|
||||
};
|
||||
|
||||
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
return MatchUtil.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace BurnOutSharp.ProtectionType
|
||||
new Matcher(new byte?[] { 0x43, 0x44, 0x53, 0x50, 0x6C, 0x61, 0x79, 0x65, 0x72 }, "Cactus Data Shield 200"),
|
||||
};
|
||||
|
||||
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
return MatchUtil.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace BurnOutSharp.ProtectionType
|
||||
new Matcher(new byte?[] { 0x2E, 0x63, 0x65, 0x6E, 0x65, 0x67, 0x61 }, "Cenega ProtectDVD"),
|
||||
};
|
||||
|
||||
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
return MatchUtil.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace BurnOutSharp.ProtectionType
|
||||
}, "Code Lock"),
|
||||
};
|
||||
|
||||
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
return MatchUtil.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace BurnOutSharp.ProtectionType
|
||||
}, "CopyKiller"),
|
||||
};
|
||||
|
||||
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
return MatchUtil.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace BurnOutSharp.ProtectionType
|
||||
}, GetVersion, "DVD-Cops"),
|
||||
};
|
||||
|
||||
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
return MatchUtil.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
}
|
||||
|
||||
public static string GetVersion(string file, byte[] fileContent, int position)
|
||||
|
||||
@@ -106,7 +106,7 @@ namespace BurnOutSharp.ProtectionType
|
||||
}, "EA DRM Protection"),
|
||||
};
|
||||
|
||||
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
return MatchUtil.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace BurnOutSharp.ProtectionType
|
||||
new Matcher(new byte?[] { 0x78, 0x6C, 0x69, 0x76, 0x65, 0x2E, 0x64, 0x6C, 0x6C }, "Games for Windows - Live"),
|
||||
};
|
||||
|
||||
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
return MatchUtil.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace BurnOutSharp.ProtectionType
|
||||
new Matcher(new byte?[] { 0x54, 0x72, 0x69, 0x61, 0x6C, 0x00, 0x50 }, "INTENIUM Trial & Buy Protection"),
|
||||
};
|
||||
|
||||
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
return MatchUtil.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace BurnOutSharp.ProtectionType
|
||||
}, "Key-Lock (Dongle)"),
|
||||
};
|
||||
|
||||
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
return MatchUtil.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace BurnOutSharp.ProtectionType
|
||||
}, "MediaMax CD-3"),
|
||||
};
|
||||
|
||||
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
return MatchUtil.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace BurnOutSharp.ProtectionType
|
||||
}, Utilities.GetFileVersion, "Executable-Based Online Registration"),
|
||||
};
|
||||
|
||||
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
return MatchUtil.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace BurnOutSharp.ProtectionType
|
||||
new Matcher(new byte?[] { 0x4F, 0x00, 0x72, 0x00, 0x69, 0x00, 0x67, 0x00, 0x69, 0x00, 0x6E, 0x00, 0x53, 0x00, 0x65, 0x00, 0x74, 0x00, 0x75, 0x00, 0x70, 0x00, 0x2E, 0x00, 0x65, 0x00, 0x78, 0x00, 0x65, 0x00 }, "Origin"),
|
||||
};
|
||||
|
||||
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
return MatchUtil.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
||||
@@ -42,7 +42,7 @@ namespace BurnOutSharp.ProtectionType
|
||||
}, "PlayStation Anti-modchip (Japanese)"),
|
||||
};
|
||||
|
||||
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
return MatchUtil.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace BurnOutSharp.ProtectionType
|
||||
}, "Ring PROTECH [Check disc for physical ring]"),
|
||||
};
|
||||
|
||||
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
return MatchUtil.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace BurnOutSharp.ProtectionType
|
||||
new Matcher(new byte?[] { 0x3F, 0x53, 0x56, 0x4B, 0x50, 0x00, 0x00 }, "SVK Protector"),
|
||||
};
|
||||
|
||||
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
return MatchUtil.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace BurnOutSharp.ProtectionType
|
||||
new Matcher(new byte?[] { 0x53, 0x61, 0x66, 0x65, 0x4C, 0x6F, 0x63, 0x6B }, "SafeLock"),
|
||||
};
|
||||
|
||||
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
return MatchUtil.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
||||
@@ -46,7 +46,7 @@ namespace BurnOutSharp.ProtectionType
|
||||
new Matcher(new byte?[] { 0x2E, 0x63, 0x6D, 0x73, 0x5F, 0x64, 0x00 }, "SecuROM 1-3"),
|
||||
};
|
||||
|
||||
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
return MatchUtil.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace BurnOutSharp.ProtectionType
|
||||
new Matcher(new byte?[] { 0x42, 0x49, 0x54, 0x41, 0x52, 0x54, 0x53 }, "SmartE"),
|
||||
};
|
||||
|
||||
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
return MatchUtil.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace BurnOutSharp.ProtectionType
|
||||
}, GetVersion, "Sysiphus"),
|
||||
};
|
||||
|
||||
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
return MatchUtil.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
}
|
||||
|
||||
public static string GetVersion(string file, byte[] fileContent, int position)
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace BurnOutSharp.ProtectionType
|
||||
// }, "3PLock"),
|
||||
};
|
||||
|
||||
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
return MatchUtil.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace BurnOutSharp.ProtectionType
|
||||
}, "321Studios Online Activation"),
|
||||
};
|
||||
|
||||
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
return MatchUtil.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace BurnOutSharp.ProtectionType
|
||||
new Matcher(new byte?[] { 0x57, 0x54, 0x4D, 0x37, 0x36, 0x35, 0x34, 0x35 }, "WTM CD Protect"),
|
||||
};
|
||||
|
||||
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
return MatchUtil.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace BurnOutSharp.ProtectionType
|
||||
}, "XCP"),
|
||||
};
|
||||
|
||||
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
return MatchUtil.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace BurnOutSharp.ProtectionType
|
||||
new Matcher(new byte?[] { 0x58, 0x50, 0x52, 0x4F, 0x54, 0x20, 0x20, 0x20 }, "Xtreme-Protector"),
|
||||
};
|
||||
|
||||
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
return MatchUtil.GetFirstContentMatch(file, fileContent, matchers, includePosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -168,11 +168,13 @@ namespace BurnOutSharp
|
||||
// Initialize the loop variables
|
||||
bool found = true;
|
||||
int lastPosition = start;
|
||||
var matcher = new ContentMatch(needle, end: end);
|
||||
|
||||
// Loop over and get all positions
|
||||
while (found)
|
||||
{
|
||||
(found, lastPosition) = FindPosition(stack, needle, lastPosition, end, false);
|
||||
matcher.Start = lastPosition;
|
||||
(found, lastPosition) = matcher.Match(stack, false);
|
||||
if (found)
|
||||
positions.Add(lastPosition);
|
||||
}
|
||||
@@ -185,7 +187,8 @@ namespace BurnOutSharp
|
||||
/// </summary>
|
||||
public static bool FirstPosition(this byte[] stack, byte?[] needle, out int position, int start = 0, int end = -1)
|
||||
{
|
||||
(bool found, int foundPosition) = FindPosition(stack, needle, start, end, false);
|
||||
var matcher = new ContentMatch(needle, start, end);
|
||||
(bool found, int foundPosition) = matcher.Match(stack, false);
|
||||
position = foundPosition;
|
||||
return found;
|
||||
}
|
||||
@@ -195,7 +198,8 @@ namespace BurnOutSharp
|
||||
/// </summary>
|
||||
public static bool LastPosition(this byte[] stack, byte?[] needle, out int position, int start = 0, int end = -1)
|
||||
{
|
||||
(bool found, int foundPosition) = FindPosition(stack, needle, start, end, true);
|
||||
var matcher = new ContentMatch(needle, start, end);
|
||||
(bool found, int foundPosition) = matcher.Match(stack, true);
|
||||
position = foundPosition;
|
||||
return found;
|
||||
}
|
||||
@@ -216,89 +220,10 @@ namespace BurnOutSharp
|
||||
return stack.FirstPosition(needle, out int _, start: stack.Length - needle.Length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find the position of one array in another, if possible
|
||||
/// </summary>
|
||||
private static (bool, int) FindPosition(byte[] stack, byte?[] needle, int start, int end, bool reverse)
|
||||
{
|
||||
// If either array is null or empty, we can't do anything
|
||||
if (stack == null || stack.Length == 0 || needle == null || needle.Length == 0)
|
||||
return (false, -1);
|
||||
|
||||
// If the needle array is larger than the stack array, it can't be contained within
|
||||
if (needle.Length > stack.Length)
|
||||
return (false, -1);
|
||||
|
||||
// If start or end are not set properly, set them to defaults
|
||||
if (start < 0)
|
||||
start = 0;
|
||||
if (end < 0)
|
||||
end = stack.Length - needle.Length;
|
||||
|
||||
for (int i = reverse ? end : start; reverse ? i > start : i < end; i += reverse ? -1 : 1)
|
||||
{
|
||||
if (stack.EqualAt(needle, i))
|
||||
return (true, i);
|
||||
}
|
||||
|
||||
return (false, -1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get if a stack at a certain index is equal to a needle
|
||||
/// </summary>
|
||||
private static bool EqualAt(this byte[] stack, byte?[] needle, int index)
|
||||
{
|
||||
// If we're too close to the end of the stack, return false
|
||||
if (needle.Length >= stack.Length - index)
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < needle.Length; i++)
|
||||
{
|
||||
// A null value is a wildcard
|
||||
if (needle[i] == null)
|
||||
continue;
|
||||
else if (stack[i + index] != needle[i])
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Protection
|
||||
|
||||
/// <summary>
|
||||
/// Get all content matches for a given list of matchers
|
||||
/// </summary>
|
||||
/// <param name="file">File to check for matches</param>
|
||||
/// <param name="fileContent">Byte array representing the file contents</param>
|
||||
/// <param name="matchers">Enumerable of matchers to be run on the file</param>
|
||||
/// <param name="includePosition">True to include positional data, false otherwise</param>
|
||||
/// <returns>List of strings representing the matched protections, null or empty otherwise</returns>
|
||||
public static List<string> GetAllContentMatches(string file, byte[] fileContent, IEnumerable<Matcher> matchers, bool includePosition = false)
|
||||
{
|
||||
return FindAllContentMatches(file, fileContent, matchers, includePosition, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get first content match for a given list of matchers
|
||||
/// </summary>
|
||||
/// <param name="file">File to check for matches</param>
|
||||
/// <param name="fileContent">Byte array representing the file contents</param>
|
||||
/// <param name="matchers">Enumerable of matchers to be run on the file</param>
|
||||
/// <param name="includePosition">True to include positional data, false otherwise</param>
|
||||
/// <returns>String representing the matched protection, null otherwise</returns>
|
||||
public static string GetFirstContentMatch(string file, byte[] fileContent, IEnumerable<Matcher> matchers, bool includePosition = false)
|
||||
{
|
||||
var contentMatches = FindAllContentMatches(file, fileContent, matchers, includePosition, false);
|
||||
if (contentMatches == null || !contentMatches.Any())
|
||||
return null;
|
||||
|
||||
return contentMatches.First();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the file version as reported by the filesystem
|
||||
/// </summary>
|
||||
@@ -382,79 +307,6 @@ namespace BurnOutSharp
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the required set of content matches on a per Matcher basis
|
||||
/// </summary>
|
||||
/// <param name="file">File to check for matches</param>
|
||||
/// <param name="fileContent">Byte array representing the file contents</param>
|
||||
/// <param name="matchers">Enumerable of matchers to be run on the file</param>
|
||||
/// <param name="includePosition">True to include positional data, false otherwise</param>
|
||||
/// <param name="stopAfterFirst">True to stop after the first match, false otherwise</param>
|
||||
/// <returns>List of strings representing the matched protections, null or empty otherwise</returns>
|
||||
private static List<string> FindAllContentMatches(
|
||||
string file,
|
||||
byte[] fileContent,
|
||||
IEnumerable<Matcher> matchers,
|
||||
bool includePosition,
|
||||
bool stopAfterFirst)
|
||||
{
|
||||
// If there's no mappings, we can't match
|
||||
if (matchers == null || !matchers.Any())
|
||||
return null;
|
||||
|
||||
// Initialize the list of matched protections
|
||||
List<string> matchedProtections = new List<string>();
|
||||
|
||||
// Loop through and try everything otherwise
|
||||
foreach (var matcher in matchers)
|
||||
{
|
||||
// Setup for a single matcher
|
||||
bool allMatches = true;
|
||||
List<int> positions = new List<int>();
|
||||
|
||||
// Loop through all content matches and make sure all pass
|
||||
foreach (var contentMatch in matcher.ContentMatches)
|
||||
{
|
||||
if (!fileContent.FirstPosition(contentMatch.Needle, out int position, contentMatch.Start, contentMatch.End))
|
||||
{
|
||||
allMatches = false;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
positions.Add(position);
|
||||
}
|
||||
}
|
||||
|
||||
// If not all matches pass, then we continue
|
||||
if (!allMatches)
|
||||
continue;
|
||||
|
||||
// Format the list of all positions found
|
||||
string positionsString = string.Join(", ", positions);
|
||||
|
||||
// If we there is no version method, just return the protection name
|
||||
if (matcher.GetVersion == null)
|
||||
{
|
||||
matchedProtections.Add((matcher.ProtectionName ?? "Unknown Protection") + (includePosition ? $" (Index {positionsString})" : string.Empty));
|
||||
}
|
||||
|
||||
// Otherwise, invoke the version method
|
||||
// TODO: Pass all positions to the version finding method
|
||||
else
|
||||
{
|
||||
string version = matcher.GetVersion(file, fileContent, positions[0]) ?? "Unknown Version";
|
||||
matchedProtections.Add($"{matcher.ProtectionName} {version}" + (includePosition ? $" (Index {positionsString})" : string.Empty));
|
||||
}
|
||||
|
||||
// If we're stopping after the first protection, bail out here
|
||||
if (stopAfterFirst)
|
||||
return matchedProtections;
|
||||
}
|
||||
|
||||
return matchedProtections;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user