More incidental cleanup

This commit is contained in:
Matt Nadareski
2024-11-21 01:32:30 -05:00
parent 07a183955b
commit 9e205ddf2a
52 changed files with 591 additions and 664 deletions

View File

@@ -19,8 +19,7 @@ namespace BinaryObjectScanner.Packer
return null;
// Get the .aspack section, if it exists
bool aspackSection = pex.ContainsSection(".aspack", exact: true);
if (aspackSection)
if (pex.ContainsSection(".aspack", exact: true))
return "ASPack 2.29";
// TODO: Re-enable all Entry Point checks after implementing
@@ -60,10 +59,10 @@ namespace BinaryObjectScanner.Packer
/// Generate the set of matchers used for each section
/// </summary>
/// <returns></returns>
private List<ContentMatchSet> GenerateMatchers()
private static List<ContentMatchSet> GenerateMatchers()
{
return new List<ContentMatchSet>
{
return
[
#region No Wildcards (Long)
new(new byte?[]
@@ -641,7 +640,7 @@ namespace BinaryObjectScanner.Packer
new(new byte?[] { 0x60, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x5D, 0x81, 0xED }, "ASPack 1.02b/1.08.03"),
#endregion
};
];
}
}
}

View File

@@ -27,7 +27,7 @@ namespace BinaryObjectScanner.Packer
name = Utilities.GetLegalCopyright(pex);
if (name?.StartsWith("Runtime Engine", StringComparison.OrdinalIgnoreCase) == true)
return $"AutoPlay Media Studio {GetVersion(pex)}";
*/
*/
return null;
}
@@ -38,7 +38,7 @@ namespace BinaryObjectScanner.Packer
return false;
}
private string GetVersion(PortableExecutable pex)
private static string GetVersion(PortableExecutable pex)
{
// Check the product version explicitly
var version = pex.ProductVersion;

View File

@@ -29,17 +29,17 @@ namespace BinaryObjectScanner.Packer
if (pex.StubExecutableData != null)
{
var matchers = new List<ContentMatchSet>
{
new(new byte?[]
{
0x25, 0x57, 0x6F, 0xC1, 0x61, 0x36, 0x01, 0x92,
0x61, 0x36, 0x01, 0x92, 0x61, 0x36, 0x01, 0x92,
0x61, 0x36, 0x00, 0x92, 0x7B, 0x36, 0x01, 0x92,
0x03, 0x29, 0x12, 0x92, 0x66, 0x36, 0x01, 0x92,
0x89, 0x29, 0x0A, 0x92, 0x60, 0x36, 0x01, 0x92,
0xD9, 0x30, 0x07, 0x92, 0x60, 0x36, 0x01, 0x92
}, "CExe")
};
new(new byte?[]
{
0x25, 0x57, 0x6F, 0xC1, 0x61, 0x36, 0x01, 0x92,
0x61, 0x36, 0x01, 0x92, 0x61, 0x36, 0x01, 0x92,
0x61, 0x36, 0x00, 0x92, 0x7B, 0x36, 0x01, 0x92,
0x03, 0x29, 0x12, 0x92, 0x66, 0x36, 0x01, 0x92,
0x89, 0x29, 0x0A, 0x92, 0x60, 0x36, 0x01, 0x92,
0xD9, 0x30, 0x07, 0x92, 0x60, 0x36, 0x01, 0x92
}, "CExe")
};
var match = MatchUtil.GetFirstMatch(file, pex.StubExecutableData, matchers, includeDebug);
if (!string.IsNullOrEmpty(match))
@@ -64,14 +64,11 @@ namespace BinaryObjectScanner.Packer
if (payload == null || payload.Length == 0)
return false;
// Determine which compression was used
bool zlib = pex.FindResourceByNamedType("99, 1").Count > 0;
// Create the output data buffer
var data = new byte[0];
byte[]? data = [];
// If we had the decompression DLL included, it's zlib
if (zlib)
if (pex.FindResourceByNamedType("99, 1").Count > 0)
{
try
{

View File

@@ -28,71 +28,67 @@ namespace BinaryObjectScanner.Packer
return null;
// Get the .text section, if it exists
if (pex.ContainsSection(".text"))
var textData = pex.GetFirstSectionData(".text");
if (textData != null)
{
var textData = pex.GetFirstSectionData(".text");
if (textData != null)
var matchers = new List<ContentMatchSet>
{
var matchers = new List<ContentMatchSet>
// Adapted from https://github.com/cod3nym/detection-rules/blob/main/yara/dotnet/obf_net_reactor.yar and confirmed to work with "KalypsoLauncher.dll" from Redump entry 95617.
// <PrivateImplementationDetails>{[8]-[4]-[4]-[4]-[12]}
new(new byte?[]
{
// Adapted from https://github.com/cod3nym/detection-rules/blob/main/yara/dotnet/obf_net_reactor.yar and confirmed to work with "KalypsoLauncher.dll" from Redump entry 95617.
// <PrivateImplementationDetails>{[8]-[4]-[4]-[4]-[12]}
new(new byte?[]
{
0x3C, 0x50, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65,
0x49, 0x6D, 0x70, 0x6C, 0x65, 0x6D, 0x65, 0x6E,
0x74, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x44, 0x65,
0x74, 0x61, 0x69, 0x6C, 0x73, 0x3E, 0x7B, null,
null, null, null, null, null, null, null, 0x2D,
null, null, null, null, 0x2D, null, null, null,
null, 0x2D, null, null, null, null, 0x2D, null,
null, null, null, null, null, null, null, null,
null, null, null, 0x7D
}, ".NET Reactor"),
0x3C, 0x50, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65,
0x49, 0x6D, 0x70, 0x6C, 0x65, 0x6D, 0x65, 0x6E,
0x74, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x44, 0x65,
0x74, 0x61, 0x69, 0x6C, 0x73, 0x3E, 0x7B, null,
null, null, null, null, null, null, null, 0x2D,
null, null, null, null, 0x2D, null, null, null,
null, 0x2D, null, null, null, null, 0x2D, null,
null, null, null, null, null, null, null, null,
null, null, null, 0x7D
}, ".NET Reactor"),
// Modified from the previous detection to detect a presumably newer version of .NET Reactor found in "KalypsoLauncher.dll" version 2.0.4.2.
// TODO: Check if this can/should be made more specific.
// <PrivateImplementationDetails>.RSA
new(new byte?[]
{
0x3C, 0x50, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65,
0x49, 0x6D, 0x70, 0x6C, 0x65, 0x6D, 0x65, 0x6E,
0x74, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x44, 0x65,
0x74, 0x61, 0x69, 0x6C, 0x73, 0x3E, 0x00, 0x52,
0x53, 0x41
}, ".NET Reactor"),
// Modified from the previous detection to detect a presumably newer version of .NET Reactor found in "KalypsoLauncher.dll" version 2.0.4.2.
// TODO: Check if this can/should be made more specific.
// <PrivateImplementationDetails>.RSA
new(new byte?[]
{
0x3C, 0x50, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65,
0x49, 0x6D, 0x70, 0x6C, 0x65, 0x6D, 0x65, 0x6E,
0x74, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x44, 0x65,
0x74, 0x61, 0x69, 0x6C, 0x73, 0x3E, 0x00, 0x52,
0x53, 0x41
}, ".NET Reactor"),
// Adapted from https://github.com/cod3nym/detection-rules/blob/main/yara/dotnet/obf_net_reactor.yar and confirmed to work with "KalypsoLauncher.dll" from Redump entry 95617.
// 3{.[9].-.[9].-.[9].}
new(new byte?[]
{
0x33, 0x7B, 0x00, null, null, null, null, null,
null, null, null, null, 0x00, 0x2D, 0x00, null,
null, null, null, null, null, null, null, null,
0x00, 0x2D, 0x00, null, null, null, null, null,
null, null, null, null, 0x00, 0x2D, 0x00, null,
null, null, null, null, null, null, null, null,
0x00, 0x7D, 0x00
}, ".NET Reactor (Unconfirmed - Please report to us on GitHub)"),
// Adapted from https://github.com/cod3nym/detection-rules/blob/main/yara/dotnet/obf_net_reactor.yar and confirmed to work with "KalypsoLauncher.dll" from Redump entry 95617.
// <Module>{[8]-[4]-[4]-[4]-[12]}
new(new byte?[]
{
0x3C, 0x4D, 0x6F, 0x64, 0x75, 0x6C, 0x65, 0x3E,
0x7B, null, null, null, null, null, null, null,
null, 0x2D, null, null, null, null, 0x2D, null,
null, null, null, 0x2D, null, null, null, null,
0x2D, null, null, null, null, null, null, null,
null, null, null, null, null, 0x7D
}, ".NET Reactor (Unconfirmed - Please report to us on GitHub)")
};
// Adapted from https://github.com/cod3nym/detection-rules/blob/main/yara/dotnet/obf_net_reactor.yar and confirmed to work with "KalypsoLauncher.dll" from Redump entry 95617.
// 3{.[9].-.[9].-.[9].}
new(new byte?[]
{
0x33, 0x7B, 0x00, null, null, null, null, null,
null, null, null, null, 0x00, 0x2D, 0x00, null,
null, null, null, null, null, null, null, null,
0x00, 0x2D, 0x00, null, null, null, null, null,
null, null, null, null, 0x00, 0x2D, 0x00, null,
null, null, null, null, null, null, null, null,
0x00, 0x7D, 0x00
}, ".NET Reactor (Unconfirmed - Please report to us on GitHub)"),
// Adapted from https://github.com/cod3nym/detection-rules/blob/main/yara/dotnet/obf_net_reactor.yar and confirmed to work with "KalypsoLauncher.dll" from Redump entry 95617.
// <Module>{[8]-[4]-[4]-[4]-[12]}
new(new byte?[]
{
0x3C, 0x4D, 0x6F, 0x64, 0x75, 0x6C, 0x65, 0x3E,
0x7B, null, null, null, null, null, null, null,
null, 0x2D, null, null, null, null, 0x2D, null,
null, null, null, 0x2D, null, null, null, null,
0x2D, null, null, null, null, null, null, null,
null, null, null, null, null, 0x7D
}, ".NET Reactor (Unconfirmed - Please report to us on GitHub)")
};
return MatchUtil.GetFirstMatch(file, textData, matchers, includeDebug);
}
return MatchUtil.GetFirstMatch(file, textData, matchers, includeDebug);
}
return null;
}

View File

@@ -15,26 +15,25 @@ namespace BinaryObjectScanner.Packer
/// <inheritdoc/>
public string? CheckContents(string file, byte[] fileContent, bool includeDebug)
{
// Only allow during debug
if (!includeDebug)
return null;
// TODO: Obtain a sample to find where this string is in a typical executable
if (includeDebug)
var contentMatchSets = new List<ContentMatchSet>
{
var contentMatchSets = new List<ContentMatchSet>
{
// ??[[__[[_ + (char)0x00 + {{ + (char)0x0 + (char)0x00 + {{ + (char)0x00 + (char)0x00 + (char)0x00 + (char)0x00 + (char)0x0 + (char)0x00 + (char)0x00 + (char)0x00 + (char)0x00 + ?;??;??
new(new byte?[]
{
0x3F, 0x3F, 0x5B, 0x5B, 0x5F, 0x5F, 0x5B, 0x5B,
0x5F, 0x00, 0x7B, 0x7B, 0x00, 0x00, 0x7B, 0x7B,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x20, 0x3F, 0x3B, 0x3F, 0x3F, 0x3B, 0x3F,
0x3F
}, "EXE Stealth"),
};
// ??[[__[[_ + (char)0x00 + {{ + (char)0x0 + (char)0x00 + {{ + (char)0x00 + (char)0x00 + (char)0x00 + (char)0x00 + (char)0x0 + (char)0x00 + (char)0x00 + (char)0x00 + (char)0x00 + ?;??;??
new(new byte?[]
{
0x3F, 0x3F, 0x5B, 0x5B, 0x5F, 0x5F, 0x5B, 0x5B,
0x5F, 0x00, 0x7B, 0x7B, 0x00, 0x00, 0x7B, 0x7B,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x20, 0x3F, 0x3B, 0x3F, 0x3F, 0x3B, 0x3F,
0x3F
}, "EXE Stealth"),
};
return MatchUtil.GetFirstMatch(file, fileContent, contentMatchSets, includeDebug);
}
return null;
return MatchUtil.GetFirstMatch(file, fileContent, contentMatchSets, includeDebug);
}
/// <inheritdoc/>
@@ -57,18 +56,17 @@ namespace BinaryObjectScanner.Packer
// `ExeStealth V2 Shareware not for public - This text not in registered version - www.webtoolmaster.com`
// Get the ExeS/EXES section, if it exists
bool exesSection = pex.ContainsSection("ExeS", exact: true) || pex.ContainsSection("EXES", exact: true);
if (exesSection)
if (pex.ContainsSection("ExeS", exact: true))
return "EXE Stealth 2.41-2.75";
if (pex.ContainsSection("EXES", exact: true))
return "EXE Stealth 2.41-2.75";
// Get the mtw section, if it exists
bool mtwSection = pex.ContainsSection("mtw", exact: true);
if (mtwSection)
if (pex.ContainsSection("mtw", exact: true))
return "EXE Stealth 1.1";
// Get the rsrr section, if it exists
bool rsrrSection = pex.ContainsSection("rsrr", exact: true);
if (rsrrSection)
if (pex.ContainsSection("rsrr", exact: true))
return "EXE Stealth 2.76";
return null;

View File

@@ -21,11 +21,10 @@ namespace BinaryObjectScanner.Packer
// This check may be overly limiting, as it excludes the sample provided to DiE (https://github.com/horsicq/Detect-It-Easy/issues/102).
// TODO: Find further samples and invesitgate if the "peC" section is only present on specific versions.
bool peCSection = pex.ContainsSection("peC", exact: true);
bool importTableMatch = Array.Exists(pex.Model.ImportTable?.ImportDirectoryTable ?? [],
idte => idte?.Name == "KeRnEl32.dLl");
if (peCSection && importTableMatch)
if (pex.ContainsSection("peC", exact: true) && importTableMatch)
return "HyperTech CrackProof";
return null;

View File

@@ -15,13 +15,17 @@ namespace BinaryObjectScanner.Packer
public string? CheckExecutable(string file, NewExecutable nex, bool includeDebug)
{
// Check for "Inno" in the reserved words
if (nex.Model.Stub?.Header?.Reserved2?[4] == 0x6E49 && nex.Model.Stub?.Header?.Reserved2?[5] == 0x6F6E)
var reserved2 = nex.Model.Stub?.Header?.Reserved2;
if (reserved2 != null && reserved2.Length > 5)
{
string version = GetOldVersion(file, nex);
if (!string.IsNullOrEmpty(version))
return $"Inno Setup {version}";
return "Inno Setup (Unknown Version)";
if (reserved2[4] == 0x6E49 && reserved2[5] == 0x6F6E)
{
string version = GetOldVersion(file, nex);
if (!string.IsNullOrEmpty(version))
return $"Inno Setup {version}";
return "Inno Setup (Unknown Version)";
}
}
return null;
@@ -78,8 +82,8 @@ namespace BinaryObjectScanner.Packer
return MatchUtil.GetFirstMatch(file, data, matchers, false) ?? "Unknown 1.X";
}
return "Unknown 1.X";
return "Unknown 1.X";
}
}
}

View File

@@ -33,7 +33,7 @@ namespace BinaryObjectScanner.Packer
return false;
}
private string GetVersion(PortableExecutable pex)
private static string GetVersion(PortableExecutable pex)
{
// Check the internal versions
var version = pex.GetInternalVersion();

View File

@@ -51,7 +51,7 @@ namespace BinaryObjectScanner.Packer
return false;
}
private string GetVersion(PortableExecutable pex)
private static string GetVersion(PortableExecutable pex)
{
// Check the internal versions
var version = pex.GetInternalVersion();

View File

@@ -14,9 +14,9 @@ namespace BinaryObjectScanner.Packer
if (sections == null)
return null;
var description = pex.AssemblyDescription;
if (!string.IsNullOrEmpty(description) && description!.StartsWith("Nullsoft Install System"))
return $"NSIS {description.Substring("Nullsoft Install System".Length).Trim()}";
var name = pex.AssemblyDescription;
if (name?.StartsWith("Nullsoft Install System") == true)
return $"NSIS {name.Substring("Nullsoft Install System".Length).Trim()}";
// Get the .data/DATA section strings, if they exist
var strs = pex.GetFirstSectionStrings(".data") ?? pex.GetFirstSectionStrings("DATA");

View File

@@ -26,8 +26,7 @@ namespace BinaryObjectScanner.Packer
// Get the .neolit section, if it exists.
// TODO: Check if this section is also present in NeoLite 1.X.
bool neolitSection = pex.ContainsSection(".neolit", exact: true);
if (neolitSection)
if (pex.ContainsSection(".neolit", exact: true))
return "NeoLite";
// If more specific or additional checks are needed, "NeoLite Executable File Compressor" should be present

View File

@@ -23,13 +23,12 @@ namespace BinaryObjectScanner.Packer
// on the data in the file. This may be related to information in other fields
// Get the pec1 section, if it exists
bool pec1Section = pex.ContainsSection("pec1", exact: true);
if (pec1Section)
if (pex.ContainsSection("pec1", exact: true))
return "PE Compact v1.x";
// Get the PEC2 section, if it exists -- TODO: Verify this comment since it's pulling the .text section
var textSection = pex.GetFirstSection(".text", exact: true);
if (textSection != null && textSection.PointerToRelocations == 0x32434550)
if (textSection?.PointerToRelocations == 0x32434550)
{
if (textSection.PointerToLinenumbers != 0)
return $"PE Compact v{textSection.PointerToLinenumbers} (internal version)";

View File

@@ -16,8 +16,7 @@ namespace BinaryObjectScanner.Packer
return null;
// Get the .petite section, if it exists -- TODO: Is there a version number that can be found?
bool petiteSection = pex.ContainsSection(".petite", exact: true);
if (petiteSection)
if (pex.ContainsSection(".petite", exact: true))
return "PEtite";
return null;

View File

@@ -43,7 +43,7 @@ namespace BinaryObjectScanner.Packer
return false;
}
private string GetVersion(PortableExecutable pex)
private static string GetVersion(PortableExecutable pex)
{
// Check the product version explicitly
var version = pex.ProductVersion;

View File

@@ -16,9 +16,7 @@ namespace BinaryObjectScanner.Packer
return null;
// Get the .shrink0 and .shrink2 sections, if they exist -- TODO: Confirm if both are needed or either/or is fine
bool shrink0Section = pex.ContainsSection(".shrink0", true);
bool shrink2Section = pex.ContainsSection(".shrink2", true);
if (shrink0Section || shrink2Section)
if (pex.ContainsSection(".shrink0", true) || pex.ContainsSection(".shrink2", true))
return "Shrinker";
return null;

View File

@@ -73,10 +73,13 @@ namespace BinaryObjectScanner.Packer
{
// Check the normal version location first
int index = positions[0] - 5;
string versionString = Encoding.ASCII.GetString(fileContent, index, 4);
if (char.IsNumber(versionString[0]))
return versionString;
if (index >= 0 && index < fileContent.Length - 4)
{
string versionString = Encoding.ASCII.GetString(fileContent, index, 4);
if (char.IsNumber(versionString[0]))
return versionString;
}
// Check for the old-style string
//
// Example:
@@ -84,9 +87,12 @@ namespace BinaryObjectScanner.Packer
// $Id: UPX 1.02 Copyright (C) 1996-2000 the UPX Team. All Rights Reserved. $
// UPX!
index = positions[0] - 67;
versionString = Encoding.ASCII.GetString(fileContent, index, 4);
if (char.IsNumber(versionString[0]))
return versionString;
if (index >= 0 && index < fileContent.Length - 4)
{
string versionString = Encoding.ASCII.GetString(fileContent, index, 4);
if (char.IsNumber(versionString[0]))
return versionString;
}
return "(Unknown Version)";
}

View File

@@ -648,8 +648,10 @@ namespace BinaryObjectScanner.Packer
string assemblyVersion = pex.AssemblyVersion ?? "Unknown Version";
// Standard
if (sfxFileName == "VW95SE.SFX" || sfxFileName == "ST32E.SFX"
|| sfxFileName == "WZIPSE32.exe" || sfxFileName == "SI32LPG.SFX"
if (sfxFileName == "VW95SE.SFX"
|| sfxFileName == "ST32E.SFX"
|| sfxFileName == "WZIPSE32.exe"
|| sfxFileName == "SI32LPG.SFX"
|| sfxFileName == "ST32E.WZE")
{
return sfxTimeDateStamp switch
@@ -672,8 +674,10 @@ namespace BinaryObjectScanner.Packer
}
// Personal Edition
if (sfxFileName == "VW95LE.SFX" || sfxFileName == "PE32E.SFX"
|| sfxFileName == "wzsepe32.exe" || sfxFileName == "SI32PE.SFX"
if (sfxFileName == "VW95LE.SFX"
|| sfxFileName == "PE32E.SFX"
|| sfxFileName == "wzsepe32.exe"
|| sfxFileName == "SI32PE.SFX"
|| sfxFileName == "SI32LPE.SFX")
{
return sfxTimeDateStamp switch
@@ -715,7 +719,8 @@ namespace BinaryObjectScanner.Packer
}
// Software Installation
else if (sfxFileName == "VW95SRE.SFX" || sfxFileName == "SI32E.SFX"
else if (sfxFileName == "VW95SRE.SFX"
|| sfxFileName == "SI32E.SFX"
|| sfxFileName == "SI32E.WZE")
{
return sfxTimeDateStamp switch

View File

@@ -188,7 +188,7 @@ namespace BinaryObjectScanner.Packer
/// </summary>
/// <param name="nex">New executable to check</param>
/// <returns>True if it matches a known version, false otherwise</returns>
private FormatProperty? MatchesNEVersion(NewExecutable nex)
private static FormatProperty? MatchesNEVersion(NewExecutable nex)
{
// TODO: Offset is _not_ the EXE header address, rather where the data starts. Fix this.
switch (nex.Model.Stub?.Header?.NewExeHeaderAddr)
@@ -245,7 +245,7 @@ namespace BinaryObjectScanner.Packer
/// </summary>
/// <param name="pex">Portable executable to check</param>
/// <returns>True if it matches a known version, false otherwise</returns>
private FormatProperty? GetPEFormat(PortableExecutable pex)
private static FormatProperty? GetPEFormat(PortableExecutable pex)
{
if (pex.OverlayAddress == 0x6e00
&& pex.GetFirstSection(".text")?.VirtualSize == 0x3cf4

View File

@@ -13,24 +13,23 @@ namespace BinaryObjectScanner.Protection
/// <inheritdoc/>
public string? CheckContents(string file, byte[] fileContent, bool includeDebug)
{
// Only allow during debug
if (!includeDebug)
return null;
// TODO: Obtain a sample to find where this string is in a typical executable
if (includeDebug)
var contentMatchSets = new List<ContentMatchSet>
{
var contentMatchSets = new List<ContentMatchSet>
// " " + (char)0xC2 + (char)0x16 + (char)0x00 + (char)0xA8 + (char)0xC1 + (char)0x16 + (char)0x00 + (char)0xB8 + (char)0xC1 + (char)0x16 + (char)0x00 + (char)0x86 + (char)0xC8 + (char)0x16 + (char)0x00 + (char)0x9A + (char)0xC1 + (char)0x16 + (char)0x00 + (char)0x10 + (char)0xC2 + (char)0x16 + (char)0x00
new(new byte?[]
{
// " " + (char)0xC2 + (char)0x16 + (char)0x00 + (char)0xA8 + (char)0xC1 + (char)0x16 + (char)0x00 + (char)0xB8 + (char)0xC1 + (char)0x16 + (char)0x00 + (char)0x86 + (char)0xC8 + (char)0x16 + (char)0x00 + (char)0x9A + (char)0xC1 + (char)0x16 + (char)0x00 + (char)0x10 + (char)0xC2 + (char)0x16 + (char)0x00
new(new byte?[]
{
0x20, 0xC2, 0x16, 0x00, 0xA8, 0xC1, 0x16, 0x00,
0xB8, 0xC1, 0x16, 0x00, 0x86, 0xC8, 0x16, 0x00,
0x9A, 0xC1, 0x16, 0x00, 0x10, 0xC2, 0x16, 0x00
}, "ActiveMARK 5 (Unconfirmed - Please report to us on Github)"),
};
0x20, 0xC2, 0x16, 0x00, 0xA8, 0xC1, 0x16, 0x00,
0xB8, 0xC1, 0x16, 0x00, 0x86, 0xC8, 0x16, 0x00,
0x9A, 0xC1, 0x16, 0x00, 0x10, 0xC2, 0x16, 0x00
}, "ActiveMARK 5 (Unconfirmed - Please report to us on Github)"),
};
return MatchUtil.GetFirstMatch(file, fileContent, contentMatchSets, includeDebug);
}
return null;
return MatchUtil.GetFirstMatch(file, fileContent, contentMatchSets, includeDebug);
}
/// <inheritdoc/>

View File

@@ -69,9 +69,11 @@ namespace BinaryObjectScanner.Protection
{
if (strs.Exists(s => s.Contains("This Game is Japan Only")))
return "Alpha-ROM";
// Found in "Filechk.exe" in Redump entry 115358.
if (strs.Exists(s => s.Contains("AlphaCheck.exe")))
return "Alpha-ROM";
// Found in "Uninstall.exe" in Redump entry 115358.
if (strs.Exists(s => s.Contains("AlphaCheck.dat")))
return "Alpha-ROM";

View File

@@ -29,14 +29,13 @@ namespace BinaryObjectScanner.Protection
return null;
// Get the .nicode section, if it exists
bool nicodeSection = pex.ContainsSection(".nicode", exact: true);
if (nicodeSection)
if (pex.ContainsSection(".nicode", exact: true))
return "Armadillo";
// Loop through all "extension" sections -- usually .data1 or .text1
if (pex.SectionNames != null)
{
foreach (var sectionName in Array.FindAll(pex.SectionNames, s => s != null && s.EndsWith("1")))
foreach (var sectionName in Array.FindAll(pex.SectionNames ?? [], s => s != null && s.EndsWith("1")))
{
// Get the section strings, if they exist
var strs = pex.GetFirstSectionStrings(sectionName);

View File

@@ -69,31 +69,30 @@ namespace BinaryObjectScanner.Protection
/// <inheritdoc/>
public string? CheckContents(string file, byte[] fileContent, bool includeDebug)
{
// Only allow during debug
if (!includeDebug)
return null;
// TODO: Obtain a sample to find where this string is in a typical executable
if (includeDebug)
var contentMatchSets = new List<ContentMatchSet>
{
var contentMatchSets = new List<ContentMatchSet>
// TODO: Remove from here once it's confirmed that no PE executables contain this string
// CD-Cops, ver.
new(new byte?[]
{
// TODO: Remove from here once it's confirmed that no PE executables contain this string
// CD-Cops, ver.
new(new byte?[]
{
0x43, 0x44, 0x2D, 0x43, 0x6F, 0x70, 0x73, 0x2C,
0x20, 0x20, 0x76, 0x65, 0x72, 0x2E, 0x20
}, GetVersion, "CD-Cops (Unconfirmed - Please report to us on Github)"),
0x43, 0x44, 0x2D, 0x43, 0x6F, 0x70, 0x73, 0x2C,
0x20, 0x20, 0x76, 0x65, 0x72, 0x2E, 0x20
}, GetVersion, "CD-Cops (Unconfirmed - Please report to us on Github)"),
// // DVD-Cops, ver.
new(new byte?[]
{
0x44, 0x56, 0x44, 0x2D, 0x43, 0x6F, 0x70, 0x73,
0x2C, 0x20, 0x20, 0x76, 0x65, 0x72, 0x2E, 0x20
}, GetVersion, "DVD-Cops (Unconfirmed - Please report to us on Github)"),
};
// // DVD-Cops, ver.
new(new byte?[]
{
0x44, 0x56, 0x44, 0x2D, 0x43, 0x6F, 0x70, 0x73,
0x2C, 0x20, 0x20, 0x76, 0x65, 0x72, 0x2E, 0x20
}, GetVersion, "DVD-Cops (Unconfirmed - Please report to us on Github)"),
};
return MatchUtil.GetFirstMatch(file, fileContent, contentMatchSets, includeDebug);
}
return null;
return MatchUtil.GetFirstMatch(file, fileContent, contentMatchSets, includeDebug);
}
/// <inheritdoc/>
@@ -152,14 +151,14 @@ namespace BinaryObjectScanner.Protection
if (pex.StubExecutableData != null)
{
var matchers = new List<ContentMatchSet>
{
// WEBCOPS
// Found in "HyperBowl.C_S" in https://web.archive.org/web/20120616074941/http://icm.games.tucows.com/files2/HyperDemo-109a.exe.
new(new byte?[]
{
0x57, 0x45, 0x42, 0x43, 0x4F, 0x50, 0x53
}, "WEB-Cops")
};
// WEBCOPS
// Found in "HyperBowl.C_S" in https://web.archive.org/web/20120616074941/http://icm.games.tucows.com/files2/HyperDemo-109a.exe.
new(new byte?[]
{
0x57, 0x45, 0x42, 0x43, 0x4F, 0x50, 0x53
}, "WEB-Cops")
};
var match = MatchUtil.GetFirstMatch(file, pex.StubExecutableData, matchers, includeDebug);
if (!string.IsNullOrEmpty(match))
@@ -168,14 +167,12 @@ namespace BinaryObjectScanner.Protection
// Get the .grand section, if it exists
// Found in "AGENTHUG.QZ_" in Redump entry 84517 and "h3blade.QZ_" in Redump entry 85077.
bool grandSection = pex.ContainsSection(".grand", exact: true);
if (grandSection)
if (pex.ContainsSection(".grand", exact: true))
return "CD/DVD/WEB-Cops";
// Get the UNICops section, if it exists
// Found in "FGP.exe" in IA item "flaklypa-grand-prix-dvd"/Redump entry 108169.
bool UNICopsSection = pex.ContainsSection("UNICops", exact: true);
if (UNICopsSection)
if (pex.ContainsSection("UNICops", exact: true))
return "UNI-Cops";
return null;
@@ -228,14 +225,11 @@ namespace BinaryObjectScanner.Protection
if (fileContent == null)
return null;
byte[] versionBytes = new byte[4];
Array.Copy(fileContent, positions[0] + 15, versionBytes, 0, 4);
char[] version = Array.ConvertAll(versionBytes, b => (char)b);
string version = Encoding.ASCII.GetString(fileContent, positions[0] + 15, 4);
if (version[0] == 0x00)
return string.Empty;
return new string(version);
return version;
}
}
}

View File

@@ -10,23 +10,22 @@ namespace BinaryObjectScanner.Protection
/// <inheritdoc/>
public string? CheckContents(string file, byte[] fileContent, bool includeDebug)
{
// Only allow during debug
if (!includeDebug)
return null;
// TODO: Limit these checks to Mac binaries
// TODO: Obtain a sample to find where this string is in a typical executable
if (includeDebug)
var contentMatchSets = new List<ContentMatchSet>
{
var contentMatchSets = new List<ContentMatchSet>
{
// CDSPlayer
new([0x43, 0x44, 0x53, 0x50, 0x6C, 0x61, 0x79, 0x65, 0x72], "Cactus Data Shield 200"),
// CDSPlayer
new([0x43, 0x44, 0x53, 0x50, 0x6C, 0x61, 0x79, 0x65, 0x72], "Cactus Data Shield 200"),
// yucca.cds
new([0x79, 0x75, 0x63, 0x63, 0x61, 0x2E, 0x63, 0x64, 0x73], "Cactus Data Shield 200"),
};
// yucca.cds
new([0x79, 0x75, 0x63, 0x63, 0x61, 0x2E, 0x63, 0x64, 0x73], "Cactus Data Shield 200"),
};
return MatchUtil.GetFirstMatch(file, fileContent, contentMatchSets, includeDebug);
}
return null;
return MatchUtil.GetFirstMatch(file, fileContent, contentMatchSets, includeDebug);
}
}
}

View File

@@ -32,21 +32,15 @@ namespace BinaryObjectScanner.Protection
}
// Get the .cenega section, if it exists. Seems to be found in the protected game executable ("game.exe" in Redump entry 31422 and "Classic Car Racing.exe" in IA item "speed-pack").
bool cenegaSection = pex.ContainsSection(".cenega", exact: true);
if (cenegaSection)
if (pex.ContainsSection(".cenega", exact: true))
return "Cenega ProtectDVD";
// Get the .cenega0 through .cenega2 sections, if they exists. Found in "cenega.dll" in Redump entry 31422 and IA item "speed-pack".
cenegaSection = pex.ContainsSection(".cenega0", exact: true);
if (cenegaSection)
if (pex.ContainsSection(".cenega0", exact: true))
return "Cenega ProtectDVD";
cenegaSection = pex.ContainsSection(".cenega1", exact: true);
if (cenegaSection)
if (pex.ContainsSection(".cenega1", exact: true))
return "Cenega ProtectDVD";
cenegaSection = pex.ContainsSection(".cenega2", exact: true);
if (cenegaSection)
if (pex.ContainsSection(".cenega2", exact: true))
return "Cenega ProtectDVD";
return null;

View File

@@ -21,25 +21,22 @@ namespace BinaryObjectScanner.Protection
return null;
// Get the .text section, if it exists
if (pex.ContainsSection(".text"))
var textData = pex.GetFirstSectionData(".text");
if (textData != null)
{
var textData = pex.GetFirstSectionData(".text");
if (textData != null)
var matchers = new List<ContentMatchSet>
{
var matchers = new List<ContentMatchSet>
// Confirmed to detect most examples known of Cucko. The only known exception is the version of "TSLHost.dll" included on Redump entry 36119.
// ŠU‰8...…™...ŠUŠ8T...
new(new byte?[]
{
// Confirmed to detect most examples known of Cucko. The only known exception is the version of "TSLHost.dll" included on Redump entry 36119.
// ŠU‰8...…™...ŠUŠ8T...
new(new byte?[]
{
0x8A, 0x55, 0x89, 0x38, 0x14, 0x1E, 0x0F, 0x85,
0x99, 0x00, 0x00, 0x00, 0x8A, 0x55, 0x8A, 0x38,
0x54, 0x1E, 0x01, 0x0F
}, "Cucko (EA Custom)")
};
0x8A, 0x55, 0x89, 0x38, 0x14, 0x1E, 0x0F, 0x85,
0x99, 0x00, 0x00, 0x00, 0x8A, 0x55, 0x8A, 0x38,
0x54, 0x1E, 0x01, 0x0F
}, "Cucko (EA Custom)")
};
return MatchUtil.GetFirstMatch(file, textData, matchers, includeDebug);
}
return MatchUtil.GetFirstMatch(file, textData, matchers, includeDebug);
}
return null;

View File

@@ -5,6 +5,7 @@ using SabreTools.Matching;
using SabreTools.Matching.Content;
using SabreTools.Matching.Paths;
using SabreTools.Serialization.Wrappers;
using OHMN = SabreTools.Models.PortableExecutable.OptionalHeaderMagicNumber;
namespace BinaryObjectScanner.Protection
{
@@ -65,199 +66,201 @@ namespace BinaryObjectScanner.Protection
// https://github.com/horsicq/Detect-It-Easy/blob/master/db/PE/Denuvo%20protector.2.sg
// https://github.com/horsicq/Detect-It-Easy/blob/master/db/PE/_denuvoComplete.2.sg
// TODO: Re-enable all Entry Point checks after implementing
// Denuvo Protector
// if (pex.OptionalHeader.Magic == OptionalHeaderType.PE32Plus && pex.EntryPointRaw != null)
// {
// byte?[] denuvoProtector = new byte?[]
// {
// 0x48, 0x8D, 0x0D, null, null, null, null, null,
// null, null, null, 0xE9, null, null, null, null,
// 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// };
if (pex.Model.OptionalHeader?.Magic == OHMN.PE32Plus
&& pex.EntryPointData != null)
{
byte?[] denuvoProtector =
[
0x48, 0x8D, 0x0D, null, null, null, null, null,
null, null, null, 0xE9, null, null, null, null,
0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
];
// if (pex.EntryPointRaw.StartsWith(denuvoProtector))
// return "Denuvo Protector";
// }
if (pex.EntryPointData.StartsWith(denuvoProtector))
return "Denuvo Protector";
}
// Denuvo
var timingMatchers = new List<ContentMatchSet>
{
// Denuvo Timing
new(
new byte?[]
{
[
0x44, 0x65, 0x6E, 0x75, 0x76, 0x6F, 0x20, 0x54,
0x69, 0x6D, 0x69, 0x6E, 0x67,
}, "Denuvo")
], "Denuvo")
};
var timingMatch = MatchUtil.GetFirstMatch(file, pex.EntryPointData, timingMatchers, includeDebug);
// TODO: Re-enable all Entry Point checks after implementing
// if (pex.ContainsSection(".arch") || pex.ContainsSection(".srdata") || !string.IsNullOrEmpty(MatchUtil.GetFirstMatch(file, pex.EntryPointRaw, timingMatchers, includeDebug)))
// {
// if (pex.OH_Magic == OptionalHeaderType.PE32Plus)
// {
// var matchers = new List<ContentMatchSet>
// {
// // Mad Max, Metal Gear Solid: TPP, Rise of the Tomb Raider
// new ContentMatchSet(
// new ContentMatch(
// new byte?[]
// {
// 0x51, 0x52, 0x41, 0x50, 0x41, 0x51, 0x4C, 0x8D,
// null, null, null, null, null, 0x4C, 0x8D, null,
// null, null, null, null, 0x4D, 0x29, 0xC1,
// },
// end: 0
// ),
// "Denuvo v1.0 (x64)"),
if (pex.ContainsSection(".arch")
|| pex.ContainsSection(".srdata")
|| !string.IsNullOrEmpty(timingMatch))
{
if (pex.Model.OptionalHeader?.Magic == OHMN.PE32Plus)
{
var matchers = new List<ContentMatchSet>
{
// Mad Max, Metal Gear Solid: TPP, Rise of the Tomb Raider
new(
new ContentMatch(
new byte?[]
{
0x51, 0x52, 0x41, 0x50, 0x41, 0x51, 0x4C, 0x8D,
null, null, null, null, null, 0x4C, 0x8D, null,
null, null, null, null, 0x4D, 0x29, 0xC1,
},
end: 0
),
"Denuvo v1.0 (x64)"),
// // Lords of the Fallen, Batman: AK, Just Cause 3, Sherlock Holmes: TdD, Tales of Berseria etc
// new ContentMatchSet(
// new ContentMatch(
// new byte?[]
// {
// 0x48, 0x8D, 0x0D, null, null, null, null, 0xE9,
// null, null, null, null,
// },
// end: 0
// ),
// "Denuvo v2.0a (x64)"),
// Lords of the Fallen, Batman: AK, Just Cause 3, Sherlock Holmes: TdD, Tales of Berseria etc
new(
new ContentMatch(
new byte?[]
{
0x48, 0x8D, 0x0D, null, null, null, null, 0xE9,
null, null, null, null,
},
end: 0
),
"Denuvo v2.0a (x64)"),
// // Yesterday Origins
// new ContentMatchSet(
// new ContentMatch(
// new byte?[]
// {
// 0x48, 0x89, null, null, null, null, null, 0x48,
// 0x89, null, null, null, null, null, 0x4C, 0x89,
// null, null, null, null, null, 0x4C, 0x89, null,
// null, null, null, null, 0x48, 0x83, 0xFA, 0x01,
// },
// end: 0
// ),
// "Denuvo v2.0b (x64)"),
// Yesterday Origins
new(
new ContentMatch(
new byte?[]
{
0x48, 0x89, null, null, null, null, null, 0x48,
0x89, null, null, null, null, null, 0x4C, 0x89,
null, null, null, null, null, 0x4C, 0x89, null,
null, null, null, null, 0x48, 0x83, 0xFA, 0x01,
},
end: 0
),
"Denuvo v2.0b (x64)"),
// // Sniper Ghost Warrior 3 (beta), Dead Rising 4 (SteamStub-free)
// new ContentMatchSet(
// new ContentMatch(
// new byte?[]
// {
// null, null, null, null, null, null, null, null,
// 0x4C, 0x89, 0x1C, 0x24, 0x49, 0x89, 0xE3,
// },
// end: 0
// ),
// "Denuvo v3.0a (x64)"),
// Sniper Ghost Warrior 3 (beta), Dead Rising 4 (SteamStub-free)
new(
new ContentMatch(
new byte?[]
{
null, null, null, null, null, null, null, null,
0x4C, 0x89, 0x1C, 0x24, 0x49, 0x89, 0xE3,
},
end: 0
),
"Denuvo v3.0a (x64)"),
// // Train Sim World CSX Heavy Haul
// new ContentMatchSet(
// new ContentMatch(
// new byte?[]
// {
// 0x4D, 0x8D, null, null, null, null, null, null,
// null, null, null, 0x48, 0x89, null, null, null,
// null, null, 0x48, 0x8D, null, null, 0x48, 0x89,
// null, 0x48, 0x89, null, 0x48, 0x89,
// },
// end: 0
// ),
// "Denuvo v3.0b (x64)"),
// };
// Train Sim World CSX Heavy Haul
new(
new ContentMatch(
new byte?[]
{
0x4D, 0x8D, null, null, null, null, null, null,
null, null, null, 0x48, 0x89, null, null, null,
null, null, 0x48, 0x8D, null, null, 0x48, 0x89,
null, 0x48, 0x89, null, 0x48, 0x89,
},
end: 0
),
"Denuvo v3.0b (x64)"),
};
// var match = MatchUtil.GetFirstMatch(file, pex.EntryPointRaw, matchers, includeDebug);
// if (!string.IsNullOrEmpty(match))
// return match;
var match = MatchUtil.GetFirstMatch(file, pex.EntryPointData, matchers, includeDebug);
if (!string.IsNullOrEmpty(match))
return match;
// return "Denuvo (Unknown x64 Version)";
return "Denuvo (Unknown x64 Version)";
// //// Check if steam_api64.dll present
// //if (PE.isLibraryPresent("steam_api64.dll"))
// //{
// // // Override additional info
// // sOptions = "x64 -> Steam";
// // bDetected = 1;
// //}
// //// Check if uplay_r1_loader64.dll present
// //if (PE.isLibraryPresent("uplay_r1_loader64.dll"))
// //{
// // // Override additional info
// // sOptions = "x64 -> uPlay";
// // bDetected = 1;
// //}
// //// Check if uplay_r2_loader64.dll present
// //if (PE.isLibraryPresent("uplay_r2_loader64.dll"))
// //{
// // // Override additional info
// // sOptions = "x64 -> uPlay";
// // bDetected = 1;
// //}
// //// Check if Core/Activation64.dll present
// //if (PE.isLibraryPresent("Core/Activation64.dll"))
// //{
// // // Override additional info
// // sOptions = "x64 -> Origin";
// // bDetected = 1;
// //}
// }
// else
// {
// var matchers = new List<ContentMatchSet>
// {
// // Pro Evolution Soccer 2017, Champions of Anteria
// new ContentMatchSet(
// new ContentMatch(
// new byte?[]
// {
// 0x55, 0x89, 0xE5, 0x8D, null, null, null, null,
// null, null, 0xE8, null, null, null, null, 0xE8,
// null, null, null, null, 0xE8, null, null, null,
// null, 0xE8, null, null, null, null,
// },
// end: 0
// ),
// "Denuvo v1.0 (x86)"),
//// Check if steam_api64.dll present
//if (PE.isLibraryPresent("steam_api64.dll"))
//{
// // Override additional info
// sOptions = "x64 -> Steam";
// bDetected = 1;
//}
//// Check if uplay_r1_loader64.dll present
//if (PE.isLibraryPresent("uplay_r1_loader64.dll"))
//{
// // Override additional info
// sOptions = "x64 -> uPlay";
// bDetected = 1;
//}
//// Check if uplay_r2_loader64.dll present
//if (PE.isLibraryPresent("uplay_r2_loader64.dll"))
//{
// // Override additional info
// sOptions = "x64 -> uPlay";
// bDetected = 1;
//}
//// Check if Core/Activation64.dll present
//if (PE.isLibraryPresent("Core/Activation64.dll"))
//{
// // Override additional info
// sOptions = "x64 -> Origin";
// bDetected = 1;
//}
}
else
{
var matchers = new List<ContentMatchSet>
{
// Pro Evolution Soccer 2017, Champions of Anteria
new(
new ContentMatch(
new byte?[]
{
0x55, 0x89, 0xE5, 0x8D, null, null, null, null,
null, null, 0xE8, null, null, null, null, 0xE8,
null, null, null, null, 0xE8, null, null, null,
null, 0xE8, null, null, null, null,
},
end: 0
),
"Denuvo v1.0 (x86)"),
// // Romance of 13 Kingdoms, 2Dark
// new ContentMatchSet(
// new ContentMatch(
// new byte?[]
// {
// 0x8D, null, null, null, null, null, null, 0x89,
// 0x7C, 0x24, 0x04, 0x89, 0xE7,
// },
// end: 0
// ),
// "Denuvo v2.0 (x86)"),
// };
// Romance of 13 Kingdoms, 2Dark
new(
new ContentMatch(
new byte?[]
{
0x8D, null, null, null, null, null, null, 0x89,
0x7C, 0x24, 0x04, 0x89, 0xE7,
},
end: 0
),
"Denuvo v2.0 (x86)"),
};
// var match = MatchUtil.GetFirstMatch(file, pex.EntryPointRaw, matchers, includeDebug);
// if (!string.IsNullOrEmpty(match))
// return match;
var match = MatchUtil.GetFirstMatch(file, pex.EntryPointData, matchers, includeDebug);
if (!string.IsNullOrEmpty(match))
return match;
// //// Check if steam_api64.dll present
// //if (PE.isLibraryPresent("steam_api.dll"))
// //{
// // // Override additional info
// // sOptions = "x86 -> Steam";
// // bDetected = 1;
// //}
// //// Check if uplay_r1_loader.dll present
// //if (PE.isLibraryPresent("uplay_r1_loader.dll"))
// //{
// // // Override additional info
// // sOptions = "x86 -> uPlay";
// // bDetected = 1;
// //}
// //// Check if Core/Activation.dll present
// //if (PE.isLibraryPresent("Core/Activation.dll"))
// //{
// // // Override additional info
// // sOptions = "x86 -> Origin";
// // bDetected = 1;
// //}
// }
// }
//// Check if steam_api64.dll present
//if (PE.isLibraryPresent("steam_api.dll"))
//{
// // Override additional info
// sOptions = "x86 -> Steam";
// bDetected = 1;
//}
//// Check if uplay_r1_loader.dll present
//if (PE.isLibraryPresent("uplay_r1_loader.dll"))
//{
// // Override additional info
// sOptions = "x86 -> uPlay";
// bDetected = 1;
//}
//// Check if Core/Activation.dll present
//if (PE.isLibraryPresent("Core/Activation.dll"))
//{
// // Override additional info
// sOptions = "x86 -> Origin";
// bDetected = 1;
//}
}
}
return null;
}

View File

@@ -76,64 +76,61 @@ namespace BinaryObjectScanner.Protection
return "DiscGuard";
// Get the .vbn section, if it exists
if (pex.ContainsSection(".vbn"))
var vbnData = pex.GetFirstSectionData(".vbn");
if (vbnData != null)
{
var vbnData = pex.GetFirstSectionData(".vbn");
if (vbnData != null)
var matchers = new List<ContentMatchSet>
{
var matchers = new List<ContentMatchSet>
// Found in "T29.dll" (Redump entry 31914).
// This check should be as long as the following check, as this data is nearly identical (including length) in the original files, but for some reason the section ends early, causing part of the remaining data to not be part of a section.
new(new byte?[]
{
// Found in "T29.dll" (Redump entry 31914).
// This check should be as long as the following check, as this data is nearly identical (including length) in the original files, but for some reason the section ends early, causing part of the remaining data to not be part of a section.
new(new byte?[]
{
0x7B, 0x39, 0x8F, 0x07, 0x47, 0xE9, 0x96, 0x8C, 0xCA, 0xB2, 0x5C, 0x50,
0xC7, 0x5A, 0x18, 0xBD, 0x75, 0xB5, 0x68, 0x6A, 0x78, 0xB5, 0xCF, 0xF2,
0xBE, 0xB3, 0xDB, 0xE9, 0x4E, 0x87, 0x8D, 0x46, 0x63, 0x0A, 0x54, 0xB8,
0x4F, 0x85, 0x60, 0x2C, 0x06, 0xEC, 0xBD, 0x75, 0xF5, 0x6A, 0x6E, 0x35,
0x4D, 0x5A, 0x8B, 0xF4, 0x12, 0x15, 0x23, 0xC8, 0xE9, 0x80, 0x01, 0x10,
0xFE, 0xDB, 0xC6, 0x70, 0x1D, 0xC1, 0x4D, 0xAE, 0x9E, 0xE1, 0x01, 0xAA,
0x9E, 0x50, 0x50, 0xC5, 0x66, 0x80, 0xC0, 0xA2, 0x2F, 0xA9, 0x7A, 0x3B,
0x48, 0x74, 0x9D, 0x17, 0x33, 0x5D, 0x4C, 0x84, 0xD9, 0x54, 0xC4, 0x08,
0xCC, 0x10, 0x2A, 0xF6, 0x91, 0x40, 0x51, 0xD3, 0xF5, 0x9A, 0x07, 0xE7,
0xAB, 0xE9, 0x0B, 0xAD, 0xD4, 0x3A, 0xEC, 0xBA, 0x4B, 0x6C, 0xD2, 0x82,
0x0D, 0xF5, 0x49, 0x83, 0x8E, 0xAB, 0x85, 0x92, 0x78, 0x1D, 0x69, 0x1E,
0x44, 0xC6, 0xF6, 0xB4, 0x5F, 0x5F, 0xC2, 0x48, 0x5A, 0xED, 0x43, 0xD3,
0xA4, 0x41, 0x81
}, GetVersion, "DiscGuard"),
0x7B, 0x39, 0x8F, 0x07, 0x47, 0xE9, 0x96, 0x8C, 0xCA, 0xB2, 0x5C, 0x50,
0xC7, 0x5A, 0x18, 0xBD, 0x75, 0xB5, 0x68, 0x6A, 0x78, 0xB5, 0xCF, 0xF2,
0xBE, 0xB3, 0xDB, 0xE9, 0x4E, 0x87, 0x8D, 0x46, 0x63, 0x0A, 0x54, 0xB8,
0x4F, 0x85, 0x60, 0x2C, 0x06, 0xEC, 0xBD, 0x75, 0xF5, 0x6A, 0x6E, 0x35,
0x4D, 0x5A, 0x8B, 0xF4, 0x12, 0x15, 0x23, 0xC8, 0xE9, 0x80, 0x01, 0x10,
0xFE, 0xDB, 0xC6, 0x70, 0x1D, 0xC1, 0x4D, 0xAE, 0x9E, 0xE1, 0x01, 0xAA,
0x9E, 0x50, 0x50, 0xC5, 0x66, 0x80, 0xC0, 0xA2, 0x2F, 0xA9, 0x7A, 0x3B,
0x48, 0x74, 0x9D, 0x17, 0x33, 0x5D, 0x4C, 0x84, 0xD9, 0x54, 0xC4, 0x08,
0xCC, 0x10, 0x2A, 0xF6, 0x91, 0x40, 0x51, 0xD3, 0xF5, 0x9A, 0x07, 0xE7,
0xAB, 0xE9, 0x0B, 0xAD, 0xD4, 0x3A, 0xEC, 0xBA, 0x4B, 0x6C, 0xD2, 0x82,
0x0D, 0xF5, 0x49, 0x83, 0x8E, 0xAB, 0x85, 0x92, 0x78, 0x1D, 0x69, 0x1E,
0x44, 0xC6, 0xF6, 0xB4, 0x5F, 0x5F, 0xC2, 0x48, 0x5A, 0xED, 0x43, 0xD3,
0xA4, 0x41, 0x81
}, GetVersion, "DiscGuard"),
// Found in "T5375.dll" (Redump entry 79284), "TD352.dll" and "TE091.dll" (Redump entry 46743), "T71E1.dll" and "T7181.dll" (Redump entry 46961), and "TA0E4.DLL" (Redump entry 79374).
new(new byte?[]
{
0x7B, 0x39, 0x8F, 0x07, 0x45, 0xE9, 0x96, 0x8C, 0xCA, 0xB2, 0x5C, 0x50,
0xC7, 0x5A, 0x18, 0xBD, 0x75, 0xB5, 0x68, 0x6A, 0x78, 0xB5, 0xCF, 0xF2,
0xBE, 0xB3, 0xDB, 0xE9, 0x4E, 0x87, 0x8D, 0x46, 0x63, 0x0A, 0x54, 0xB8,
0x4F, 0x85, 0x60, 0x2C, 0x06, 0xEC, 0xBD, 0x75, 0xC6, 0xEB, 0x6E, 0x35,
0xED, 0xD0, 0x8B, 0xF4, 0x15, 0x12, 0x3D, 0xF3, 0x65, 0xF7, 0x01, 0x10,
0xF8, 0xFA, 0xC6, 0x70, 0x1D, 0xC1, 0x4D, 0xAE, 0x9E, 0xE1, 0x01, 0xAA,
0x9E, 0x50, 0x50, 0xC5, 0x66, 0x80, 0xC0, 0xA2, 0x2F, 0xA9, 0x7A, 0x3B,
0x48, 0x74, 0x9D, 0x17, 0x33, 0x5D, 0x4C, 0x84, 0xD9, 0x54, 0xC4, 0x08,
0xCC, 0x10, 0x2A, 0xF6, 0x91, 0x40, 0x51, 0xD3, 0x41, 0x9A, 0x07, 0xE7,
0xAB, 0xE9, 0x0B, 0xAD, 0xD4, 0x3A, 0xEC, 0xBA, 0xAF, 0x69, 0xD2, 0x82,
0x67, 0xF5, 0x49, 0x83, 0x8E, 0xAB, 0x85, 0x92, 0x04, 0x19, 0x69, 0x1E,
0x44, 0xC6, 0xF6, 0xB4, 0x5F, 0x5F, 0xC2, 0x48, 0x5A, 0xED, 0x43, 0xD3,
0xA4, 0x41, 0x81, 0xAF, 0xB8, 0xCB, 0x46, 0xE3, 0xDA, 0x05, 0x36, 0xEA,
0x05, 0xF5, 0xB9, 0xCE, 0x5F, 0x9A, 0xF5, 0x7D, 0x9E, 0x64, 0x66, 0xF9,
0xA5, 0x7C, 0x4D, 0x1D, 0x1D, 0x95, 0x02, 0x52, 0x66, 0x23, 0xEF, 0xFF,
0xEC, 0x63, 0x11, 0xEB, 0xF6, 0x66, 0x8F, 0x2B, 0xCF, 0x07, 0x50, 0x18,
0xBE, 0x58, 0xCA, 0x08, 0x24, 0xAD, 0x81, 0x1A, 0xAB, 0x0E, 0x2D, 0x16,
0x38, 0xAB, 0x22, 0xB5, 0xA8, 0xF0, 0x7D, 0x2E, 0xAF, 0x5E, 0xEA, 0x02,
0x72, 0x20, 0x14, 0x19, 0x0E, 0x31, 0xF3, 0xD0, 0x40, 0xAE, 0xA2, 0xD5,
0x0A, 0xA7, 0xB7, 0xAE, 0x02, 0xCF, 0xAC, 0x5F, 0xB8, 0x03, 0x15, 0x80,
0x9A, 0x58, 0x5C, 0x03, 0x28, 0x31, 0x9E, 0xB8, 0x21, 0x5D, 0x07, 0xB3,
0xB9, 0xEC, 0x75, 0xBA, 0xC2, 0xC8, 0x9D, 0x6F, 0x7A, 0xA1, 0x00, 0x8A
}, GetVersion, "DiscGuard"),
};
// Found in "T5375.dll" (Redump entry 79284), "TD352.dll" and "TE091.dll" (Redump entry 46743), "T71E1.dll" and "T7181.dll" (Redump entry 46961), and "TA0E4.DLL" (Redump entry 79374).
new(new byte?[]
{
0x7B, 0x39, 0x8F, 0x07, 0x45, 0xE9, 0x96, 0x8C, 0xCA, 0xB2, 0x5C, 0x50,
0xC7, 0x5A, 0x18, 0xBD, 0x75, 0xB5, 0x68, 0x6A, 0x78, 0xB5, 0xCF, 0xF2,
0xBE, 0xB3, 0xDB, 0xE9, 0x4E, 0x87, 0x8D, 0x46, 0x63, 0x0A, 0x54, 0xB8,
0x4F, 0x85, 0x60, 0x2C, 0x06, 0xEC, 0xBD, 0x75, 0xC6, 0xEB, 0x6E, 0x35,
0xED, 0xD0, 0x8B, 0xF4, 0x15, 0x12, 0x3D, 0xF3, 0x65, 0xF7, 0x01, 0x10,
0xF8, 0xFA, 0xC6, 0x70, 0x1D, 0xC1, 0x4D, 0xAE, 0x9E, 0xE1, 0x01, 0xAA,
0x9E, 0x50, 0x50, 0xC5, 0x66, 0x80, 0xC0, 0xA2, 0x2F, 0xA9, 0x7A, 0x3B,
0x48, 0x74, 0x9D, 0x17, 0x33, 0x5D, 0x4C, 0x84, 0xD9, 0x54, 0xC4, 0x08,
0xCC, 0x10, 0x2A, 0xF6, 0x91, 0x40, 0x51, 0xD3, 0x41, 0x9A, 0x07, 0xE7,
0xAB, 0xE9, 0x0B, 0xAD, 0xD4, 0x3A, 0xEC, 0xBA, 0xAF, 0x69, 0xD2, 0x82,
0x67, 0xF5, 0x49, 0x83, 0x8E, 0xAB, 0x85, 0x92, 0x04, 0x19, 0x69, 0x1E,
0x44, 0xC6, 0xF6, 0xB4, 0x5F, 0x5F, 0xC2, 0x48, 0x5A, 0xED, 0x43, 0xD3,
0xA4, 0x41, 0x81, 0xAF, 0xB8, 0xCB, 0x46, 0xE3, 0xDA, 0x05, 0x36, 0xEA,
0x05, 0xF5, 0xB9, 0xCE, 0x5F, 0x9A, 0xF5, 0x7D, 0x9E, 0x64, 0x66, 0xF9,
0xA5, 0x7C, 0x4D, 0x1D, 0x1D, 0x95, 0x02, 0x52, 0x66, 0x23, 0xEF, 0xFF,
0xEC, 0x63, 0x11, 0xEB, 0xF6, 0x66, 0x8F, 0x2B, 0xCF, 0x07, 0x50, 0x18,
0xBE, 0x58, 0xCA, 0x08, 0x24, 0xAD, 0x81, 0x1A, 0xAB, 0x0E, 0x2D, 0x16,
0x38, 0xAB, 0x22, 0xB5, 0xA8, 0xF0, 0x7D, 0x2E, 0xAF, 0x5E, 0xEA, 0x02,
0x72, 0x20, 0x14, 0x19, 0x0E, 0x31, 0xF3, 0xD0, 0x40, 0xAE, 0xA2, 0xD5,
0x0A, 0xA7, 0xB7, 0xAE, 0x02, 0xCF, 0xAC, 0x5F, 0xB8, 0x03, 0x15, 0x80,
0x9A, 0x58, 0x5C, 0x03, 0x28, 0x31, 0x9E, 0xB8, 0x21, 0x5D, 0x07, 0xB3,
0xB9, 0xEC, 0x75, 0xBA, 0xC2, 0xC8, 0x9D, 0x6F, 0x7A, 0xA1, 0x00, 0x8A
}, GetVersion, "DiscGuard"),
};
var match = MatchUtil.GetFirstMatch(file, vbnData, matchers, includeDebug);
if (!string.IsNullOrEmpty(match))
return match;
}
var match = MatchUtil.GetFirstMatch(file, vbnData, matchers, includeDebug);
if (!string.IsNullOrEmpty(match))
return match;
}
return null;

View File

@@ -27,11 +27,12 @@ namespace BinaryObjectScanner.Protection
// Detects Engine32 within the game executables that contain it.
if (pex.Model.ImportTable?.ImportDirectoryTable != null && pex.Model.ImportTable?.HintNameTable != null)
{
bool importDirectoryTableMatch = Array.Exists(pex.Model.ImportTable.ImportDirectoryTable, idte => idte?.Name != null && idte.Name.Equals("ENGINE32.DLL", StringComparison.OrdinalIgnoreCase));
bool hintNameTableMatch = Array.Exists(pex.Model.ImportTable?.HintNameTable ?? [], ihne => ihne?.Name == "InitEngine");
bool importDirectoryTableMatch = Array.Exists(pex.Model.ImportTable.ImportDirectoryTable,
idte => idte?.Name != null && idte.Name.Equals("ENGINE32.DLL", StringComparison.OrdinalIgnoreCase));
bool hintNameTableMatch = Array.Exists(pex.Model.ImportTable.HintNameTable,
ihne => ihne?.Name == "InitEngine");
// The Hint/Name Table Entry "DeinitEngine" is present in every tested sample, aside from TOCA Race Driver 2 (Redump entries 104593-104596).
if (hintNameTableMatch && importDirectoryTableMatch)
return "Engine32";
}

View File

@@ -33,10 +33,12 @@ namespace BinaryObjectScanner.Protection
return $"Stardock Product Activation {pex.GetInternalVersion()}";
// TODO: Check for CVP* instead?
bool containsCheck = Array.Exists(pex.Model.ExportTable?.ExportNameTable?.Strings ?? [], s => s?.StartsWith("CVPInitializeClient") ?? false);
bool containsCheck2 = false;
bool containsCheck = false;
if (pex.Model.ExportTable?.ExportNameTable?.Strings != null)
containsCheck = Array.Exists(pex.Model.ExportTable.ExportNameTable.Strings, s => s?.StartsWith("CVPInitializeClient") ?? false);
// Get the .rdata section strings, if they exist
bool containsCheck2 = false;
var strs = pex.GetFirstSectionStrings(".rdata");
if (strs != null)
{

View File

@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Text;
using BinaryObjectScanner.Interfaces;
using SabreTools.Matching;
using SabreTools.Matching.Content;
@@ -72,12 +73,7 @@ namespace BinaryObjectScanner.Protection
if (fileContent == null)
return null;
int position = positions[0];
byte[] versionBytes = new byte[8];
Array.Copy(fileContent, position + 67, versionBytes, 0, 8);
char[] version = Array.ConvertAll(versionBytes, b => (char)b);
return new string(version);
return Encoding.ASCII.GetString(fileContent, positions[0] + 67, 8);
}
}
}

View File

@@ -10,23 +10,22 @@ namespace BinaryObjectScanner.Protection
/// <inheritdoc/>
public string? CheckContents(string file, byte[] fileContent, bool includeDebug)
{
// Only allow during debug
if (!includeDebug)
return null;
// TODO: Obtain a sample to find where this string is in a typical executable
if (includeDebug)
var contentMatchSets = new List<ContentMatchSet>
{
var contentMatchSets = new List<ContentMatchSet>
// KEY-LOCK COMMAND
new(new byte?[]
{
// KEY-LOCK COMMAND
new(new byte?[]
{
0x4B, 0x45, 0x59, 0x2D, 0x4C, 0x4F, 0x43, 0x4B,
0x20, 0x43, 0x4F, 0x4D, 0x4D, 0x41, 0x4E, 0x44
}, "Key-Lock (Dongle) (Unconfirmed - Please report to us on Github)"),
};
0x4B, 0x45, 0x59, 0x2D, 0x4C, 0x4F, 0x43, 0x4B,
0x20, 0x43, 0x4F, 0x4D, 0x4D, 0x41, 0x4E, 0x44
}, "Key-Lock (Dongle) (Unconfirmed - Please report to us on Github)"),
};
return MatchUtil.GetFirstMatch(file, fileContent, contentMatchSets, includeDebug);
}
return null;
return MatchUtil.GetFirstMatch(file, fileContent, contentMatchSets, includeDebug);
}
}
}

View File

@@ -1,7 +1,9 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using BinaryObjectScanner.Interfaces;
using SabreTools.IO.Extensions;
using SabreTools.Matching;
using SabreTools.Matching.Paths;
using SabreTools.Serialization.Wrappers;
@@ -164,35 +166,11 @@ namespace BinaryObjectScanner.Protection
if (!sectionContent.FirstPosition(check, out int position))
return "(Build unknown)";
string year, month, day;
if (versionTwo)
{
int index = position + 14;
int index = versionTwo ? position + 14 : position + 13;
byte[] temp = new byte[2];
Array.Copy(sectionContent, index, temp, 0, 2);
day = new string(Array.ConvertAll(temp, b => (char)b));
index += 3;
Array.Copy(sectionContent, index, temp, 0, 2);
month = new string(Array.ConvertAll(temp, b => (char)b));
index += 3;
Array.Copy(sectionContent, index, temp, 0, 2);
year = "20" + new string(Array.ConvertAll(temp, b => (char)b));
}
else
{
int index = position + 13;
byte[] temp = new byte[2];
Array.Copy(sectionContent, index, temp, 0, 2);
day = new string(Array.ConvertAll(temp, b => (char)b));
index += 3;
Array.Copy(sectionContent, index, temp, 0, 2);
month = new string(Array.ConvertAll(temp, b => (char)b));
index += 3;
Array.Copy(sectionContent, index, temp, 0, 2);
year = "20" + new string(Array.ConvertAll(temp, b => (char)b));
}
string day = Encoding.ASCII.GetString(sectionContent, index + 0, 2);
string month = Encoding.ASCII.GetString(sectionContent, index + 3, 2);
string year = "20" + Encoding.ASCII.GetString(sectionContent, index + 6, 2);
return $"(Build {year}-{month}-{day})";
}
@@ -203,9 +181,7 @@ namespace BinaryObjectScanner.Protection
if (sectionContent == null)
return null;
byte[] temp = new byte[4];
Array.Copy(sectionContent, position + 76, temp, 0, 4);
return new string(Array.ConvertAll(temp, b => (char)b));
return Encoding.ASCII.GetString(sectionContent, position + 76, 4);
}
public static string? GetVersion16Bit(string firstMatchedString, IEnumerable<string>? files)
@@ -214,16 +190,12 @@ namespace BinaryObjectScanner.Protection
return string.Empty;
using var fs = File.Open(firstMatchedString, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
using var br = new BinaryReader(fs);
return GetVersion16Bit(br.ReadBytes((int)fs.Length));
return GetVersion16Bit(fs.ReadBytes((int)fs.Length));
}
private static string GetVersion16Bit(byte[] fileContent)
{
byte[] temp = new byte[7];
Array.Copy(fileContent, 71, temp, 0, 7);
char[] version = Array.ConvertAll(temp, b => (char)b);
string version = Encoding.ASCII.GetString(fileContent, 71, 7);
if (char.IsNumber(version[0]) && char.IsNumber(version[2]) && char.IsNumber(version[3]))
{
if (char.IsNumber(version[5]) && char.IsNumber(version[6]))

View File

@@ -34,7 +34,7 @@ namespace BinaryObjectScanner.Protection
public partial class Macrovision
{
/// <inheritdoc cref="Interfaces.IExecutableCheck{T}.CheckExecutable(string, T, bool)"/>
internal string? CDillaCheckExecutable(string file, NewExecutable nex, bool includeDebug)
internal static string? CDillaCheckExecutable(string file, NewExecutable nex, bool includeDebug)
{
// TODO: Implement NE checks for "CDILLA05", "CDILLA10", "CDILLA16", and "CDILLA40".
@@ -60,7 +60,7 @@ namespace BinaryObjectScanner.Protection
}
/// <inheritdoc cref="Interfaces.IExecutableCheck{T}.CheckExecutable(string, T, bool)"/>
internal string? CDillaCheckExecutable(string file, PortableExecutable pex, bool includeDebug)
internal static string? CDillaCheckExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// Get the sections from the executable, if possible
var sections = pex.Model.SectionTable;
@@ -132,7 +132,7 @@ namespace BinaryObjectScanner.Protection
}
/// <inheritdoc cref="Interfaces.IPathCheck.CheckDirectoryPath(string, List{string})"/>
internal List<string> CDillaCheckDirectoryPath(string path, List<string>? files)
internal static List<string> CDillaCheckDirectoryPath(string path, List<string>? files)
{
var matchers = new List<PathMatchSet>
{
@@ -175,7 +175,7 @@ namespace BinaryObjectScanner.Protection
}
/// <inheritdoc cref="Interfaces.IPathCheck.CheckFilePath(string)"/>
internal string? CDillaCheckFilePath(string path)
internal static string? CDillaCheckFilePath(string path)
{
var matchers = new List<PathMatchSet>
{

View File

@@ -31,7 +31,7 @@ namespace BinaryObjectScanner.Protection
public partial class Macrovision
{
/// <inheritdoc cref="Interfaces.IExecutableCheck{T}.CheckExecutable(string, T, bool)"/>
internal string? CactusDataShieldCheckExecutable(string file, PortableExecutable pex, bool includeDebug)
internal static string? CactusDataShieldCheckExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// Get the sections from the executable, if possible
var sections = pex.Model.SectionTable;
@@ -62,7 +62,7 @@ namespace BinaryObjectScanner.Protection
}
/// <inheritdoc cref="Interfaces.IPathCheck.CheckDirectoryPath(string, List{string})"/>
internal List<string> CactusDataShieldCheckDirectoryPath(string path, List<string>? files)
internal static List<string> CactusDataShieldCheckDirectoryPath(string path, List<string>? files)
{
// TODO: Verify if these are OR or AND
var matchers = new List<PathMatchSet>
@@ -89,7 +89,7 @@ namespace BinaryObjectScanner.Protection
}
/// <inheritdoc cref="Interfaces.IPathCheck.CheckFilePath(string)"/>
internal string? CactusDataShieldCheckFilePath(string path)
internal static string? CactusDataShieldCheckFilePath(string path)
{
var matchers = new List<PathMatchSet>
{

View File

@@ -12,7 +12,7 @@ namespace BinaryObjectScanner.Protection
public partial class Macrovision
{
/// <inheritdoc cref="Interfaces.IExecutableCheck{T}.CheckExecutable(string, T, bool)"/>
internal string? FLEXnetCheckExecutable(string file, PortableExecutable pex, bool includeDebug)
internal static string? FLEXnetCheckExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// Get the sections from the executable, if possible
var sections = pex.Model.SectionTable;
@@ -68,7 +68,7 @@ namespace BinaryObjectScanner.Protection
}
/// <inheritdoc cref="Interfaces.IPathCheck.CheckDirectoryPath(string, List{string})"/>
internal List<string> FLEXNetCheckDirectoryPath(string path, List<string>? files)
internal static List<string> FLEXNetCheckDirectoryPath(string path, List<string>? files)
{
var matchers = new List<PathMatchSet>
{
@@ -88,7 +88,7 @@ namespace BinaryObjectScanner.Protection
}
/// <inheritdoc cref="Interfaces.IPathCheck.CheckFilePath(string)"/>
internal string? FLEXNetCheckFilePath(string path)
internal static string? FLEXNetCheckFilePath(string path)
{
var matchers = new List<PathMatchSet>
{

View File

@@ -19,7 +19,7 @@ namespace BinaryObjectScanner.Protection
public partial class Macrovision
{
/// <inheritdoc cref="Interfaces.IExecutableCheck{T}.CheckExecutable(string, T, bool)"/>
internal string? RipGuardCheckExecutable(string file, PortableExecutable pex, bool includeDebug)
internal static string? RipGuardCheckExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// Get the sections from the executable, if possible
var sections = pex.Model.SectionTable;
@@ -50,16 +50,14 @@ namespace BinaryObjectScanner.Protection
return "RipGuard";
}
}
catch
{
}
catch { }
}
return null;
}
/// <inheritdoc cref="Interfaces.IPathCheck.CheckDirectoryPath(string, List{string})"/>
internal List<string> RipGuardCheckDirectoryPath(string path, List<string>? files)
internal static List<string> RipGuardCheckDirectoryPath(string path, List<string>? files)
{
var matchers = new List<PathMatchSet>
{
@@ -75,7 +73,7 @@ namespace BinaryObjectScanner.Protection
}
/// <inheritdoc cref="Interfaces.IPathCheck.CheckFilePath(string)"/>
internal string? RipGuardCheckFilePath(string path)
internal static string? RipGuardCheckFilePath(string path)
{
var matchers = new List<PathMatchSet>
{

View File

@@ -40,7 +40,7 @@ namespace BinaryObjectScanner.Protection
public partial class Macrovision
{
/// <inheritdoc cref="Interfaces.IExecutableCheck{T}.CheckExecutable(string, T, bool)"/>
internal string? SafeCastCheckExecutable(string file, NewExecutable nex, bool includeDebug)
internal static string? SafeCastCheckExecutable(string file, NewExecutable nex, bool includeDebug)
{
// Check for the CDAC01AA name string.
if (nex.Model.ResidentNameTable != null)
@@ -67,7 +67,7 @@ namespace BinaryObjectScanner.Protection
}
/// <inheritdoc cref="Interfaces.IExecutableCheck{T}.CheckExecutable(string, T, bool)"/>
internal string? SafeCastCheckExecutable(string file, PortableExecutable pex, bool includeDebug)
internal static string? SafeCastCheckExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// Get the sections from the executable, if possible
var sections = pex.Model.SectionTable;
@@ -147,7 +147,7 @@ namespace BinaryObjectScanner.Protection
}
/// <inheritdoc cref="Interfaces.IPathCheck.CheckDirectoryPath(string, List{string})"/>
internal List<string> SafeCastCheckDirectoryPath(string path, List<string>? files)
internal static List<string> SafeCastCheckDirectoryPath(string path, List<string>? files)
{
var matchers = new List<PathMatchSet>
{
@@ -190,7 +190,7 @@ namespace BinaryObjectScanner.Protection
}
/// <inheritdoc cref="Interfaces.IPathCheck.CheckFilePath(string)"/>
internal string? SafeCastCheckFilePath(string path)
internal static string? SafeCastCheckFilePath(string path)
{
var matchers = new List<PathMatchSet>
{

View File

@@ -41,7 +41,7 @@ namespace BinaryObjectScanner.Protection
public partial class Macrovision
{
/// <inheritdoc cref="Interfaces.IExecutableCheck{T}.CheckExecutable(string, T, bool)"/>
internal string? SafeDiscCheckExecutable(string file, PortableExecutable pex, bool includeDebug)
internal static string? SafeDiscCheckExecutable(string file, PortableExecutable pex, bool includeDebug)
{
// Get the sections from the executable, if possible
var sections = pex.Model.SectionTable;
@@ -49,12 +49,18 @@ namespace BinaryObjectScanner.Protection
return null;
// Found in Redump entry 57986.
if (Array.Exists(pex.Model.ImportTable?.HintNameTable ?? [], ihne => ihne?.Name == "LTDLL_Authenticate"))
return "SafeDisc Lite";
if (pex.Model.ImportTable?.HintNameTable != null)
{
if (Array.Exists(pex.Model.ImportTable.HintNameTable, ihne => ihne?.Name == "LTDLL_Authenticate"))
return "SafeDisc Lite";
}
// Found in Redump entry 57986.
if (Array.Exists(pex.Model.ImportTable?.ImportDirectoryTable ?? [], idte => idte?.Name == "ltdll.dll"))
return "SafeDisc Lite";
if (pex.Model.ImportTable?.ImportDirectoryTable != null)
{
if (Array.Exists(pex.Model.ImportTable.ImportDirectoryTable, idte => idte?.Name == "ltdll.dll"))
return "SafeDisc Lite";
}
// Get the .data/DATA section strings, if they exist
var strs = pex.GetFirstSectionStrings(".data") ?? pex.GetFirstSectionStrings("DATA");
@@ -103,14 +109,10 @@ namespace BinaryObjectScanner.Protection
// Found in Redump entries 20729 and 65569.
// Get the debug data
try
{
if (pex.FindCodeViewDebugTableByPath("SafeDisc").Count > 0)
return "SafeDisc";
if (pex.FindCodeViewDebugTableByPath("Safedisk").Count > 0)
return "SafeDisc";
}
catch { }
if (pex.FindCodeViewDebugTableByPath("SafeDisc").Count > 0)
return "SafeDisc";
if (pex.FindCodeViewDebugTableByPath("Safedisk").Count > 0)
return "SafeDisc";
// TODO: Investigate various section names:
// "STLPORT_" - Found in Redump entry 11638.
@@ -126,7 +128,7 @@ namespace BinaryObjectScanner.Protection
}
/// <inheritdoc cref="Interfaces.IPathCheck.CheckDirectoryPath(string, List{string})"/>
internal List<string> SafeDiscCheckDirectoryPath(string path, List<string>? files)
internal static List<string> SafeDiscCheckDirectoryPath(string path, List<string>? files)
{
var matchers = new List<PathMatchSet>
{
@@ -264,7 +266,7 @@ namespace BinaryObjectScanner.Protection
}
/// <inheritdoc cref="Interfaces.IPathCheck.CheckFilePath(string)"/>
internal string? SafeDiscCheckFilePath(string path)
internal static string? SafeDiscCheckFilePath(string path)
{
var matchers = new List<PathMatchSet>
{
@@ -927,7 +929,7 @@ namespace BinaryObjectScanner.Protection
// "SPLSH256.BMP": Found in SafeDisc versions 1.00.025-1.01.044 (Redump entries 66005 and 81619).
}
private string GetSafeDiscDiagExecutableVersion(PortableExecutable pex)
private static string GetSafeDiscDiagExecutableVersion(PortableExecutable pex)
{
// Different versions of this executable correspond to different SafeDisc versions.
var version = pex.FileVersion;

View File

@@ -70,23 +70,17 @@ namespace BinaryObjectScanner.Protection
// Almost every single sample known has both sections, though one only contains the "stxt371" section. It is unknown if this is intentional, or if the game functions without it.
// It is present in the "Texas HoldEm!" game in "boontybox_PCGamer_DVD.exe" in IA items PC_Gamer_Disc_7.55_July_2005 and cdrom-pcgamercd7.58.
// Other games in this set also aren't functional despite having the normal layout of stxt sections, and the primary program doesn't install at all due to activation servers being down.
bool stxt371Section = pex.ContainsSection("stxt371", exact: true);
bool stxt774Section = pex.ContainsSection("stxt774", exact: true);
if (stxt371Section || stxt774Section)
if (pex.ContainsSection("stxt371", exact: true) || pex.ContainsSection("stxt774", exact: true))
{
// Check the header padding for protected sections.
var sectionMatch = CheckSectionForProtection(file, includeDebug, pex.HeaderPaddingStrings, pex.HeaderPaddingData, true);
if (!string.IsNullOrEmpty(sectionMatch))
{
if (sectionMatch != null)
resultsList.Add(sectionMatch);
// Get the .data section, if it exists, for protected sections.
sectionMatch = CheckSectionForProtection(file, includeDebug, pex.GetFirstSectionStrings(".data"), pex.GetFirstSectionData(".data"), true);
if (sectionMatch != null)
resultsList.Add(sectionMatch!);
}
else
{
// Get the .data section, if it exists, for protected sections.
sectionMatch = CheckSectionForProtection(file, includeDebug, pex.GetFirstSectionStrings(".data"), pex.GetFirstSectionData(".data"), true);
if (!string.IsNullOrEmpty(sectionMatch))
resultsList.Add(sectionMatch!);
}
int entryPointIndex = pex.FindEntryPointSectionIndex();
var entryPointSectionName = pex.SectionNames?[entryPointIndex];
@@ -113,17 +107,13 @@ namespace BinaryObjectScanner.Protection
{
// Check the header padding for protected sections.
var sectionMatch = CheckSectionForProtection(file, includeDebug, pex.HeaderPaddingStrings, pex.HeaderPaddingData, false);
if (!string.IsNullOrEmpty(sectionMatch))
{
resultsList.Add(sectionMatch!);
}
else
{
// Check the .data section, if it exists, for protected sections.
sectionMatch = CheckSectionForProtection(file, includeDebug, pex.GetFirstSectionStrings(".data"), pex.GetFirstSectionData(".data"), false);
if (!string.IsNullOrEmpty(sectionMatch))
resultsList.Add(sectionMatch!);
}
if (sectionMatch != null)
resultsList.Add(sectionMatch);
// Check the .data section, if it exists, for protected sections.
sectionMatch = CheckSectionForProtection(file, includeDebug, pex.GetFirstSectionStrings(".data"), pex.GetFirstSectionData(".data"), false);
if (sectionMatch != null)
resultsList.Add(sectionMatch);
}
// Run Cactus Data Shield PE checks
@@ -249,7 +239,7 @@ namespace BinaryObjectScanner.Protection
}
/// <inheritdoc cref="IPathCheck.CheckDirectoryPath(string, List{string})"/>
internal List<string> MacrovisionCheckDirectoryPath(string path, List<string>? files)
internal static List<string> MacrovisionCheckDirectoryPath(string path, List<string>? files)
{
var matchers = new List<PathMatchSet>
{
@@ -261,7 +251,7 @@ namespace BinaryObjectScanner.Protection
}
/// <inheritdoc cref="IPathCheck.CheckFilePath(string)"/>
internal string? MacrovisionCheckFilePath(string path)
internal static string? MacrovisionCheckFilePath(string path)
{
var matchers = new List<PathMatchSet>
{

View File

@@ -32,11 +32,7 @@ namespace BinaryObjectScanner.Protection
// Get the .neac0 and .neac1 sections, if they exist.
// Found in "NeacSafe64.sys" and "NeacSafe.sys".
bool neac0Section = pex.ContainsSection(".neac0", exact: true);
bool neac1Section = pex.ContainsSection(".neac1", exact: true);
// Check if either .neac section is present.
if (neac0Section || neac1Section)
if (pex.ContainsSection(".neac0", exact: true) || pex.ContainsSection(".neac1", exact: true))
return "NEAC Protect";
var name = pex.ProductName;

View File

@@ -89,8 +89,7 @@ namespace BinaryObjectScanner.Protection
}
// Get the .vob.pcd section, if it exists
bool vobpcdSection = pex.ContainsSection(".vob.pcd", exact: true);
if (vobpcdSection)
if (pex.ContainsSection(".vob.pcd", exact: true))
return "VOB ProtectCD";
return null;
@@ -217,16 +216,22 @@ namespace BinaryObjectScanner.Protection
int index = positions[0] + 37;
byte subversion = fileContent[index];
index += 2;
byte version = fileContent[index];
index = positions[0] + 49;
int irefBuild = BitConverter.ToInt32(fileContent, index);
index = positions[0] + 53;
byte versionindicatorPD9 = fileContent[index];
index = positions[0] + 0x40;
byte subsubversionPD9x = fileContent[index];
index++;
byte subversionPD9x2 = fileContent[index];
index++;
byte subversionPD9x1 = fileContent[index];
@@ -308,10 +313,11 @@ namespace BinaryObjectScanner.Protection
// TODO: Ensure that this version finding works for all known versions
private static string GetVOBVersion(byte[] fileContent, int position)
{
byte version = fileContent[position - 2];
byte subVersion = (byte)((fileContent[position - 3] & 0xF0) >> 4);
byte subSubVersion = (byte)((fileContent[position - 4] & 0xF0) >> 4);
return $"{version}.{subVersion}.{subSubVersion}";
byte major = fileContent[position - 2];
byte minor = (byte)((fileContent[position - 3] & 0xF0) >> 4);
byte patch = (byte)((fileContent[position - 4] & 0xF0) >> 4);
return $"{major}.{minor}.{patch}";
}
}
}

View File

@@ -13,23 +13,22 @@ namespace BinaryObjectScanner.Protection
/// <inheritdoc/>
public string? CheckContents(string file, byte[] fileContent, bool includeDebug)
{
// Only allow during debug
if (!includeDebug)
return null;
// TODO: Obtain a sample to find where this string is in a typical executable
if (includeDebug)
var contentMatchSets = new List<ContentMatchSet>
{
var contentMatchSets = new List<ContentMatchSet>
// (char)0x00 + Allocator + (char)0x00 + (char)0x00 + (char)0x00 + (char)0x00
new(new byte?[]
{
// (char)0x00 + Allocator + (char)0x00 + (char)0x00 + (char)0x00 + (char)0x00
new(new byte?[]
{
0x00, 0x41, 0x6C, 0x6C, 0x6F, 0x63, 0x61, 0x74,
0x6F, 0x72, 0x00, 0x00, 0x00, 0x00
}, "Ring PROTECH / ProRing [Check disc for physical ring] (Unconfirmed - Please report to us on Github)"),
};
0x00, 0x41, 0x6C, 0x6C, 0x6F, 0x63, 0x61, 0x74,
0x6F, 0x72, 0x00, 0x00, 0x00, 0x00
}, "Ring PROTECH / ProRing [Check disc for physical ring] (Unconfirmed - Please report to us on Github)"),
};
return MatchUtil.GetFirstMatch(file, fileContent, contentMatchSets, includeDebug);
}
return null;
return MatchUtil.GetFirstMatch(file, fileContent, contentMatchSets, includeDebug);
}
// TODO: Confirm if these checks are only for ProRing or if they are also for older Ring PROTECH

View File

@@ -82,8 +82,7 @@ namespace BinaryObjectScanner.Protection
// Get the .svkp section, if it exists.
// This section is present in at least versions 1.05-1.32, but isn't present in every known sample of these versions. Removing this section name may be a perk of the licensed version.
bool neolitSection = pex.ContainsSection(".svkp", exact: true);
if (neolitSection)
if (pex.ContainsSection(".svkp", exact: true))
return "SVKP";
return null;

View File

@@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Text;
using BinaryObjectScanner.Interfaces;
using SabreTools.Matching;
@@ -41,22 +40,18 @@ namespace BinaryObjectScanner.Protection
return $"SecuROM Product Activation v{pex.GetInternalVersion()}";
// Get the matrosch section, if it exists
bool matroschSection = pex.ContainsSection("matrosch", exact: true);
if (matroschSection)
if (pex.ContainsSection("matrosch", exact: true))
return $"SecuROM Matroschka Package";
bool dsstextSection = pex.ContainsSection(".dsstext", exact: true);
if (dsstextSection)
if (pex.ContainsSection(".dsstext", exact: true))
return $"SecuROM 8.03.03+";
// Get the .securom section, if it exists
bool securomSection = pex.ContainsSection(".securom", exact: true);
if (securomSection)
if (pex.ContainsSection(".securom", exact: true))
return $"SecuROM {GetV7Version(pex)}";
// Get the .sll section, if it exists
bool sllSection = pex.ContainsSection(".sll", exact: true);
if (sllSection)
if (pex.ContainsSection(".sll", exact: true))
return $"SecuROM SLL Protected (for SecuROM v8.x)";
// Search after the last section
@@ -73,7 +68,7 @@ namespace BinaryObjectScanner.Protection
if (nthSection == null)
continue;
string nthSectionName = Encoding.UTF8.GetString(nthSection.Name ?? []).TrimEnd('\0');
string nthSectionName = Encoding.ASCII.GetString(nthSection.Name ?? []).TrimEnd('\0');
if (nthSectionName != ".idata" && nthSectionName != ".rsrc")
{
var nthSectionData = pex.GetFirstSectionData(nthSectionName);
@@ -104,9 +99,7 @@ namespace BinaryObjectScanner.Protection
}
// Get the .cms_d and .cms_t sections, if they exist -- TODO: Confirm if both are needed or either/or is fine
bool cmsdSection = pex.ContainsSection(".cmd_d", true);
bool cmstSection = pex.ContainsSection(".cms_t", true);
if (cmsdSection || cmstSection)
if (pex.ContainsSection(".cmd_d", true) || pex.ContainsSection(".cms_t", true))
return $"SecuROM 1-3";
return null;

View File

@@ -62,7 +62,7 @@ namespace BinaryObjectScanner.Protection
// Found in "TafseerVer4.exe" in IA item "TAFSEERVER4SETUP"
var strings = pex.GetFirstSectionStrings(".section") ?? [];
if (strings.Exists(s => s?.Contains("SOFTLOCKPROTECTION") == true))
if (strings.Exists(s => s.Contains("SOFTLOCKPROTECTION")))
return "SoftLock";
// Investigate if the ".section" section is an indicator of SoftLock

View File

@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using BinaryObjectScanner.Interfaces;
using SabreTools.Matching;
using SabreTools.Matching.Content;
@@ -77,7 +76,7 @@ namespace BinaryObjectScanner.Protection
return "SolidShield EXE Wrapper v1";
// Search the last two available sections
for (int i = (pex.SectionNames != null && pex.SectionNames.Length >= 2 ? pex.SectionNames.Length - 2 : 0); i < (pex.SectionNames?.Length ?? 0); i++)
for (int i = Math.Max(sections.Length - 2, 0); i < sections.Length; i++)
{
// Get the nth section strings, if they exist
var strs = pex.GetSectionStrings(i);
@@ -152,23 +151,18 @@ namespace BinaryObjectScanner.Protection
int position = positions[0];
#if NET20 || NET35 || NET40
byte[] id1 = new byte[3];
Array.Copy(fileContent, position + 5, id1, 0, 3);
byte[] id2 = new byte[4];
Array.Copy(fileContent, position + 16, id2, 0, 3);
#else
var id1 = new ArraySegment<byte>(fileContent, position + 5, 3);
var id2 = new ArraySegment<byte>(fileContent, position + 16, 4);
#endif
if (id1.SequenceEqual(new byte[] { 0x00, 0x00, 0x00 })
&& id2.SequenceEqual(new byte[] { 0x00, 0x10, 0x00, 0x00 }))
if (id1[0] == 0x00 && id1[1] == 0x00 && id1[2] == 0x00
&& id2[0] == 0x00 && id2[1] == 0x10 && id2[2] == 0x00 && id2[3] == 0x00)
{
return "v1";
}
else if (id1.SequenceEqual(new byte[] { 0x2E, 0x6F, 0x26 })
&& id2.SequenceEqual(new byte[] { 0xDB, 0xC5, 0x20, 0x3A })) // [0xDB, 0xC5, 0x20, 0x3A, 0xB9]
else if (id1[0] == 0x2E && id1[1] == 0x6F && id1[2] == 0x26
&& id2[0] == 0xDB && id2[1] == 0xC5 && id2[2] == 0x20 && id2[3] == 0x3A) // [0xDB, 0xC5, 0x20, 0x3A, 0xB9]
{
return "v2"; // TODO: Verify against other SolidShield 2 discs
}
@@ -183,24 +177,20 @@ namespace BinaryObjectScanner.Protection
return null;
int position = positions[0];
#if NET20 || NET35 || NET40
byte[] id1 = new byte[3];
Array.Copy(fileContent, position + 4, id1, 0, 3);
byte[] id2 = new byte[4];
Array.Copy(fileContent, position + 15, id2, 0, 3);
#else
var id1 = new ArraySegment<byte>(fileContent, position + 4, 3);
var id2 = new ArraySegment<byte>(fileContent, position + 15, 4);
#endif
if ((fileContent[position + 3] == 0x04 || fileContent[position + 3] == 0x05)
&& id1.SequenceEqual(new byte[] { 0x00, 0x00, 0x00 })
&& id2.SequenceEqual(new byte[] { 0x00, 0x10, 0x00, 0x00 }))
&& id1[0] == 0x00 && id1[1] == 0x00 && id1[2] == 0x00
&& id2[0] == 0x00 && id2[1] == 0x10 && id2[2] == 0x00 && id2[3] == 0x00)
{
return "2 (SolidShield v2 EXE Wrapper)";
}
else if (id1.SequenceEqual(new byte[] { 0x00, 0x00, 0x00 })
&& id2.SequenceEqual(new byte[] { 0x00, 0x00, 0x00, 0x00 }))
else if (id1[0] == 0x00 && id1[1] == 0x00 && id1[2] == 0x00
&& id2[0] == 0x00 && id2[1] == 0x10 && id2[2] == 0x00 && id2[3] == 0x00)
{
// "T" + (char)0x00 + "a" + (char)0x00 + "g" + (char)0x00 + "e" + (char)0x00 + "s" + (char)0x00 + "S" + (char)0x00 + "e" + (char)0x00 + "t" + (char)0x00 + "u" + (char)0x00 + "p" + (char)0x00 + (char)0x00 + (char)0x00 + (char)0x00 + (char)0x00 + "0" + (char)0x00 + (char)0x8 + (char)0x00 + (char)0x1 + (char)0x0 + "F" + (char)0x00 + "i" + (char)0x00 + "l" + (char)0x00 + "e" + (char)0x00 + "V" + (char)0x00 + "e" + (char)0x00 + "r" + (char)0x00 + "s" + (char)0x00 + "i" + (char)0x00 + "o" + (char)0x00 + "n" + (char)0x00 + (char)0x00 + (char)0x00 + (char)0x00
byte?[] check2 =

View File

@@ -90,13 +90,11 @@ namespace BinaryObjectScanner.Protection
// https://github.com/horsicq/Detect-It-Easy/blob/master/db/PE/StarForce.2.sg
// Get the .brick section, if it exists
bool brickSection = pex.ContainsSection(".brick", exact: true);
if (brickSection)
if (pex.ContainsSection(".brick", exact: true))
return "StarForce 3-5";
// Get the .sforce* section, if it exists
bool sforceSection = pex.ContainsSection(".sforce", exact: false);
if (sforceSection)
if (pex.ContainsSection(".sforce", exact: false))
return "StarForce 3-5";
return null;

View File

@@ -17,21 +17,21 @@ namespace BinaryObjectScanner.Protection
return null;
var name = pex.FileDescription;
if (!string.IsNullOrEmpty(name) && name!.Contains("Steam Autorun Setup"))
if (name?.Contains("Steam Autorun Setup") == true)
return "Steam";
else if (!string.IsNullOrEmpty(name) && name!.Contains("Steam Client API"))
else if (name?.Contains("Steam Client API") == true)
return "Steam";
else if (!string.IsNullOrEmpty(name) && name!.Contains("Steam Client Engine"))
else if (name?.Contains("Steam Client Engine") == true)
return $"Steam Client Engine {pex.GetInternalVersion()}";
else if (!string.IsNullOrEmpty(name) && name!.Contains("Steam Client Service"))
else if (name?.Contains("Steam Client Service") == true)
return "Steam";
name = pex.ProductName;
if (!string.IsNullOrEmpty(name) && name!.Contains("Steam Autorun Setup"))
if (name?.Contains("Steam Autorun Setup") == true)
return "Steam";
else if (!string.IsNullOrEmpty(name) && name!.Contains("Steam Client API"))
else if (name?.Contains("Steam Client API") == true)
return "Steam";
else if (!string.IsNullOrEmpty(name) && name!.Contains("Steam Client Service"))
else if (name?.Contains("Steam Client Service") == true)
return "Steam";
/// TODO: Add entry point checks

View File

@@ -51,7 +51,11 @@ namespace BinaryObjectScanner.Protection
var matchers = new List<ContentMatchSet>
{
// (char)0xE8 + u + (char)0x00 + (char)0x00 + (char)0x00 + (char)0xE8 + ?? + ?? + (char)0xFF + (char)0xFF + "h"
new(new byte?[] { 0xE8, 0x75, 0x00, 0x00, 0x00, 0xE8, null, null, 0xFF, 0xFF, 0x68 }, GetVersion, "TAGES"),
new(new byte?[]
{
0xE8, 0x75, 0x00, 0x00, 0x00, 0xE8, null, null,
0xFF, 0xFF, 0x68
}, GetVersion, "TAGES"),
};
var match = MatchUtil.GetFirstMatch(file, dataSectionRaw, matchers, includeDebug);

View File

@@ -1,5 +1,4 @@
using System.Collections.Generic;
using BinaryObjectScanner.Interfaces;
using BinaryObjectScanner.Interfaces;
using SabreTools.Serialization.Wrappers;
namespace BinaryObjectScanner.Protection
@@ -33,7 +32,7 @@ namespace BinaryObjectScanner.Protection
return null;
// Get the "Arcsoft " section strings, if they exist
List<string>? strs = pex.GetFirstSectionStrings("Arcsoft ");
var strs = pex.GetFirstSectionStrings("Arcsoft ");
if (strs != null)
{
// Found in "uDigital Theatre.exe" in http://downloads.fyxm.net/ArcSoft-TotalMedia-23085.html (https://web.archive.org/web/20221114042838/http://files.fyxm.net/23/23085/totalmediatheatre3platinum_retail_tbyb_all.exe).

View File

@@ -18,26 +18,26 @@ namespace BinaryObjectScanner.Protection
return null;
var name = pex.FileDescription;
if (!string.IsNullOrEmpty(name) && name!.Contains("Ubisoft Connect Installer"))
if (name?.Contains("Ubisoft Connect Installer") == true)
return "Uplay / Ubisoft Connect";
else if (!string.IsNullOrEmpty(name) && name!.Contains("Ubisoft Connect Service"))
else if (name?.Contains("Ubisoft Connect Service") == true)
return "Uplay / Ubisoft Connect";
else if (!string.IsNullOrEmpty(name) && name!.Contains("Ubisoft Connect WebCore"))
else if (name?.Contains("Ubisoft Connect WebCore") == true)
return "Uplay / Ubisoft Connect";
else if (!string.IsNullOrEmpty(name) && name!.Contains("Ubisoft Crash Reporter"))
else if (name?.Contains("Ubisoft Crash Reporter") == true)
return "Uplay / Ubisoft Connect";
else if (!string.IsNullOrEmpty(name) && name!.Contains("Ubisoft Game Launcher"))
else if (name?.Contains("Ubisoft Game Launcher") == true)
return "Uplay / Ubisoft Connect";
else if (!string.IsNullOrEmpty(name) && name!.Contains("Ubisoft Uplay Installer"))
else if (name?.Contains("Ubisoft Uplay Installer") == true)
return "Uplay / Ubisoft Connect";
else if (!string.IsNullOrEmpty(name) && name!.Contains("Uplay launcher"))
else if (name?.Contains("Uplay launcher") == true)
return "Uplay / Ubisoft Connect";
// There's also a variant that looks like "Uplay <version> installer"
name = pex.ProductName;
if (!string.IsNullOrEmpty(name) && name!.Contains("Ubisoft Connect"))
if (name?.Contains("Ubisoft Connect") == true)
return "Uplay / Ubisoft Connect";
else if (!string.IsNullOrEmpty(name) && name!.Contains("Uplay"))
else if (name?.Contains("Uplay") == true)
return "Uplay / Ubisoft Connect";
return null;