diff --git a/BurnOutSharp/Matching/ContentMatch.cs b/BurnOutSharp/Matching/ContentMatch.cs
index 9fef7cf9..d4d86fe8 100644
--- a/BurnOutSharp/Matching/ContentMatch.cs
+++ b/BurnOutSharp/Matching/ContentMatch.cs
@@ -1,3 +1,5 @@
+using System.Diagnostics.Eventing.Reader;
+
namespace BurnOutSharp.Matching
{
///
@@ -26,5 +28,66 @@ namespace BurnOutSharp.Matching
Start = start;
End = end;
}
+
+ #region Matching
+
+ ///
+ /// Get if this match can be found in a stack
+ ///
+ /// Array to search for the given content
+ /// True to search from the end of the array, false from the start
+ 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);
+ }
+
+ ///
+ /// Get if a stack at a certain index is equal to a needle
+ ///
+ /// Array to search for the given content
+ /// Starting index to check equality
+ 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
}
}
\ No newline at end of file
diff --git a/BurnOutSharp/Matching/MatchUtil.cs b/BurnOutSharp/Matching/MatchUtil.cs
new file mode 100644
index 00000000..d60847f4
--- /dev/null
+++ b/BurnOutSharp/Matching/MatchUtil.cs
@@ -0,0 +1,105 @@
+using System.Collections.Generic;
+using System.Linq;
+
+namespace BurnOutSharp.Matching
+{
+ ///
+ /// Helper class for content matching
+ ///
+ internal static class MatchUtil
+ {
+ ///
+ /// Get all content matches for a given list of matchers
+ ///
+ /// File to check for matches
+ /// Byte array representing the file contents
+ /// Enumerable of matchers to be run on the file
+ /// True to include positional data, false otherwise
+ /// List of strings representing the matched protections, null or empty otherwise
+ public static List GetAllContentMatches(
+ string file,
+ byte[] fileContent,
+ IEnumerable matchers,
+ bool includePosition = false)
+ {
+ return FindAllContentMatches(file, fileContent, matchers, includePosition, false);
+ }
+
+ ///
+ /// Get first content match for a given list of matchers
+ ///
+ /// File to check for matches
+ /// Byte array representing the file contents
+ /// Enumerable of matchers to be run on the file
+ /// True to include positional data, false otherwise
+ /// String representing the matched protection, null otherwise
+ public static string GetFirstContentMatch(
+ string file,
+ byte[] fileContent,
+ IEnumerable matchers,
+ bool includePosition = false)
+ {
+ var contentMatches = FindAllContentMatches(file, fileContent, matchers, includePosition, true);
+ if (contentMatches == null || !contentMatches.Any())
+ return null;
+
+ return contentMatches.First();
+ }
+
+ ///
+ /// Get the required set of content matches on a per Matcher basis
+ ///
+ /// File to check for matches
+ /// Byte array representing the file contents
+ /// Enumerable of matchers to be run on the file
+ /// True to include positional data, false otherwise
+ /// True to stop after the first match, false otherwise
+ /// List of strings representing the matched protections, null or empty otherwise
+ private static List FindAllContentMatches(
+ string file,
+ byte[] fileContent,
+ IEnumerable 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 matchedProtections = new List();
+
+ // Loop through and try everything otherwise
+ foreach (var matcher in matchers)
+ {
+ // Determine if the matcher passes
+ (bool passes, List 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;
+ }
+ }
+}
\ No newline at end of file
diff --git a/BurnOutSharp/Matching/Matcher.cs b/BurnOutSharp/Matching/Matcher.cs
index 327f7aca..7e1fbb81 100644
--- a/BurnOutSharp/Matching/Matcher.cs
+++ b/BurnOutSharp/Matching/Matcher.cs
@@ -55,5 +55,36 @@ namespace BurnOutSharp.Matching
}
#endregion
+
+ #region Matching
+
+ ///
+ /// Determine wheter all content matches pass
+ ///
+ /// Byte array representing the file contents
+ /// Tuole of passing status and matching positions
+ public (bool, List) 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 positions = new List();
+
+ // 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
}
}
\ No newline at end of file
diff --git a/BurnOutSharp/PackerType/AdvancedInstaller.cs b/BurnOutSharp/PackerType/AdvancedInstaller.cs
index c990c392..00430e62 100644
--- a/BurnOutSharp/PackerType/AdvancedInstaller.cs
+++ b/BurnOutSharp/PackerType/AdvancedInstaller.cs
@@ -22,7 +22,7 @@ namespace BurnOutSharp.PackerType
}, "Caphyon Advanced Installer"),
};
- return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
+ return MatchUtil.GetFirstContentMatch(file, fileContent, matchers, includePosition);
}
}
}
diff --git a/BurnOutSharp/PackerType/Armadillo.cs b/BurnOutSharp/PackerType/Armadillo.cs
index 1af61985..11d1310b 100644
--- a/BurnOutSharp/PackerType/Armadillo.cs
+++ b/BurnOutSharp/PackerType/Armadillo.cs
@@ -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);
}
}
}
diff --git a/BurnOutSharp/PackerType/CExe.cs b/BurnOutSharp/PackerType/CExe.cs
index 94c2686d..ced25a9a 100644
--- a/BurnOutSharp/PackerType/CExe.cs
+++ b/BurnOutSharp/PackerType/CExe.cs
@@ -29,7 +29,7 @@ namespace BurnOutSharp.PackerType
}, end: 200), "CExe"),
};
- return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
+ return MatchUtil.GetFirstContentMatch(file, fileContent, matchers, includePosition);
}
///
diff --git a/BurnOutSharp/PackerType/EXEStealth.cs b/BurnOutSharp/PackerType/EXEStealth.cs
index 145cfbfa..331f9d1e 100644
--- a/BurnOutSharp/PackerType/EXEStealth.cs
+++ b/BurnOutSharp/PackerType/EXEStealth.cs
@@ -21,7 +21,7 @@ namespace BurnOutSharp.PackerType
}, "EXE Stealth"),
};
- return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
+ return MatchUtil.GetFirstContentMatch(file, fileContent, matchers, includePosition);
}
}
}
diff --git a/BurnOutSharp/PackerType/InnoSetup.cs b/BurnOutSharp/PackerType/InnoSetup.cs
index 056108de..f57ba1f3 100644
--- a/BurnOutSharp/PackerType/InnoSetup.cs
+++ b/BurnOutSharp/PackerType/InnoSetup.cs
@@ -23,7 +23,7 @@ namespace BurnOutSharp.PackerType
"Inno Setup"),
};
- return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
+ return MatchUtil.GetFirstContentMatch(file, fileContent, matchers, includePosition);
}
///
diff --git a/BurnOutSharp/PackerType/NSIS.cs b/BurnOutSharp/PackerType/NSIS.cs
index 9af6f50e..00e997fd 100644
--- a/BurnOutSharp/PackerType/NSIS.cs
+++ b/BurnOutSharp/PackerType/NSIS.cs
@@ -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)
diff --git a/BurnOutSharp/PackerType/PECompact.cs b/BurnOutSharp/PackerType/PECompact.cs
index b294eb32..7d21e37a 100644
--- a/BurnOutSharp/PackerType/PECompact.cs
+++ b/BurnOutSharp/PackerType/PECompact.cs
@@ -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)
diff --git a/BurnOutSharp/PackerType/SetupFactory.cs b/BurnOutSharp/PackerType/SetupFactory.cs
index 5317a45b..c663d127 100644
--- a/BurnOutSharp/PackerType/SetupFactory.cs
+++ b/BurnOutSharp/PackerType/SetupFactory.cs
@@ -44,7 +44,7 @@ namespace BurnOutSharp.PackerType
// }, GetVersion, "Setup Factory"),
};
- return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
+ return MatchUtil.GetFirstContentMatch(file, fileContent, matchers, includePosition);
}
///
diff --git a/BurnOutSharp/PackerType/UPX.cs b/BurnOutSharp/PackerType/UPX.cs
index 827fd36d..6d86abde 100644
--- a/BurnOutSharp/PackerType/UPX.cs
+++ b/BurnOutSharp/PackerType/UPX.cs
@@ -12,7 +12,7 @@ namespace BurnOutSharp.PackerType
var matchers = new List
{
// 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)
diff --git a/BurnOutSharp/PackerType/WinRARSFX.cs b/BurnOutSharp/PackerType/WinRARSFX.cs
index 339b214a..0f518834 100644
--- a/BurnOutSharp/PackerType/WinRARSFX.cs
+++ b/BurnOutSharp/PackerType/WinRARSFX.cs
@@ -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> Scan(Scanner scanner, string file)
diff --git a/BurnOutSharp/PackerType/WinZipSFX.cs b/BurnOutSharp/PackerType/WinZipSFX.cs
index 39fde7a9..c44f1583 100644
--- a/BurnOutSharp/PackerType/WinZipSFX.cs
+++ b/BurnOutSharp/PackerType/WinZipSFX.cs
@@ -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);
}
///
diff --git a/BurnOutSharp/PackerType/WiseInstaller.cs b/BurnOutSharp/PackerType/WiseInstaller.cs
index 7df7d59b..ee221894 100644
--- a/BurnOutSharp/PackerType/WiseInstaller.cs
+++ b/BurnOutSharp/PackerType/WiseInstaller.cs
@@ -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);
}
///
diff --git a/BurnOutSharp/PackerType/dotFuscator.cs b/BurnOutSharp/PackerType/dotFuscator.cs
index 43ff6fe8..931a1e07 100644
--- a/BurnOutSharp/PackerType/dotFuscator.cs
+++ b/BurnOutSharp/PackerType/dotFuscator.cs
@@ -19,7 +19,7 @@ namespace BurnOutSharp.PackerType
}, "dotFuscator"),
};
- return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
+ return MatchUtil.GetFirstContentMatch(file, fileContent, matchers, includePosition);
}
}
}
diff --git a/BurnOutSharp/ProtectionType/ActiveMARK.cs b/BurnOutSharp/ProtectionType/ActiveMARK.cs
index 52712d6e..d7b6be96 100644
--- a/BurnOutSharp/ProtectionType/ActiveMARK.cs
+++ b/BurnOutSharp/ProtectionType/ActiveMARK.cs
@@ -22,7 +22,7 @@ namespace BurnOutSharp.ProtectionType
}, "ActiveMARK 5"),
};
- return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
+ return MatchUtil.GetFirstContentMatch(file, fileContent, matchers, includePosition);
}
}
}
diff --git a/BurnOutSharp/ProtectionType/AlphaROM.cs b/BurnOutSharp/ProtectionType/AlphaROM.cs
index 0cb4448b..01c06a4c 100644
--- a/BurnOutSharp/ProtectionType/AlphaROM.cs
+++ b/BurnOutSharp/ProtectionType/AlphaROM.cs
@@ -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);
}
}
}
diff --git a/BurnOutSharp/ProtectionType/CDCheck.cs b/BurnOutSharp/ProtectionType/CDCheck.cs
index e8e069d4..6408866d 100644
--- a/BurnOutSharp/ProtectionType/CDCheck.cs
+++ b/BurnOutSharp/ProtectionType/CDCheck.cs
@@ -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);
}
}
}
diff --git a/BurnOutSharp/ProtectionType/CDCops.cs b/BurnOutSharp/ProtectionType/CDCops.cs
index 8ebabe53..356f7b3e 100644
--- a/BurnOutSharp/ProtectionType/CDCops.cs
+++ b/BurnOutSharp/ProtectionType/CDCops.cs
@@ -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);
}
///
diff --git a/BurnOutSharp/ProtectionType/CDLock.cs b/BurnOutSharp/ProtectionType/CDLock.cs
index 60a52933..9ad413db 100644
--- a/BurnOutSharp/ProtectionType/CDLock.cs
+++ b/BurnOutSharp/ProtectionType/CDLock.cs
@@ -23,7 +23,7 @@ namespace BurnOutSharp.ProtectionType
}, "CD-Lock"),
};
- return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
+ return MatchUtil.GetFirstContentMatch(file, fileContent, matchers, includePosition);
}
///
diff --git a/BurnOutSharp/ProtectionType/CDSHiELDSE.cs b/BurnOutSharp/ProtectionType/CDSHiELDSE.cs
index 90cf7d76..7fd5b644 100644
--- a/BurnOutSharp/ProtectionType/CDSHiELDSE.cs
+++ b/BurnOutSharp/ProtectionType/CDSHiELDSE.cs
@@ -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);
}
}
}
diff --git a/BurnOutSharp/ProtectionType/CactusDataShield.cs b/BurnOutSharp/ProtectionType/CactusDataShield.cs
index 60c04902..55ce78f8 100644
--- a/BurnOutSharp/ProtectionType/CactusDataShield.cs
+++ b/BurnOutSharp/ProtectionType/CactusDataShield.cs
@@ -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);
}
///
diff --git a/BurnOutSharp/ProtectionType/CengaProtectDVD.cs b/BurnOutSharp/ProtectionType/CengaProtectDVD.cs
index 70e331e9..de121a8e 100644
--- a/BurnOutSharp/ProtectionType/CengaProtectDVD.cs
+++ b/BurnOutSharp/ProtectionType/CengaProtectDVD.cs
@@ -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);
}
}
}
diff --git a/BurnOutSharp/ProtectionType/CodeLock.cs b/BurnOutSharp/ProtectionType/CodeLock.cs
index a03c8d15..81ed4d3e 100644
--- a/BurnOutSharp/ProtectionType/CodeLock.cs
+++ b/BurnOutSharp/ProtectionType/CodeLock.cs
@@ -25,7 +25,7 @@ namespace BurnOutSharp.ProtectionType
}, "Code Lock"),
};
- return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
+ return MatchUtil.GetFirstContentMatch(file, fileContent, matchers, includePosition);
}
}
}
diff --git a/BurnOutSharp/ProtectionType/CopyKiller.cs b/BurnOutSharp/ProtectionType/CopyKiller.cs
index 6fb404e1..b96c9fbd 100644
--- a/BurnOutSharp/ProtectionType/CopyKiller.cs
+++ b/BurnOutSharp/ProtectionType/CopyKiller.cs
@@ -21,7 +21,7 @@ namespace BurnOutSharp.ProtectionType
}, "CopyKiller"),
};
- return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
+ return MatchUtil.GetFirstContentMatch(file, fileContent, matchers, includePosition);
}
///
diff --git a/BurnOutSharp/ProtectionType/DVDCops.cs b/BurnOutSharp/ProtectionType/DVDCops.cs
index ad7b014b..7118cbe8 100644
--- a/BurnOutSharp/ProtectionType/DVDCops.cs
+++ b/BurnOutSharp/ProtectionType/DVDCops.cs
@@ -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)
diff --git a/BurnOutSharp/ProtectionType/ElectronicArts.cs b/BurnOutSharp/ProtectionType/ElectronicArts.cs
index 7874658e..1af77592 100644
--- a/BurnOutSharp/ProtectionType/ElectronicArts.cs
+++ b/BurnOutSharp/ProtectionType/ElectronicArts.cs
@@ -106,7 +106,7 @@ namespace BurnOutSharp.ProtectionType
}, "EA DRM Protection"),
};
- return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
+ return MatchUtil.GetFirstContentMatch(file, fileContent, matchers, includePosition);
}
}
}
diff --git a/BurnOutSharp/ProtectionType/GFWL.cs b/BurnOutSharp/ProtectionType/GFWL.cs
index 579a8908..151a710f 100644
--- a/BurnOutSharp/ProtectionType/GFWL.cs
+++ b/BurnOutSharp/ProtectionType/GFWL.cs
@@ -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);
}
///
diff --git a/BurnOutSharp/ProtectionType/Intenium.cs b/BurnOutSharp/ProtectionType/Intenium.cs
index 21e1c399..ca8c74e8 100644
--- a/BurnOutSharp/ProtectionType/Intenium.cs
+++ b/BurnOutSharp/ProtectionType/Intenium.cs
@@ -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);
}
}
}
diff --git a/BurnOutSharp/ProtectionType/KeyLock.cs b/BurnOutSharp/ProtectionType/KeyLock.cs
index cf8015db..9f20eb2f 100644
--- a/BurnOutSharp/ProtectionType/KeyLock.cs
+++ b/BurnOutSharp/ProtectionType/KeyLock.cs
@@ -18,7 +18,7 @@ namespace BurnOutSharp.ProtectionType
}, "Key-Lock (Dongle)"),
};
- return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
+ return MatchUtil.GetFirstContentMatch(file, fileContent, matchers, includePosition);
}
}
}
diff --git a/BurnOutSharp/ProtectionType/MediaMaxCD3.cs b/BurnOutSharp/ProtectionType/MediaMaxCD3.cs
index 906f9584..0e363aea 100644
--- a/BurnOutSharp/ProtectionType/MediaMaxCD3.cs
+++ b/BurnOutSharp/ProtectionType/MediaMaxCD3.cs
@@ -24,7 +24,7 @@ namespace BurnOutSharp.ProtectionType
}, "MediaMax CD-3"),
};
- return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
+ return MatchUtil.GetFirstContentMatch(file, fileContent, matchers, includePosition);
}
///
diff --git a/BurnOutSharp/ProtectionType/OnlineRegistration.cs b/BurnOutSharp/ProtectionType/OnlineRegistration.cs
index 33a52789..8aeb9f1c 100644
--- a/BurnOutSharp/ProtectionType/OnlineRegistration.cs
+++ b/BurnOutSharp/ProtectionType/OnlineRegistration.cs
@@ -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);
}
}
}
diff --git a/BurnOutSharp/ProtectionType/Origin.cs b/BurnOutSharp/ProtectionType/Origin.cs
index ce3120ce..dd2914f2 100644
--- a/BurnOutSharp/ProtectionType/Origin.cs
+++ b/BurnOutSharp/ProtectionType/Origin.cs
@@ -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);
}
///
diff --git a/BurnOutSharp/ProtectionType/PSXAntiModchip.cs b/BurnOutSharp/ProtectionType/PSXAntiModchip.cs
index 23a3a8e9..26c0034b 100644
--- a/BurnOutSharp/ProtectionType/PSXAntiModchip.cs
+++ b/BurnOutSharp/ProtectionType/PSXAntiModchip.cs
@@ -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);
}
}
}
diff --git a/BurnOutSharp/ProtectionType/RingPROTECH.cs b/BurnOutSharp/ProtectionType/RingPROTECH.cs
index c7396b4f..1e2be7d0 100644
--- a/BurnOutSharp/ProtectionType/RingPROTECH.cs
+++ b/BurnOutSharp/ProtectionType/RingPROTECH.cs
@@ -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);
}
}
}
diff --git a/BurnOutSharp/ProtectionType/SVKProtector.cs b/BurnOutSharp/ProtectionType/SVKProtector.cs
index 4635443a..64f4b3e2 100644
--- a/BurnOutSharp/ProtectionType/SVKProtector.cs
+++ b/BurnOutSharp/ProtectionType/SVKProtector.cs
@@ -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);
}
}
}
diff --git a/BurnOutSharp/ProtectionType/SafeLock.cs b/BurnOutSharp/ProtectionType/SafeLock.cs
index d5bbf222..3077ab31 100644
--- a/BurnOutSharp/ProtectionType/SafeLock.cs
+++ b/BurnOutSharp/ProtectionType/SafeLock.cs
@@ -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);
}
///
diff --git a/BurnOutSharp/ProtectionType/SecuROM.cs b/BurnOutSharp/ProtectionType/SecuROM.cs
index 64288112..9b290ded 100644
--- a/BurnOutSharp/ProtectionType/SecuROM.cs
+++ b/BurnOutSharp/ProtectionType/SecuROM.cs
@@ -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);
}
///
diff --git a/BurnOutSharp/ProtectionType/SmartE.cs b/BurnOutSharp/ProtectionType/SmartE.cs
index 1e6f5def..71c9022b 100644
--- a/BurnOutSharp/ProtectionType/SmartE.cs
+++ b/BurnOutSharp/ProtectionType/SmartE.cs
@@ -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);
}
///
diff --git a/BurnOutSharp/ProtectionType/Sysiphus.cs b/BurnOutSharp/ProtectionType/Sysiphus.cs
index c9597c9b..1b7418aa 100644
--- a/BurnOutSharp/ProtectionType/Sysiphus.cs
+++ b/BurnOutSharp/ProtectionType/Sysiphus.cs
@@ -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)
diff --git a/BurnOutSharp/ProtectionType/ThreePLock.cs b/BurnOutSharp/ProtectionType/ThreePLock.cs
index f61856c1..3ef1b077 100644
--- a/BurnOutSharp/ProtectionType/ThreePLock.cs
+++ b/BurnOutSharp/ProtectionType/ThreePLock.cs
@@ -28,7 +28,7 @@ namespace BurnOutSharp.ProtectionType
// }, "3PLock"),
};
- return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
+ return MatchUtil.GetFirstContentMatch(file, fileContent, matchers, includePosition);
}
}
}
diff --git a/BurnOutSharp/ProtectionType/ThreeTwoOneStudios.cs b/BurnOutSharp/ProtectionType/ThreeTwoOneStudios.cs
index 0f226324..e4d3a115 100644
--- a/BurnOutSharp/ProtectionType/ThreeTwoOneStudios.cs
+++ b/BurnOutSharp/ProtectionType/ThreeTwoOneStudios.cs
@@ -22,7 +22,7 @@ namespace BurnOutSharp.ProtectionType
}, "321Studios Online Activation"),
};
- return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
+ return MatchUtil.GetFirstContentMatch(file, fileContent, matchers, includePosition);
}
}
}
diff --git a/BurnOutSharp/ProtectionType/WTMCDProtect.cs b/BurnOutSharp/ProtectionType/WTMCDProtect.cs
index 08014d22..c9b9ff2e 100644
--- a/BurnOutSharp/ProtectionType/WTMCDProtect.cs
+++ b/BurnOutSharp/ProtectionType/WTMCDProtect.cs
@@ -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);
}
///
diff --git a/BurnOutSharp/ProtectionType/XCP.cs b/BurnOutSharp/ProtectionType/XCP.cs
index 5e8ab71c..936484e5 100644
--- a/BurnOutSharp/ProtectionType/XCP.cs
+++ b/BurnOutSharp/ProtectionType/XCP.cs
@@ -32,7 +32,7 @@ namespace BurnOutSharp.ProtectionType
}, "XCP"),
};
- return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
+ return MatchUtil.GetFirstContentMatch(file, fileContent, matchers, includePosition);
}
///
diff --git a/BurnOutSharp/ProtectionType/XtremeProtector.cs b/BurnOutSharp/ProtectionType/XtremeProtector.cs
index e45e14e7..2592ae6c 100644
--- a/BurnOutSharp/ProtectionType/XtremeProtector.cs
+++ b/BurnOutSharp/ProtectionType/XtremeProtector.cs
@@ -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);
}
}
}
diff --git a/BurnOutSharp/Utilities.cs b/BurnOutSharp/Utilities.cs
index fd8bcd07..36a5ea63 100644
--- a/BurnOutSharp/Utilities.cs
+++ b/BurnOutSharp/Utilities.cs
@@ -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
///
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
///
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);
}
- ///
- /// Find the position of one array in another, if possible
- ///
- 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);
- }
-
- ///
- /// Get if a stack at a certain index is equal to a needle
- ///
- 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
- ///
- /// Get all content matches for a given list of matchers
- ///
- /// File to check for matches
- /// Byte array representing the file contents
- /// Enumerable of matchers to be run on the file
- /// True to include positional data, false otherwise
- /// List of strings representing the matched protections, null or empty otherwise
- public static List GetAllContentMatches(string file, byte[] fileContent, IEnumerable matchers, bool includePosition = false)
- {
- return FindAllContentMatches(file, fileContent, matchers, includePosition, false);
- }
-
- ///
- /// Get first content match for a given list of matchers
- ///
- /// File to check for matches
- /// Byte array representing the file contents
- /// Enumerable of matchers to be run on the file
- /// True to include positional data, false otherwise
- /// String representing the matched protection, null otherwise
- public static string GetFirstContentMatch(string file, byte[] fileContent, IEnumerable matchers, bool includePosition = false)
- {
- var contentMatches = FindAllContentMatches(file, fileContent, matchers, includePosition, false);
- if (contentMatches == null || !contentMatches.Any())
- return null;
-
- return contentMatches.First();
- }
-
///
/// Get the file version as reported by the filesystem
///
@@ -382,79 +307,6 @@ namespace BurnOutSharp
}
}
- ///
- /// Get the required set of content matches on a per Matcher basis
- ///
- /// File to check for matches
- /// Byte array representing the file contents
- /// Enumerable of matchers to be run on the file
- /// True to include positional data, false otherwise
- /// True to stop after the first match, false otherwise
- /// List of strings representing the matched protections, null or empty otherwise
- private static List FindAllContentMatches(
- string file,
- byte[] fileContent,
- IEnumerable 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 matchedProtections = new List();
-
- // Loop through and try everything otherwise
- foreach (var matcher in matchers)
- {
- // Setup for a single matcher
- bool allMatches = true;
- List positions = new List();
-
- // 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
}
}