diff --git a/Steamless.CLI/App.config b/Steamless.CLI/App.config
new file mode 100644
index 0000000..88fa402
--- /dev/null
+++ b/Steamless.CLI/App.config
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Steamless.CLI/Program.cs b/Steamless.CLI/Program.cs
new file mode 100644
index 0000000..053cc5f
--- /dev/null
+++ b/Steamless.CLI/Program.cs
@@ -0,0 +1,250 @@
+/**
+ * Steamless - Copyright (c) 2015 - 2022 atom0s [atom0s@live.com]
+ *
+ * This work is licensed under the Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License.
+ * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/4.0/ or send a letter to
+ * Creative Commons, PO Box 1866, Mountain View, CA 94042, USA.
+ *
+ * By using Steamless, you agree to the above license and its terms.
+ *
+ * Attribution - You must give appropriate credit, provide a link to the license and indicate if changes were
+ * made. You must do so in any reasonable manner, but not in any way that suggests the licensor
+ * endorses you or your use.
+ *
+ * Non-Commercial - You may not use the material (Steamless) for commercial purposes.
+ *
+ * No-Derivatives - If you remix, transform, or build upon the material (Steamless), you may not distribute the
+ * modified material. You are, however, allowed to submit the modified works back to the original
+ * Steamless project in attempt to have it added to the original project.
+ *
+ * You may not apply legal terms or technological measures that legally restrict others
+ * from doing anything the license permits.
+ *
+ * No warranties are given.
+ */
+
+namespace Steamless.CLI
+{
+ using Steamless.API;
+ using Steamless.API.Events;
+ using Steamless.API.Model;
+ using System;
+ using System.Collections.Generic;
+ using System.IO;
+ using System.Linq;
+ using System.Reflection;
+
+ internal class Program
+ {
+ ///
+ /// Steamless API Version
+ ///
+ /// Main define for this is within DataService.cs and should match that value.
+ ///
+ private static readonly Version SteamlessApiVersion = new Version(1, 0);
+
+ ///
+ /// Steamless logging service.
+ ///
+ private static readonly API.Services.LoggingService LoggingService = new API.Services.LoggingService();
+
+ ///
+ /// Prints the Steamless header information.
+ ///
+ static void PrintHeader()
+ {
+ Console.WriteLine(" _________ __ .__ ");
+ Console.WriteLine(" / _____// |_ ____ _____ _____ | | ____ ______ ______");
+ Console.WriteLine(" \\_____ \\\\ __\\/ __ \\\\__ \\ / \\| | _/ __ \\ / ___// ___/");
+ Console.WriteLine(" / \\| | \\ ___/ / __ \\| Y Y \\ |_\\ ___/ \\___ \\ \\___ \\ ");
+ Console.WriteLine("/_______ /|__| \\___ >____ /__|_| /____/\\___ >____ >____ >");
+ Console.WriteLine(" \\/ \\/ \\/ \\/ \\/ \\/ \\/ \n");
+ Console.WriteLine("Steamless - SteamStub DRM Remover");
+ Console.WriteLine("by atom0s\n");
+ Console.WriteLine("GitHub : https://github.com/atom0s/Steamless");
+ Console.WriteLine("Homepage : https://atom0s.com");
+ Console.WriteLine("Donations : https://paypal.me/atom0s");
+ Console.WriteLine("Donations : https://github.com/sponsors/atom0s");
+ Console.WriteLine("Donations : https://patreon.com/atom0s\n");
+ }
+
+ ///
+ /// Prints the Steamless command line help information.
+ ///
+ static void PrintHelp()
+ {
+ Console.WriteLine("Usage:");
+ Console.WriteLine(" Steamless.CLI.exe [options] [file]\n");
+ Console.WriteLine("Options:");
+ Console.WriteLine(" --quiet");
+ Console.WriteLine(" --keepbind - Keeps the .bind section in the unpacked file.");
+ Console.WriteLine(" --keepstub - Keeps the DOS stub in the unpacked file.");
+ Console.WriteLine(" --dumppayload - Dumps the stub payload to disk.");
+ Console.WriteLine(" --dumpdrmp - Dumps the SteamDRMP.dll to disk.");
+ Console.WriteLine(" --realign - Realigns the unpacked file sections.");
+ Console.WriteLine(" --recalcchecksum - Recalculates the unpacked file checksum.");
+ Console.WriteLine(" --exp - Use experimental features.");
+ }
+
+ ///
+ /// Obtains a list of available Steamless plugins.
+ ///
+ ///
+ static List GetSteamlessPlugins()
+ {
+ try
+ {
+ // The list of valid plugins..
+ var plugins = new List();
+
+ // Build a path to the plugins folder..
+ var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Plugins");
+
+ // Loop the DLL files and attempt to load them..
+ foreach (var dll in Directory.GetFiles(path, "*.dll"))
+ {
+ // Skip the Steamless.API.dll file..
+ if (dll.ToLower().Contains("steamless.api.dll"))
+ continue;
+
+ try
+ {
+ // Load the assembly..
+ var asm = Assembly.Load(File.ReadAllBytes(dll));
+
+ // Locate the class inheriting the plugin base..
+ var baseClass = asm.GetTypes().SingleOrDefault(t => t.BaseType == typeof(SteamlessPlugin));
+ if (baseClass == null)
+ continue;
+
+ // Locate the SteamlessApiVersion attribute on the base class..
+ var baseAttr = baseClass.GetCustomAttributes(typeof(SteamlessApiVersionAttribute), false);
+ if (baseAttr.Length == 0)
+ continue;
+
+ // Validate the interface version..
+ var apiVersion = (SteamlessApiVersionAttribute)baseAttr[0];
+ if (apiVersion.Version != SteamlessApiVersion)
+ continue;
+
+ // Create an instance of the plugin..
+ var plugin = (SteamlessPlugin)Activator.CreateInstance(baseClass);
+ if (!plugin.Initialize(LoggingService))
+ continue;
+
+ plugins.Add(plugin);
+ }
+ catch
+ {
+ }
+ }
+
+ // Order the plugins by their name..
+ return plugins.OrderBy(p => p.Name).ToList();
+ }
+ catch
+ {
+ return new List();
+ }
+ }
+
+ ///
+ /// Application entry point.
+ ///
+ ///
+ static int Main(string[] args)
+ {
+ PrintHeader();
+
+ var opts = new SteamlessOptions();
+ var file = string.Empty;
+
+ // Process command line arguments for the various Steamless options..
+ foreach (var arg in args)
+ {
+ if (arg.ToLower() == "--quiet")
+ opts.VerboseOutput = false;
+ if (arg.ToLower() == "--keepbind")
+ opts.KeepBindSection = true;
+ if (arg.ToLower() == "--keepstub")
+ opts.ZeroDosStubData = false;
+ if (arg.ToLower() == "--dumppayload")
+ opts.DumpPayloadToDisk = true;
+ if (arg.ToLower() == "--dumpdrmp")
+ opts.DumpSteamDrmpToDisk = true;
+ if (arg.ToLower() == "--realign")
+ opts.DontRealignSections = false;
+ if (arg.ToLower() == "--recalcchecksum")
+ opts.RecalculateFileChecksum = true;
+ if (arg.ToLower() == "--exp")
+ opts.UseExperimentalFeatures = true;
+ if (!arg.StartsWith("--"))
+ file = arg;
+ }
+
+ // Prepare the logging service..
+ LoggingService.AddLogMessage += (sender, e) =>
+ {
+ if (!opts.VerboseOutput && e.MessageType == LogMessageType.Debug)
+ return;
+
+ try
+ {
+ if (sender != null)
+ e.Message = $"[{sender.GetType().Assembly.GetName().Name}] {e.Message}";
+ else
+ e.Message = $"[Steamless] {e.Message}";
+ }
+ catch
+ {
+ }
+
+ Console.WriteLine(e.Message);
+ };
+
+ // Ensure an input file was given..
+ if (string.IsNullOrEmpty(file))
+ {
+ PrintHelp();
+ return 1;
+ }
+
+ // Ensure the input file exists..
+ if (!File.Exists(file))
+ {
+ LoggingService.OnAddLogMessage(null, new LogMessageEventArgs("Invalid input file given; cannot continue.", LogMessageType.Error));
+ return 1;
+ }
+
+ // Collect the list of available plugins..
+ var plugins = GetSteamlessPlugins();
+ plugins.ForEach(p => LoggingService.OnAddLogMessage(null, new LogMessageEventArgs($"Loaded plugin: {p.Name} - by {p.Author} (v.{p.Version})", LogMessageType.Success)));
+
+ // Ensure plugins were found and loaded..
+ if (plugins.Count == 0)
+ {
+ LoggingService.OnAddLogMessage(null, new LogMessageEventArgs("No plugins were loaded; be sure to fully extract Steamless before running!", LogMessageType.Error));
+ return 1;
+ }
+
+ // Loop through the plugins and try to unpack the file..
+ foreach (var p in plugins)
+ {
+ // Check if the plugin can process the file..
+ if (p.CanProcessFile(file))
+ {
+ var ret = p.ProcessFile(file, opts);
+
+ LoggingService.OnAddLogMessage(null, !ret
+ ? new LogMessageEventArgs("Failed to unpack file.", LogMessageType.Error)
+ : new LogMessageEventArgs("Successfully unpacked file!", LogMessageType.Success));
+
+ if (ret) return 0;
+ }
+ }
+
+ LoggingService.OnAddLogMessage(null, new LogMessageEventArgs("All unpackers failed to unpack file.", LogMessageType.Error));
+ return 1;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Steamless.CLI/Properties/AssemblyInfo.cs b/Steamless.CLI/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..9717d32
--- /dev/null
+++ b/Steamless.CLI/Properties/AssemblyInfo.cs
@@ -0,0 +1,40 @@
+/**
+ * Steamless - Copyright (c) 2015 - 2022 atom0s [atom0s@live.com]
+ *
+ * This work is licensed under the Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License.
+ * To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/4.0/ or send a letter to
+ * Creative Commons, PO Box 1866, Mountain View, CA 94042, USA.
+ *
+ * By using Steamless, you agree to the above license and its terms.
+ *
+ * Attribution - You must give appropriate credit, provide a link to the license and indicate if changes were
+ * made. You must do so in any reasonable manner, but not in any way that suggests the licensor
+ * endorses you or your use.
+ *
+ * Non-Commercial - You may not use the material (Steamless) for commercial purposes.
+ *
+ * No-Derivatives - If you remix, transform, or build upon the material (Steamless), you may not distribute the
+ * modified material. You are, however, allowed to submit the modified works back to the original
+ * Steamless project in attempt to have it added to the original project.
+ *
+ * You may not apply legal terms or technological measures that legally restrict others
+ * from doing anything the license permits.
+ *
+ * No warranties are given.
+ */
+
+using System.Reflection;
+using System.Runtime.InteropServices;
+
+[assembly: AssemblyTitle("Steamless.CLI")]
+[assembly: AssemblyDescription("Removes the SteamStub DRM protection from Steam applications.")]
+[assembly: AssemblyConfiguration("Release")]
+[assembly: AssemblyCompany("atom0s")]
+[assembly: AssemblyProduct("Steamless")]
+[assembly: AssemblyCopyright("Copyright © atom0s 2015 - 2022")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+[assembly: ComVisible(false)]
+[assembly: Guid("d128d7ad-2e6f-43bd-ba36-bea3b9b77437")]
+[assembly: AssemblyVersion("3.0.0.15")]
+[assembly: AssemblyFileVersion("3.0.0.15")]
\ No newline at end of file
diff --git a/Steamless.CLI/Steamless.CLI.csproj b/Steamless.CLI/Steamless.CLI.csproj
new file mode 100644
index 0000000..0bed712
--- /dev/null
+++ b/Steamless.CLI/Steamless.CLI.csproj
@@ -0,0 +1,65 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {D128D7AD-2E6F-43BD-BA36-BEA3B9B77437}
+ Exe
+ Steamless.CLI
+ Steamless.CLI
+ v4.5.2
+ 512
+ true
+ true
+
+
+ x86
+ true
+ full
+ false
+ ..\Steamless\bin\x86\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ x86
+ pdbonly
+ true
+ ..\Steamless\bin\x86\Debug\
+ TRACE
+ prompt
+ 4
+
+
+ steam.ico
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {56c95629-3b34-47fe-b988-04274409294f}
+ Steamless.API
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Steamless.CLI/steam.ico b/Steamless.CLI/steam.ico
new file mode 100644
index 0000000..13ce382
Binary files /dev/null and b/Steamless.CLI/steam.ico differ
diff --git a/Steamless.sln b/Steamless.sln
index 8baeba8..fb5b69e 100644
--- a/Steamless.sln
+++ b/Steamless.sln
@@ -23,6 +23,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Steamless.Unpacker.Variant2
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Steamless.Unpacker.Variant10.x86", "Steamless.Unpacker.Variant10.x86\Steamless.Unpacker.Variant10.x86.csproj", "{02B58AB0-9B00-4B31-8D61-9D22D13D2C4A}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Steamless.CLI", "Steamless.CLI\Steamless.CLI.csproj", "{D128D7AD-2E6F-43BD-BA36-BEA3B9B77437}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -111,6 +113,14 @@ Global
{02B58AB0-9B00-4B31-8D61-9D22D13D2C4A}.Release|Any CPU.Build.0 = Release|Any CPU
{02B58AB0-9B00-4B31-8D61-9D22D13D2C4A}.Release|x86.ActiveCfg = Release|Any CPU
{02B58AB0-9B00-4B31-8D61-9D22D13D2C4A}.Release|x86.Build.0 = Release|Any CPU
+ {D128D7AD-2E6F-43BD-BA36-BEA3B9B77437}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {D128D7AD-2E6F-43BD-BA36-BEA3B9B77437}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D128D7AD-2E6F-43BD-BA36-BEA3B9B77437}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {D128D7AD-2E6F-43BD-BA36-BEA3B9B77437}.Debug|x86.Build.0 = Debug|Any CPU
+ {D128D7AD-2E6F-43BD-BA36-BEA3B9B77437}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {D128D7AD-2E6F-43BD-BA36-BEA3B9B77437}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D128D7AD-2E6F-43BD-BA36-BEA3B9B77437}.Release|x86.ActiveCfg = Release|Any CPU
+ {D128D7AD-2E6F-43BD-BA36-BEA3B9B77437}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/Steamless/Properties/AssemblyInfo.cs b/Steamless/Properties/AssemblyInfo.cs
index 37114f7..5641ccf 100644
--- a/Steamless/Properties/AssemblyInfo.cs
+++ b/Steamless/Properties/AssemblyInfo.cs
@@ -37,5 +37,5 @@ using System.Windows;
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
[assembly: ThemeInfo(ResourceDictionaryLocation.None, ResourceDictionaryLocation.SourceAssembly)]
-[assembly: AssemblyVersion("3.0.0.14")]
-[assembly: AssemblyFileVersion("3.0.0.14")]
\ No newline at end of file
+[assembly: AssemblyVersion("3.0.0.15")]
+[assembly: AssemblyFileVersion("3.0.0.15")]
\ No newline at end of file