Add game engine detection skeleton

This commit is contained in:
Matt Nadareski
2023-03-21 10:42:14 -04:00
parent 815acf2ce0
commit 0983073538
11 changed files with 134 additions and 29 deletions

View File

@@ -22,6 +22,7 @@
<ItemGroup>
<ProjectReference Include="..\BinaryObjectScanner.Compression\BinaryObjectScanner.Compression.csproj" />
<ProjectReference Include="..\BinaryObjectScanner.GameEngine\BinaryObjectScanner.GameEngine.csproj" />
<ProjectReference Include="..\BinaryObjectScanner.Interfaces\BinaryObjectScanner.Interfaces.csproj" />
<ProjectReference Include="..\BinaryObjectScanner.Matching\BinaryObjectScanner.Matching.csproj" />
<ProjectReference Include="..\BinaryObjectScanner.Packer\BinaryObjectScanner.Packer.csproj" />

View File

@@ -23,6 +23,11 @@ namespace BinaryObjectScanner.FileType
{
#region Properties
/// <summary>
/// Determines if game engines are counted as detected protections or not
/// </summary>
public bool IncludeGameEngines { get; set; }
/// <summary>
/// Determines if packers are counted as detected protections or not
/// </summary>
@@ -233,8 +238,12 @@ namespace BinaryObjectScanner.FileType
if (string.IsNullOrWhiteSpace(protection))
return;
// If we are filtering the output of the check
if (!CheckIfPacker(checkClass) || !IncludePackers)
// If we are filtering on game engines
if (CheckIfGameEngine(checkClass) && !IncludeGameEngines)
return;
// If we are filtering on packers
if (CheckIfPacker(checkClass) && !IncludePackers)
return;
protections.TryAdd(checkClass, protection);
@@ -263,8 +272,12 @@ namespace BinaryObjectScanner.FileType
if (string.IsNullOrWhiteSpace(protection))
return;
// If we are filtering the output of the check
if (!CheckIfPacker(checkClass) || !IncludePackers)
// If we are filtering on game engines
if (CheckIfGameEngine(checkClass) && !IncludeGameEngines)
return;
// If we are filtering on packers
if (CheckIfPacker(checkClass) && !IncludePackers)
return;
protections.TryAdd(checkClass, protection);
@@ -293,8 +306,12 @@ namespace BinaryObjectScanner.FileType
if (string.IsNullOrWhiteSpace(protection))
return;
// If we are filtering the output of the check
if (!CheckIfPacker(checkClass) || !IncludePackers)
// If we are filtering on game engines
if (CheckIfGameEngine(checkClass) && !IncludeGameEngines)
return;
// If we are filtering on packers
if (CheckIfPacker(checkClass) && !IncludePackers)
return;
protections.TryAdd(checkClass, protection);
@@ -323,8 +340,12 @@ namespace BinaryObjectScanner.FileType
if (string.IsNullOrWhiteSpace(protection))
return;
// If we are filtering the output of the check
if (!CheckIfPacker(checkClass) || !IncludePackers)
// If we are filtering on game engines
if (CheckIfGameEngine(checkClass) && !IncludeGameEngines)
return;
// If we are filtering on packers
if (CheckIfPacker(checkClass) && !IncludePackers)
return;
protections.TryAdd(checkClass, protection);
@@ -353,8 +374,12 @@ namespace BinaryObjectScanner.FileType
if (string.IsNullOrWhiteSpace(protection))
return;
// If we are filtering the output of the check
if (!CheckIfPacker(checkClass) || !IncludePackers)
// If we are filtering on game engines
if (CheckIfGameEngine(checkClass) && !IncludeGameEngines)
return;
// If we are filtering on packers
if (CheckIfPacker(checkClass) && !IncludePackers)
return;
protections.TryAdd(checkClass, protection);
@@ -371,8 +396,9 @@ namespace BinaryObjectScanner.FileType
/// Initialize all implementations of a type
/// </summary>
private static IEnumerable<T> InitCheckClasses<T>()
=> InitCheckClasses<T>(typeof(BinaryObjectScanner.Packer._DUMMY).Assembly)
.Concat(InitCheckClasses<T>(typeof(BinaryObjectScanner.Protection._DUMMY).Assembly));
=> InitCheckClasses<T>(typeof(GameEngine._DUMMY).Assembly)
.Concat(InitCheckClasses<T>(typeof(Packer._DUMMY).Assembly))
.Concat(InitCheckClasses<T>(typeof(Protection._DUMMY).Assembly));
/// <summary>
/// Initialize all implementations of a type
@@ -388,6 +414,15 @@ namespace BinaryObjectScanner.FileType
#region Helpers
/// <summary>
/// Check to see if an implementation is a game engine using reflection
/// </summary>
/// <param name="impl">Implementation that was last used to check</param>
private static bool CheckIfGameEngine(object impl)
{
return impl.GetType().Namespace.ToLowerInvariant().Contains("gameengine");
}
/// <summary>
/// Check to see if an implementation is a packer using reflection
/// </summary>

View File

@@ -0,0 +1,29 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net48;net6.0;net7.0</TargetFrameworks>
<RuntimeIdentifiers>win-x86;win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
<Title>BinaryObjectScanner.GameEngine</Title>
<AssemblyName>BinaryObjectScanner.GameEngine</AssemblyName>
<Authors>Matt Nadareski</Authors>
<Product>BurnOutSharp</Product>
<Copyright>Copyright (c)2022 Matt Nadareski</Copyright>
<RepositoryUrl>https://github.com/mnadareski/BurnOutSharp</RepositoryUrl>
<Version>2.7</Version>
<AssemblyVersion>2.7</AssemblyVersion>
<FileVersion>2.7</FileVersion>
<IncludeSource>true</IncludeSource>
<IncludeSymbols>true</IncludeSymbols>
</PropertyGroup>
<PropertyGroup>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\BinaryObjectScanner.Interfaces\BinaryObjectScanner.Interfaces.csproj" />
<ProjectReference Include="..\BinaryObjectScanner.Matching\BinaryObjectScanner.Matching.csproj" />
<ProjectReference Include="..\BinaryObjectScanner.Wrappers\BinaryObjectScanner.Wrappers.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,7 @@
namespace BinaryObjectScanner.GameEngine
{
/// <summary>
/// This class exists for reflection purposes and should not be used
/// </summary>
public sealed class _DUMMY { }
}

View File

@@ -38,7 +38,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BinaryObjectScanner.Protect
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BinaryObjectScanner.Packer", "BinaryObjectScanner.Packer\BinaryObjectScanner.Packer.csproj", "{59B3DE26-9399-4B5A-B39B-6239DAF1A017}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BinaryObjectScanner.FileType", "BinaryObjectScanner.FileType\BinaryObjectScanner.FileType.csproj", "{6733368B-63D4-4921-AE13-FD1A53C5180C}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BinaryObjectScanner.FileType", "BinaryObjectScanner.FileType\BinaryObjectScanner.FileType.csproj", "{6733368B-63D4-4921-AE13-FD1A53C5180C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BinaryObjectScanner.GameEngine", "BinaryObjectScanner.GameEngine\BinaryObjectScanner.GameEngine.csproj", "{8AFC9C4C-CC57-4382-8C32-F6B4C46E321A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -102,6 +104,10 @@ Global
{6733368B-63D4-4921-AE13-FD1A53C5180C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6733368B-63D4-4921-AE13-FD1A53C5180C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6733368B-63D4-4921-AE13-FD1A53C5180C}.Release|Any CPU.Build.0 = Release|Any CPU
{8AFC9C4C-CC57-4382-8C32-F6B4C46E321A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8AFC9C4C-CC57-4382-8C32-F6B4C46E321A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8AFC9C4C-CC57-4382-8C32-F6B4C46E321A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8AFC9C4C-CC57-4382-8C32-F6B4C46E321A}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@@ -15,6 +15,11 @@
/// </summary>
public bool ScanContents { get; set; }
/// <summary>
/// Determines if game engines are counted as detected protections or not
/// </summary>
public bool ScanGameEngines { get; set; }
/// <summary>
/// Determines if packers are counted as detected protections or not
/// </summary>

View File

@@ -23,10 +23,13 @@ namespace BurnOutSharp
/// <inheritdoc cref="Options.ScanContents"/>
public bool ScanContents => options?.ScanContents ?? false;
/// <inheritdoc cref="Options.ScanPaths"/>
/// <inheritdoc cref="Options.ScanGameEngines"/>
public bool ScanGameEngines => options?.ScanGameEngines ?? false;
/// <inheritdoc cref="Options.ScanPackers"/>
public bool ScanPackers => options?.ScanPackers ?? false;
/// <inheritdoc cref="Options.ScanArchives"/>
/// <inheritdoc cref="Options.ScanPaths"/>
public bool ScanPaths => options?.ScanPaths ?? false;
/// <inheritdoc cref="Options.IncludeDebug"/>
@@ -49,16 +52,18 @@ namespace BurnOutSharp
/// </summary>
/// <param name="scanArchives">Enable scanning archive contents</param>
/// <param name="scanContents">Enable including content detections in output</param>
/// <param name="scanGameEngines">Enable including game engines in output</param>
/// <param name="scanPackers">Enable including packers in output</param>
/// <param name="scanPaths">Enable including path detections in output</param>
/// <param name="includeDebug">Enable including debug information</param>
/// <param name="fileProgress">Optional progress callback</param>
public Scanner(bool scanArchives, bool scanContents, bool scanPackers, bool scanPaths, bool includeDebug, IProgress<ProtectionProgress> fileProgress = null)
public Scanner(bool scanArchives, bool scanContents, bool scanGameEngines, bool scanPackers, bool scanPaths, bool includeDebug, IProgress<ProtectionProgress> fileProgress = null)
{
this.options = new Options
{
ScanArchives = scanArchives,
ScanContents = scanContents,
ScanGameEngines = scanGameEngines,
ScanPackers = scanPackers,
ScanPaths = scanPaths,
IncludeDebug = includeDebug,
@@ -300,6 +305,7 @@ namespace BurnOutSharp
// If we have an executable, it needs to bypass normal handling
if (detectable is Executable executable)
{
executable.IncludeGameEngines = ScanGameEngines;
executable.IncludePackers = ScanPackers;
var subProtections = ProcessExecutable(executable, fileName, stream);
if (subProtections != null)

View File

@@ -325,6 +325,7 @@ This section contains information on project and class organization principles t
| `BinaryObjectScanner.Builders` | One file per executable type. |
| `BinaryObjectScanner.Compression` | One directory per compression type. |
| `BinaryObjectScanner.FileType` | One file per file type. |
| `BinaryObjectScanner.GameEngine` | At least one file per game engine. Partial classes allowed. |
| `BinaryObjectScanner.Interfaces` | One file per interface. |
| `BinaryObjectScanner.Matching` | Flat directory structure. Include interfaces and base classes. |
| `BinaryObjectScanner.Models` | One directory per executable type. One file per object model. |
@@ -344,19 +345,19 @@ This section contains information on in-code organization principles that depend
| Project | Description |
| --- | --- |
| `BurnOutSharp` | Varies from file to file. |
| `BurnOutSharp/FileType` | `IDetectable` implementations, `IExtractable` implementations, `IScannable` implementations, helper methods. |
| `BurnOutSharp/Tools` | Methods grouped by function. Regions ordered alphabetically. |
| `BinaryObjectScanner.ASN1` | Partial classes suggested for different implmentations. |
| `BinaryObjectScanner.Builders` | Two copies of each non-generic method: one for byte arrays and one for Streams. |
| `BinaryObjectScanner.Compression` | Varies from file to file. |
| `BinaryObjectScanner.FileType` | `IDetectable` implementations, `IExtractable` implementations, helper methods. |
| `BinaryObjectScanner.GameEngine` | `IContentCheck` implementations, `ILinearExecutableCheck` implementations, `INewExecutableCheck` implementations, `IPortableExecutableCheck` implementations, `IPathCheck` implementations, `IExtractable` implementations, helper methods. |
| `BinaryObjectScanner.Interfaces` | Methods ordered alphabetically. |
| `BinaryObjectScanner.Matching` | Varies from file to file. |
| `BinaryObjectScanner.Models` | No methods at all, just properties. |
| `BinaryObjectScanner.Packer` | `IContentCheck` implementations, `ILinearExecutableCheck` implementations, `INewExecutableCheck` implementations, `IPortableExecutableCheck` implementations, `IPathCheck` implementations, `IExtractable` implementations, helper methods. |
| `BinaryObjectScanner.Protection` | `IContentCheck` implementations, `ILinearExecutableCheck` implementations, `INewExecutableCheck` implementations, `IPortableExecutableCheck` implementations, `IPathCheck` implementations, `IExtractable` implementations, helper methods. |
| `BinaryObjectScanner.Utilities` | Varies from file to file. |
| `BurnOutSharp.Wrappers` | Follow region and method grouping from existing wrappers. |
| `BinaryObjectScanner.Wrappers` | Follow region and method grouping from existing wrappers. |
| `psxt001z` | Varies from file to file. |
| `Test` | New functionality should be added as a combination of a flag with a long and a short form, a new line in the help text, and a new method (if necessary). |

View File

@@ -13,6 +13,7 @@ This is a guide for any developers who wish to research protections, implement n
| `BinaryObjectScanner.Builder` | Library containing classes that assist in populating the various object models defined in `BinaryObjectScanner.Models`. Builders can work with either byte arrays or streams for input. At the time of writing, the following executable types have builders: **MS-DOS**, **New Executable**, **Portable Executable**. |
| `BinaryObjectScanner.Compression` | Library containing classes that deal with different compression formats. This library is used extensively by the wrappers in `BinaryObjectScanner.Wrappers`. |
| `BinaryObjectScanner.FileType` | Library containing file type definitions specific to scanning. |
| `BinaryObjectScanner.GameEngine` | Library containing game engine scanning definitions. |
| `BinaryObjectScanner.Interfaces` | Library containing interface definitions for scanning and detection. |
| `BinaryObjectScanner.Matching` | Library containing models and logic for generic searching and matching. This library is used extensively by the packer and protection checks in `BurnOutSharp`. |
| `BinaryObjectScanner.Models` | Library containing object models that represent various pieces of known executable formats. At the time of writing, the following executable types have models: **MS-DOS**, **New Executable**, **Linear Executable (partial)**, **Portable Executable**. |
@@ -91,6 +92,8 @@ Adding a new checker or format should happen in a few distinct steps:
- If it is a new supported file type (such as an archive format), create the file in `BinaryObjectScanner.FileType`. By default, you will need to implement `BurnOutSharp.Interfaces.IDetectable` or `BinaryObjectScanner.Interfaces.IExtractable`. Do not implement any other interfaces. Please consider asking project maintainers before doing this work, especially if there are external dependencies.
- If it is a new supported game engine or standard library, create the file in `BinaryObjectScanner.GameEngine`. By default, you will need to implement at least one of: `BinaryObjectScanner.Interfaces.ILinearExecutableCheck`, `BinaryObjectScanner.Interfaces.INewExecutableCheck`, and `BinaryObjectScanner.Interfaces.IPortableExecutableCheck`. It is exceptionally rare to need to implement `BinaryObjectScanner.Interfaces.IPathCheck`.
- If it is a new supported executable packer, compressor, or installer format, create the file in `BinaryObjectScanner.Packer`. By default, you will need to implement `BinaryObjectScanner.Interfaces.IExtractable` as well as at least one of: `BinaryObjectScanner.Interfaces.ILinearExecutableCheck`, `BinaryObjectScanner.Interfaces.INewExecutableCheck`, and `BinaryObjectScanner.Interfaces.IPortableExecutableCheck`. It is exceptionally rare to need to implement `BinaryObjectScanner.Interfaces.IPathCheck`.
- If it is a new supported DRM scheme, copy protection, or obfuscator, create the file in `BinaryObjectScanner.Protection`. By default, you will need to implement at least one of:`BinaryObjectScanner.Interfaces.ILinearExecutableCheck`, `BinaryObjectScanner.Interfaces.INewExecutableCheck`, `BinaryObjectScanner.Interfaces.IPortableExecutableCheck`, and `BinaryObjectScanner.Interfaces.IPathCheck`. It is exceptionally rare to need to implement `BinaryObjectScanner.Interfaces.Extractable`.

View File

@@ -68,6 +68,11 @@ namespace Test
/// </summary>
public bool ScanContents { get; private set; } = true;
/// <summary>
/// Scan game engines during protection scanning
/// </summary>
public bool ScanGameEngines { get; private set; } = true;
/// <summary>
/// Scan packers during protection scanning
/// </summary>
@@ -180,6 +185,11 @@ namespace Test
options.ScanContents = false;
break;
case "-ng":
case "--no-game-engines":
options.ScanGameEngines = false;
break;
case "-np":
case "--no-packers":
options.ScanPackers = false;
@@ -230,27 +240,28 @@ namespace Test
Console.WriteLine("test.exe <features> <options> file|directory ...");
Console.WriteLine();
Console.WriteLine("Features:");
Console.WriteLine("-x, --extract Extract archive formats");
Console.WriteLine("-i, --info Print executable info");
Console.WriteLine("-s, --scan Enable protection scanning (default if none)");
Console.WriteLine("-x, --extract Extract archive formats");
Console.WriteLine("-i, --info Print executable info");
Console.WriteLine("-s, --scan Enable protection scanning (default if none)");
Console.WriteLine();
Console.WriteLine("Common options:");
Console.WriteLine("-?, -h, --help Display this help text and quit");
Console.WriteLine("-d, --debug Enable debug mode");
Console.WriteLine("-?, -h, --help Display this help text and quit");
Console.WriteLine("-d, --debug Enable debug mode");
Console.WriteLine();
Console.WriteLine("Extraction options:");
Console.WriteLine("-o, --outdir [PATH] Set output path for extraction (required)");
Console.WriteLine("-o, --outdir [PATH] Set output path for extraction (required)");
#if NET6_0_OR_GREATER
Console.WriteLine();
Console.WriteLine("Information options:");
Console.WriteLine("-j, --json Print executable info as JSON");
Console.WriteLine("-j, --json Print executable info as JSON");
#endif
Console.WriteLine();
Console.WriteLine("Scanning options:");
Console.WriteLine("-nc, --no-contents Disable scanning for content checks");
Console.WriteLine("-na, --no-archives Disable scanning archives");
Console.WriteLine("-np, --no-packers Disable scanning for packers");
Console.WriteLine("-ns, --no-paths Disable scanning for path checks");
Console.WriteLine("-nc, --no-contents Disable scanning for content checks");
Console.WriteLine("-na, --no-archives Disable scanning archives");
Console.WriteLine("-ng, --no-game-engines Disable scanning for game engines");
Console.WriteLine("-np, --no-packers Disable scanning for packers");
Console.WriteLine("-ns, --no-paths Disable scanning for path checks");
}
/// <summary>

View File

@@ -31,6 +31,7 @@ namespace Test
var scanner = new Scanner(
options.ScanArchives,
options.ScanContents,
options.ScanGameEngines,
options.ScanPackers,
options.ScanPaths,
options.Debug,