Remove ExtractionTool and all references

This commit is contained in:
Matt Nadareski
2025-08-29 14:05:07 -04:00
parent a82d1e729c
commit 55e368e23a
9 changed files with 7 additions and 838 deletions

View File

@@ -18,8 +18,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BinaryObjectScanner", "Bina
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProtectionScan", "ProtectionScan\ProtectionScan.csproj", "{14CC56E0-7D56-497C-BF3D-4C06FA169831}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProtectionScan", "ProtectionScan\ProtectionScan.csproj", "{14CC56E0-7D56-497C-BF3D-4C06FA169831}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExtractionTool", "ExtractionTool\ExtractionTool.csproj", "{89767A19-043F-4251-805B-B2CBC48E2B79}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BinaryObjectScanner.Test", "BinaryObjectScanner.Test\BinaryObjectScanner.Test.csproj", "{227A8E39-0230-47CE-8F1D-42368129357D}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BinaryObjectScanner.Test", "BinaryObjectScanner.Test\BinaryObjectScanner.Test.csproj", "{227A8E39-0230-47CE-8F1D-42368129357D}"
EndProject EndProject
Global Global
@@ -36,10 +34,6 @@ Global
{14CC56E0-7D56-497C-BF3D-4C06FA169831}.Debug|Any CPU.Build.0 = Debug|Any CPU {14CC56E0-7D56-497C-BF3D-4C06FA169831}.Debug|Any CPU.Build.0 = Debug|Any CPU
{14CC56E0-7D56-497C-BF3D-4C06FA169831}.Release|Any CPU.ActiveCfg = Release|Any CPU {14CC56E0-7D56-497C-BF3D-4C06FA169831}.Release|Any CPU.ActiveCfg = Release|Any CPU
{14CC56E0-7D56-497C-BF3D-4C06FA169831}.Release|Any CPU.Build.0 = Release|Any CPU {14CC56E0-7D56-497C-BF3D-4C06FA169831}.Release|Any CPU.Build.0 = Release|Any CPU
{89767A19-043F-4251-805B-B2CBC48E2B79}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{89767A19-043F-4251-805B-B2CBC48E2B79}.Debug|Any CPU.Build.0 = Debug|Any CPU
{89767A19-043F-4251-805B-B2CBC48E2B79}.Release|Any CPU.ActiveCfg = Release|Any CPU
{89767A19-043F-4251-805B-B2CBC48E2B79}.Release|Any CPU.Build.0 = Release|Any CPU
{227A8E39-0230-47CE-8F1D-42368129357D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {227A8E39-0230-47CE-8F1D-42368129357D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{227A8E39-0230-47CE-8F1D-42368129357D}.Debug|Any CPU.Build.0 = Debug|Any CPU {227A8E39-0230-47CE-8F1D-42368129357D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{227A8E39-0230-47CE-8F1D-42368129357D}.Release|Any CPU.ActiveCfg = Release|Any CPU {227A8E39-0230-47CE-8F1D-42368129357D}.Release|Any CPU.ActiveCfg = Release|Any CPU

View File

@@ -364,7 +364,6 @@ This section contains information on project and class organization principles t
| `BinaryObjectScanner/Interfaces` | One file per interface. | | `BinaryObjectScanner/Interfaces` | One file per interface. |
| `BinaryObjectScanner/Packer` | At least one file per packer type. Partial classes allowed. | | `BinaryObjectScanner/Packer` | At least one file per packer type. Partial classes allowed. |
| `BinaryObjectScanner/Protection` | At least one file per protection type. Partial classes allowed. | | `BinaryObjectScanner/Protection` | At least one file per protection type. Partial classes allowed. |
| `ExtractionTool` | All functionality lives in `Program.cs`. |
| `ProtectionScan` | All functionality lives in `Program.cs`. | | `ProtectionScan` | All functionality lives in `Program.cs`. |
If the project or directory you are looking for is not included in the above, please consider it to be outside the context of this document. If the project or directory you are looking for is not included in the above, please consider it to be outside the context of this document.
@@ -383,7 +382,6 @@ Typed checks, such as `IExecutableCheck<T>` should always follow this order: `MS
| `BinaryObjectScanner/Interfaces` | Methods ordered alphabetically. | | `BinaryObjectScanner/Interfaces` | Methods ordered alphabetically. |
| `BinaryObjectScanner/Packer` | `IContentCheck` implementations, `IExecutableCheck<T>` implementations, `IPathCheck` implementations, `IExtractableExecutable<T>` implementations, helper methods. | | `BinaryObjectScanner/Packer` | `IContentCheck` implementations, `IExecutableCheck<T>` implementations, `IPathCheck` implementations, `IExtractableExecutable<T>` implementations, helper methods. |
| `BinaryObjectScanner/Protection` | `IContentCheck` implementations, `IExecutableCheck<T>` implementations, `IPathCheck` implementations, `IExtractableExecutable<T>` implementations, helper methods. | | `BinaryObjectScanner/Protection` | `IContentCheck` implementations, `IExecutableCheck<T>` implementations, `IPathCheck` implementations, `IExtractableExecutable<T>` implementations, helper methods. |
| `ExtractionTool` | 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). |
| `ProtectionScan` | 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). | | `ProtectionScan` | 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). |
If the project or directory you are looking for is not included in the above, please consider it to be outside the context of this document. If the project or directory you are looking for is not included in the above, please consider it to be outside the context of this document.

View File

@@ -14,7 +14,6 @@ This is a guide for any developers who wish to research protections, implement n
| `BinaryObjectScanner.Interfaces` | Namespace containing interface definitions for scanning and detection. | | `BinaryObjectScanner.Interfaces` | Namespace containing interface definitions for scanning and detection. |
| `BinaryObjectScanner.Packer` | Namespace containing packer scanning definitions. | | `BinaryObjectScanner.Packer` | Namespace containing packer scanning definitions. |
| `BinaryObjectScanner.Protection` | Namespace containing protection scanning definitions. | | `BinaryObjectScanner.Protection` | Namespace containing protection scanning definitions. |
| `ExtractionTool` | Testing executable that allows for standalone testing of extraction features of the library. |
| `ProtectionScan` | Testing executable that allows for standalone testing of protection detection features of the library. | | `ProtectionScan` | Testing executable that allows for standalone testing of protection detection features of the library. |
## Researching Protections ## Researching Protections

View File

@@ -1,72 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net20;net35;net40;net452;net462;net472;net48;netcoreapp3.1;net5.0;net6.0;net7.0;net8.0;net9.0</TargetFrameworks>
<OutputType>Exe</OutputType>
<CheckEolTargetFramework>false</CheckEolTargetFramework>
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<Version>3.3.4</Version>
</PropertyGroup>
<!-- Support All Frameworks -->
<PropertyGroup Condition="$(TargetFramework.StartsWith(`net2`)) OR $(TargetFramework.StartsWith(`net3`)) OR $(TargetFramework.StartsWith(`net4`))">
<RuntimeIdentifiers>win-x86;win-x64</RuntimeIdentifiers>
</PropertyGroup>
<PropertyGroup Condition="$(TargetFramework.StartsWith(`netcoreapp`)) OR $(TargetFramework.StartsWith(`net5`))">
<RuntimeIdentifiers>win-x86;win-x64;win-arm64;linux-x64;linux-arm64;osx-x64</RuntimeIdentifiers>
</PropertyGroup>
<PropertyGroup Condition="$(TargetFramework.StartsWith(`net6`)) OR $(TargetFramework.StartsWith(`net7`)) OR $(TargetFramework.StartsWith(`net8`)) OR $(TargetFramework.StartsWith(`net9`))">
<RuntimeIdentifiers>win-x86;win-x64;win-arm64;linux-x64;linux-arm64;osx-x64;osx-arm64</RuntimeIdentifiers>
</PropertyGroup>
<PropertyGroup Condition="$(RuntimeIdentifier.StartsWith(`osx-arm`))">
<TargetFrameworks>net6.0;net7.0;net8.0;net9.0</TargetFrameworks>
</PropertyGroup>
<!-- Set a build flag for Windows specifically -->
<PropertyGroup Condition="'$(RuntimeIdentifier)'=='win-x86'">
<DefineConstants>$(DefineConstants);WINX86</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="'$(RuntimeIdentifier)'=='win-x64'">
<DefineConstants>$(DefineConstants);WINX64</DefineConstants>
</PropertyGroup>
<!-- These are needed for dealing with native Windows DLLs -->
<ItemGroup Condition="'$(RuntimeIdentifier)'=='win-x86'">
<ContentWithTargetPath Include="..\BinaryObjectScanner\runtimes\win-x86\native\CascLib.dll">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<CopyToPublishDirectory>Always</CopyToPublishDirectory>
<TargetPath>CascLib.dll</TargetPath>
</ContentWithTargetPath>
<ContentWithTargetPath Include="..\BinaryObjectScanner\runtimes\win-x86\native\StormLib.dll">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<CopyToPublishDirectory>Always</CopyToPublishDirectory>
<TargetPath>StormLib.dll</TargetPath>
</ContentWithTargetPath>
</ItemGroup>
<ItemGroup Condition="'$(RuntimeIdentifier)'=='win-x64'">
<ContentWithTargetPath Include="..\BinaryObjectScanner\runtimes\win-x64\native\CascLib.dll">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<CopyToPublishDirectory>Always</CopyToPublishDirectory>
<TargetPath>CascLib.dll</TargetPath>
</ContentWithTargetPath>
<ContentWithTargetPath Include="..\BinaryObjectScanner\runtimes\win-x64\native\StormLib.dll">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<CopyToPublishDirectory>Always</CopyToPublishDirectory>
<TargetPath>StormLib.dll</TargetPath>
</ContentWithTargetPath>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\BinaryObjectScanner\BinaryObjectScanner.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="SabreTools.IO" Version="1.6.3" />
<PackageReference Include="SabreTools.Serialization" Version="1.8.6" />
</ItemGroup>
</Project>

View File

@@ -1,129 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
namespace ExtractionTool
{
/// <summary>
/// Set of options for the test executable
/// </summary>
internal sealed class Options
{
#region Properties
/// <summary>
/// Enable debug output for relevant operations
/// </summary>
public bool Debug { get; private set; } = false;
/// <summary>
/// Set of input paths to use for operations
/// </summary>
public List<string> InputPaths { get; private set; } = [];
/// <summary>
/// Output path for archive extraction
/// </summary>
public string OutputPath { get; private set; } = string.Empty;
#endregion
/// <summary>
/// Parse commandline arguments into an Options object
/// </summary>
public static Options? ParseOptions(string[] args)
{
// If we have invalid arguments
if (args == null || args.Length == 0)
return null;
// Create an Options object
var options = new Options();
// Parse the options and paths
for (int index = 0; index < args.Length; index++)
{
string arg = args[index];
switch (arg)
{
case "-?":
case "-h":
case "--help":
return null;
case "-d":
case "--debug":
options.Debug = true;
break;
case "-o":
case "--outdir":
options.OutputPath = index + 1 < args.Length ? args[++index] : string.Empty;
break;
default:
options.InputPaths.Add(arg);
break;
}
}
// Validate we have any input paths to work on
if (options.InputPaths.Count == 0)
{
Console.WriteLine("At least one path is required!");
return null;
}
// Validate the output path
bool validPath = ValidateExtractionPath(options);
if (!validPath)
return null;
return options;
}
/// <summary>
/// Display help text
/// </summary>
public static void DisplayHelp()
{
Console.WriteLine("Extraction Tool");
Console.WriteLine();
Console.WriteLine("ExtractionTool.exe <options> file|directory ...");
Console.WriteLine();
Console.WriteLine("Options:");
Console.WriteLine("-?, -h, --help Display this help text and quit");
Console.WriteLine("-d, --debug Enable debug mode");
Console.WriteLine("-o, --outdir [PATH] Set output path for extraction (required)");
}
/// <summary>
/// Validate the extraction path
/// </summary>
private static bool ValidateExtractionPath(Options options)
{
// Null or empty output path
if (string.IsNullOrEmpty(options.OutputPath))
{
Console.WriteLine("Output directory required for extraction!");
Console.WriteLine();
return false;
}
// Malformed output path or invalid location
try
{
options.OutputPath = Path.GetFullPath(options.OutputPath);
Directory.CreateDirectory(options.OutputPath);
}
catch
{
Console.WriteLine("Output directory could not be created!");
Console.WriteLine();
return false;
}
return true;
}
}
}

View File

@@ -1,476 +0,0 @@
using System;
using System.IO;
using BinaryObjectScanner.FileType;
using BinaryObjectScanner.Packer;
using SabreTools.IO.Extensions;
using WrapperFactory = SabreTools.Serialization.Wrappers.WrapperFactory;
using WrapperType = SabreTools.Serialization.Wrappers.WrapperType;
namespace ExtractionTool
{
class Program
{
static void Main(string[] args)
{
#if NET462_OR_GREATER || NETCOREAPP
// Register the codepages
System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);
#endif
// Get the options from the arguments
var options = Options.ParseOptions(args);
// If we have an invalid state
if (options == null)
{
Options.DisplayHelp();
return;
}
// Loop through the input paths
foreach (string inputPath in options.InputPaths)
{
ExtractPath(inputPath, options.OutputPath, options.Debug);
}
}
/// <summary>
/// Wrapper to extract data for a single path
/// </summary>
/// <param name="path">File or directory path</param>
/// <param name="outputDirectory">Output directory path</param>
/// <param name="includeDebug">Enable including debug information</param>
private static void ExtractPath(string path, string outputDirectory, bool includeDebug)
{
// Normalize by getting the full path
path = Path.GetFullPath(path);
Console.WriteLine($"Checking possible path: {path}");
// Check if the file or directory exists
if (File.Exists(path))
{
ExtractFile(path, outputDirectory, includeDebug);
}
else if (Directory.Exists(path))
{
foreach (string file in IOExtensions.SafeEnumerateFiles(path, "*", SearchOption.AllDirectories))
{
ExtractFile(file, outputDirectory, includeDebug);
}
}
else
{
Console.WriteLine($"{path} does not exist, skipping...");
}
}
/// <summary>
/// Print information for a single file, if possible
/// </summary>
private static void ExtractFile(string file, string outputDirectory, bool includeDebug)
{
Console.WriteLine($"Attempting to extract all files from {file}");
using Stream stream = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
// Get the extension for certain checks
string extension = Path.GetExtension(file).ToLower().TrimStart('.');
// Get the first 16 bytes for matching
byte[] magic = new byte[16];
try
{
int read = stream.Read(magic, 0, 16);
stream.Seek(0, SeekOrigin.Begin);
}
catch (Exception ex)
{
if (includeDebug) Console.Error.WriteLine(ex);
return;
}
// TODO: When extractable wrapper types are exposed to this, use them instead of guessing
// Get the file type
WrapperType ft = WrapperFactory.GetFileType(magic, extension);
var wrapper = WrapperFactory.CreateWrapper(ft, stream);
// Create the output directory
Directory.CreateDirectory(outputDirectory);
// 7-zip -- Implementation moved to Serialization
if (ft == WrapperType.SevenZip)
{
// Build the archive information
Console.WriteLine("Extracting 7-zip contents");
Console.WriteLine();
#if NET20 || NET35 || NET40 || NET452
Console.WriteLine("Extraction is not supported for this framework!");
Console.WriteLine();
#else
// Extract using the FileType
var sevenZip = new SevenZip();
sevenZip.Extract(stream, file, outputDirectory, includeDebug: true);
#endif
}
// BFPK archive
else if (wrapper is SabreTools.Serialization.Wrappers.BFPK bfpk)
{
Console.WriteLine("Extracting BFPK contents");
Console.WriteLine();
bfpk.ExtractAll(outputDirectory);
}
// BSP
else if (wrapper is SabreTools.Serialization.Wrappers.BSP bsp)
{
Console.WriteLine("Extracting BSP contents");
Console.WriteLine();
bsp.ExtractAllLumps(outputDirectory);
}
// bzip2 -- Implementation moved to Serialization
else if (ft == WrapperType.BZip2)
{
// Build the bzip2 information
Console.WriteLine("Extracting bzip2 contents");
Console.WriteLine();
// Extract using the FileType
var bzip2 = new BZip2();
bzip2.Extract(stream, file, outputDirectory, includeDebug: true);
}
// CFB -- Implementation moved to Serialization
else if (ft == WrapperType.CFB)
{
// Build the installer information
Console.WriteLine("Extracting CFB contents");
Console.WriteLine();
#if NET20 || NET35
Console.WriteLine("Extraction is not supported for this framework!");
Console.WriteLine();
#else
// Extract using the FileType
var cfb = new CFB();
cfb.Extract(stream, file, outputDirectory, includeDebug: true);
#endif
}
// Executable -- Implementation partially moved to Serialization
else if (ft == WrapperType.Executable)
{
// Build the executable information
Console.WriteLine("Extracting executable contents");
Console.WriteLine();
// Extract using the FileType
var exe = WrapperFactory.CreateExecutableWrapper(stream);
if (exe == null)
return;
// New Executable
if (exe is SabreTools.Serialization.Wrappers.NewExecutable nex)
{
// Wise Installer
var wi = new WiseInstaller();
if (wi.CheckExecutable(file, nex, includeDebug) != null)
wi.Extract(file, nex, outputDirectory, includeDebug);
}
// Portable Executable
else if (exe is SabreTools.Serialization.Wrappers.PortableExecutable pex)
{
// 7-zip SFX
var szsfx = new SevenZipSFX();
if (szsfx.CheckExecutable(file, pex, includeDebug) != null)
szsfx.Extract(file, pex, outputDirectory, includeDebug);
// CExe -- Implementation moved to Serialization
var ce = new CExe();
if (ce.CheckExecutable(file, pex, includeDebug) != null)
ce.Extract(file, pex, outputDirectory, includeDebug);
// Embedded archives -- Implementation moved to Serialization
var ea = new EmbeddedArchive();
if (ea.CheckExecutable(file, pex, includeDebug) != null)
ea.Extract(file, pex, outputDirectory, includeDebug);
// Embedded executables -- Implementation moved to Serialization
var ee = new EmbeddedExecutable();
if (ee.CheckExecutable(file, pex, includeDebug) != null)
ee.Extract(file, pex, outputDirectory, includeDebug);
// WinRAR SFX
var wrsfx = new WinRARSFX();
if (wrsfx.CheckExecutable(file, pex, includeDebug) != null)
wrsfx.Extract(file, pex, outputDirectory, includeDebug);
// WinZip SFX
var wzsfx = new WinZipSFX();
if (wzsfx.CheckExecutable(file, pex, includeDebug) != null)
wzsfx.Extract(file, pex, outputDirectory, includeDebug);
// Wise Installer
var wi = new WiseInstaller();
if (wi.CheckExecutable(file, pex, includeDebug) != null)
wi.Extract(file, pex, outputDirectory, includeDebug);
}
}
// GCF
else if (wrapper is SabreTools.Serialization.Wrappers.GCF gcf)
{
Console.WriteLine("Extracting GCF contents");
Console.WriteLine();
gcf.ExtractAll(outputDirectory);
}
// gzip -- Implementation moved to Serialization
else if (ft == WrapperType.GZIP)
{
// Build the gzip information
Console.WriteLine("Extracting gzip contents");
Console.WriteLine();
// Extract using the FileType
var gzip = new GZIP();
gzip.Extract(stream, file, outputDirectory, includeDebug: true);
}
// InstallShield Archive V3 (Z)
else if (wrapper is SabreTools.Serialization.Wrappers.InstallShieldArchiveV3 isv3)
{
Console.WriteLine("Extracting InstallShield Archive V3 contents");
Console.WriteLine();
isv3.ExtractAll(outputDirectory);
}
// IS-CAB archive
else if (ft == WrapperType.InstallShieldCAB)
{
// Build the archive information
Console.WriteLine("Extracting IS-CAB contents");
Console.WriteLine();
// Extract using the FileType
var iscab = new InstallShieldCAB();
iscab.Extract(stream, file, outputDirectory, includeDebug: true);
}
// LZ-compressed file, KWAJ variant
else if (wrapper is SabreTools.Serialization.Wrappers.LZKWAJ kwaj)
{
Console.WriteLine("Extracting LZ-compressed file, KWAJ variant contents");
Console.WriteLine();
kwaj.Extract(outputDirectory);
}
// LZ-compressed file, QBasic variant
else if (wrapper is SabreTools.Serialization.Wrappers.LZQBasic qbasic)
{
Console.WriteLine("Extracting LZ-compressed file, QBasic variant contents");
Console.WriteLine();
qbasic.Extract(outputDirectory);
}
// LZ-compressed file, SZDD variant
else if (wrapper is SabreTools.Serialization.Wrappers.LZSZDD szdd)
{
Console.WriteLine("Extracting LZ-compressed file, SZDD variant contents");
Console.WriteLine();
szdd.Extract(Path.GetFileName(file), outputDirectory);
}
// Microsoft Cabinet archive -- Implementation moved to Serialization
else if (ft == WrapperType.MicrosoftCAB)
{
// Build the cabinet information
Console.WriteLine("Extracting MS-CAB contents");
Console.WriteLine("WARNING: LZX and Quantum compression schemes are not supported so some files may be skipped!");
Console.WriteLine();
// Extract using the FileType
var mscab = new MicrosoftCAB();
mscab.Extract(stream, file, outputDirectory, includeDebug: true);
}
// MoPaQ (MPQ) archive
else if (ft == WrapperType.MoPaQ)
{
// Build the cabinet information
Console.WriteLine("Extracting MoPaQ contents");
Console.WriteLine();
#if NET20 || NET35 || !(WINX86 || WINX64)
Console.WriteLine("Extraction is not supported for this framework!");
Console.WriteLine();
#else
// Extract using the FileType
var mpq = new MPQ();
mpq.Extract(stream, file, outputDirectory, includeDebug: true);
#endif
}
// PAK
else if (wrapper is SabreTools.Serialization.Wrappers.PAK pak)
{
Console.WriteLine("Extracting PAK contents");
Console.WriteLine();
pak.ExtractAll(outputDirectory);
}
// PFF
else if (wrapper is SabreTools.Serialization.Wrappers.PFF pff)
{
Console.WriteLine("Extracting PFF contents");
Console.WriteLine();
pff.ExtractAll(outputDirectory);
}
// PKZIP -- Implementation moved to Serialization
else if (ft == WrapperType.PKZIP)
{
// Build the archive information
Console.WriteLine("Extracting PKZIP contents");
Console.WriteLine();
#if NET20 || NET35 || NET40 || NET452
Console.WriteLine("Extraction is not supported for this framework!");
Console.WriteLine();
#else
// Extract using the FileType
var pkzip = new PKZIP();
pkzip.Extract(stream, file, outputDirectory, includeDebug: true);
#endif
}
// Quantum -- Implementation moved to Serialization
else if (ft == WrapperType.Quantum)
{
// Build the archive information
Console.WriteLine("Extracting Quantum contents");
Console.WriteLine();
// Extract using the FileType
var quantum = new Quantum();
quantum.Extract(stream, file, outputDirectory, includeDebug: true);
}
// RAR -- Implementation moved to Serialization
else if (ft == WrapperType.RAR)
{
// Build the archive information
Console.WriteLine("Extracting RAR contents");
Console.WriteLine();
#if NET20 || NET35 || NET40 || NET452
Console.WriteLine("Extraction is not supported for this framework!");
Console.WriteLine();
#else
// Extract using the FileType
var rar = new RAR();
rar.Extract(stream, file, outputDirectory, includeDebug: true);
#endif
}
// SGA
else if (wrapper is SabreTools.Serialization.Wrappers.SGA sga)
{
Console.WriteLine("Extracting SGA contents");
Console.WriteLine();
sga.ExtractAll(outputDirectory);
}
// Tape Archive -- Implementation moved to Serialization
else if (ft == WrapperType.TapeArchive)
{
// Build the archive information
Console.WriteLine("Extracting Tape Archive contents");
Console.WriteLine();
#if NET20 || NET35 || NET40 || NET452
Console.WriteLine("Extraction is not supported for this framework!");
Console.WriteLine();
#else
// Extract using the FileType
var tar = new TapeArchive();
tar.Extract(stream, file, outputDirectory, includeDebug: true);
#endif
}
// VBSP
else if (wrapper is SabreTools.Serialization.Wrappers.VBSP vbsp)
{
Console.WriteLine("Extracting VBSP contents");
Console.WriteLine();
vbsp.ExtractAllLumps(outputDirectory);
}
// VPK
else if (wrapper is SabreTools.Serialization.Wrappers.VPK vpk)
{
Console.WriteLine("Extracting VPK contents");
Console.WriteLine();
vpk.ExtractAll(outputDirectory);
}
// WAD3
else if (wrapper is SabreTools.Serialization.Wrappers.WAD3 wad)
{
Console.WriteLine("Extracting WAD3 contents");
Console.WriteLine();
wad.ExtractAllLumps(outputDirectory);
}
// xz -- Implementation moved to Serialization
else if (ft == WrapperType.XZ)
{
// Build the xz information
Console.WriteLine("Extracting xz contents");
Console.WriteLine();
#if NET20 || NET35 || NET40 || NET452
Console.WriteLine("Extraction is not supported for this framework!");
Console.WriteLine();
#else
// Extract using the FileType
var xz = new XZ();
xz.Extract(stream, file, outputDirectory, includeDebug: true);
#endif
}
// XZP
else if (wrapper is SabreTools.Serialization.Wrappers.XZP xzp)
{
Console.WriteLine("Extracting XZP contents");
Console.WriteLine();
xzp.ExtractAll(outputDirectory);
}
// Everything else
else
{
Console.WriteLine("Not a supported extractable file format, skipping...");
Console.WriteLine();
return;
}
}
}
}

View File

@@ -2,14 +2,9 @@
[![Build and Test](https://github.com/SabreTools/BinaryObjectScanner/actions/workflows/build_and_test.yml/badge.svg)](https://github.com/SabreTools/BinaryObjectScanner/actions/workflows/build_and_test.yml) [![Build and Test](https://github.com/SabreTools/BinaryObjectScanner/actions/workflows/build_and_test.yml/badge.svg)](https://github.com/SabreTools/BinaryObjectScanner/actions/workflows/build_and_test.yml)
C# protection, packer, and archive scanning library. This currently compiles as a library so it can be used in any C# application. Two reference applications called `ProtectionScan` and `ExtractionTool` are also included to demonstrate the abilities of the library. For an example of a program implementing the library, see [MPF](https://github.com/SabreTools/MPF). C# protection, packer, and archive scanning library. This currently compiles as a library so it can be used in any C# application. A reference application called `ProtectionScan` is also included to demonstrate the abilities of the library. For an example of a program implementing the library, see [MPF](https://github.com/SabreTools/MPF).
The following non-project libraries (or ports thereof) are used for file handling: The former **ExtractionTool** application that was included is now included in the [SabreTools.Serialization repository](https://github.com/SabreTools/SabreTools.Serialization).
- [SharpCompress](https://github.com/adamhathcock/sharpcompress) - Common archive format extraction
- [StormLibSharp](https://github.com/robpaveza/stormlibsharp) - MoPaQ extraction [Unused in .NET Framework 2.0/3.5/4.0, non-Windows, and non-x86 builds due to Windows-specific libraries]
- [UnshieldSharp](https://github.com/mnadareski/UnshieldSharp) - InstallShield CAB extraction
- [WiseUnpacker](https://github.com/mnadareski/WiseUnpacker) - Wise Installer extraction
The following projects have influenced this library: The following projects have influenced this library:
@@ -17,7 +12,6 @@ The following projects have influenced this library:
- [HLLibSharp](https://github.com/mnadareski/HLLibSharp) - Documentation around Valve package handling, including extraction. - [HLLibSharp](https://github.com/mnadareski/HLLibSharp) - Documentation around Valve package handling, including extraction.
- [libbdplus](https://www.videolan.org/developers/libbdplus.html) - Documentation around the BD+ SVM files. - [libbdplus](https://www.videolan.org/developers/libbdplus.html) - Documentation around the BD+ SVM files.
- [libmspack](https://github.com/kyz/libmspack) - Documentation around the MS-CAB format and associated compression methods. - [libmspack](https://github.com/kyz/libmspack) - Documentation around the MS-CAB format and associated compression methods.
- [NDecrypt](https://github.com/SabreTools/NDecrypt) - NDS (Nitro) and 3DS cart image file layouts and documentation, though not encrypt/decrypt.
Please visit our sibling project, [DRML](https://github.com/TheRogueArchivist/DRML), the DRM Library for a more in-depth look at some of the protections detected. Please visit our sibling project, [DRML](https://github.com/TheRogueArchivist/DRML), the DRM Library for a more in-depth look at some of the protections detected.
@@ -35,12 +29,9 @@ Binary Object Scanner strives to have both full compatibility for scanning acros
- **7-zip archive** - Extraction is only supported on .NET Framework 4.6.2 and higher due to `SharpCompress` support limitations - **7-zip archive** - Extraction is only supported on .NET Framework 4.6.2 and higher due to `SharpCompress` support limitations
- **bzip2 archive** - Extraction is only supported on .NET Framework 4.6.2 and higher due to `SharpCompress` support limitations - **bzip2 archive** - Extraction is only supported on .NET Framework 4.6.2 and higher due to `SharpCompress` support limitations
- **gzip archive** - Extraction is only supported on .NET Framework 4.6.2 and higher due to `SharpCompress` support limitations
- **MS-CAB** - Extraction is only supported in Windows x86 builds running .NET Framework 4.5.2 and higher due to native DLL requirements
- **MoPaQ** - Extraction is only supported in Windows x86 builds running .NET Framework 4.5.2 and higher due to native DLL requirements - **MoPaQ** - Extraction is only supported in Windows x86 builds running .NET Framework 4.5.2 and higher due to native DLL requirements
- **PKZIP and derived files (ZIP, etc.)** - Extraction is only supported on .NET Framework 4.6.2 and higher - **PKZIP and derived files (ZIP, etc.)** - Extraction is only supported on .NET Framework 4.6.2 and higher due to `SharpCompress` support limitations
- **RAR archive** - Extraction is only supported on .NET Framework 4.6.2 and higher due to `SharpCompress` support limitations - **RAR archive** - Extraction is only supported on .NET Framework 4.6.2 and higher due to `SharpCompress` support limitations
- **Tape archive** - Extraction is only supported on .NET Framework 4.6.2 and higher due to `SharpCompress` support limitations
- **xz archive** - Extraction is only supported on .NET Framework 4.6.2 and higher due to `SharpCompress` support limitations - **xz archive** - Extraction is only supported on .NET Framework 4.6.2 and higher due to `SharpCompress` support limitations
## Protections Detected ## Protections Detected
@@ -199,15 +190,15 @@ Below is a list of container formats that are supported in some way:
| BFPK custom archive format | Yes | Yes | Yes | | | BFPK custom archive format | Yes | Yes | Yes | |
| bzip2 archive | No | Yes | Yes | Via `SharpCompress` | | bzip2 archive | No | Yes | Yes | Via `SharpCompress` |
| Compound File Binary (CFB) | Yes* | Yes | Yes | Only CFB common pieces printable | | Compound File Binary (CFB) | Yes* | Yes | Yes | Only CFB common pieces printable |
| gzip archive | No | Yes | Yes | Via `SharpCompress` | | gzip archive | No | Yes | Yes | |
| Half-Life Game Cache File (GCF) | Yes | Yes | Yes | | | Half-Life Game Cache File (GCF) | Yes | Yes | Yes | |
| Half-Life Level (BSP) | Yes | Yes | Yes | | | Half-Life Level (BSP) | Yes | Yes | Yes | |
| Half-Life Package File (PAK) | Yes | Yes | Yes | | | Half-Life Package File (PAK) | Yes | Yes | Yes | |
| Half-Life Texture Package File (WAD3) | Yes | Yes | Yes | | | Half-Life Texture Package File (WAD3) | Yes | Yes | Yes | |
| Half-Life 2 Level (VBSP) | Yes | Yes | Yes | | | Half-Life 2 Level (VBSP) | Yes | Yes | Yes | |
| INI configuration file | No | No | No | Used in other detections currently | | INI configuration file | No | No | No | Used in other detections currently |
| InstallShield Archive V3 (Z) | No | Yes | Yes | Via `UnshieldSharp` | | InstallShield Archive V3 (Z) | No | Yes | Yes | |
| InstallShield CAB | Yes | Yes | Yes | Via `UnshieldSharp` | | InstallShield CAB | Yes | Yes | Yes | |
| Linear Executable | No | No | No | Skeleton only | | Linear Executable | No | No | No | Skeleton only |
| Link Data Security encrypted file | No | Yes | No | | | Link Data Security encrypted file | No | Yes | No | |
| Microsoft cabinet file | Yes | Yes | Yes* | Does not support LZX or Quantum compression | | Microsoft cabinet file | Yes | Yes | Yes* | Does not support LZX or Quantum compression |
@@ -226,7 +217,7 @@ Below is a list of container formats that are supported in some way:
| RAR archive (RAR) | No | Yes | Yes | Via `SharpCompress` | | RAR archive (RAR) | No | Yes | Yes | Via `SharpCompress` |
| SGA game archive | Yes | Yes | Yes | | | SGA game archive | Yes | Yes | Yes | |
| StarForce Filesystem file (SFFS) | No | Yes | No | Skeleton only | | StarForce Filesystem file (SFFS) | No | Yes | No | Skeleton only |
| Tape archive (TAR) | No | Yes | Yes | Via `SharpCompress` | | Tape archive (TAR) | No | Yes | Yes | |
| Valve Package File (VPK) | Yes | Yes | Yes | | | Valve Package File (VPK) | Yes | Yes | Yes | |
| XBox Package File (XZP) | Yes | Yes | Yes | | | XBox Package File (XZP) | Yes | Yes | Yes | |
| xz archive (XZ) | No | Yes | Yes | Via `SharpCompress` | | xz archive (XZ) | No | Yes | Yes | Via `SharpCompress` |

View File

@@ -72,45 +72,6 @@ if [ $NO_BUILD = false ]; then
# Create Nuget Package # Create Nuget Package
dotnet pack BinaryObjectScanner/BinaryObjectScanner.csproj --output $BUILD_FOLDER dotnet pack BinaryObjectScanner/BinaryObjectScanner.csproj --output $BUILD_FOLDER
# Build ExtractionTool
for FRAMEWORK in "${FRAMEWORKS[@]}"; do
for RUNTIME in "${RUNTIMES[@]}"; do
# Output the current build
echo "===== Build ExtractionTool - $FRAMEWORK, $RUNTIME ====="
# If we have an invalid combination of framework and runtime
if [[ ! $(echo ${VALID_CROSS_PLATFORM_FRAMEWORKS[@]} | fgrep -w $FRAMEWORK) ]]; then
if [[ $(echo ${VALID_CROSS_PLATFORM_RUNTIMES[@]} | fgrep -w $RUNTIME) ]]; then
echo "Skipped due to invalid combination"
continue
fi
fi
# If we have Apple silicon but an unsupported framework
if [[ ! $(echo ${VALID_APPLE_FRAMEWORKS[@]} | fgrep -w $FRAMEWORK) ]]; then
if [ $RUNTIME = "osx-arm64" ]; then
echo "Skipped due to no Apple Silicon support"
continue
fi
fi
# Only .NET 5 and above can publish to a single file
if [[ $(echo ${SINGLE_FILE_CAPABLE[@]} | fgrep -w $FRAMEWORK) ]]; then
# Only include Debug if set
if [ $INCLUDE_DEBUG = true ]; then
dotnet publish ExtractionTool/ExtractionTool.csproj -f $FRAMEWORK -r $RUNTIME -c Debug --self-contained true --version-suffix $COMMIT -p:PublishSingleFile=true
fi
dotnet publish ExtractionTool/ExtractionTool.csproj -f $FRAMEWORK -r $RUNTIME -c Release --self-contained true --version-suffix $COMMIT -p:PublishSingleFile=true -p:DebugType=None -p:DebugSymbols=false
else
# Only include Debug if set
if [ $INCLUDE_DEBUG = true ]; then
dotnet publish ExtractionTool/ExtractionTool.csproj -f $FRAMEWORK -r $RUNTIME -c Debug --self-contained true --version-suffix $COMMIT
fi
dotnet publish ExtractionTool/ExtractionTool.csproj -f $FRAMEWORK -r $RUNTIME -c Release --self-contained true --version-suffix $COMMIT -p:DebugType=None -p:DebugSymbols=false
fi
done
done
# Build ProtectionScan # Build ProtectionScan
for FRAMEWORK in "${FRAMEWORKS[@]}"; do for FRAMEWORK in "${FRAMEWORKS[@]}"; do
for RUNTIME in "${RUNTIMES[@]}"; do for RUNTIME in "${RUNTIMES[@]}"; do
@@ -153,38 +114,6 @@ fi
# Only create archives if requested # Only create archives if requested
if [ $NO_ARCHIVE = false ]; then if [ $NO_ARCHIVE = false ]; then
# Create ExtractionTool archives
for FRAMEWORK in "${FRAMEWORKS[@]}"; do
for RUNTIME in "${RUNTIMES[@]}"; do
# Output the current build
echo "===== Archive ExtractionTool - $FRAMEWORK, $RUNTIME ====="
# If we have an invalid combination of framework and runtime
if [[ ! $(echo ${VALID_CROSS_PLATFORM_FRAMEWORKS[@]} | fgrep -w $FRAMEWORK) ]]; then
if [[ $(echo ${VALID_CROSS_PLATFORM_RUNTIMES[@]} | fgrep -w $RUNTIME) ]]; then
echo "Skipped due to invalid combination"
continue
fi
fi
# If we have Apple silicon but an unsupported framework
if [[ ! $(echo ${VALID_APPLE_FRAMEWORKS[@]} | fgrep -w $FRAMEWORK) ]]; then
if [ $RUNTIME = "osx-arm64" ]; then
echo "Skipped due to no Apple Silicon support"
continue
fi
fi
# Only include Debug if set
if [ $INCLUDE_DEBUG = true ]; then
cd $BUILD_FOLDER/ExtractionTool/bin/Debug/${FRAMEWORK}/${RUNTIME}/publish/
zip -r $BUILD_FOLDER/ExtractionTool_${FRAMEWORK}_${RUNTIME}_debug.zip .
fi
cd $BUILD_FOLDER/ExtractionTool/bin/Release/${FRAMEWORK}/${RUNTIME}/publish/
zip -r $BUILD_FOLDER/ExtractionTool_${FRAMEWORK}_${RUNTIME}_release.zip .
done
done
# Create ProtectionScan archives # Create ProtectionScan archives
for FRAMEWORK in "${FRAMEWORKS[@]}"; do for FRAMEWORK in "${FRAMEWORKS[@]}"; do
for RUNTIME in "${RUNTIMES[@]}"; do for RUNTIME in "${RUNTIMES[@]}"; do

View File

@@ -63,42 +63,6 @@ if (!$NO_BUILD.IsPresent) {
# Create Nuget Package # Create Nuget Package
dotnet pack BinaryObjectScanner\BinaryObjectScanner.csproj --output $BUILD_FOLDER dotnet pack BinaryObjectScanner\BinaryObjectScanner.csproj --output $BUILD_FOLDER
# Build ExtractionTool
foreach ($FRAMEWORK in $FRAMEWORKS) {
foreach ($RUNTIME in $RUNTIMES) {
# Output the current build
Write-Host "===== Build ExtractionTool - $FRAMEWORK, $RUNTIME ====="
# If we have an invalid combination of framework and runtime
if ($VALID_CROSS_PLATFORM_FRAMEWORKS -notcontains $FRAMEWORK -and $VALID_CROSS_PLATFORM_RUNTIMES -contains $RUNTIME) {
Write-Host "Skipped due to invalid combination"
continue
}
# If we have Apple silicon but an unsupported framework
if ($VALID_APPLE_FRAMEWORKS -notcontains $FRAMEWORK -and $RUNTIME -eq 'osx-arm64') {
Write-Host "Skipped due to no Apple Silicon support"
continue
}
# Only .NET 5 and above can publish to a single file
if ($SINGLE_FILE_CAPABLE -contains $FRAMEWORK) {
# Only include Debug if set
if ($INCLUDE_DEBUG.IsPresent) {
dotnet publish ExtractionTool\ExtractionTool.csproj -f $FRAMEWORK -r $RUNTIME -c Debug --self-contained true --version-suffix $COMMIT -p:PublishSingleFile=true
}
dotnet publish ExtractionTool\ExtractionTool.csproj -f $FRAMEWORK -r $RUNTIME -c Release --self-contained true --version-suffix $COMMIT -p:PublishSingleFile=true -p:DebugType=None -p:DebugSymbols=false
}
else {
# Only include Debug if set
if ($INCLUDE_DEBUG.IsPresent) {
dotnet publish ExtractionTool\ExtractionTool.csproj -f $FRAMEWORK -r $RUNTIME -c Debug --self-contained true --version-suffix $COMMIT
}
dotnet publish ExtractionTool\ExtractionTool.csproj -f $FRAMEWORK -r $RUNTIME -c Release --self-contained true --version-suffix $COMMIT -p:DebugType=None -p:DebugSymbols=false
}
}
}
# Build ProtectionScan # Build ProtectionScan
foreach ($FRAMEWORK in $FRAMEWORKS) { foreach ($FRAMEWORK in $FRAMEWORKS) {
foreach ($RUNTIME in $RUNTIMES) { foreach ($RUNTIME in $RUNTIMES) {
@@ -138,35 +102,6 @@ if (!$NO_BUILD.IsPresent) {
# Only create archives if requested # Only create archives if requested
if (!$NO_ARCHIVE.IsPresent) { if (!$NO_ARCHIVE.IsPresent) {
# Create ExtractionTool archives
foreach ($FRAMEWORK in $FRAMEWORKS) {
foreach ($RUNTIME in $RUNTIMES) {
# Output the current build
Write-Host "===== Archive ExtractionTool - $FRAMEWORK, $RUNTIME ====="
# If we have an invalid combination of framework and runtime
if ($VALID_CROSS_PLATFORM_FRAMEWORKS -notcontains $FRAMEWORK -and $VALID_CROSS_PLATFORM_RUNTIMES -contains $RUNTIME) {
Write-Host "Skipped due to invalid combination"
continue
}
# If we have Apple silicon but an unsupported framework
if ($VALID_APPLE_FRAMEWORKS -notcontains $FRAMEWORK -and $RUNTIME -eq 'osx-arm64') {
Write-Host "Skipped due to no Apple Silicon support"
continue
}
# Only include Debug if set
if ($INCLUDE_DEBUG.IsPresent) {
Set-Location -Path $BUILD_FOLDER\ExtractionTool\bin\Debug\${FRAMEWORK}\${RUNTIME}\publish\
7z a -tzip $BUILD_FOLDER\ExtractionTool_${FRAMEWORK}_${RUNTIME}_debug.zip *
}
Set-Location -Path $BUILD_FOLDER\ExtractionTool\bin\Release\${FRAMEWORK}\${RUNTIME}\publish\
7z a -tzip $BUILD_FOLDER\ExtractionTool_${FRAMEWORK}_${RUNTIME}_release.zip *
}
}
# Create ProtectionScan archives # Create ProtectionScan archives
foreach ($FRAMEWORK in $FRAMEWORKS) { foreach ($FRAMEWORK in $FRAMEWORKS) {
foreach ($RUNTIME in $RUNTIMES) { foreach ($RUNTIME in $RUNTIMES) {