From 2c979f291e8db725b8ba20b58f98224d870c30ac Mon Sep 17 00:00:00 2001 From: Matt Nadareski Date: Mon, 16 Jan 2023 21:52:32 -0800 Subject: [PATCH] Add Options class, allow multiple features --- Test/App.config | 6 - Test/Options.cs | 282 ++++++++++++++++++++++++++++++++ Test/Printer.cs | 39 +++-- Test/Program.cs | 172 ++++--------------- Test/Properties/AssemblyInfo.cs | 36 ---- 5 files changed, 338 insertions(+), 197 deletions(-) delete mode 100644 Test/App.config create mode 100644 Test/Options.cs delete mode 100644 Test/Properties/AssemblyInfo.cs diff --git a/Test/App.config b/Test/App.config deleted file mode 100644 index ecdcf8a5..00000000 --- a/Test/App.config +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/Test/Options.cs b/Test/Options.cs new file mode 100644 index 00000000..1227d1e1 --- /dev/null +++ b/Test/Options.cs @@ -0,0 +1,282 @@ +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; } = new List(); + + #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 NET6_0_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 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] : null; + break; + + #endregion + + #region Information + +#if NET6_0_OR_GREATER + case "-j": + case "--json": + options.Json = true; + break; +#endif + + #endregion + + #region Scanning + + case "-na": + case "--no-archives": + options.ScanArchives = false; + break; + + case "-nc": + case "--no-contents": + options.ScanContents = 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("BurnOutSharp 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("-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.IsNullOrWhiteSpace(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; + } + } +} \ No newline at end of file diff --git a/Test/Printer.cs b/Test/Printer.cs index d18351a1..9c734301 100644 --- a/Test/Printer.cs +++ b/Test/Printer.cs @@ -16,20 +16,32 @@ namespace Test /// File or directory path /// Enable JSON output, if supported /// Enable debug output +#if NET6_0_OR_GREATER public static void PrintPathInfo(string path, bool json, bool debug) +#else + public static void PrintPathInfo(string path, bool debug) +#endif { Console.WriteLine($"Checking possible path: {path}"); // Check if the file or directory exists if (File.Exists(path)) { +#if NET6_0_OR_GREATER PrintFileInfo(path, json, debug); +#else + PrintFileInfo(path, debug); +#endif } else if (Directory.Exists(path)) { foreach (string file in Directory.EnumerateFiles(path, "*", SearchOption.AllDirectories)) { +#if NET6_0_OR_GREATER PrintFileInfo(file, json, debug); +#else + PrintFileInfo(file, debug); +#endif } } else @@ -41,7 +53,11 @@ namespace Test /// /// Print information for a single file, if possible /// +#if NET6_0_OR_GREATER private static void PrintFileInfo(string file, bool json, bool debug) +#else + private static void PrintFileInfo(string file, bool debug) +#endif { Console.WriteLine($"Attempting to print info for {file}"); @@ -260,6 +276,9 @@ namespace Test // Print the wrapper name Console.WriteLine($"{wrapperName} wrapper created successfully!"); + // Get the base info output name + string filenameBase = $"info-{DateTime.Now:yyyy-MM-dd_HHmmss.ffff}"; + #if NET6_0_OR_GREATER // If we have the JSON flag if (json) @@ -269,24 +288,20 @@ namespace Test Console.WriteLine(serializedData); // Write the output data - using (var sw = new StreamWriter(File.OpenWrite($"info-{DateTime.Now:yyyy-MM-dd_HHmmss.ffff}.json"))) + using (var sw = new StreamWriter(File.OpenWrite($"{filenameBase}.json"))) { sw.WriteLine(serializedData); } } #endif - // If we don't have the JSON flag - if (!json) - { - // Create the output data - StringBuilder builder = wrapper.PrettyPrint(); - Console.WriteLine(builder); + // Create the output data + StringBuilder builder = wrapper.PrettyPrint(); + Console.WriteLine(builder); - // Write the output data - using (var sw = new StreamWriter(File.OpenWrite($"info-{DateTime.Now:yyyy-MM-dd_HHmmss.ffff}.txt"))) - { - sw.WriteLine(builder.ToString()); - } + // Write the output data + using (var sw = new StreamWriter(File.OpenWrite($"{filenameBase}.txt"))) + { + sw.WriteLine(builder.ToString()); } } } diff --git a/Test/Program.cs b/Test/Program.cs index 6a3467f6..a6fe7d0c 100644 --- a/Test/Program.cs +++ b/Test/Program.cs @@ -1,6 +1,4 @@ using System; -using System.Collections.Generic; -using System.IO; using System.Text; using BurnOutSharp; @@ -14,164 +12,52 @@ namespace Test Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); // Create progress indicator - var p = new Progress(); - p.ProgressChanged += Protector.Changed; + var fileProgress = new Progress(); + fileProgress.ProgressChanged += Protector.Changed; - // Set initial values for scanner flags - bool debug = false, archives = true, contents = true, json = false, packers = true, paths = true, info = false, extract = false; - string outputPath = string.Empty; - var inputPaths = new List(); + // Get the options from the arguments + var options = Options.ParseOptions(args); - // Loop through the arguments to get the flags - for (int i = 0; i < args.Length; i++) + // If we have an invalid state + if (options == null) { - string arg = args[i]; - - switch (arg) - { - case "-?": - case "-h": - case "--help": - DisplayHelp(); - Console.WriteLine("Press enter to close the program..."); - Console.ReadLine(); - return; - - case "-d": - case "--debug": - debug = true; - break; - - case "-na": - case "--no-archives": - archives = false; - break; - - case "-nc": - case "--no-contents": - contents = false; - break; - -#if NET6_0_OR_GREATER - - case "-j": - case "--json": - json = true; - break; - -#endif - - case "-np": - case "--no-packers": - packers = false; - break; - - case "-ns": - case "--no-paths": - paths = false; - break; - - case "-i": - case "--info": - info = true; - break; - - case "-x": - case "--extract": - extract = true; - break; - - case "-o": - case "--outdir": - outputPath = i + 1 < args.Length ? args[++i] : null; - break; - - default: - inputPaths.Add(arg); - break; - } - } - - // If we have no arguments, show the help - if (inputPaths.Count == 0) - { - DisplayHelp(); + Options.DisplayHelp(); Console.WriteLine("Press enter to close the program..."); Console.ReadLine(); return; } // Create scanner for all paths - var scanner = new Scanner(archives, contents, packers, paths, debug, p); - - // If we have extraction, check the output path exists and is valid - if (extract) - { - // Null or empty output path - if (string.IsNullOrWhiteSpace(outputPath)) - { - Console.WriteLine("Output directory required for extraction!"); - Console.WriteLine(); - DisplayHelp(); - Console.WriteLine("Press enter to close the program..."); - Console.ReadLine(); - return; - } - - // Malformed output path or invalid location - try - { - outputPath = Path.GetFullPath(outputPath); - Directory.CreateDirectory(outputPath); - } - catch - { - Console.WriteLine("Output directory could not be created!"); - Console.WriteLine(); - DisplayHelp(); - Console.WriteLine("Press enter to close the program..."); - Console.ReadLine(); - return; - } - } + var scanner = new Scanner( + options.ScanArchives, + options.ScanContents, + options.ScanPackers, + options.ScanPaths, + options.Debug, + fileProgress); // Loop through the input paths - foreach (string inputPath in inputPaths) + foreach (string inputPath in options.InputPaths) { - if (info) - Printer.PrintPathInfo(inputPath, json, debug); - else if (extract) - Extractor.ExtractPath(inputPath, outputPath); - else + // Extraction + if (options.EnableExtraction) + Extractor.ExtractPath(inputPath, options.OutputPath); + + // Information printing + if (options.EnableInformation) +#if NET6_0_OR_GREATER + Printer.PrintPathInfo(inputPath, options.Json, options.Debug); +#else + Printer.PrintPathInfo(inputPath, options.Debug); +#endif + + // Scanning + if (options.EnableScanning) Protector.GetAndWriteProtections(scanner, inputPath); } Console.WriteLine("Press enter to close the program..."); Console.ReadLine(); } - - /// - /// Display help text - /// - private static void DisplayHelp() - { - Console.WriteLine("BurnOutSharp Test Program"); - Console.WriteLine(); - Console.WriteLine("test.exe file|directory ..."); - Console.WriteLine(); - Console.WriteLine("Possible options:"); - Console.WriteLine("-?, -h, --help Display this help text and quit"); - Console.WriteLine("-d, --debug Enable debug mode"); - 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("-i, --info Print executable info"); -#if NET6_0_OR_GREATER - Console.WriteLine("-j, --json Print executable info as JSON"); -#endif - Console.WriteLine("-x, --extract Extract archive formats (Requires -o)"); - Console.WriteLine("-o, --outdir [PATH] Set output path for extraction (Requires -x)"); - } } } diff --git a/Test/Properties/AssemblyInfo.cs b/Test/Properties/AssemblyInfo.cs deleted file mode 100644 index 55172df6..00000000 --- a/Test/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("Test")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("Test")] -[assembly: AssemblyCopyright("Copyright © 2018")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("88735ba2-778d-4192-8eb2-fff6843719e2")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")]