Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions BurnOutSharp/Enums.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,11 @@ public enum SupportedFileType
/// </summary>
SevenZip,

/// <summary>
/// StarForce FileSystem file
/// </summary>
SFFS,

/// <summary>
/// Tape archive
/// </summary>
Expand Down
49 changes: 49 additions & 0 deletions BurnOutSharp/FileType/SFFS.cs
Original file line number Diff line number Diff line change
@@ -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;
}
}
}
98 changes: 76 additions & 22 deletions BurnOutSharp/ProtectionType/StarForce.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,21 @@
using System.Collections.Generic;
using System.Linq;
using BurnOutSharp.Interfaces;
using BurnOutSharp.Matching;
using BurnOutSharp.Tools;
using BurnOutSharp.Wrappers;

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)
{
Expand All @@ -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)
{
Expand All @@ -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";

Expand All @@ -62,30 +103,43 @@ public string CheckPortableExecutable(string file, PortableExecutable pex, bool
/// <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"),
// };

// return MatchUtil.GetAllMatches(files, matchers, any: false);
return null;
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"),

// 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;
}
}
Expand Down
2 changes: 1 addition & 1 deletion BurnOutSharp/ProtectionType/Tages.cs
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ public ConcurrentQueue<string> CheckDirectoryPath(string path, IEnumerable<strin
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/>
Expand Down
7 changes: 7 additions & 0 deletions BurnOutSharp/Scanner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,13 @@ private ConcurrentDictionary<string, ConcurrentQueue<string>> 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)
{
Expand Down
8 changes: 8 additions & 0 deletions BurnOutSharp/Tools/Utilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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 }))
Expand Down