From 7a51f6bff53fc83ac70d1ee762fa05bd67965ad5 Mon Sep 17 00:00:00 2001 From: SilasLaspada Date: Tue, 13 Dec 2022 00:53:07 -0700 Subject: [PATCH] Why is there so much StarForce, geez * Begin work on overhauling StarForce detection, and to add notes. * Attempt to add SFFS file detection. * Fix minor TAGES issue. --- BurnOutSharp/Enums.cs | 5 ++ BurnOutSharp/FileType/SFFS.cs | 49 ++++++++++++ BurnOutSharp/ProtectionType/StarForce.cs | 98 ++++++++++++++++++------ BurnOutSharp/ProtectionType/Tages.cs | 2 +- BurnOutSharp/Scanner.cs | 7 ++ BurnOutSharp/Tools/Utilities.cs | 8 ++ 6 files changed, 146 insertions(+), 23 deletions(-) create mode 100644 BurnOutSharp/FileType/SFFS.cs diff --git a/BurnOutSharp/Enums.cs b/BurnOutSharp/Enums.cs index 8731daf7..d799bc09 100644 --- a/BurnOutSharp/Enums.cs +++ b/BurnOutSharp/Enums.cs @@ -80,6 +80,11 @@ public enum SupportedFileType /// SevenZip, + /// + /// StarForce FileSystem file + /// + SFFS, + /// /// Tape archive /// diff --git a/BurnOutSharp/FileType/SFFS.cs b/BurnOutSharp/FileType/SFFS.cs new file mode 100644 index 00000000..180be1e0 --- /dev/null +++ b/BurnOutSharp/FileType/SFFS.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Concurrent; +using System.IO; +using BurnOutSharp.Interfaces; +using BurnOutSharp.Tools; + +namespace BurnOutSharp.FileType +{ + /// + /// StarForce Filesystem file + /// + public class SFFS : IScannable + { + /// + public ConcurrentDictionary> Scan(Scanner scanner, string file) + { + if (!File.Exists(file)) + return null; + + using (var fs = File.OpenRead(file)) + { + return Scan(scanner, fs, file); + } + } + + /// + public ConcurrentDictionary> Scan(Scanner scanner, Stream stream, string file) + { + var protections = new ConcurrentDictionary>(); + 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; + } + } +} diff --git a/BurnOutSharp/ProtectionType/StarForce.cs b/BurnOutSharp/ProtectionType/StarForce.cs index 03fa8e66..1f010036 100644 --- a/BurnOutSharp/ProtectionType/StarForce.cs +++ b/BurnOutSharp/ProtectionType/StarForce.cs @@ -3,6 +3,7 @@ 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). /// public string CheckPortableExecutable(string file, PortableExecutable pex, bool includeDebug) { @@ -24,12 +32,26 @@ public string CheckPortableExecutable(string file, PortableExecutable pex, bool 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 @@ public string CheckPortableExecutable(string file, PortableExecutable pex, bool // 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 @@ public string CheckPortableExecutable(string file, PortableExecutable pex, bool /// public ConcurrentQueue CheckDirectoryPath(string path, IEnumerable files) { - // These have too high of a chance of over-matching by themselves - // var matchers = new List - // { - // // 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.GetAllMatches(files, matchers, any: false); - return null; + var matchers = new List + { + // This file combination is found in Redump entry 21136. + new PathMatchSet(new List + { + 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"), + + // This file combination is found in multiple games, such as Redump entries 81756, 91336, and 93657. + new PathMatchSet(new List + { + 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 + { + 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); } /// public string CheckFilePath(string path) { - // These have too high of a chance of over-matching by themselves - // var matchers = new List - // { - // // 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; } } diff --git a/BurnOutSharp/ProtectionType/Tages.cs b/BurnOutSharp/ProtectionType/Tages.cs index 8081db1f..dbbd466e 100644 --- a/BurnOutSharp/ProtectionType/Tages.cs +++ b/BurnOutSharp/ProtectionType/Tages.cs @@ -151,7 +151,7 @@ public ConcurrentQueue CheckDirectoryPath(string path, IEnumerable diff --git a/BurnOutSharp/Scanner.cs b/BurnOutSharp/Scanner.cs index b367d845..4983eb2d 100644 --- a/BurnOutSharp/Scanner.cs +++ b/BurnOutSharp/Scanner.cs @@ -339,6 +339,13 @@ private ConcurrentDictionary> GetInternalProtect 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) { diff --git a/BurnOutSharp/Tools/Utilities.cs b/BurnOutSharp/Tools/Utilities.cs index b25232c0..c9818a30 100644 --- a/BurnOutSharp/Tools/Utilities.cs +++ b/BurnOutSharp/Tools/Utilities.cs @@ -327,6 +327,14 @@ public static SupportedFileType GetFileType(byte[] magic) #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 }))