Organize StarForce, get rid of all Model calls

This commit is contained in:
Matt Nadareski
2025-09-08 17:58:48 -04:00
parent d6a3a37d49
commit 6cb86512c3
27 changed files with 533 additions and 519 deletions

View File

@@ -12,7 +12,7 @@ namespace BinaryObjectScanner.Packer
public string? CheckExecutable(string file, PortableExecutable exe, bool includeDebug)
{
// Get the last section strings, if they exist
var sections = exe.Model.SectionTable ?? [];
var sections = exe.SectionTable ?? [];
var strs = exe.GetSectionStrings(sections.Length - 1);
if (strs != null)
{

View File

@@ -16,7 +16,7 @@ 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 importTableMatch = Array.Exists(exe.Model.ImportTable?.ImportDirectoryTable ?? [],
bool importTableMatch = Array.Exists(exe.ImportTable?.ImportDirectoryTable ?? [],
idte => idte?.Name == "KeRnEl32.dLl");
if (exe.ContainsSection("peC", exact: true) && importTableMatch)

View File

@@ -14,7 +14,7 @@ namespace BinaryObjectScanner.Packer
public string? CheckExecutable(string file, NewExecutable exe, bool includeDebug)
{
// Check for "Inno" in the reserved words
var reserved2 = exe.Model.Stub?.Header?.Reserved2;
var reserved2 = exe.Stub?.Header?.Reserved2;
if (reserved2 != null && reserved2.Length > 5)
{
if (reserved2[4] == 0x6E49 && reserved2[5] == 0x6F6E)

View File

@@ -11,7 +11,7 @@ namespace BinaryObjectScanner.Packer
public string? CheckExecutable(string file, PortableExecutable exe, bool includeDebug)
{
// 0x4F434550 is "PECO"
if (exe.Model.COFFFileHeader?.PointerToSymbolTable == 0x4F434550)
if (exe.COFFFileHeader?.PointerToSymbolTable == 0x4F434550)
return "PE Compact v1.x";
// TODO: Get more granular version detection. PiD is somehow able to detect version ranges based

File diff suppressed because it is too large Load Diff

View File

@@ -63,7 +63,7 @@ namespace BinaryObjectScanner.Protection
return $"ByteShield Activation Client {exe.GetInternalVersion()}";
// Found in "ByteShield.dll" in Redump entry 6236
name = exe.Model.ExportTable?.ExportDirectoryTable?.Name;
name = exe.ExportTable?.ExportDirectoryTable?.Name;
if (name.OptionalEquals("ByteShield Client"))
return "ByteShield Component Module";

View File

@@ -120,14 +120,14 @@ namespace BinaryObjectScanner.Protection
return match;
// Get the resident and non-resident name table strings
var nrntStrs = Array.ConvertAll(exe.Model.NonResidentNameTable ?? [],
var nrntStrs = Array.ConvertAll(exe.NonResidentNameTable ?? [],
nrnte => nrnte?.NameString == null ? string.Empty : Encoding.ASCII.GetString(nrnte.NameString));
// Check the imported-name table
// Found in "h3blade.exe" in Redump entry 85077.
if (exe.Model.ImportedNameTable != null)
if (exe.ImportedNameTable != null)
{
foreach (var inte in exe.Model.ImportedNameTable.Values)
foreach (var inte in exe.ImportedNameTable.Values)
{
if (inte.NameString.IsNullOrEmpty())
continue;

View File

@@ -28,19 +28,19 @@ namespace BinaryObjectScanner.Protection
// TODO: Investigate the numerous ".guard" sections present in "Randevu.exe" in Redump entry 97142.
// Get the export directory table
if (exe.Model.ExportTable?.ExportDirectoryTable != null)
if (exe.ExportTable?.ExportDirectoryTable != null)
{
// Found in "cdguard.dll" in Redump entry 97142 and IA item "pahgeby-he3hakomkou".
bool match = exe.Model.ExportTable.ExportDirectoryTable.Name.OptionalEquals("cdguard.dll", StringComparison.OrdinalIgnoreCase);
bool match = exe.ExportTable.ExportDirectoryTable.Name.OptionalEquals("cdguard.dll", StringComparison.OrdinalIgnoreCase);
if (match)
return "CD-Guard Copy Protection System";
}
// Get the import directory table
if (exe.Model.ImportTable?.ImportDirectoryTable != null)
if (exe.ImportTable?.ImportDirectoryTable != null)
{
// Found in "Randevu.exe" in Redump entry 97142.
bool match = Array.Exists(exe.Model.ImportTable.ImportDirectoryTable, idte => idte?.Name != null && idte.Name.Equals("cdguard.dll", StringComparison.OrdinalIgnoreCase));
bool match = Array.Exists(exe.ImportTable.ImportDirectoryTable, idte => idte?.Name != null && idte.Name.Equals("cdguard.dll", StringComparison.OrdinalIgnoreCase));
if (match)
return "CD-Guard Copy Protection System";
}

View File

@@ -10,9 +10,9 @@ namespace BinaryObjectScanner.Protection
{
// TODO: Indicates Hypertech Crack Proof as well?
//// Get the import directory table
//if (exe.Model.ImportTable?.ImportDirectoryTable != null)
//if (exe.ImportTable?.ImportDirectoryTable != null)
//{
// bool match = exe.Model.ImportTable.ImportDirectoryTable.Any(idte => idte.Name == "KeRnEl32.dLl");
// bool match = exe.ImportTable.ImportDirectoryTable.Any(idte => idte.Name == "KeRnEl32.dLl");
// if (match)
// return "CDSHiELD SE";
//}

View File

@@ -18,10 +18,10 @@ namespace BinaryObjectScanner.Protection
public string? CheckExecutable(string file, PortableExecutable exe, bool includeDebug)
{
// Get the export directory table
if (exe.Model.ExportTable?.ExportDirectoryTable != null)
if (exe.ExportTable?.ExportDirectoryTable != null)
{
// Found in "cenega.dll" in IA item "speed-pack".
bool match = exe.Model.ExportTable.ExportDirectoryTable.Name.OptionalEquals("ProtectDVD.dll", StringComparison.OrdinalIgnoreCase);
bool match = exe.ExportTable.ExportDirectoryTable.Name.OptionalEquals("ProtectDVD.dll", StringComparison.OrdinalIgnoreCase);
if (match)
return "Cenega ProtectDVD";
}

View File

@@ -62,7 +62,7 @@ namespace BinaryObjectScanner.Protection
// Checks for Professional
// PEX checks intentionally only detect Professional
var sections = exe.Model.SectionTable;
var sections = exe.SectionTable;
if (sections == null)
return null;

View File

@@ -62,7 +62,7 @@ namespace BinaryObjectScanner.Protection
// https://github.com/horsicq/Detect-It-Easy/blob/master/db/PE/_denuvoComplete.2.sg
// Denuvo Protector
if (exe.Model.OptionalHeader?.Magic == OHMN.PE32Plus
if (exe.OptionalHeader?.Magic == OHMN.PE32Plus
&& exe.EntryPointData != null)
{
byte?[] denuvoProtector =
@@ -95,7 +95,7 @@ namespace BinaryObjectScanner.Protection
// || exe.ContainsSection(".srdata")
|| !string.IsNullOrEmpty(timingMatch))
{
if (exe.Model.OptionalHeader?.Magic == OHMN.PE32Plus)
if (exe.OptionalHeader?.Magic == OHMN.PE32Plus)
{
var matchers = new List<ContentMatchSet>
{

View File

@@ -20,11 +20,11 @@ namespace BinaryObjectScanner.Protection
// Most every tested sample of "engine32.dll" has a product name of "engine32", and the file description typically follows the naming pattern of "[Game Name] DLL-helper".
// Detects Engine32 within the game executables that contain it.
if (exe.Model.ImportTable?.ImportDirectoryTable != null && exe.Model.ImportTable?.HintNameTable != null)
if (exe.ImportTable?.ImportDirectoryTable != null && exe.ImportTable?.HintNameTable != null)
{
bool importDirectoryTableMatch = Array.Exists(exe.Model.ImportTable.ImportDirectoryTable,
bool importDirectoryTableMatch = Array.Exists(exe.ImportTable.ImportDirectoryTable,
idte => idte?.Name != null && idte.Name.Equals("ENGINE32.DLL", StringComparison.OrdinalIgnoreCase));
bool hintNameTableMatch = Array.Exists(exe.Model.ImportTable.HintNameTable,
bool hintNameTableMatch = Array.Exists(exe.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).
@@ -33,10 +33,10 @@ namespace BinaryObjectScanner.Protection
}
// Detects Engine32 within the file "engine32.dll".
if (exe.Model.ExportTable?.ExportNameTable?.Strings != null)
if (exe.ExportTable?.ExportNameTable?.Strings != null)
{
bool exportNameTableMatch1 = Array.Exists(exe.Model.ExportTable.ExportNameTable.Strings, s => s == "engine32.dll");
bool exportNameTableMatch2 = Array.Exists(exe.Model.ExportTable.ExportNameTable.Strings, s => s == "DeinitEngine");
bool exportNameTableMatch1 = Array.Exists(exe.ExportTable.ExportNameTable.Strings, s => s == "engine32.dll");
bool exportNameTableMatch2 = Array.Exists(exe.ExportTable.ExportNameTable.Strings, s => s == "DeinitEngine");
if (exportNameTableMatch1 && exportNameTableMatch2)
return "Engine32";

View File

@@ -20,9 +20,9 @@ namespace BinaryObjectScanner.Protection
return $"Games for Windows LIVE {exe.GetInternalVersion()}";
// Get the import directory table
if (exe.Model.ImportTable?.ImportDirectoryTable != null)
if (exe.ImportTable?.ImportDirectoryTable != null)
{
if (Array.Exists(exe.Model.ImportTable.ImportDirectoryTable, idte => idte?.Name == "xlive.dll"))
if (Array.Exists(exe.ImportTable.ImportDirectoryTable, idte => idte?.Name == "xlive.dll"))
return "Games for Windows LIVE";
}

View File

@@ -29,8 +29,8 @@ namespace BinaryObjectScanner.Protection
// TODO: Check for CVP* instead?
bool containsCheck = false;
if (exe.Model.ExportTable?.ExportNameTable?.Strings != null)
containsCheck = Array.Exists(exe.Model.ExportTable.ExportNameTable.Strings, s => s.OptionalStartsWith("CVPInitializeClient"));
if (exe.ExportTable?.ExportNameTable?.Strings != null)
containsCheck = Array.Exists(exe.ExportTable.ExportNameTable.Strings, s => s.OptionalStartsWith("CVPInitializeClient"));
// Get the .rdata section strings, if they exist
bool containsCheck2 = false;

View File

@@ -19,8 +19,8 @@ namespace BinaryObjectScanner.Protection
// Get the .ext section, if it exists
if (exe.ContainsSection(".ext ", exact: true))
{
bool importTableMatches = Array.Exists(exe.Model.ImportTable?.ImportDirectoryTable ?? [], idte => idte?.Name == "kernel32.dll")
&& Array.Exists(exe.Model.ImportTable?.HintNameTable ?? [], s => s?.Name == "VirtualProtect");
bool importTableMatches = Array.Exists(exe.ImportTable?.ImportDirectoryTable ?? [], idte => idte?.Name == "kernel32.dll")
&& Array.Exists(exe.ImportTable?.HintNameTable ?? [], s => s?.Name == "VirtualProtect");
// Get the .dcrtext section, if it exists
if (exe.ContainsSection(".dcrtext") && importTableMatches)

View File

@@ -59,16 +59,16 @@ namespace BinaryObjectScanner.Protection
0x6C, 0x61, 0x6D, 0x65, 0x6E, 0x74, 0x61, 0x73,
0x2E, 0x50, 0x45
];
int endDosStub = (int)(exe.Model.Stub?.Header?.NewExeHeaderAddr ?? 0);
int endDosStub = (int)(exe.Stub?.Header?.NewExeHeaderAddr ?? 0);
int position = -1;
// Check the executable tables
position = exe.StubExecutableData?.FirstPosition(check) ?? -1;
bool containsCheck = position > -1;
bool containsCheck2 = Array.Exists(exe.Model.ImportTable?.HintNameTable ?? [], hnte => hnte?.Name == "GetModuleHandleA")
&& Array.Exists(exe.Model.ImportTable?.HintNameTable ?? [], hnte => hnte?.Name == "GetProcAddress")
&& Array.Exists(exe.Model.ImportTable?.HintNameTable ?? [], hnte => hnte?.Name == "LoadLibraryA")
&& Array.Exists(exe.Model.ImportTable?.ImportDirectoryTable ?? [], idte => idte?.Name == "KERNEL32.dll");
bool containsCheck2 = Array.Exists(exe.ImportTable?.HintNameTable ?? [], hnte => hnte?.Name == "GetModuleHandleA")
&& Array.Exists(exe.ImportTable?.HintNameTable ?? [], hnte => hnte?.Name == "GetProcAddress")
&& Array.Exists(exe.ImportTable?.HintNameTable ?? [], hnte => hnte?.Name == "LoadLibraryA")
&& Array.Exists(exe.ImportTable?.ImportDirectoryTable ?? [], idte => idte?.Name == "KERNEL32.dll");
int position2 = -1;

View File

@@ -43,9 +43,9 @@ namespace BinaryObjectScanner.Protection
internal static string? SafeCastCheckExecutable(string file, NewExecutable exe, bool includeDebug)
{
// Check for the CDAC01AA name string.
if (exe.Model.ResidentNameTable != null)
if (exe.ResidentNameTable != null)
{
var residentNames = Array.ConvertAll(exe.Model.ResidentNameTable,
var residentNames = Array.ConvertAll(exe.ResidentNameTable,
rnte => rnte?.NameString == null ? string.Empty : Encoding.ASCII.GetString(rnte.NameString));
if (Array.Exists(residentNames, s => s.Contains("CDAC01AA")))
return "SafeCast";
@@ -74,9 +74,9 @@ namespace BinaryObjectScanner.Protection
// TODO: Invesitgate if the "AdobeLM.dll" file (along with mentions of "AdobeLM" in executables) uniquely identifies SafeCast, or if it can be used with different DRM. (Found in IA item ccd0605)
// Get the import directory table, if it exists
if (exe.Model.ImportTable?.ImportDirectoryTable != null)
if (exe.ImportTable?.ImportDirectoryTable != null)
{
if (Array.Exists(exe.Model.ImportTable.ImportDirectoryTable,
if (Array.Exists(exe.ImportTable.ImportDirectoryTable,
idte => idte?.Name != null && idte.Name.Equals("CdaC14BA.dll", StringComparison.OrdinalIgnoreCase)))
{
return "SafeCast";

View File

@@ -51,16 +51,16 @@ namespace BinaryObjectScanner.Protection
internal static string? SafeDiscCheckExecutable(string file, PortableExecutable exe, bool includeDebug)
{
// Found in Redump entry 57986.
if (exe.Model.ImportTable?.HintNameTable != null)
if (exe.ImportTable?.HintNameTable != null)
{
if (Array.Exists(exe.Model.ImportTable.HintNameTable, ihne => ihne?.Name == "LTDLL_Authenticate"))
if (Array.Exists(exe.ImportTable.HintNameTable, ihne => ihne?.Name == "LTDLL_Authenticate"))
return "SafeDisc Lite";
}
// Found in Redump entry 57986.
if (exe.Model.ImportTable?.ImportDirectoryTable != null)
if (exe.ImportTable?.ImportDirectoryTable != null)
{
if (Array.Exists(exe.Model.ImportTable.ImportDirectoryTable, idte => idte?.Name == "ltdll.dll"))
if (Array.Exists(exe.ImportTable.ImportDirectoryTable, idte => idte?.Name == "ltdll.dll"))
return "SafeDisc Lite";
}

View File

@@ -45,9 +45,9 @@ namespace BinaryObjectScanner.Protection
}
// Get the export name table
if (exe.Model.ExportTable?.ExportNameTable?.Strings != null)
if (exe.ExportTable?.ExportNameTable?.Strings != null)
{
if (Array.Exists(exe.Model.ExportTable.ExportNameTable.Strings, s => s == "DllInstallSbcp"))
if (Array.Exists(exe.ExportTable.ExportNameTable.Strings, s => s == "DllInstallSbcp"))
return "MediaMax CD-3";
}

View File

@@ -17,7 +17,7 @@ namespace BinaryObjectScanner.Protection
public string? CheckExecutable(string file, PortableExecutable exe, bool includeDebug)
{
// Get the 4th and 5th sections, if they exist (example names: ACE4/ACE5) (Found in Redump entries 94792, 94793)
var sections = exe.Model.SectionTable ?? [];
var sections = exe.SectionTable ?? [];
for (int i = 3; i < sections.Length; i++)
{
var nthSectionData = exe.GetSectionData(i);

View File

@@ -105,7 +105,7 @@ namespace BinaryObjectScanner.Protection
return match;
// Get the resident and non-resident name table strings
var nrntStrs = Array.ConvertAll(exe.Model.NonResidentNameTable ?? [],
var nrntStrs = Array.ConvertAll(exe.NonResidentNameTable ?? [],
rnte => rnte?.NameString == null ? string.Empty : Encoding.ASCII.GetString(rnte.NameString));
// Check the nonresident-name table

View File

@@ -72,7 +72,7 @@ namespace BinaryObjectScanner.Protection
}
// 0x504B5653 is "SVKP"
if (exe.Model.COFFFileHeader?.PointerToSymbolTable == 0x504B5653)
if (exe.COFFFileHeader?.PointerToSymbolTable == 0x504B5653)
return "SVKP";
// Get the .svkp section, if it exists.

View File

@@ -49,7 +49,7 @@ namespace BinaryObjectScanner.Protection
}
// Get the sections 5+, if they exist (example names: .fmqyrx, .vcltz, .iywiak)
var sections = exe.Model.SectionTable ?? [];
var sections = exe.SectionTable ?? [];
for (int i = 4; i < sections.Length; i++)
{
var nthSection = sections[i];

View File

@@ -15,7 +15,7 @@ namespace BinaryObjectScanner.Protection
if (exe.InternalName.OptionalEquals("SmarteSECURE"))
return "SmartE";
var sections = exe.Model.SectionTable ?? [];
var sections = exe.SectionTable ?? [];
if (sections.Length > 0)
{

View File

@@ -75,7 +75,7 @@ namespace BinaryObjectScanner.Protection
return "SolidShield EXE Wrapper v1";
// Search the last two available sections
var sections = exe.Model.SectionTable ?? [];
var sections = exe.SectionTable ?? [];
for (int i = Math.Max(sections.Length - 2, 0); i < sections.Length; i++)
{
// Get the nth section strings, if they exist
@@ -89,15 +89,15 @@ namespace BinaryObjectScanner.Protection
}
// Get the import directory table, if it exists
if (exe.Model.ImportTable?.ImportDirectoryTable != null)
if (exe.ImportTable?.ImportDirectoryTable != null)
{
if (Array.Exists(exe.Model.ImportTable.ImportDirectoryTable, idte => idte?.Name == "dvm.dll"))
if (Array.Exists(exe.ImportTable.ImportDirectoryTable, idte => idte?.Name == "dvm.dll"))
return "SolidShield EXE Wrapper v1";
if (Array.Exists(exe.Model.ImportTable.ImportDirectoryTable, idte => idte?.Name == "activation.x86.dll"))
if (Array.Exists(exe.ImportTable.ImportDirectoryTable, idte => idte?.Name == "activation.x86.dll"))
return "SolidShield EXE Wrapper v2";
if (Array.Exists(exe.Model.ImportTable.ImportDirectoryTable, idte => idte?.Name == "activation.x64.dll"))
if (Array.Exists(exe.ImportTable.ImportDirectoryTable, idte => idte?.Name == "activation.x64.dll"))
return "SolidShield EXE Wrapper v2";
}

View File

@@ -19,7 +19,8 @@ namespace BinaryObjectScanner.Protection
/// <inheritdoc/>
public string? CheckExecutable(string file, PortableExecutable exe, bool includeDebug)
{
// TODO: Find what fvinfo field actually maps to this
#region File Description
var name = exe.FileDescription;
// There are some File Description checks that are currently too generic to use.
@@ -47,18 +48,26 @@ namespace BinaryObjectScanner.Protection
if (name.OptionalContains("Protected Module"))
return $"StarForce 5";
#endregion
#region Legal Copyright
name = exe.LegalCopyright;
if (name.OptionalStartsWith("(c) Protection Technology")) // (c) Protection Technology (StarForce)?
return $"StarForce {exe.GetInternalVersion()}";
else if (name.OptionalContains("Protection Technology")) // Protection Technology (StarForce)?
return $"StarForce {exe.GetInternalVersion()}";
#endregion
#region Trade Name
// FrontLine ProActive (digital activation), samples:
// https://dbox.tools/titles/pc/46450FA4/
// https://dbox.tools/titles/pc/4F430FA0/
// https://dbox.tools/titles/pc/53450FA1/
name = exe.TradeName;
if (name.OptionalContains("FL ProActive"))
if (name.OptionalContains("FL ProActive"))
return "FrontLine ProActive";
// StarForce Crypto (SF Crypto)
@@ -66,14 +75,17 @@ namespace BinaryObjectScanner.Protection
if (name.OptionalContains("SF Crypto"))
return "StarForce Crypto";
#endregion
#region Internal Name
// TODO: Decide if internal name checks are safe to use.
name = exe.InternalName;
name = exe.InternalName;
// Found in "protect.x64" and "protect.x86" in Redump entry 94805.
if (name.OptionalEquals("CORE.ADMIN", StringComparison.Ordinal))
return $"StarForce {exe.GetInternalVersion()}";
// These checks currently disabled due being possibly too generic:
// Found in "protect.dll" in Redump entry 94805.
// if (name.OptionalEquals("CORE.DLL", StringComparison.Ordinal))
@@ -86,11 +98,13 @@ namespace BinaryObjectScanner.Protection
// else if (name.OptionalEquals("protect.exe", StringComparison.Ordinal))
// return $"StarForce {Tools.Utilities.GetInternalVersion(exe)}";
#endregion
// Check the export name table
if (exe.Model.ExportTable?.ExportNameTable?.Strings != null)
if (exe.ExportTable?.ExportNameTable?.Strings != null)
{
// TODO: Should we just check for "PSA_*" instead of a single entry?
if (Array.Exists(exe.Model.ExportTable.ExportNameTable.Strings, s => s == "PSA_GetDiscLabel"))
if (Array.Exists(exe.ExportTable.ExportNameTable.Strings, s => s == "PSA_GetDiscLabel"))
return $"StarForce {exe.GetInternalVersion()}";
}