Use content matching helper, part 5

This commit is contained in:
Matt Nadareski
2021-03-21 22:37:16 -07:00
parent cf9bd99f3d
commit 15ae2441c3
42 changed files with 157 additions and 87 deletions

View File

@@ -17,7 +17,7 @@ namespace BurnOutSharp.PackerType
new Matcher(new byte?[] { 0x41, 0x52, 0x4D, 0x44, 0x45, 0x42, 0x55, 0x47 }, "Armadillo"),
};
return Utilities.GetContentMatches(file, fileContent, matchers, includePosition);
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
}
}
}

View File

@@ -21,7 +21,7 @@ namespace BurnOutSharp.PackerType
}, "EXE Stealth"),
};
return Utilities.GetContentMatches(file, fileContent, matchers, includePosition);
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
}
}
}

View File

@@ -23,7 +23,7 @@ namespace BurnOutSharp.PackerType
"Inno Setup"),
};
return Utilities.GetContentMatches(file, fileContent, matchers, includePosition);
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
}
/// <inheritdoc/>

View File

@@ -29,7 +29,7 @@ namespace BurnOutSharp.PackerType
}, "NSIS"),
};
return Utilities.GetContentMatches(file, fileContent, matchers, includePosition);
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
}
public static string GetVersion(string file, byte[] fileContent, int index)

View File

@@ -27,7 +27,7 @@ namespace BurnOutSharp.PackerType
}, "PE Compact 2"),
};
return Utilities.GetContentMatches(file, fileContent, matchers, includePosition);
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
}
public static string GetVersion(string file, byte[] fileContent, int position)

View File

@@ -28,7 +28,7 @@ namespace BurnOutSharp.PackerType
}, GetVersion, "Setup Factory"),
};
return Utilities.GetContentMatches(file, fileContent, matchers, includePosition);
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
}
/// <inheritdoc/>

View File

@@ -42,7 +42,7 @@ namespace BurnOutSharp.PackerType
),
};
return Utilities.GetContentMatches(file, fileContent, matchers, includePosition);
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
}
public static string GetVersion(string file, byte[] fileContent, int index)

View File

@@ -26,7 +26,7 @@ namespace BurnOutSharp.PackerType
}, "WinRAR SFX"),
};
return Utilities.GetContentMatches(file, fileContent, matchers, includePosition);
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
}
public Dictionary<string, List<string>> Scan(Scanner scanner, string file)

View 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.GetContentMatches(file, fileContent, matchers, includePosition);
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
}
/// <inheritdoc/>

View File

@@ -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.GetContentMatches(file, fileContent, matchers, includePosition);
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
}
/// <inheritdoc/>

View File

@@ -19,7 +19,7 @@ namespace BurnOutSharp.PackerType
}, "dotFuscator"),
};
return Utilities.GetContentMatches(file, fileContent, matchers, includePosition);
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
}
}
}

View File

@@ -22,7 +22,7 @@ namespace BurnOutSharp.ProtectionType
}, "ActiveMARK 5"),
};
return Utilities.GetContentMatches(file, fileContent, matchers, includePosition);
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
}
}
}

View File

@@ -14,7 +14,7 @@ namespace BurnOutSharp.ProtectionType
new Matcher(new byte?[] { 0x53, 0x45, 0x54, 0x54, 0x45, 0x43 }, "Alpha-ROM"),
};
return Utilities.GetContentMatches(file, fileContent, matchers, includePosition);
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
}
}
}

View File

@@ -21,7 +21,7 @@ namespace BurnOutSharp.ProtectionType
new Matcher(new byte?[] { 0x43, 0x44, 0x43, 0x68, 0x65, 0x63, 0x6B }, "Executable-Based CD Check"),
};
return Utilities.GetContentMatches(file, fileContent, matchers, includePosition);
return Utilities.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.GetContentMatches(file, fileContent, matchers, includePosition);
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
}
}
}

View File

@@ -24,7 +24,7 @@ namespace BurnOutSharp.ProtectionType
new Matcher(new byte?[] { 0x2E, 0x67, 0x72, 0x61, 0x6E, 0x64, 0x00 }, "CD-Cops"),
};
return Utilities.GetContentMatches(file, fileContent, matchers, includePosition);
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
}
/// <inheritdoc/>

View File

@@ -23,7 +23,7 @@ namespace BurnOutSharp.ProtectionType
}, "CD-Lock"),
};
return Utilities.GetContentMatches(file, fileContent, matchers, includePosition);
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
}
/// <inheritdoc/>

View File

@@ -14,7 +14,7 @@ namespace BurnOutSharp.ProtectionType
new Matcher(new byte?[] { 0x7E, 0x30, 0x30, 0x31, 0x37, 0x2E, 0x74, 0x6D, 0x70 }, "CDSHiELD SE"),
};
return Utilities.GetContentMatches(file, fileContent, matchers, includePosition);
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
}
}
}

View File

@@ -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.GetContentMatches(file, fileContent, matchers, includePosition);
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
}
/// <inheritdoc/>

View File

@@ -14,7 +14,7 @@ namespace BurnOutSharp.ProtectionType
new Matcher(new byte?[] { 0x2E, 0x63, 0x65, 0x6E, 0x65, 0x67, 0x61 }, "Cenega ProtectDVD"),
};
return Utilities.GetContentMatches(file, fileContent, matchers, includePosition);
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
}
}
}

View File

@@ -25,7 +25,7 @@ namespace BurnOutSharp.ProtectionType
}, "Code Lock"),
};
return Utilities.GetContentMatches(file, fileContent, matchers, includePosition);
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
}
}
}

View File

@@ -21,7 +21,7 @@ namespace BurnOutSharp.ProtectionType
}, "CopyKiller"),
};
return Utilities.GetContentMatches(file, fileContent, matchers, includePosition);
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
}
/// <inheritdoc/>

View File

@@ -20,7 +20,7 @@ namespace BurnOutSharp.ProtectionType
}, GetVersion, "DVD-Cops"),
};
return Utilities.GetContentMatches(file, fileContent, matchers, includePosition);
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
}
public static string GetVersion(string file, byte[] fileContent, int position)

View File

@@ -106,7 +106,7 @@ namespace BurnOutSharp.ProtectionType
}, "EA DRM Protection"),
};
return Utilities.GetContentMatches(file, fileContent, matchers, includePosition);
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
}
}
}

View File

@@ -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.GetContentMatches(file, fileContent, matchers, includePosition);
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
}
/// <inheritdoc/>

View File

@@ -30,7 +30,7 @@ namespace BurnOutSharp.ProtectionType
new Matcher(new byte?[] { 0x54, 0x72, 0x69, 0x61, 0x6C, 0x00, 0x50 }, "INTENIUM Trial & Buy Protection"),
};
return Utilities.GetContentMatches(file, fileContent, matchers, includePosition);
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
}
}
}

View File

@@ -18,7 +18,7 @@ namespace BurnOutSharp.ProtectionType
}, "Key-Lock (Dongle)"),
};
return Utilities.GetContentMatches(file, fileContent, matchers, includePosition);
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
}
}
}

View File

@@ -24,7 +24,7 @@ namespace BurnOutSharp.ProtectionType
}, "MediaMax CD-3"),
};
return Utilities.GetContentMatches(file, fileContent, matchers, includePosition);
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
}
/// <inheritdoc/>

View File

@@ -21,7 +21,7 @@ namespace BurnOutSharp.ProtectionType
}, Utilities.GetFileVersion, "Executable-Based Online Registration"),
};
return Utilities.GetContentMatches(file, fileContent, matchers, includePosition);
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
}
}
}

View File

@@ -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.GetContentMatches(file, fileContent, matchers, includePosition);
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
}
/// <inheritdoc/>

View File

@@ -42,7 +42,7 @@ namespace BurnOutSharp.ProtectionType
}, "PlayStation Anti-modchip (Japanese)"),
};
return Utilities.GetContentMatches(file, fileContent, matchers, includePosition);
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
}
}
}

View File

@@ -19,7 +19,7 @@ namespace BurnOutSharp.ProtectionType
}, "Ring PROTECH [Check disc for physical ring]"),
};
return Utilities.GetContentMatches(file, fileContent, matchers, includePosition);
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
}
}
}

View File

@@ -14,7 +14,7 @@ namespace BurnOutSharp.ProtectionType
new Matcher(new byte?[] { 0x3F, 0x53, 0x56, 0x4B, 0x50, 0x00, 0x00 }, "SVK Protector"),
};
return Utilities.GetContentMatches(file, fileContent, matchers, includePosition);
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
}
}
}

View File

@@ -17,7 +17,7 @@ namespace BurnOutSharp.ProtectionType
new Matcher(new byte?[] { 0x53, 0x61, 0x66, 0x65, 0x4C, 0x6F, 0x63, 0x6B }, "SafeLock"),
};
return Utilities.GetContentMatches(file, fileContent, matchers, includePosition);
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
}
/// <inheritdoc/>

View File

@@ -46,7 +46,7 @@ namespace BurnOutSharp.ProtectionType
new Matcher(new byte?[] { 0x2E, 0x63, 0x6D, 0x73, 0x5F, 0x64, 0x00 }, "SecuROM 1-3"),
};
return Utilities.GetContentMatches(file, fileContent, matchers, includePosition);
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
}
/// <inheritdoc/>

View File

@@ -17,7 +17,7 @@ namespace BurnOutSharp.ProtectionType
new Matcher(new byte?[] { 0x42, 0x49, 0x54, 0x41, 0x52, 0x54, 0x53 }, "SmartE"),
};
return Utilities.GetContentMatches(file, fileContent, matchers, includePosition);
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
}
/// <inheritdoc/>

View File

@@ -25,7 +25,7 @@ namespace BurnOutSharp.ProtectionType
}, GetVersion, "Sysiphus"),
};
return Utilities.GetContentMatches(file, fileContent, matchers, includePosition);
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
}
public static string GetVersion(string file, byte[] fileContent, int position)

View File

@@ -28,7 +28,7 @@ namespace BurnOutSharp.ProtectionType
// }, "3PLock"),
};
return Utilities.GetContentMatches(file, fileContent, matchers, includePosition);
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
}
}
}

View File

@@ -22,7 +22,7 @@ namespace BurnOutSharp.ProtectionType
}, "321Studios Online Activation"),
};
return Utilities.GetContentMatches(file, fileContent, matchers, includePosition);
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
}
}
}

View File

@@ -17,7 +17,7 @@ namespace BurnOutSharp.ProtectionType
new Matcher(new byte?[] { 0x57, 0x54, 0x4D, 0x37, 0x36, 0x35, 0x34, 0x35 }, "WTM CD Protect"),
};
return Utilities.GetContentMatches(file, fileContent, matchers, includePosition);
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
}
/// <inheritdoc/>

View File

@@ -32,7 +32,7 @@ namespace BurnOutSharp.ProtectionType
}, "XCP"),
};
return Utilities.GetContentMatches(file, fileContent, matchers, includePosition);
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
}
/// <inheritdoc/>

View File

@@ -14,7 +14,7 @@ namespace BurnOutSharp.ProtectionType
new Matcher(new byte?[] { 0x58, 0x50, 0x52, 0x4F, 0x54, 0x20, 0x20, 0x20 }, "Xtreme-Protector"),
};
return Utilities.GetContentMatches(file, fileContent, matchers, includePosition);
return Utilities.GetFirstContentMatch(file, fileContent, matchers, includePosition);
}
}
}

View File

@@ -157,6 +157,29 @@ namespace BurnOutSharp
#region Byte Arrays
/// <summary>
/// Find all positions of one array in another, if possible, if possible
/// </summary>
public static List<int> FindAllPositions(this byte[] stack, byte?[] needle, int start = 0, int end = -1)
{
// Get the outgoing list
List<int> positions = new List<int>();
// Initialize the loop variables
bool found = true;
int lastPosition = start;
// Loop over and get all positions
while (found)
{
(found, lastPosition) = FindPosition(stack, needle, lastPosition, end, false);
if (found)
positions.Add(lastPosition);
}
return positions;
}
/// <summary>
/// Find the first position of one array in another, if possible
/// </summary>
@@ -247,59 +270,33 @@ namespace BurnOutSharp
#region Protection
/// <summary>
/// Get content matches for a given protection
/// 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>
/// TODO: Make variant of this that returns *all* content matches for later
public static string GetContentMatches(string file, byte[] fileContent, IEnumerable<Matcher> matchers, bool includePosition = false)
public static string GetFirstContentMatch(string file, byte[] fileContent, IEnumerable<Matcher> matchers, bool includePosition = false)
{
// If there's no mappings, we can't match
if (matchers == null || !matchers.Any())
var contentMatches = FindAllContentMatches(file, fileContent, matchers, includePosition, false);
if (contentMatches == null || !contentMatches.Any())
return null;
// 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)
return (matcher.ProtectionName ?? "Unknown Protection") + (includePosition ? $" (Index {positionsString})" : string.Empty);
// Otherwise, invoke the version method
// TODO: Pass all positions to the version finding method
string version = matcher.GetVersion(file, fileContent, positions[0]) ?? "Unknown Version";
return $"{matcher.ProtectionName} {version}" + (includePosition ? $" (Index {positionsString})" : string.Empty);
}
return null;
return contentMatches.First();
}
/// <summary>
@@ -385,6 +382,79 @@ 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
}
}