mirror of
https://github.com/atom0s/Steamless.git
synced 2024-12-19 23:07:41 +01:00
286 lines
No EOL
12 KiB
C#
286 lines
No EOL
12 KiB
C#
/**
|
|
* Steamless - Copyright (c) 2015 - 2023 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 Steamless.API.Services;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
|
|
internal class Program
|
|
{
|
|
/// <summary>
|
|
/// Steamless API Version
|
|
///
|
|
/// Main define for this is within DataService.cs and should match that value.
|
|
/// </summary>
|
|
private static readonly Version SteamlessApiVersion = new Version(1, 0);
|
|
|
|
/// <summary>
|
|
/// Prints the Steamless header information.
|
|
/// </summary>
|
|
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");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Prints the Steamless command line help information.
|
|
/// </summary>
|
|
static void PrintHelp()
|
|
{
|
|
Console.WriteLine("Usage:");
|
|
Console.WriteLine(" Steamless.CLI.exe [options] [file]\n\n");
|
|
Console.WriteLine("Options:");
|
|
Console.WriteLine(" --quiet - Disables output of debug log messages.");
|
|
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.");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Obtains a list of available Steamless plugins.
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
static List<SteamlessPlugin> GetSteamlessPlugins(LoggingService logService)
|
|
{
|
|
try
|
|
{
|
|
// The list of valid plugins..
|
|
var plugins = new List<SteamlessPlugin>();
|
|
|
|
// 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(logService))
|
|
continue;
|
|
|
|
plugins.Add(plugin);
|
|
}
|
|
catch
|
|
{
|
|
}
|
|
}
|
|
|
|
// Order the plugins by their name..
|
|
return plugins.OrderBy(p => p.Name).ToList();
|
|
}
|
|
catch
|
|
{
|
|
return new List<SteamlessPlugin>();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Application entry point.
|
|
/// </summary>
|
|
/// <param name="args"></param>
|
|
static int Main(string[] args)
|
|
{
|
|
// AssemblyResolve override to load modules from the Plugins folder..
|
|
AppDomain.CurrentDomain.AssemblyResolve += (sender, e) =>
|
|
{
|
|
// Obtain the name of the assembly being loaded..
|
|
var name = e.Name.Contains(",") ? e.Name.Substring(0, e.Name.IndexOf(",", StringComparison.InvariantCultureIgnoreCase)) : e.Name.Replace(".dll", "");
|
|
|
|
// Ignore resource assembly loading..
|
|
if (name.ToLower().EndsWith(".resources"))
|
|
return null;
|
|
|
|
// Build a full path to the possible embedded file..
|
|
var fullName = $"{Assembly.GetExecutingAssembly().EntryPoint.DeclaringType?.Namespace}.Embedded.{new AssemblyName(e.Name).Name}.dll";
|
|
using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(fullName))
|
|
{
|
|
// If not embedded try to load from the plugin folder..
|
|
if (stream == null)
|
|
{
|
|
var f = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Plugins", name + ".dll");
|
|
return File.Exists(f) ? Assembly.Load(File.ReadAllBytes(f)) : null;
|
|
}
|
|
|
|
// Read and load the embedded resource..
|
|
var data = new byte[stream.Length];
|
|
stream.Read(data, 0, (int)stream.Length);
|
|
return Assembly.Load(data);
|
|
}
|
|
};
|
|
|
|
return Program.Run(args);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Runs the Steamless command line operations.
|
|
/// </summary>
|
|
/// <param name="args"></param>
|
|
/// <returns></returns>
|
|
static int Run(string[] args)
|
|
{
|
|
var logService = new LoggingService();
|
|
var opts = new SteamlessOptions();
|
|
var file = string.Empty;
|
|
|
|
// Prepare the logging service..
|
|
logService.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);
|
|
};
|
|
|
|
// Print the program header..
|
|
Program.PrintHeader();
|
|
|
|
// 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;
|
|
}
|
|
|
|
// Ensure an input file was given..
|
|
if (string.IsNullOrEmpty(file))
|
|
{
|
|
Program.PrintHelp();
|
|
return 1;
|
|
}
|
|
|
|
// Ensure the input file exists..
|
|
if (!File.Exists(file))
|
|
{
|
|
logService.OnAddLogMessage(null, new LogMessageEventArgs("Invalid input file given; cannot continue.", LogMessageType.Error));
|
|
return 1;
|
|
}
|
|
|
|
// Collect the list of available plugins..
|
|
var plugins = GetSteamlessPlugins(logService);
|
|
plugins.ForEach(p => logService.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)
|
|
{
|
|
logService.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);
|
|
|
|
logService.OnAddLogMessage(null, !ret
|
|
? new LogMessageEventArgs("Failed to unpack file.", LogMessageType.Error)
|
|
: new LogMessageEventArgs("Successfully unpacked file!", LogMessageType.Success));
|
|
|
|
if (ret) return 0;
|
|
}
|
|
}
|
|
|
|
logService.OnAddLogMessage(null, new LogMessageEventArgs("All unpackers failed to unpack file.", LogMessageType.Error));
|
|
return 1;
|
|
}
|
|
}
|
|
} |