using System; using System.Collections.Generic; using System.IO; namespace Test { /// /// Set of options for the test executable /// internal sealed class Options { #region Properties /// /// Enable debug output for relevant operations /// public bool Debug { get; private set; } = false; /// /// Set of input paths to use for operations /// public List InputPaths { get; private set; } = []; #region Extraction /// /// Perform archive extraction /// public bool EnableExtraction { get; private set; } = false; /// /// Output path for archive extraction /// public string OutputPath { get; private set; } = string.Empty; #endregion #region Information /// /// Perform information printing /// public bool EnableInformation { get; private set; } = false; #if NETCOREAPP3_1_OR_GREATER /// /// Enable JSON output /// public bool Json { get; private set; } = false; #endif #endregion #region Scanning /// /// Perform protection scanning /// public bool EnableScanning { get; private set; } = false; /// /// Scan archives during protection scanning /// public bool ScanArchives { get; private set; } = true; /// /// Scan file contents during protection scanning /// public bool ScanContents { get; private set; } = true; /// /// Scan game engines during protection scanning /// public bool ScanGameEngines { get; private set; } = true; /// /// Scan packers during protection scanning /// public bool ScanPackers { get; private set; } = true; /// /// Scan file paths during protection scanning /// public bool ScanPaths { get; private set; } = true; #endregion #endregion /// /// Parse commandline arguments into an Options object /// 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 features int index = 0; for (; index < args.Length; index++) { string arg = args[index]; bool featureFound = false; switch (arg) { case "-?": case "-h": case "--help": return null; case "-x": case "--extract": options.EnableExtraction = true; featureFound = true; break; case "-i": case "--info": options.EnableInformation = true; featureFound = true; break; case "-s": case "--scan": options.EnableScanning = true; featureFound = true; break; default: break; } // If the flag wasn't a feature if (!featureFound) break; } // Parse the options and paths for (; index < args.Length; index++) { string arg = args[index]; switch (arg) { case "-d": case "--debug": options.Debug = true; break; #region Extraction case "-o": case "--outdir": options.OutputPath = index + 1 < args.Length ? args[++index] : string.Empty; break; #endregion #region Information case "-j": case "--json": #if NET6_0_OR_GREATER options.Json = true; #else Console.WriteLine("JSON output not available in .NET Framework"); #endif break; #endregion #region Scanning case "-na": case "--no-archives": options.ScanArchives = false; break; case "-nc": case "--no-contents": options.ScanContents = false; break; case "-ng": case "--no-game-engines": options.ScanGameEngines = false; break; case "-np": case "--no-packers": options.ScanPackers = false; break; case "-ns": case "--no-paths": options.ScanPaths = false; break; #endregion default: options.InputPaths.Add(arg); break; } } // If we have no features set, enable protection scanning if (!options.EnableExtraction && !options.EnableInformation && !options.EnableScanning) options.EnableScanning = true; // Validate we have any input paths to work on if (options.InputPaths.Count == 0) { Console.WriteLine("At least one path is required!"); return null; } // If we have extraction enabled, validate the path if (options.EnableExtraction) { bool validPath = ValidateExtractionPath(options); if (!validPath) return null; } return options; } /// /// Display help text /// public static void DisplayHelp() { Console.WriteLine("BinaryObjectScanner Test Program"); Console.WriteLine(); Console.WriteLine("test.exe 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(); Console.WriteLine("Common options:"); 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)"); #if NET6_0_OR_GREATER Console.WriteLine(); Console.WriteLine("Information options:"); 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("-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"); } /// /// Validate the extraction path /// 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; } } }