2022-04-05 06:37:35 +02:00
/ * *
2024-03-30 06:13:07 +01:00
* Steamless - Copyright ( c ) 2015 - 2024 atom0s [ atom0s @live . com ]
2022-04-05 06:37:35 +02:00
*
* 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 ;
2022-04-05 06:55:49 +02:00
using Steamless.API.Services ;
2022-04-05 06:37:35 +02:00
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:" ) ;
2022-04-05 07:03:28 +02:00
Console . WriteLine ( " Steamless.CLI.exe [options] [file]\n\n" ) ;
2022-04-05 06:37:35 +02:00
Console . WriteLine ( "Options:" ) ;
2022-04-05 07:03:28 +02:00
Console . WriteLine ( " --quiet - Disables output of debug log messages." ) ;
2022-04-05 06:37:35 +02:00
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>
2022-04-05 06:55:49 +02:00
static List < SteamlessPlugin > GetSteamlessPlugins ( LoggingService logService )
2022-04-05 06:37:35 +02:00
{
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 ) ;
2022-04-05 06:55:49 +02:00
if ( ! plugin . Initialize ( logService ) )
2022-04-05 06:37:35 +02:00
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 )
{
2022-04-05 06:55:49 +02:00
// 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" , "" ) ;
2022-04-05 06:37:35 +02:00
2022-04-05 06:55:49 +02:00
// 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 ( ) ;
2022-04-05 06:37:35 +02:00
var opts = new SteamlessOptions ( ) ;
var file = string . Empty ;
2022-04-05 06:55:49 +02:00
// 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 ( ) ;
2022-04-05 06:37:35 +02:00
// 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 ) )
{
2022-04-05 06:55:49 +02:00
Program . PrintHelp ( ) ;
2022-04-05 06:37:35 +02:00
return 1 ;
}
// Ensure the input file exists..
if ( ! File . Exists ( file ) )
{
2022-04-05 06:55:49 +02:00
logService . OnAddLogMessage ( null , new LogMessageEventArgs ( "Invalid input file given; cannot continue." , LogMessageType . Error ) ) ;
2022-04-05 06:37:35 +02:00
return 1 ;
}
// Collect the list of available plugins..
2022-04-05 06:55:49 +02:00
var plugins = GetSteamlessPlugins ( logService ) ;
plugins . ForEach ( p = > logService . OnAddLogMessage ( null , new LogMessageEventArgs ( $"Loaded plugin: {p.Name} - by {p.Author} (v.{p.Version})" , LogMessageType . Success ) ) ) ;
2022-04-05 06:37:35 +02:00
// Ensure plugins were found and loaded..
if ( plugins . Count = = 0 )
{
2022-04-05 06:55:49 +02:00
logService . OnAddLogMessage ( null , new LogMessageEventArgs ( "No plugins were loaded; be sure to fully extract Steamless before running!" , LogMessageType . Error ) ) ;
2022-04-05 06:37:35 +02:00
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 ) ;
2022-04-05 06:55:49 +02:00
logService . OnAddLogMessage ( null , ! ret
2022-04-05 06:37:35 +02:00
? new LogMessageEventArgs ( "Failed to unpack file." , LogMessageType . Error )
: new LogMessageEventArgs ( "Successfully unpacked file!" , LogMessageType . Success ) ) ;
if ( ret ) return 0 ;
}
}
2022-04-05 06:55:49 +02:00
logService . OnAddLogMessage ( null , new LogMessageEventArgs ( "All unpackers failed to unpack file." , LogMessageType . Error ) ) ;
2022-04-05 06:37:35 +02:00
return 1 ;
}
}
}