Why is there so much StarForce, geez (#180)

* Begin work on overhauling StarForce detection, and to add notes.

* Attempt to add SFFS file detection.

* Fix minor TAGES issue.
This commit is contained in:
TheRogueArchivist
2022-12-13 12:42:55 -07:00
committed by GitHub
parent 9c173fd3a1
commit 56c27d0b8f
6 changed files with 145 additions and 22 deletions

View File

@@ -80,6 +80,11 @@
/// </summary>
SevenZip,
/// <summary>
/// StarForce FileSystem file
/// </summary>
SFFS,
/// <summary>
/// Tape archive
/// </summary>

View File

@@ -0,0 +1,49 @@
using System;
using System.Collections.Concurrent;
using System.IO;
using BurnOutSharp.Interfaces;
using BurnOutSharp.Tools;
namespace BurnOutSharp.FileType
{
/// <summary>
/// StarForce Filesystem file
/// </summary>
public class SFFS : IScannable
{
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, string file)
{
if (!File.Exists(file))
return null;
using (var fs = File.OpenRead(file))
{
return Scan(scanner, fs, file);
}
}
/// <inheritdoc/>
public ConcurrentDictionary<string, ConcurrentQueue<string>> Scan(Scanner scanner, Stream stream, string file)
{
var protections = new ConcurrentDictionary<string, ConcurrentQueue<string>>();
try
{
byte[] magic = new byte[16];
stream.Read(magic, 0, 16);
if (Utilities.GetFileType(magic) == SupportedFileType.SFFS)
{
Utilities.AppendToDictionary(protections, file, "StarForce Filesystem Container");
return protections;
}
}
catch (Exception ex)
{
if (scanner.IncludeDebug) Console.WriteLine(ex);
}
return null;
}
}
}

View File

@@ -3,6 +3,7 @@ using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using BurnOutSharp.Interfaces;
using BurnOutSharp.Matching;
using BurnOutSharp.Tools;
using BurnOutSharp.Wrappers;
@@ -10,6 +11,13 @@ namespace BurnOutSharp.ProtectionType
{
public class StarForce : IPathCheck, IPortableExecutableCheck
{
// TODO: Bring up to par with PiD.
// Known issues:
// "Game.exe" not detected, "SF Crypto" not found in protect.* files (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 CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug)
{
@@ -24,12 +32,26 @@ namespace BurnOutSharp.ProtectionType
else if (name?.Contains("Protection Technology") == true) // Protection Technology (StarForce)?
return $"StarForce {Utilities.GetInternalVersion(pex)}";
// TODO: Decide if internal name checks are safe to use.
name = pex.InternalName;
if (name?.Equals("CORE.EXE", StringComparison.Ordinal) == true)
return $"StarForce {Utilities.GetInternalVersion(pex)}";
else if (name?.Equals("protect.exe", StringComparison.Ordinal) == true)
// Found in "protect.x64" and "protect.x86" in Redump entry 94805.
if (name?.Equals("CORE.ADMIN", StringComparison.Ordinal) == true)
return $"StarForce {Utilities.GetInternalVersion(pex)}";
// These checks currently disabled due being possibly too generic:
// Found in "protect.dll" in Redump entry 94805.
// if (name?.Equals("CORE.DLL", StringComparison.Ordinal) == true)
// return $"StarForce {Utilities.GetInternalVersion(pex)}";
//
// Found in "protect.exe" in Redump entry 94805.
// if (name?.Equals("CORE.EXE", StringComparison.Ordinal) == true)
// return $"StarForce {Utilities.GetInternalVersion(pex)}";
//
// else if (name?.Equals("protect.exe", StringComparison.Ordinal) == true)
// return $"StarForce {Utilities.GetInternalVersion(pex)}";
// Check the export name table
if (pex.ExportNameTable != null)
{
@@ -40,6 +62,25 @@ namespace BurnOutSharp.ProtectionType
// TODO: Find what fvinfo field actually maps to this
name = pex.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 "protect.exe" in Redump entry 94805.
if (name?.Contains("FrontLine Protection GUI Application") == true)
return $"StarForce {Utilities.GetInternalVersion(pex)}";
// Found in "protect.dll" in Redump entry 94805.
if (name?.Contains("FrontLine Protection Library") == true)
return $"StarForce {Utilities.GetInternalVersion(pex)}";
// Found in "protect.x64" and "protect.x86" in Redump entry 94805.
if (name?.Contains("FrontLine Helper") == true)
return $"StarForce {Utilities.GetInternalVersion(pex)}";
// TODO: Find a sample of this check.
if (name?.Contains("Protected Module") == true)
return $"StarForce 5";
@@ -62,30 +103,43 @@ namespace BurnOutSharp.ProtectionType
/// <inheritdoc/>
public ConcurrentQueue<string> CheckDirectoryPath(string path, IEnumerable<string> files)
{
// These have too high of a chance of over-matching by themselves
// var matchers = new List<PathMatchSet>
// {
// // TODO: Re-consolidate these once path matching is improved
// new PathMatchSet(new PathMatch("/protect.dll", useEndsWith: true), "StarForce"),
// new PathMatchSet(new PathMatch("/protect.exe", useEndsWith: true), "StarForce"),
// };
var matchers = new List<PathMatchSet>
{
// This file combination is found in Redump entry 21136.
new PathMatchSet(new List<PathMatch>
{
new PathMatch("protect.x86", useEndsWith: true),
new PathMatch("protect.x64", useEndsWith: true),
new PathMatch("protect.dll", useEndsWith: true),
new PathMatch("protect.exe", useEndsWith: true),
new PathMatch("protect.msg", useEndsWith: true),
}, "StarForce"),
// return MatchUtil.GetAllMatches(files, matchers, any: false);
return null;
// This file combination is found in multiple games, such as Redump entries 81756, 91336, and 93657.
new PathMatchSet(new List<PathMatch>
{
new PathMatch("protect.x86", useEndsWith: true),
new PathMatch("protect.x64", useEndsWith: true),
new PathMatch("protect.dll", useEndsWith: true),
new PathMatch("protect.exe", useEndsWith: true),
}, "StarForce"),
// This file combination is found in Redump entry 96137.
new PathMatchSet(new List<PathMatch>
{
new PathMatch("protect.x86", useEndsWith: true),
new PathMatch("protect.dll", useEndsWith: true),
new PathMatch("protect.exe", useEndsWith: true),
}, "StarForce"),
};
return MatchUtil.GetAllMatches(files, matchers, any: false);
}
/// <inheritdoc/>
public string CheckFilePath(string path)
{
// These have too high of a chance of over-matching by themselves
// var matchers = new List<PathMatchSet>
// {
// // TODO: Re-consolidate these once path matching is improved
// new PathMatchSet(new PathMatch("/protect.dll", useEndsWith: true), "StarForce"),
// new PathMatchSet(new PathMatch("/protect.exe", useEndsWith: true), "StarForce"),
// };
// return MatchUtil.GetFirstMatch(path, matchers, any: true);
// TODO: Determine if there are any file name checks that aren't too generic to use on their own.
return null;
}
}

View File

@@ -151,7 +151,7 @@ namespace BurnOutSharp.ProtectionType
new PathMatchSet(new PathMatch("GAME.KWN", useEndsWith: true), "TAGES (BASIC?)"),
};
return MatchUtil.GetAllMatches(files, matchers, any: true);
return MatchUtil.GetAllMatches(files, matchers, any: false);
}
/// <inheritdoc/>

View File

@@ -339,6 +339,13 @@ namespace BurnOutSharp
Utilities.AppendToDictionary(protections, subProtections);
}
// SFFS
if (scannable is SFFS)
{
var subProtections = scannable.Scan(this, stream, fileName);
Utilities.AppendToDictionary(protections, subProtections);
}
// Text-based files
if (scannable is Textfile)
{

View File

@@ -327,6 +327,14 @@ namespace BurnOutSharp.Tools
#endregion
#region SFFS
// Found in Redump entry 81756, confirmed to be "StarForce Filesystem" by PiD.
if (magic.StartsWith(new byte?[] { 0x53, 0x46, 0x46, 0x53, 0x01, 0x00, 0x00, 0x00 }))
return SupportedFileType.SFFS;
#endregion
#region SevenZip
if (magic.StartsWith(new byte?[] { 0x37, 0x7a, 0xbc, 0xaf, 0x27, 0x1c }))