Files
BinaryObjectScanner/BinaryObjectScanner/Protection/StarForce.cs
2025-09-08 17:58:48 -04:00

176 lines
7.4 KiB
C#

using System;
using System.Collections.Generic;
using BinaryObjectScanner.Interfaces;
using SabreTools.Matching;
using SabreTools.Matching.Paths;
using SabreTools.Serialization.Wrappers;
namespace BinaryObjectScanner.Protection
{
public class StarForce : IExecutableCheck<PortableExecutable>, IPathCheck
{
// TODO: Bring up to par with PiD.
// Known issues:
// "Game.exe" not detected (Redump entry 96137).
// "HR.exe" Themida not detected, doesn't detect "[Builder]" (Is that the default StarForce?) (Redump entry 94805).
// "ChromeEngine3.dll" and "SGP4.dll" not detected, doesn't detect "[FL Disc]" (Redump entry 93098).
// "Replay.exe" not detected, doesn't detect "[FL Disc]" (Redump entry 81756).
// Doesn't detect "[Pro]" (Redump entry 91336).
/// <inheritdoc/>
public string? CheckExecutable(string file, PortableExecutable exe, bool includeDebug)
{
#region File Description
var name = exe.FileDescription;
// There are some File Description checks that are currently too generic to use.
// "Host Library" - Found in "protect.dll" in Redump entry 81756.
// "User Interface Application" - Found in "protect.exe" in Redump entry 81756.
// "Helper Application" - Found in "protect.x64" and "protect.x86" in Redump entry 81756.
// Found in "sfdrvrem.exe" in Redump entry 102677.
if (name.OptionalContains("FrontLine Drivers Removal Tool"))
return $"StarForce FrontLine Driver Removal Tool";
// Found in "protect.exe" in Redump entry 94805.
if (name.OptionalContains("FrontLine Protection GUI Application"))
return $"StarForce {exe.GetInternalVersion()}";
// Found in "protect.dll" in Redump entry 94805.
if (name.OptionalContains("FrontLine Protection Library"))
return $"StarForce {exe.GetInternalVersion()}";
// Found in "protect.x64" and "protect.x86" in Redump entry 94805.
if (name.OptionalContains("FrontLine Helper"))
return $"StarForce {exe.GetInternalVersion()}";
// TODO: Find a sample of this check.
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"))
return "FrontLine ProActive";
// StarForce Crypto (SF Crypto)
// Found in "pcnsl.exe" in Redump entry 119679
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;
// 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))
// return $"StarForce {Tools.Utilities.GetInternalVersion(exe)}";
//
// Found in "protect.exe" in Redump entry 94805.
// if (name.OptionalEquals("CORE.EXE", StringComparison.Ordinal))
// return $"StarForce {Tools.Utilities.GetInternalVersion(exe)}";
//
// else if (name.OptionalEquals("protect.exe", StringComparison.Ordinal))
// return $"StarForce {Tools.Utilities.GetInternalVersion(exe)}";
#endregion
// Check the export name table
if (exe.ExportTable?.ExportNameTable?.Strings != null)
{
// TODO: Should we just check for "PSA_*" instead of a single entry?
if (Array.Exists(exe.ExportTable.ExportNameTable.Strings, s => s == "PSA_GetDiscLabel"))
return $"StarForce {exe.GetInternalVersion()}";
}
// TODO: Check to see if there are any missing checks
// https://github.com/horsicq/Detect-It-Easy/blob/master/db/PE/StarForce.2.sg
// Get the .brick section, if it exists
if (exe.ContainsSection(".brick", exact: true))
return "StarForce 3-5";
// Get the .sforce* section, if it exists
if (exe.ContainsSection(".sforce", exact: false))
return "StarForce 3-5";
// TODO: Investigate the .common and .ps4 sections found in apache.exe
// .common doesn't map to any table
// The section is largely empty with a 3 or 4 byte value at
// offset 0x40. Sample has "D4 DB DD 00"
// .ps4 has a virtual size of 4096 and a physical size of 0
// The physical offset is the end of the file
return null;
}
/// <inheritdoc/>
public List<string> CheckDirectoryPath(string path, List<string>? files)
{
var matchers = new List<PathMatchSet>
{
// This file combination is found in Redump entry 21136.
new(new List<PathMatch>
{
new FilePathMatch("protect.x86"),
new FilePathMatch("protect.x64"),
new FilePathMatch("protect.dll"),
new FilePathMatch("protect.exe"),
new FilePathMatch("protect.msg"),
}, "StarForce"),
// This file combination is found in multiple games, such as Redump entries 81756, 91336, and 93657.
new(new List<PathMatch>
{
new FilePathMatch("protect.x86"),
new FilePathMatch("protect.x64"),
new FilePathMatch("protect.dll"),
new FilePathMatch("protect.exe"),
}, "StarForce"),
// This file combination is found in Redump entry 96137.
new(new List<PathMatch>
{
new FilePathMatch("protect.x86"),
new FilePathMatch("protect.dll"),
new FilePathMatch("protect.exe"),
}, "StarForce"),
};
return MatchUtil.GetAllMatches(files, matchers, any: false);
}
/// <inheritdoc/>
public string? CheckFilePath(string path)
{
// TODO: Determine if there are any file name checks that aren't too generic to use on their own.
return null;
}
}
}