diff --git a/ExamplePlugin/ExamplePlugin.csproj b/ExamplePlugin/ExamplePlugin.csproj
new file mode 100644
index 0000000..acefbee
--- /dev/null
+++ b/ExamplePlugin/ExamplePlugin.csproj
@@ -0,0 +1,54 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {97AC964A-E56F-415C-BAEA-D503E3D4D7B8}
+ Library
+ Properties
+ ExamplePlugin
+ ExamplePlugin
+ v4.5.2
+ 512
+
+
+ x86
+ ..\Steamless\bin\x86\Debug\Plugins\
+ TRACE;DEBUG
+
+
+ x86
+ ..\Steamless\bin\x86\Release\Plugins\
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {56c95629-3b34-47fe-b988-04274409294f}
+ Steamless.API
+ False
+
+
+
+
+
\ No newline at end of file
diff --git a/ExamplePlugin/Main.cs b/ExamplePlugin/Main.cs
new file mode 100644
index 0000000..31edbad
--- /dev/null
+++ b/ExamplePlugin/Main.cs
@@ -0,0 +1,101 @@
+/**
+ * Steamless - Copyright (c) 2015 - 2017 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 ExamplePlugin
+{
+ using Steamless.API;
+ using Steamless.API.Events;
+ using Steamless.API.Model;
+ using Steamless.API.Services;
+ using System;
+
+ [SteamlessApiVersion(1, 0)]
+ public class Main : SteamlessPlugin
+ {
+ ///
+ /// Internal logging service instance.
+ ///
+ private LoggingService m_LoggingService;
+
+ ///
+ /// Gets the author of this plugin.
+ ///
+ public override string Author => "Steamless Development Team";
+
+ ///
+ /// Gets the name of this plugin.
+ ///
+ public override string Name => "Example Plugin";
+
+ ///
+ /// Gets the description of this plugin.
+ ///
+ public override string Description => "A simple plugin example.";
+
+ ///
+ /// Gets the version of this plugin.
+ ///
+ public override Version Version => new Version(1, 0, 0, 0);
+
+ ///
+ /// Initialize function called when this plugin is first loaded.
+ ///
+ ///
+ ///
+ public override bool Initialize(LoggingService logService)
+ {
+ this.m_LoggingService = logService;
+ this.m_LoggingService.OnAddLogMessage(this, new LogMessageEventArgs("ExamplePlugin was initialized!", LogMessageType.Debug));
+
+ return true;
+ }
+
+ ///
+ /// Processing function called when a file is being unpacked. Allows plugins to check the file
+ /// and see if it can handle the file for its intended purpose.
+ ///
+ ///
+ ///
+ public override bool CanProcessFile(string file)
+ {
+ this.m_LoggingService.OnAddLogMessage(this, new LogMessageEventArgs("ExamplePlugin was asked to check if it can process a file!", LogMessageType.Debug));
+
+ return false;
+ }
+
+ ///
+ /// Processing function called to allow the plugin to process the file.
+ ///
+ ///
+ ///
+ ///
+ public override bool ProcessFile(string file, SteamlessOptions options)
+ {
+ this.m_LoggingService.OnAddLogMessage(this, new LogMessageEventArgs("ExamplePlugin was asked to process a file!", LogMessageType.Debug));
+
+ return false;
+ }
+ }
+}
\ No newline at end of file
diff --git a/ExamplePlugin/Properties/AssemblyInfo.cs b/ExamplePlugin/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..1313c14
--- /dev/null
+++ b/ExamplePlugin/Properties/AssemblyInfo.cs
@@ -0,0 +1,40 @@
+/**
+ * Steamless - Copyright (c) 2015 - 2017 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("ExamplePlugin")]
+[assembly: AssemblyDescription("Example plugin used with Steamless v3.")]
+[assembly: AssemblyConfiguration("Release")]
+[assembly: AssemblyCompany("atom0s")]
+[assembly: AssemblyProduct("ExamplePlugin")]
+[assembly: AssemblyCopyright("Copyright © atom0s 2015 - 2017")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+[assembly: ComVisible(false)]
+[assembly: Guid("97ac964a-e56f-415c-baea-d503e3d4d7b8")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
\ No newline at end of file
diff --git a/Steamless.API/Crypto/AesHelper.cs b/Steamless.API/Crypto/AesHelper.cs
new file mode 100644
index 0000000..2514609
--- /dev/null
+++ b/Steamless.API/Crypto/AesHelper.cs
@@ -0,0 +1,172 @@
+/**
+ * Steamless - Copyright (c) 2015 - 2017 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.API.Crypto
+{
+ using System;
+ using System.Collections.Generic;
+ using System.IO;
+ using System.Security.Cryptography;
+
+ public class AesHelper : IDisposable
+ {
+ ///
+ /// Internal original key set by the user of this class.
+ ///
+ private readonly byte[] m_OriginalKey;
+
+ ///
+ /// Internal original iv set by the user of this class.
+ ///
+ private readonly byte[] m_OriginalIv;
+
+ ///
+ /// Internal AES crypto provider.
+ ///
+ private AesCryptoServiceProvider m_AesCryptoProvider;
+
+ ///
+ /// Default Constructor
+ ///
+ ///
+ ///
+ ///
+ ///
+ public AesHelper(byte[] key, byte[] iv, CipherMode mode = CipherMode.ECB, PaddingMode padding = PaddingMode.None)
+ {
+ // Store the original key and iv..
+ this.m_OriginalKey = key;
+ this.m_OriginalIv = iv;
+
+ // Create the AES crypto provider..
+ this.m_AesCryptoProvider = new AesCryptoServiceProvider
+ {
+ Key = key,
+ IV = iv,
+ Mode = mode,
+ Padding = padding
+ };
+ }
+
+ ///
+ /// Default Deconstructor
+ ///
+ ~AesHelper()
+ {
+ this.Dispose(false);
+ }
+
+ ///
+ /// IDispose implementation.
+ ///
+ public void Dispose()
+ {
+ this.Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ ///
+ /// IDispose implementation.
+ ///
+ ///
+ protected virtual void Dispose(bool disposing)
+ {
+ this.m_AesCryptoProvider?.Dispose();
+ this.m_AesCryptoProvider = null;
+ }
+
+ ///
+ /// Rebuilds the current iv (or the one given).
+ ///
+ ///
+ ///
+ public bool RebuildIv(byte[] iv = null)
+ {
+ // Use the current iv if none is set..
+ if (iv == null)
+ iv = this.m_OriginalIv;
+
+ try
+ {
+ using (var decryptor = this.m_AesCryptoProvider.CreateDecryptor())
+ {
+ return decryptor.TransformBlock(iv, 0, iv.Length, this.m_OriginalIv, 0) > 0;
+ }
+ }
+ catch
+ {
+ return false;
+ }
+ }
+
+ ///
+ /// Decrypts the given data using the given mode and padding.
+ ///
+ ///
+ ///
+ ///
+ ///
+ public byte[] Decrypt(byte[] data, CipherMode mode, PaddingMode padding)
+ {
+ ICryptoTransform decryptor = null;
+ MemoryStream mStream = null;
+ CryptoStream cStream = null;
+
+ try
+ {
+ // Update the mode and padding for the decryption..
+ this.m_AesCryptoProvider.Mode = mode;
+ this.m_AesCryptoProvider.Padding = padding;
+
+ // Create the decryptor..
+ decryptor = this.m_AesCryptoProvider.CreateDecryptor(this.m_OriginalKey, this.m_OriginalIv);
+
+ // Create a memory stream for our data..
+ mStream = new MemoryStream(data);
+
+ // Create the crypto stream..
+ cStream = new CryptoStream(mStream, decryptor, CryptoStreamMode.Read);
+
+ // Decrypt the data..
+ var totalBuffer = new List();
+ var buffer = new byte[2048];
+ while ((cStream.Read(buffer, 0, 2048)) > 0)
+ totalBuffer.AddRange(buffer);
+
+ return totalBuffer.ToArray();
+ }
+ catch
+ {
+ return null;
+ }
+ finally
+ {
+ cStream?.Dispose();
+ mStream?.Dispose();
+ decryptor?.Dispose();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Steamless.API/Events/LogMessageEventArgs.cs b/Steamless.API/Events/LogMessageEventArgs.cs
new file mode 100644
index 0000000..3c9b4e6
--- /dev/null
+++ b/Steamless.API/Events/LogMessageEventArgs.cs
@@ -0,0 +1,62 @@
+/**
+ * Steamless - Copyright (c) 2015 - 2017 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.API.Events
+{
+ using System;
+
+ public class LogMessageEventArgs : EventArgs
+ {
+ ///
+ /// Default Constructor
+ ///
+ public LogMessageEventArgs()
+ {
+ this.Message = string.Empty;
+ this.MessageType = LogMessageType.Debug;
+ }
+
+ ///
+ /// Overloaded Constructor
+ ///
+ ///
+ ///
+ public LogMessageEventArgs(string msg, LogMessageType type)
+ {
+ this.Message = msg;
+ this.MessageType = type;
+ }
+
+ ///
+ /// Gets or sets the message text.
+ ///
+ public string Message { get; set; }
+
+ ///
+ /// Gets or sets the type of message.
+ ///
+ public LogMessageType MessageType { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/Steamless.API/Events/LogMessageType.cs b/Steamless.API/Events/LogMessageType.cs
new file mode 100644
index 0000000..46b06be
--- /dev/null
+++ b/Steamless.API/Events/LogMessageType.cs
@@ -0,0 +1,58 @@
+/**
+ * Steamless - Copyright (c) 2015 - 2017 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.API.Events
+{
+ ///
+ /// Log Message Type Enumeration
+ ///
+ public enum LogMessageType
+ {
+ ///
+ /// Used for general purpose messages.
+ ///
+ Information = 0,
+
+ ///
+ /// Used for successful messages.
+ ///
+ Success = 1,
+
+ ///
+ /// Used for warnings.
+ ///
+ Warning = 2,
+
+ ///
+ /// Used for errors.
+ ///
+ Error = 3,
+
+ ///
+ /// Used for debug messages.
+ ///
+ Debug = 4
+ }
+}
\ No newline at end of file
diff --git a/Steamless.API/Extensions/FileStreamExtensions.cs b/Steamless.API/Extensions/FileStreamExtensions.cs
new file mode 100644
index 0000000..fa47ab5
--- /dev/null
+++ b/Steamless.API/Extensions/FileStreamExtensions.cs
@@ -0,0 +1,42 @@
+/**
+ * Steamless - Copyright (c) 2015 - 2017 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.API.Extensions
+{
+ using System.IO;
+
+ public static class FileStreamExtensions
+ {
+ ///
+ /// Writes a byte array to the file stream.
+ ///
+ ///
+ ///
+ public static void WriteBytes(this FileStream fStream, byte[] data)
+ {
+ fStream.Write(data, 0, data.Length);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Steamless.API/Model/NavigatedEventArgs.cs b/Steamless.API/Model/NavigatedEventArgs.cs
new file mode 100644
index 0000000..5a4e782
--- /dev/null
+++ b/Steamless.API/Model/NavigatedEventArgs.cs
@@ -0,0 +1,42 @@
+/**
+ * Steamless - Copyright (c) 2015 - 2017 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.API.Model
+{
+ using System;
+
+ public class NavigatedEventArgs : EventArgs
+ {
+ ///
+ /// Gets or sets the previous view being navigated from.
+ ///
+ public ViewModelBase PreviousView { get; internal set; }
+
+ ///
+ /// Gets or sets the current view being navigated to.
+ ///
+ public ViewModelBase CurrentView { get; internal set; }
+ }
+}
\ No newline at end of file
diff --git a/Steamless.API/Model/NotifiableModel.cs b/Steamless.API/Model/NotifiableModel.cs
new file mode 100644
index 0000000..2c2e15b
--- /dev/null
+++ b/Steamless.API/Model/NotifiableModel.cs
@@ -0,0 +1,104 @@
+/**
+ * Steamless - Copyright (c) 2015 - 2017 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.API.Model
+{
+ using System;
+ using System.Collections.Generic;
+ using System.ComponentModel;
+
+ [Serializable]
+ public class NotifiableModel : INotifyPropertyChanged
+ {
+ ///
+ /// Internal properties container.
+ ///
+ private readonly Dictionary m_Properties;
+
+ ///
+ /// Default Constructor
+ ///
+ public NotifiableModel()
+ {
+ this.m_Properties = new Dictionary();
+ }
+
+ ///
+ /// Event triggered when a property is changed.
+ ///
+ public event PropertyChangedEventHandler PropertyChanged;
+
+ ///
+ /// Method used to raise the PropertyChanged event.
+ ///
+ ///
+ public void OnPropertyChanged(string prop)
+ {
+ this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(prop));
+ }
+
+ ///
+ /// Method to raise the PropertyChanged event.
+ ///
+ ///
+ protected void RaisePropertyChanged(string property)
+ {
+ if (string.IsNullOrEmpty(property))
+ throw new ArgumentNullException(property);
+ this.OnPropertyChanged(property);
+ }
+
+ ///
+ /// Gets a property from the internal container.
+ ///
+ ///
+ ///
+ ///
+ protected T Get(string prop)
+ {
+ if (this.m_Properties.ContainsKey(prop))
+ {
+ return (T)this.m_Properties[prop];
+ }
+ return default(T);
+ }
+
+ ///
+ /// Sets a property in the internal container.
+ ///
+ ///
+ ///
+ ///
+ protected void Set(string prop, T val)
+ {
+ var curr = this.Get(prop);
+ if (Equals(curr, val))
+ return;
+
+ this.m_Properties[prop] = val;
+ this.OnPropertyChanged(prop);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Steamless.API/Model/SteamlessOptions.cs b/Steamless.API/Model/SteamlessOptions.cs
new file mode 100644
index 0000000..68eb675
--- /dev/null
+++ b/Steamless.API/Model/SteamlessOptions.cs
@@ -0,0 +1,77 @@
+/**
+ * Steamless - Copyright (c) 2015 - 2017 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.API.Model
+{
+ public class SteamlessOptions : NotifiableModel
+ {
+ ///
+ /// Default Constructor
+ ///
+ public SteamlessOptions()
+ {
+ this.VerboseOutput = true;
+ this.KeepBindSection = false;
+ this.DumpPayloadToDisk = false;
+ this.DumpSteamDrmpToDisk = false;
+ }
+
+ ///
+ /// Gets or sets the verbose output option value.
+ ///
+ public bool VerboseOutput
+ {
+ get { return this.Get("VerboseOutput"); }
+ set { this.Set("VerboseOutput", value); }
+ }
+
+ ///
+ /// Gets or sets the keep bind section option value.
+ ///
+ public bool KeepBindSection
+ {
+ get { return this.Get("KeepBindSection"); }
+ set { this.Set("KeepBindSection", value); }
+ }
+
+ ///
+ /// Gets or sets the dump payload to disk option value.
+ ///
+ public bool DumpPayloadToDisk
+ {
+ get { return this.Get("DumpPayloadToDisk"); }
+ set { this.Set("DumpPayloadToDisk", value); }
+ }
+
+ ///
+ /// Gets or sets the dump SteamDRMP.dll to disk option value.
+ ///
+ public bool DumpSteamDrmpToDisk
+ {
+ get { return this.Get("DumpSteamDrmpToDisk"); }
+ set { this.Set("DumpSteamDrmpToDisk", value); }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Steamless.API/Model/SteamlessPlugin.cs b/Steamless.API/Model/SteamlessPlugin.cs
new file mode 100644
index 0000000..89cd29c
--- /dev/null
+++ b/Steamless.API/Model/SteamlessPlugin.cs
@@ -0,0 +1,118 @@
+/**
+ * Steamless - Copyright (c) 2015 - 2017 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.API.Model
+{
+ using Services;
+ using System;
+
+ public abstract class SteamlessPlugin : IDisposable
+ {
+ ///
+ /// Gets the author of this plugin.
+ ///
+ public virtual string Author => "Steamless Development Team";
+
+ ///
+ /// Gets the name of this plugin.
+ ///
+ public virtual string Name => "Steamless Plugin";
+
+ ///
+ /// Gets the description of this plugin.
+ ///
+ public virtual string Description => "The Steamless base plugin class.";
+
+ ///
+ /// Gets the version of this plugin.
+ ///
+ public virtual Version Version => new Version(1, 0, 0, 0);
+
+ ///
+ /// Deconstructor
+ ///
+ ~SteamlessPlugin()
+ {
+ this.Dispose(false);
+ }
+
+ ///
+ /// IDisposable implementation.
+ ///
+ public void Dispose()
+ {
+ this.Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ ///
+ /// IDisposable implementation.
+ ///
+ ///
+ protected virtual void Dispose(bool disposing)
+ {
+ }
+
+ ///
+ /// Initialize function called when this plugin is first loaded.
+ ///
+ ///
+ ///
+ public virtual bool Initialize(LoggingService logService)
+ {
+ return false;
+ }
+
+ ///
+ /// Processing function called when a file is being unpacked. Allows plugins to check the file
+ /// and see if it can handle the file for its intended purpose.
+ ///
+ ///
+ ///
+ public virtual bool CanProcessFile(string file)
+ {
+ return false;
+ }
+
+ ///
+ /// Processing function called to allow the plugin to process the file.
+ ///
+ ///
+ ///
+ ///
+ public virtual bool ProcessFile(string file, SteamlessOptions options)
+ {
+ return false;
+ }
+
+ ///
+ /// Returns a string that represents the current object.
+ ///
+ ///
+ /// A string that represents the current object.
+ ///
+ public string DisplayName => this.Name + " - " + this.Description;
+ }
+}
\ No newline at end of file
diff --git a/Steamless.API/Model/ViewModelBase.cs b/Steamless.API/Model/ViewModelBase.cs
new file mode 100644
index 0000000..a8cbdb6
--- /dev/null
+++ b/Steamless.API/Model/ViewModelBase.cs
@@ -0,0 +1,115 @@
+/**
+ * Steamless - Copyright (c) 2015 - 2017 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.API.Model
+{
+ using System;
+ using System.ComponentModel;
+ using System.Windows;
+
+ public abstract class ViewModelBase : NotifiableModel
+ {
+ ///
+ /// Default Constructor
+ ///
+ protected ViewModelBase()
+ {
+ this.Events = new EventHandlerList();
+ }
+
+ ///
+ /// Internal static design mode flag.
+ ///
+ private static bool? m_IsInDesignMode;
+
+ ///
+ /// Gets if this ViewModelBase is in design mode.
+ ///
+ public bool IsInDesignMode => IsInDesignModeStatic;
+
+ ///
+ /// Gets the static ViewModelBase design mode flag.
+ ///
+ public static bool IsInDesignModeStatic
+ {
+ get
+ {
+ if (m_IsInDesignMode.HasValue)
+ return m_IsInDesignMode.Value;
+
+ var isInDesignModeProperty = DesignerProperties.IsInDesignModeProperty;
+ m_IsInDesignMode = (bool)DependencyPropertyDescriptor.FromProperty(isInDesignModeProperty, typeof(FrameworkElement)).Metadata.DefaultValue;
+ return m_IsInDesignMode.Value;
+ }
+ }
+
+ ///
+ /// Gets or sets the internal event handler list.
+ ///
+ private EventHandlerList Events
+ {
+ get { return this.Get("Events"); }
+ set { this.Set("Events", value); }
+ }
+
+ ///
+ /// Event to subscribe to to be notified when a view is navigated from.
+ ///
+ public event EventHandler NavigatedFrom
+ {
+ add { this.Events.AddHandler("NavigatedFromEvent", value); }
+ remove { this.Events.RemoveHandler("NavigatedFromEvent", value); }
+ }
+
+ ///
+ /// Event to subscribe to to be notified when a view is navigated to.
+ ///
+ public event EventHandler NavigatedTo
+ {
+ add { this.Events.AddHandler("NavigatedToEvent", value); }
+ remove { this.Events.RemoveHandler("NavigatedToEvent", value); }
+ }
+
+ ///
+ /// Internal navigated from event invoker.
+ ///
+ ///
+ public void OnNavigatedFrom(NavigatedEventArgs e)
+ {
+ var eventHandler = (EventHandler)this.Events["NavigatedFromEvent"];
+ eventHandler?.Invoke(this, e);
+ }
+
+ ///
+ /// Internal navigated to event invoker.
+ ///
+ ///
+ public void OnNavigatedTo(NavigatedEventArgs e)
+ {
+ var eventHandler = (EventHandler)this.Events["NavigatedToEvent"];
+ eventHandler?.Invoke(this, e);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Steamless.API/PE32/NativeApi32.cs b/Steamless.API/PE32/NativeApi32.cs
new file mode 100644
index 0000000..46f2a41
--- /dev/null
+++ b/Steamless.API/PE32/NativeApi32.cs
@@ -0,0 +1,603 @@
+/**
+ * Steamless - Copyright (c) 2015 - 2017 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.API.PE32
+{
+ using System;
+ using System.Runtime.InteropServices;
+
+ public class NativeApi32
+ {
+ ///
+ /// IMAGE_DOS_HEADER Structure
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ public struct ImageDosHeader32
+ {
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
+ public char[] e_magic;
+
+ public ushort e_cblp;
+ public ushort e_cp;
+ public ushort e_crlc;
+ public ushort e_cparhdr;
+ public ushort e_minalloc;
+ public ushort e_maxalloc;
+ public ushort e_ss;
+ public ushort e_sp;
+ public ushort e_csum;
+ public ushort e_ip;
+ public ushort e_cs;
+ public ushort e_lfarlc;
+ public ushort e_ovno;
+
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
+ public ushort[] e_res1;
+
+ public ushort e_oemid;
+ public ushort e_oeminfo;
+
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
+ public ushort[] e_res2;
+
+ public int e_lfanew;
+
+ ///
+ /// Gets if this structure is valid for a PE file.
+ ///
+ public bool IsValid => new string(this.e_magic) == "MZ";
+ }
+
+ ///
+ /// IMAGE_NT_HEADERS Structure
+ ///
+ [StructLayout(LayoutKind.Explicit)]
+ public struct ImageNtHeaders32
+ {
+ [FieldOffset(0)]
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
+ public char[] Signature;
+
+ [FieldOffset(4)]
+ public ImageFileHeader32 FileHeader;
+
+ [FieldOffset(24)]
+ public ImageOptionalHeader32 OptionalHeader;
+
+ ///
+ /// Gets if this structure is valid for a PE file.
+ ///
+ public bool IsValid => new string(this.Signature).Trim('\0') == "PE";
+ }
+
+ ///
+ /// IMAGE_FILE_HEADER Structure
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ public struct ImageFileHeader32
+ {
+ public ushort Machine;
+ public ushort NumberOfSections;
+ public uint TimeDateStamp;
+ public uint PointerToSymbolTable;
+ public uint NumberOfSymbols;
+ public ushort SizeOfOptionalHeader;
+ public ushort Characteristics;
+ }
+
+ ///
+ /// Machine Type Enumeration
+ ///
+ public enum MachineType : ushort
+ {
+ Native = 0,
+ I386 = 0x014C,
+ Itanium = 0x0200,
+ X64 = 0x8664
+ }
+
+ ///
+ /// Magic Type Enumeration
+ ///
+ public enum MagicType : ushort
+ {
+ ImageNtOptionalHdr32Magic = 0x10B,
+ ImageNtOptionalHdr64Magic = 0x20B
+ }
+
+ ///
+ /// Sub System Type Enumeration
+ ///
+ public enum SubSystemType : ushort
+ {
+ ImageSubsystemUnknown = 0,
+ ImageSubsystemNative = 1,
+ ImageSubsystemWindowsGui = 2,
+ ImageSubsystemWindowsCui = 3,
+ ImageSubsystemPosixCui = 7,
+ ImageSubsystemWindowsCeGui = 9,
+ ImageSubsystemEfiApplication = 10,
+ ImageSubsystemEfiBootServiceDriver = 11,
+ ImageSubsystemEfiRuntimeDriver = 12,
+ ImageSubsystemEfiRom = 13,
+ ImageSubsystemXbox = 14
+ }
+
+ ///
+ /// Dll Characteristics Type Enumeration
+ ///
+ public enum DllCharacteristicsType : ushort
+ {
+ Reserved0 = 0x0001,
+ Reserved1 = 0x0002,
+ Reserved2 = 0x0004,
+ Reserved3 = 0x0008,
+ ImageDllCharacteristicsDynamicBase = 0x0040,
+ ImageDllCharacteristicsForceIntegrity = 0x0080,
+ ImageDllCharacteristicsNxCompat = 0x0100,
+ ImageDllcharacteristicsNoIsolation = 0x0200,
+ ImageDllcharacteristicsNoSeh = 0x0400,
+ ImageDllcharacteristicsNoBind = 0x0800,
+ Reserved4 = 0x1000,
+ ImageDllcharacteristicsWdmDriver = 0x2000,
+ ImageDllcharacteristicsTerminalServerAware = 0x8000
+ }
+
+ ///
+ /// IMAGE_OPTIONAL_HEADER Structure
+ ///
+ [StructLayout(LayoutKind.Explicit)]
+ public struct ImageOptionalHeader32
+ {
+ [FieldOffset(0)]
+ public MagicType Magic;
+
+ [FieldOffset(2)]
+ public byte MajorLinkerVersion;
+
+ [FieldOffset(3)]
+ public byte MinorLinkerVersion;
+
+ [FieldOffset(4)]
+ public uint SizeOfCode;
+
+ [FieldOffset(8)]
+ public uint SizeOfInitializedData;
+
+ [FieldOffset(12)]
+ public uint SizeOfUninitializedData;
+
+ [FieldOffset(16)]
+ public uint AddressOfEntryPoint;
+
+ [FieldOffset(20)]
+ public uint BaseOfCode;
+
+ // PE32 contains this additional field
+ [FieldOffset(24)]
+ public uint BaseOfData;
+
+ [FieldOffset(28)]
+ public uint ImageBase;
+
+ [FieldOffset(32)]
+ public uint SectionAlignment;
+
+ [FieldOffset(36)]
+ public uint FileAlignment;
+
+ [FieldOffset(40)]
+ public ushort MajorOperatingSystemVersion;
+
+ [FieldOffset(42)]
+ public ushort MinorOperatingSystemVersion;
+
+ [FieldOffset(44)]
+ public ushort MajorImageVersion;
+
+ [FieldOffset(46)]
+ public ushort MinorImageVersion;
+
+ [FieldOffset(48)]
+ public ushort MajorSubsystemVersion;
+
+ [FieldOffset(50)]
+ public ushort MinorSubsystemVersion;
+
+ [FieldOffset(52)]
+ public uint Win32VersionValue;
+
+ [FieldOffset(56)]
+ public uint SizeOfImage;
+
+ [FieldOffset(60)]
+ public uint SizeOfHeaders;
+
+ [FieldOffset(64)]
+ public uint CheckSum;
+
+ [FieldOffset(68)]
+ public SubSystemType Subsystem;
+
+ [FieldOffset(70)]
+ public DllCharacteristicsType DllCharacteristics;
+
+ [FieldOffset(72)]
+ public uint SizeOfStackReserve;
+
+ [FieldOffset(76)]
+ public uint SizeOfStackCommit;
+
+ [FieldOffset(80)]
+ public uint SizeOfHeapReserve;
+
+ [FieldOffset(84)]
+ public uint SizeOfHeapCommit;
+
+ [FieldOffset(88)]
+ public uint LoaderFlags;
+
+ [FieldOffset(92)]
+ public uint NumberOfRvaAndSizes;
+
+ [FieldOffset(96)]
+ public ImageDataDirectory32 ExportTable;
+
+ [FieldOffset(104)]
+ public ImageDataDirectory32 ImportTable;
+
+ [FieldOffset(112)]
+ public ImageDataDirectory32 ResourceTable;
+
+ [FieldOffset(120)]
+ public ImageDataDirectory32 ExceptionTable;
+
+ [FieldOffset(128)]
+ public ImageDataDirectory32 CertificateTable;
+
+ [FieldOffset(136)]
+ public ImageDataDirectory32 BaseRelocationTable;
+
+ [FieldOffset(144)]
+ public ImageDataDirectory32 Debug;
+
+ [FieldOffset(152)]
+ public ImageDataDirectory32 Architecture;
+
+ [FieldOffset(160)]
+ public ImageDataDirectory32 GlobalPtr;
+
+ [FieldOffset(168)]
+ public ImageDataDirectory32 TLSTable;
+
+ [FieldOffset(176)]
+ public ImageDataDirectory32 LoadConfigTable;
+
+ [FieldOffset(184)]
+ public ImageDataDirectory32 BoundImport;
+
+ [FieldOffset(192)]
+ public ImageDataDirectory32 IAT;
+
+ [FieldOffset(200)]
+ public ImageDataDirectory32 DelayImportDescriptor;
+
+ [FieldOffset(208)]
+ public ImageDataDirectory32 CLRRuntimeHeader;
+
+ [FieldOffset(216)]
+ public ImageDataDirectory32 Reserved;
+ }
+
+ ///
+ /// IMAGE_DATA_DIRECTORY Structure
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ public struct ImageDataDirectory32
+ {
+ public uint VirtualAddress;
+ public uint Size;
+ }
+
+ ///
+ /// IMAGE_SECTION_HEADER Structure
+ ///
+ [StructLayout(LayoutKind.Explicit)]
+ public struct ImageSectionHeader32
+ {
+ [FieldOffset(0)]
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
+ public char[] Name;
+
+ [FieldOffset(8)]
+ public uint VirtualSize;
+
+ [FieldOffset(12)]
+ public uint VirtualAddress;
+
+ [FieldOffset(16)]
+ public uint SizeOfRawData;
+
+ [FieldOffset(20)]
+ public uint PointerToRawData;
+
+ [FieldOffset(24)]
+ public uint PointerToRelocations;
+
+ [FieldOffset(28)]
+ public uint PointerToLinenumbers;
+
+ [FieldOffset(32)]
+ public ushort NumberOfRelocations;
+
+ [FieldOffset(34)]
+ public ushort NumberOfLinenumbers;
+
+ [FieldOffset(36)]
+ public DataSectionFlags Characteristics;
+
+ ///
+ /// Gets the section name of this current section object.
+ ///
+ public string SectionName => new string(this.Name).Trim('\0');
+
+ ///
+ /// Gets if this structure is valid for a PE file.
+ ///
+ public bool IsValid => this.SizeOfRawData != 0 && this.PointerToRawData != 0;
+ }
+
+ ///
+ /// Data Section Flags Enumeration
+ ///
+ [Flags]
+ public enum DataSectionFlags : uint
+ {
+ ///
+ /// Reserved for future use.
+ ///
+ TypeReg = 0x00000000,
+
+ ///
+ /// Reserved for future use.
+ ///
+ TypeDsect = 0x00000001,
+
+ ///
+ /// Reserved for future use.
+ ///
+ TypeNoLoad = 0x00000002,
+
+ ///
+ /// Reserved for future use.
+ ///
+ TypeGroup = 0x00000004,
+
+ ///
+ /// The section should not be padded to the next boundary. This flag is obsolete and is replaced by IMAGE_SCN_ALIGN_1BYTES. This is valid only for object files.
+ ///
+ TypeNoPadded = 0x00000008,
+
+ ///
+ /// Reserved for future use.
+ ///
+ TypeCopy = 0x00000010,
+
+ ///
+ /// The section contains executable code.
+ ///
+ ContentCode = 0x00000020,
+
+ ///
+ /// The section contains initialized data.
+ ///
+ ContentInitializedData = 0x00000040,
+
+ ///
+ /// The section contains uninitialized data.
+ ///
+ ContentUninitializedData = 0x00000080,
+
+ ///
+ /// Reserved for future use.
+ ///
+ LinkOther = 0x00000100,
+
+ ///
+ /// The section contains comments or other information. The .drectve section has this type. This is valid for object files only.
+ ///
+ LinkInfo = 0x00000200,
+
+ ///
+ /// Reserved for future use.
+ ///
+ TypeOver = 0x00000400,
+
+ ///
+ /// The section will not become part of the image. This is valid only for object files.
+ ///
+ LinkRemove = 0x00000800,
+
+ ///
+ /// The section contains COMDAT data. For more information, see section 5.5.6, COMDAT Sections (Object Only). This is valid only for object files.
+ ///
+ LinkComDat = 0x00001000,
+
+ ///
+ /// Reset speculative exceptions handling bits in the TLB entries for this section.
+ ///
+ NoDeferSpecExceptions = 0x00004000,
+
+ ///
+ /// The section contains data referenced through the global pointer (GP).
+ ///
+ RelativeGp = 0x00008000,
+
+ ///
+ /// Reserved for future use.
+ ///
+ MemPurgeable = 0x00020000,
+
+ ///
+ /// Reserved for future use.
+ ///
+ Memory16Bit = 0x00020000,
+
+ ///
+ /// Reserved for future use.
+ ///
+ MemoryLocked = 0x00040000,
+
+ ///
+ /// Reserved for future use.
+ ///
+ MemoryPreload = 0x00080000,
+
+ ///
+ /// Align data on a 1-byte boundary. Valid only for object files.
+ ///
+ Align1Bytes = 0x00100000,
+
+ ///
+ /// Align data on a 2-byte boundary. Valid only for object files.
+ ///
+ Align2Bytes = 0x00200000,
+
+ ///
+ /// Align data on a 4-byte boundary. Valid only for object files.
+ ///
+ Align4Bytes = 0x00300000,
+
+ ///
+ /// Align data on an 8-byte boundary. Valid only for object files.
+ ///
+ Align8Bytes = 0x00400000,
+
+ ///
+ /// Align data on a 16-byte boundary. Valid only for object files.
+ ///
+ Align16Bytes = 0x00500000,
+
+ ///
+ /// Align data on a 32-byte boundary. Valid only for object files.
+ ///
+ Align32Bytes = 0x00600000,
+
+ ///
+ /// Align data on a 64-byte boundary. Valid only for object files.
+ ///
+ Align64Bytes = 0x00700000,
+
+ ///
+ /// Align data on a 128-byte boundary. Valid only for object files.
+ ///
+ Align128Bytes = 0x00800000,
+
+ ///
+ /// Align data on a 256-byte boundary. Valid only for object files.
+ ///
+ Align256Bytes = 0x00900000,
+
+ ///
+ /// Align data on a 512-byte boundary. Valid only for object files.
+ ///
+ Align512Bytes = 0x00A00000,
+
+ ///
+ /// Align data on a 1024-byte boundary. Valid only for object files.
+ ///
+ Align1024Bytes = 0x00B00000,
+
+ ///
+ /// Align data on a 2048-byte boundary. Valid only for object files.
+ ///
+ Align2048Bytes = 0x00C00000,
+
+ ///
+ /// Align data on a 4096-byte boundary. Valid only for object files.
+ ///
+ Align4096Bytes = 0x00D00000,
+
+ ///
+ /// Align data on an 8192-byte boundary. Valid only for object files.
+ ///
+ Align8192Bytes = 0x00E00000,
+
+ ///
+ /// The section contains extended relocations.
+ ///
+ LinkExtendedRelocationOverflow = 0x01000000,
+
+ ///
+ /// The section can be discarded as needed.
+ ///
+ MemoryDiscardable = 0x02000000,
+
+ ///
+ /// The section cannot be cached.
+ ///
+ MemoryNotCached = 0x04000000,
+
+ ///
+ /// The section is not pageable.
+ ///
+ MemoryNotPaged = 0x08000000,
+
+ ///
+ /// The section can be shared in memory.
+ ///
+ MemoryShared = 0x10000000,
+
+ ///
+ /// The section can be executed as code.
+ ///
+ MemoryExecute = 0x20000000,
+
+ ///
+ /// The section can be read.
+ ///
+ MemoryRead = 0x40000000,
+
+ ///
+ /// The section can be written to.
+ ///
+ MemoryWrite = 0x80000000
+ }
+
+ ///
+ /// IMAGE_TLS_DIRECTORY Structure
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ public struct ImageTlsDirectory32
+ {
+ public uint StartAddressOfRawData;
+ public uint EndAddressOfRawData;
+ public uint AddressOfIndex;
+ public uint AddressOfCallBacks;
+ public uint SizeOfZeroFill;
+ public uint Characteristics;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Steamless.API/PE32/Pe32File.cs b/Steamless.API/PE32/Pe32File.cs
new file mode 100644
index 0000000..97e9209
--- /dev/null
+++ b/Steamless.API/PE32/Pe32File.cs
@@ -0,0 +1,421 @@
+/**
+ * Steamless - Copyright (c) 2015 - 2017 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.API.PE32
+{
+ using System;
+ using System.Collections.Generic;
+ using System.IO;
+ using System.Linq;
+ using System.Runtime.InteropServices;
+
+ ///
+ /// Portable Executable (32bit) Class
+ ///
+ public class Pe32File
+ {
+ ///
+ /// Default Constructor
+ ///
+ public Pe32File()
+ {
+ }
+
+ ///
+ /// Overloaded Constructor
+ ///
+ ///
+ public Pe32File(string file)
+ {
+ this.FilePath = file;
+ }
+
+ ///
+ /// Parses a Win32 PE file.
+ ///
+ ///
+ ///
+ public bool Parse(string file = null)
+ {
+ // Prepare the class variables..
+ if (file != null)
+ this.FilePath = file;
+
+ this.FileData = null;
+ this.DosHeader = new NativeApi32.ImageDosHeader32();
+ this.NtHeaders = new NativeApi32.ImageNtHeaders32();
+ this.DosStubSize = 0;
+ this.DosStubOffset = 0;
+ this.DosStubData = null;
+ this.Sections = new List();
+ this.SectionData = new List();
+ this.TlsDirectory = new NativeApi32.ImageTlsDirectory32();
+ this.TlsCallbacks = new List();
+
+ // Ensure a file path has been set..
+ if (string.IsNullOrEmpty(this.FilePath) || !File.Exists(this.FilePath))
+ return false;
+
+ // Read the file data..
+ this.FileData = File.ReadAllBytes(this.FilePath);
+
+ // Ensure we have valid data by the overall length..
+ if (this.FileData.Length < (Marshal.SizeOf(typeof(NativeApi32.ImageDosHeader32)) + Marshal.SizeOf(typeof(NativeApi32.ImageNtHeaders32))))
+ return false;
+
+ // Read the file headers..
+ this.DosHeader = Pe32Helpers.GetStructure(this.FileData);
+ this.NtHeaders = Pe32Helpers.GetStructure(this.FileData, this.DosHeader.e_lfanew);
+
+ // Validate the headers..
+ if (!this.DosHeader.IsValid || !this.NtHeaders.IsValid)
+ return false;
+
+ // Read and store the dos header if it exists..
+ this.DosStubSize = (uint)(this.DosHeader.e_lfanew - Marshal.SizeOf(typeof(NativeApi32.ImageDosHeader32)));
+ if (this.DosStubSize > 0)
+ {
+ this.DosStubOffset = (uint)Marshal.SizeOf(typeof(NativeApi32.ImageDosHeader32));
+ this.DosStubData = new byte[this.DosStubSize];
+ Array.Copy(this.FileData, this.DosStubOffset, this.DosStubData, 0, this.DosStubSize);
+ }
+
+ // Read the file sections..
+ for (var x = 0; x < this.NtHeaders.FileHeader.NumberOfSections; x++)
+ {
+ var section = Pe32Helpers.GetSection(this.FileData, x, this.DosHeader, this.NtHeaders);
+ this.Sections.Add(section);
+
+ // Get the sections data..
+ var sectionData = new byte[this.GetAlignment(section.SizeOfRawData, this.NtHeaders.OptionalHeader.FileAlignment)];
+ Array.Copy(this.FileData, section.PointerToRawData, sectionData, 0, section.SizeOfRawData);
+ this.SectionData.Add(sectionData);
+ }
+
+ try
+ {
+ // Obtain the file overlay if one exists..
+ var lastSection = this.Sections.Last();
+ var fileSize = lastSection.SizeOfRawData + lastSection.PointerToRawData;
+ if (fileSize < this.FileData.Length)
+ {
+ this.OverlayData = new byte[this.FileData.Length - fileSize];
+ Array.Copy(this.FileData, fileSize, this.OverlayData, 0, this.FileData.Length - fileSize);
+ }
+ }
+ catch
+ {
+ return false;
+ }
+
+ // Read the files Tls information if available..
+ if (this.NtHeaders.OptionalHeader.TLSTable.VirtualAddress != 0)
+ {
+ // Get the file offset to the Tls data..
+ var tls = this.NtHeaders.OptionalHeader.TLSTable;
+ var addr = this.GetFileOffsetFromRva(tls.VirtualAddress);
+
+ // Read the Tls directory..
+ this.TlsDirectory = Pe32Helpers.GetStructure(this.FileData, (int)addr);
+
+ // Read the Tls callbacks..
+ addr = this.GetRvaFromVa(this.TlsDirectory.AddressOfCallBacks);
+ addr = this.GetFileOffsetFromRva(addr);
+
+ // Loop until we hit a null pointer..
+ var count = 0;
+ while (true)
+ {
+ var callback = BitConverter.ToUInt32(this.FileData, (int)addr + (count * 4));
+ if (callback == 0)
+ break;
+
+ this.TlsCallbacks.Add(callback);
+ count++;
+ }
+ }
+
+ return true;
+ }
+
+ ///
+ /// Determines if the current file is 64bit.
+ ///
+ ///
+ public bool IsFile64Bit()
+ {
+ return (this.NtHeaders.FileHeader.Machine & (uint)NativeApi32.MachineType.X64) == (uint)NativeApi32.MachineType.X64;
+ }
+
+ ///
+ /// Determines if the file has a section containing the given name.
+ ///
+ ///
+ ///
+ public bool HasSection(string name)
+ {
+ return this.Sections.Any(s => string.Compare(s.SectionName, name, StringComparison.InvariantCultureIgnoreCase) == 0);
+ }
+
+ ///
+ /// Obtains a section by its name.
+ ///
+ ///
+ ///
+ public NativeApi32.ImageSectionHeader32 GetSection(string name)
+ {
+ return this.Sections.FirstOrDefault(s => string.Compare(s.SectionName, name, StringComparison.InvariantCultureIgnoreCase) == 0);
+ }
+
+ ///
+ /// Obtains the owner section of the given rva.
+ ///
+ ///
+ ///
+ public NativeApi32.ImageSectionHeader32 GetOwnerSection(uint rva)
+ {
+ foreach (var s in this.Sections)
+ {
+ var size = s.VirtualSize;
+ if (size == 0)
+ size = s.SizeOfRawData;
+
+ if ((rva >= s.VirtualAddress) && (rva < s.VirtualAddress + size))
+ return s;
+ }
+
+ return default(NativeApi32.ImageSectionHeader32);
+ }
+
+ ///
+ /// Obtains the owner section of the given rva.
+ ///
+ ///
+ ///
+ public NativeApi32.ImageSectionHeader32 GetOwnerSection(ulong rva)
+ {
+ foreach (var s in this.Sections)
+ {
+ var size = s.VirtualSize;
+ if (size == 0)
+ size = s.SizeOfRawData;
+
+ if ((rva >= s.VirtualAddress) && (rva < s.VirtualAddress + size))
+ return s;
+ }
+
+ return default(NativeApi32.ImageSectionHeader32);
+ }
+
+ ///
+ /// Obtains a sections data by its index.
+ ///
+ ///
+ ///
+ public byte[] GetSectionData(int index)
+ {
+ if (index < 0 || index > this.Sections.Count)
+ return null;
+
+ return this.SectionData[index];
+ }
+
+ ///
+ /// Obtains a sections data by its name.
+ ///
+ ///
+ ///
+ public byte[] GetSectionData(string name)
+ {
+ for (var x = 0; x < this.Sections.Count; x++)
+ {
+ if (string.Compare(this.Sections[x].SectionName, name, StringComparison.InvariantCultureIgnoreCase) == 0)
+ return this.SectionData[x];
+ }
+
+ return null;
+ }
+
+ ///
+ /// Gets a sections index by its name.
+ ///
+ ///
+ ///
+ public int GetSectionIndex(string name)
+ {
+ for (var x = 0; x < this.Sections.Count; x++)
+ {
+ if (string.Compare(this.Sections[x].SectionName, name, StringComparison.InvariantCultureIgnoreCase) == 0)
+ return x;
+ }
+
+ return -1;
+ }
+
+ ///
+ /// Gets a sections index by its name.
+ ///
+ ///
+ ///
+ public int GetSectionIndex(NativeApi32.ImageSectionHeader32 section)
+ {
+ return this.Sections.IndexOf(section);
+ }
+
+ ///
+ /// Removes a section from the files section list.
+ ///
+ ///
+ ///
+ public bool RemoveSection(NativeApi32.ImageSectionHeader32 section)
+ {
+ var index = this.Sections.IndexOf(section);
+ if (index == -1)
+ return false;
+
+ this.Sections.RemoveAt(index);
+ this.SectionData.RemoveAt(index);
+
+ return true;
+ }
+
+ ///
+ /// Rebuilds the sections by aligning them as needed. Updates the Nt headers to
+ /// correct the new SizeOfImage after alignment is completed.
+ ///
+ public void RebuildSections()
+ {
+ for (var x = 0; x < this.Sections.Count; x++)
+ {
+ // Obtain the current section and realign the data..
+ var section = this.Sections[x];
+ section.VirtualAddress = this.GetAlignment(section.VirtualAddress, this.NtHeaders.OptionalHeader.SectionAlignment);
+ section.VirtualSize = this.GetAlignment(section.VirtualSize, this.NtHeaders.OptionalHeader.SectionAlignment);
+ section.PointerToRawData = this.GetAlignment(section.PointerToRawData, this.NtHeaders.OptionalHeader.FileAlignment);
+ section.SizeOfRawData = this.GetAlignment(section.SizeOfRawData, this.NtHeaders.OptionalHeader.FileAlignment);
+
+ // Store the sections updates..
+ this.Sections[x] = section;
+ }
+
+ // Update the size of the image..
+ var ntHeaders = this.NtHeaders;
+ ntHeaders.OptionalHeader.SizeOfImage = this.Sections.Last().VirtualAddress + this.Sections.Last().VirtualSize;
+ this.NtHeaders = ntHeaders;
+ }
+
+ ///
+ /// Obtains the relative virtual address from the given virtual address.
+ ///
+ ///
+ ///
+ public uint GetRvaFromVa(uint va)
+ {
+ return va - this.NtHeaders.OptionalHeader.ImageBase;
+ }
+
+ ///
+ /// Obtains the file offset from the given relative virtual address.
+ ///
+ ///
+ ///
+ public uint GetFileOffsetFromRva(uint rva)
+ {
+ var section = this.GetOwnerSection(rva);
+ return (rva - (section.VirtualAddress - section.PointerToRawData));
+ }
+
+ ///
+ /// Aligns the value based on the given alignment.
+ ///
+ ///
+ ///
+ ///
+ public uint GetAlignment(uint val, uint align)
+ {
+ return (((val + align - 1) / align) * align);
+ }
+
+ ///
+ /// Gets or sets the path to the file being processed.
+ ///
+ public string FilePath { get; set; }
+
+ ///
+ /// Gets or sets the raw file data read from disk.
+ ///
+ public byte[] FileData { get; set; }
+
+ ///
+ /// Gets or sets the dos header of the file.
+ ///
+ public NativeApi32.ImageDosHeader32 DosHeader { get; set; }
+
+ ///
+ /// Gets or sets the NT headers of the file.
+ ///
+ public NativeApi32.ImageNtHeaders32 NtHeaders { get; set; }
+
+ ///
+ /// Gets or sets the optional dos stub size.
+ ///
+ public uint DosStubSize { get; set; }
+
+ ///
+ /// Gets or sets the optional dos stub offset.
+ ///
+ public uint DosStubOffset { get; set; }
+
+ ///
+ /// Gets or sets the optional dos stub data.
+ ///
+ public byte[] DosStubData { get; set; }
+
+ ///
+ /// Gets or sets the sections of the file.
+ ///
+ public List Sections;
+
+ ///
+ /// Gets or sets the section data of the file.
+ ///
+ public List SectionData;
+
+ ///
+ /// Gets or sets the overlay data of the file.
+ ///
+ public byte[] OverlayData;
+
+ ///
+ /// Gets or sets the Tls directory of the file.
+ ///
+ public NativeApi32.ImageTlsDirectory32 TlsDirectory { get; set; }
+
+ ///
+ /// Gets or sets a list of Tls callbacks of the file.
+ ///
+ public List TlsCallbacks { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/Steamless.API/PE32/Pe32Helpers.cs b/Steamless.API/PE32/Pe32Helpers.cs
new file mode 100644
index 0000000..0a2aa68
--- /dev/null
+++ b/Steamless.API/PE32/Pe32Helpers.cs
@@ -0,0 +1,128 @@
+/**
+ * Steamless - Copyright (c) 2015 - 2017 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.API.PE32
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Runtime.InteropServices;
+
+ public class Pe32Helpers
+ {
+ ///
+ /// Converts a byte array to the given structure type.
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static T GetStructure(byte[] data, int offset = 0)
+ {
+ var ptr = Marshal.AllocHGlobal(data.Length);
+ Marshal.Copy(data, offset, ptr, data.Length - offset);
+ var obj = (T)Marshal.PtrToStructure(ptr, typeof(T));
+ Marshal.FreeHGlobal(ptr);
+
+ return obj;
+ }
+
+ ///
+ /// Converts the given object back to a byte array.
+ ///
+ ///
+ ///
+ ///
+ public static byte[] GetStructureBytes(T obj)
+ {
+ var size = Marshal.SizeOf(obj);
+ var data = new byte[size];
+ var ptr = Marshal.AllocHGlobal(size);
+ Marshal.StructureToPtr(obj, ptr, true);
+ Marshal.Copy(ptr, data, 0, size);
+ Marshal.FreeHGlobal(ptr);
+ return data;
+ }
+
+ ///
+ /// Obtains a section from the given file information.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static NativeApi32.ImageSectionHeader32 GetSection(byte[] rawData, int index, NativeApi32.ImageDosHeader32 dosHeader, NativeApi32.ImageNtHeaders32 ntHeaders)
+ {
+ var sectionSize = Marshal.SizeOf(typeof(NativeApi32.ImageSectionHeader32));
+ var optionalHeaderOffset = Marshal.OffsetOf(typeof(NativeApi32.ImageNtHeaders32), "OptionalHeader").ToInt32();
+ var dataOffset = dosHeader.e_lfanew + optionalHeaderOffset + ntHeaders.FileHeader.SizeOfOptionalHeader;
+
+ return GetStructure(rawData, dataOffset + (index * sectionSize));
+ }
+
+ ///
+ /// Scans the given data for the given pattern.
+ ///
+ /// Notes:
+ /// Patterns are assumed to be 2 byte hex values with spaces.
+ /// Wildcards are represented by ??.
+ ///
+ ///
+ ///
+ ///
+ public static uint FindPattern(byte[] data, string pattern)
+ {
+ try
+ {
+ // Trim the pattern from extra whitespace..
+ var trimPattern = pattern.Replace(" ", "").Trim();
+
+ // Convert the pattern to a byte array..
+ var patternMask = new List();
+ var patternData = Enumerable.Range(0, trimPattern.Length).Where(x => x % 2 == 0)
+ .Select(x =>
+ {
+ var bt = trimPattern.Substring(x, 2);
+ patternMask.Add(!bt.Contains('?'));
+ return bt.Contains('?') ? (byte)0 : Convert.ToByte(bt, 16);
+ }).ToArray();
+
+ // Scan the given data for our pattern..
+ for (var x = 0; x < data.Length; x++)
+ {
+ if (!patternData.Where((t, y) => patternMask[y] && t != data[x + y]).Any())
+ return (uint)x;
+ }
+
+ return 0;
+ }
+ catch
+ {
+ return 0;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Steamless.API/Properties/AssemblyInfo.cs b/Steamless.API/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..d9a4d96
--- /dev/null
+++ b/Steamless.API/Properties/AssemblyInfo.cs
@@ -0,0 +1,40 @@
+/**
+ * Steamless - Copyright (c) 2015 - 2017 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.API")]
+[assembly: AssemblyDescription("SteamStub API Module")]
+[assembly: AssemblyConfiguration("Release")]
+[assembly: AssemblyCompany("atom0s")]
+[assembly: AssemblyProduct("Steamless.API")]
+[assembly: AssemblyCopyright("Copyright © atom0s 2015 - 2017")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+[assembly: ComVisible(false)]
+[assembly: Guid("56c95629-3b34-47fe-b988-04274409294f")]
+[assembly: AssemblyVersion("1.0.0.1")]
+[assembly: AssemblyFileVersion("1.0.0.1")]
\ No newline at end of file
diff --git a/Steamless.API/Services/LoggingService.cs b/Steamless.API/Services/LoggingService.cs
new file mode 100644
index 0000000..57a7732
--- /dev/null
+++ b/Steamless.API/Services/LoggingService.cs
@@ -0,0 +1,63 @@
+/**
+ * Steamless - Copyright (c) 2015 - 2017 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.API.Services
+{
+ using Events;
+ using System;
+
+ public class LoggingService
+ {
+ ///
+ /// Adds a log message to the logging pane of Steamless.
+ ///
+ public event SteamlessEvents.AddLogMessageEventHandler AddLogMessage;
+
+ ///
+ /// Clears the logging pane of Steamless.
+ ///
+ public event SteamlessEvents.ClearLogMessagesEventHandler ClearLogMessages;
+
+ ///
+ /// Invokes the AddLogMessage event to add a log message to Steamless.
+ ///
+ ///
+ ///
+ public virtual void OnAddLogMessage(object sender, LogMessageEventArgs e)
+ {
+ this.AddLogMessage?.Invoke(sender, e);
+ }
+
+ ///
+ /// Invokes the ClearLogMessages event to remove all current log messages from Steamless.
+ ///
+ ///
+ ///
+ public virtual void OnClearLogMessages(object sender, EventArgs e)
+ {
+ this.ClearLogMessages?.Invoke(sender, e);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Steamless.API/Steamless.API.csproj b/Steamless.API/Steamless.API.csproj
new file mode 100644
index 0000000..3f8fe1a
--- /dev/null
+++ b/Steamless.API/Steamless.API.csproj
@@ -0,0 +1,68 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {56C95629-3B34-47FE-B988-04274409294F}
+ Library
+ Properties
+ Steamless.API
+ Steamless.API
+ v4.5.2
+ 512
+
+
+ x86
+ ..\Steamless\bin\x86\Debug\Plugins\
+ TRACE;DEBUG
+
+
+ x86
+ ..\Steamless\bin\x86\Release\Plugins\
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Steamless.API/SteamlessApiVersionAttribute.cs b/Steamless.API/SteamlessApiVersionAttribute.cs
new file mode 100644
index 0000000..9668968
--- /dev/null
+++ b/Steamless.API/SteamlessApiVersionAttribute.cs
@@ -0,0 +1,48 @@
+/**
+ * Steamless - Copyright (c) 2015 - 2017 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.API
+{
+ using System;
+
+ [AttributeUsage(AttributeTargets.Class, Inherited = false)]
+ public class SteamlessApiVersionAttribute : Attribute
+ {
+ ///
+ /// Default Constructor
+ ///
+ ///
+ ///
+ public SteamlessApiVersionAttribute(int major, int minor)
+ {
+ this.Version = new Version(major, minor);
+ }
+
+ ///
+ /// Gets or sets the API version of this attribute.
+ ///
+ public Version Version { get; internal set; }
+ }
+}
\ No newline at end of file
diff --git a/Steamless.API/SteamlessEvents.cs b/Steamless.API/SteamlessEvents.cs
new file mode 100644
index 0000000..2697ee2
--- /dev/null
+++ b/Steamless.API/SteamlessEvents.cs
@@ -0,0 +1,47 @@
+/**
+ * Steamless - Copyright (c) 2015 - 2017 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.API
+{
+ using Events;
+ using System;
+
+ public class SteamlessEvents
+ {
+ ///
+ /// Log message event handler.
+ ///
+ ///
+ ///
+ public delegate void AddLogMessageEventHandler(object sender, LogMessageEventArgs e);
+
+ ///
+ /// Clear log messages event handler.
+ ///
+ ///
+ ///
+ public delegate void ClearLogMessagesEventHandler(object sender, EventArgs e);
+ }
+}
\ No newline at end of file
diff --git a/Steamless.Unpacker.Variant20.x86/Classes/SteamStubDrmFlags.cs b/Steamless.Unpacker.Variant20.x86/Classes/SteamStubDrmFlags.cs
new file mode 100644
index 0000000..667289b
--- /dev/null
+++ b/Steamless.Unpacker.Variant20.x86/Classes/SteamStubDrmFlags.cs
@@ -0,0 +1,38 @@
+/**
+ * Steamless - Copyright (c) 2015 - 2017 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.Unpacker.Variant20.x86.Classes
+{
+ ///
+ /// Steam Stub Variant 2.0 DRM Flags
+ ///
+ public enum DrmFlags
+ {
+ NoModuleVerification = 0x02,
+ NoEncryption = 0x04,
+ NoOwnershipCheck = 0x10,
+ NoDebuggerCheck = 0x20,
+ }
+}
\ No newline at end of file
diff --git a/Steamless.Unpacker.Variant20.x86/Classes/SteamStubHeader.cs b/Steamless.Unpacker.Variant20.x86/Classes/SteamStubHeader.cs
new file mode 100644
index 0000000..e8406b2
--- /dev/null
+++ b/Steamless.Unpacker.Variant20.x86/Classes/SteamStubHeader.cs
@@ -0,0 +1,60 @@
+/**
+ * Steamless - Copyright (c) 2015 - 2017 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.Unpacker.Variant20.x86.Classes
+{
+ using System.Runtime.InteropServices;
+
+ ///
+ /// SteamStub DRM Variant 2.0 Header
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ public struct SteamStub32Var20Header
+ {
+ public uint XorKey; // The base XOR key, if defined, to unpack the file with.
+ public uint GetModuleHandleA_idata; // The address of GetModuleHandleA inside of the .idata section.
+ public uint GetModuleHandleW_idata; // The address of GetModuleHandleW inside of the .idata section.
+ public uint GetProcAddress_idata; // The address of GetProcAddress inside of the .idata section.
+ public uint LoadLibraryA_idata; // The address of LoadLibraryA inside of the .idata section.
+ public uint Unknown0000; // Unknown (Was 0 when testing. Possibly LoadLibraryW.)
+ public uint BindSectionVirtualAddress; // The virtual address to the .bind section.
+ public uint BindStartFunctionSize; // The size of the start function from the .bind section.
+ public uint PayloadKeyMatch; // The key inside of the SteamDRMP.dll file that is matched to this structures data. (This matches the first 4 bytes of the payload data.)
+ public uint PayloadDataVirtualAddress; // The virtual address to the payload data.
+ public uint PayloadDataSize; // The size of the payload data.
+ public uint SteamAppID; // The steam application id of the packed file.
+ public uint Unknown0001; // Unknown
+
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x08)]
+ public byte[] SteamAppIDString; // The SteamAppID of the packed file, in string format.
+
+ public uint SteamDRMPDllVirtualAddress; // The offset inside of the payload data holding the virtual address to the SteamDRMP.dll file data.
+ public uint SteamDRMPDllSize; // The offset inside of the payload data holding the size of the SteamDRMP.dll file data.
+ public uint XTeaKeys; // The offset inside of the payload data holding the address to the Xtea keys to decrypt the SteamDRMP.dll file.
+
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x31C)]
+ public byte[] StubData; // Misc stub data, such as strings, error messages, etc.
+ }
+}
\ No newline at end of file
diff --git a/Steamless.Unpacker.Variant20.x86/Classes/SteamStubHelpers.cs b/Steamless.Unpacker.Variant20.x86/Classes/SteamStubHelpers.cs
new file mode 100644
index 0000000..7a6610e
--- /dev/null
+++ b/Steamless.Unpacker.Variant20.x86/Classes/SteamStubHelpers.cs
@@ -0,0 +1,122 @@
+/**
+ * Steamless - Copyright (c) 2015 - 2017 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.Unpacker.Variant20.x86.Classes
+{
+ using System;
+
+ public static class SteamStubHelpers
+ {
+ ///
+ /// Xor decrypts the given data starting with the given key, if any.
+ ///
+ /// @note If no key is given (0) then the first key is read from the first
+ /// 4 bytes inside of the data given.
+ ///
+ /// The data to xor decode.
+ /// The size of the data to decode.
+ /// The starting xor key to decode with.
+ ///
+ public static uint SteamXor(ref byte[] data, uint size, uint key = 0)
+ {
+ var offset = (uint)0;
+
+ // Read the first key as the base xor key if we had none given..
+ if (key == 0)
+ {
+ offset += 4;
+ key = BitConverter.ToUInt32(data, 0);
+ }
+
+ // Decode the data..
+ for (var x = offset; x < size; x += 4)
+ {
+ var val = BitConverter.ToUInt32(data, (int)x);
+ Array.Copy(BitConverter.GetBytes(val ^ key), 0, data, x, 4);
+
+ key = val;
+ }
+
+ return key;
+ }
+
+ ///
+ /// The second pass of decryption for the SteamDRMP.dll file.
+ ///
+ /// @note The encryption method here is known as XTEA.
+ ///
+ /// The result value buffer to write our returns to.
+ /// The keys used for the decryption.
+ /// The first value to decrypt from.
+ /// The second value to decrypt from.
+ /// The number of passes to crypt the data with.
+ public static void SteamDrmpDecryptPass2(ref uint[] res, uint[] keys, uint v1, uint v2, uint n = 32)
+ {
+ const uint delta = 0x9E3779B9;
+ const uint mask = 0xFFFFFFFF;
+ var sum = (delta * n) & mask;
+
+ for (var x = 0; x < n; x++)
+ {
+ v2 = (v2 - (((v1 << 4 ^ v1 >> 5) + v1) ^ (sum + keys[sum >> 11 & 3]))) & mask;
+ sum = (sum - delta) & mask;
+ v1 = (v1 - (((v2 << 4 ^ v2 >> 5) + v2) ^ (sum + keys[sum & 3]))) & mask;
+ }
+
+ res[0] = v1;
+ res[1] = v2;
+ }
+
+ ///
+ /// The first pass of the decryption for the SteamDRMP.dll file.
+ ///
+ /// @note The encryption method here is known as XTEA. It is modded to include
+ /// some basic xor'ing.
+ ///
+ /// The data to decrypt.
+ /// The size of the data to decrypt.
+ /// The keys used for the decryption.
+ public static void SteamDrmpDecryptPass1(ref byte[] data, uint size, uint[] keys)
+ {
+ var v1 = (uint)0x55555555;
+ var v2 = (uint)0x55555555;
+
+ for (var x = 0; x < size; x += 8)
+ {
+ var d1 = BitConverter.ToUInt32(data, x + 0);
+ var d2 = BitConverter.ToUInt32(data, x + 4);
+
+ var res = new uint[2];
+ SteamDrmpDecryptPass2(ref res, keys, d1, d2);
+
+ Array.Copy(BitConverter.GetBytes(res[0] ^ v1), 0, data, x + 0, 4);
+ Array.Copy(BitConverter.GetBytes(res[1] ^ v2), 0, data, x + 4, 4);
+
+ v1 = d1;
+ v2 = d2;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Steamless.Unpacker.Variant20.x86/Main.cs b/Steamless.Unpacker.Variant20.x86/Main.cs
new file mode 100644
index 0000000..b1b6811
--- /dev/null
+++ b/Steamless.Unpacker.Variant20.x86/Main.cs
@@ -0,0 +1,632 @@
+/**
+ * Steamless - Copyright (c) 2015 - 2017 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.Unpacker.Variant20.x86
+{
+ using API;
+ using API.Crypto;
+ using API.Events;
+ using API.Extensions;
+ using API.Model;
+ using API.PE32;
+ using API.Services;
+ using Classes;
+ using SharpDisasm;
+ using SharpDisasm.Udis86;
+ using System;
+ using System.Collections.Generic;
+ using System.IO;
+ using System.Linq;
+ using System.Runtime.InteropServices;
+ using System.Security.Cryptography;
+
+ [SteamlessApiVersion(1, 0)]
+ public class Main : SteamlessPlugin
+ {
+ ///
+ /// Internal logging service instance.
+ ///
+ private LoggingService m_LoggingService;
+
+ ///
+ /// Gets the author of this plugin.
+ ///
+ public override string Author => "atom0s";
+
+ ///
+ /// Gets the name of this plugin.
+ ///
+ public override string Name => "SteamStub Variant 2.0 Unpacker (x86)";
+
+ ///
+ /// Gets the description of this plugin.
+ ///
+ public override string Description => "Unpacker for the 32bit SteamStub variant 2.0.";
+
+ ///
+ /// Gets the version of this plugin.
+ ///
+ public override Version Version => new Version(1, 0, 0, 0);
+
+ ///
+ /// Internal wrapper to log a message.
+ ///
+ ///
+ ///
+ private void Log(string msg, LogMessageType type)
+ {
+ this.m_LoggingService.OnAddLogMessage(this, new LogMessageEventArgs(msg, type));
+ }
+
+ ///
+ /// Initialize function called when this plugin is first loaded.
+ ///
+ ///
+ ///
+ public override bool Initialize(LoggingService logService)
+ {
+ this.m_LoggingService = logService;
+ return true;
+ }
+
+ ///
+ /// Processing function called when a file is being unpacked. Allows plugins to check the file
+ /// and see if it can handle the file for its intended purpose.
+ ///
+ ///
+ ///
+ public override bool CanProcessFile(string file)
+ {
+ try
+ {
+ // Load the file..
+ var f = new Pe32File(file);
+ if (!f.Parse() || f.IsFile64Bit() || !f.HasSection(".bind"))
+ return false;
+
+ // Obtain the bind section data..
+ var bind = f.GetSectionData(".bind");
+
+ // Attempt to locate the known v2.x signature..
+ return Pe32Helpers.FindPattern(bind, "53 51 52 56 57 55 8B EC 81 EC 00 10 00 00 C7") > 0;
+ }
+ catch
+ {
+ return false;
+ }
+ }
+
+ ///
+ /// Processing function called to allow the plugin to process the file.
+ ///
+ ///
+ ///
+ ///
+ public override bool ProcessFile(string file, SteamlessOptions options)
+ {
+ // Initialize the class members..
+ this.Options = options;
+ this.CodeSectionData = null;
+ this.CodeSectionIndex = -1;
+ this.PayloadData = null;
+ this.SteamDrmpData = null;
+ this.SteamDrmpOffsets = new List();
+ this.XorKey = 0;
+
+ // Parse the file..
+ this.File = new Pe32File(file);
+ if (!this.File.Parse())
+ return false;
+
+ // Announce we are being unpacked with this packer..
+ this.Log("File is packed with SteamStub Variant 2.0!", LogMessageType.Information);
+
+ this.Log("Step 1 - Read, disassemble and decode the SteamStub DRM header.", LogMessageType.Information);
+ if (!this.Step1())
+ return false;
+
+ this.Log("Step 2 - Read, decode and process the payload data.", LogMessageType.Information);
+ if (!this.Step2())
+ return false;
+
+ this.Log("Step 3 - Read, decode and dump the SteamDRMP.dll file.", LogMessageType.Information);
+ if (!this.Step3())
+ return false;
+
+ this.Log("Step 4 - Scan, dump and pull needed offsets from within the SteamDRMP.dll file.", LogMessageType.Information);
+ if (!this.Step4())
+ return false;
+
+ this.Log("Step 5 - Read, decrypt and process the main code section.", LogMessageType.Information);
+ if (!this.Step5())
+ return false;
+
+ this.Log("Step 6 - Rebuild and save the unpacked file.", LogMessageType.Information);
+ if (!this.Step6())
+ return false;
+
+ return true;
+ }
+
+ ///
+ /// Step #1
+ ///
+ /// Read, disassemble and decode the SteamStub DRM header.
+ ///
+ ///
+ private bool Step1()
+ {
+ // Obtain the file entry offset..
+ var fileOffset = this.File.GetFileOffsetFromRva(this.File.NtHeaders.OptionalHeader.AddressOfEntryPoint);
+
+ // Validate the DRM header..
+ if (BitConverter.ToUInt32(this.File.FileData, (int)fileOffset - 4) != 0xC0DEC0DE)
+ return false;
+
+ int structOffset;
+ int structSize;
+ int structXorKey;
+
+ // Disassemble the file to locate the needed DRM information..
+ if (!this.DisassembleFile(out structOffset, out structSize, out structXorKey))
+ return false;
+
+ // Obtain the DRM header data..
+ var headerData = new byte[structSize];
+ Array.Copy(this.File.FileData, this.File.GetFileOffsetFromRva((uint)structOffset), headerData, 0, structSize);
+
+ // Xor decode the header data..
+ this.XorKey = SteamStubHelpers.SteamXor(ref headerData, (uint)headerData.Length, (uint)structXorKey);
+ this.StubHeader = Pe32Helpers.GetStructure(headerData);
+
+ return true;
+ }
+
+ ///
+ /// Step #2
+ ///
+ /// Read, decode and process the payload data.
+ ///
+ ///
+ private bool Step2()
+ {
+ // Obtain the payload address and size..
+ var payloadAddr = this.File.GetFileOffsetFromRva(this.File.GetRvaFromVa(this.StubHeader.PayloadDataVirtualAddress));
+ var payloadData = new byte[this.StubHeader.PayloadDataSize];
+ Array.Copy(this.File.FileData, payloadAddr, payloadData, 0, this.StubHeader.PayloadDataSize);
+
+ // Decode the payload data..
+ this.XorKey = SteamStubHelpers.SteamXor(ref payloadData, this.StubHeader.PayloadDataSize, this.XorKey);
+ this.PayloadData = payloadData;
+
+ try
+ {
+ if (this.Options.DumpPayloadToDisk)
+ {
+ System.IO.File.WriteAllBytes(this.File.FilePath + ".payload", payloadData);
+ this.Log(" --> Saved payload to disk!", LogMessageType.Debug);
+ }
+ }
+ catch
+ {
+ // Do nothing here since it doesn't matter if this fails..
+ }
+
+ return true;
+ }
+
+ ///
+ /// Step #3
+ ///
+ /// Read, decode and dump the SteamDRMP.dll file.
+ ///
+ ///
+ private bool Step3()
+ {
+ this.Log(" --> File has SteamDRMP.dll file!", LogMessageType.Debug);
+
+ try
+ {
+ // Obtain the SteamDRMP.dll file address and data..
+ var drmpAddr = this.File.GetFileOffsetFromRva(this.File.GetRvaFromVa(BitConverter.ToUInt32(this.PayloadData, (int)this.StubHeader.SteamDRMPDllVirtualAddress)));
+ var drmpSize = BitConverter.ToUInt32(this.PayloadData, (int)this.StubHeader.SteamDRMPDllSize);
+ var drmpData = new byte[drmpSize];
+ Array.Copy(this.File.FileData, drmpAddr, drmpData, 0, drmpSize);
+
+ // Obtain the XTea encryption keys..
+ var xteyKeys = new uint[(this.PayloadData.Length - this.StubHeader.XTeaKeys) / 4];
+ for (var x = 0; x < (this.PayloadData.Length - this.StubHeader.XTeaKeys) / 4; x++)
+ xteyKeys[x] = BitConverter.ToUInt32(this.PayloadData, (int)this.StubHeader.XTeaKeys + (x * 4));
+
+ // Decrypt the file data..
+ SteamStubHelpers.SteamDrmpDecryptPass1(ref drmpData, drmpSize, xteyKeys);
+ this.SteamDrmpData = drmpData;
+
+ try
+ {
+ if (this.Options.DumpSteamDrmpToDisk)
+ {
+ var basePath = Path.GetDirectoryName(this.File.FilePath) ?? string.Empty;
+ System.IO.File.WriteAllBytes(Path.Combine(basePath, "SteamDRMP.dll"), drmpData);
+ this.Log(" --> Saved SteamDRMP.dll to disk!", LogMessageType.Debug);
+ }
+ }
+ catch
+ {
+ // Do nothing here since it doesn't matter if this fails..
+ }
+
+ return true;
+ }
+ catch
+ {
+ this.Log(" --> Error trying to decrypt the files SteamDRMP.dll data!", LogMessageType.Error);
+ return false;
+ }
+ }
+
+ ///
+ /// Step #4
+ ///
+ /// Scan, dump and pull needed offsets from within the SteamDRMP.dll file.
+ ///
+ ///
+ private bool Step4()
+ {
+ // Scan for the needed data by a known pattern for the block of offset data..
+ var drmpOffset = Pe32Helpers.FindPattern(this.SteamDrmpData, "8B ?? ?? ?? ?? ?? 89 ?? ?? ?? ?? ?? 8B ?? ?? ?? ?? ?? 89 ?? ?? ?? ?? ?? 8B ?? ?? ?? ?? ?? 89 ?? ?? ?? ?? ?? 8B ?? ?? ?? ?? ?? 89 ?? ?? ?? ?? ?? 8B ?? ?? ?? ?? ?? 89 ?? ?? ?? ?? ?? 8D ?? ?? ?? ?? ?? 05");
+ if (drmpOffset == 0)
+ return false;
+
+ // Copy the block of data from the SteamDRMP.dll data..
+ var drmpOffsetData = new byte[1024];
+ Array.Copy(this.SteamDrmpData, drmpOffset, drmpOffsetData, 0, 1024);
+
+ // Obtain the offsets from the file data..
+ var drmpOffsets = this.GetSteamDrmpOffsets(drmpOffsetData);
+ if (drmpOffsets.Count != 8)
+ return false;
+
+ // Store the offsets..
+ this.SteamDrmpOffsets = drmpOffsets;
+
+ return true;
+ }
+
+ ///
+ /// Step #5
+ ///
+ /// Read, decrypt and process the main code section.
+ ///
+ ///
+ private bool Step5()
+ {
+ // Remove the bind section if its not requested to be saved..
+ if (!this.Options.KeepBindSection)
+ {
+ // Obtain the .bind section..
+ var bindSection = this.File.GetSection(".bind");
+ if (!bindSection.IsValid)
+ return false;
+
+ // Remove the section..
+ this.File.RemoveSection(bindSection);
+
+ // Decrease the header section count..
+ var ntHeaders = this.File.NtHeaders;
+ ntHeaders.FileHeader.NumberOfSections--;
+ this.File.NtHeaders = ntHeaders;
+
+ this.Log(" --> .bind section was removed from the file.", LogMessageType.Debug);
+ }
+ else
+ this.Log(" --> .bind section was kept in the file.", LogMessageType.Debug);
+
+ byte[] codeSectionData;
+
+ // Obtain the main code section (typically .text)..
+ var mainSection = this.File.GetOwnerSection(this.File.GetRvaFromVa(BitConverter.ToUInt32(this.PayloadData.Skip(this.SteamDrmpOffsets[3]).Take(4).ToArray(), 0)));
+ if (mainSection.PointerToRawData == 0 || mainSection.SizeOfRawData == 0)
+ return false;
+
+ this.Log($" --> {mainSection.SectionName} linked as main code section.", LogMessageType.Debug);
+
+ // Save the code section index for later use..
+ this.CodeSectionIndex = this.File.GetSectionIndex(mainSection);
+
+ // Determine if we are using encryption on the section..
+ var flags = BitConverter.ToUInt32(this.PayloadData.Skip(this.SteamDrmpOffsets[0]).Take(4).ToArray(), 0);
+ if ((flags & (uint)DrmFlags.NoEncryption) == (uint)DrmFlags.NoEncryption)
+ {
+ this.Log($" --> {mainSection.SectionName} section is not encrypted.", LogMessageType.Debug);
+
+ // No encryption was used, just read the original data..
+ codeSectionData = new byte[mainSection.SizeOfRawData];
+ Array.Copy(this.File.FileData, this.File.GetFileOffsetFromRva(mainSection.VirtualAddress), codeSectionData, 0, mainSection.SizeOfRawData);
+ }
+ else
+ {
+ this.Log($" --> {mainSection.SectionName} section is encrypted.", LogMessageType.Debug);
+
+ try
+ {
+ // Encryption was used, obtain the encryption information..
+ var aesKey = this.PayloadData.Skip(this.SteamDrmpOffsets[5]).Take(32).ToArray();
+ var aesIv = this.PayloadData.Skip(this.SteamDrmpOffsets[6]).Take(16).ToArray();
+ var codeStolen = this.PayloadData.Skip(this.SteamDrmpOffsets[7]).Take(16).ToArray();
+
+ // Restore the stolen data then read the rest of the section data..
+ codeSectionData = new byte[mainSection.SizeOfRawData + codeStolen.Length];
+ Array.Copy(codeStolen, 0, codeSectionData, 0, codeStolen.Length);
+ Array.Copy(this.File.FileData, this.File.GetFileOffsetFromRva(mainSection.VirtualAddress), codeSectionData, codeStolen.Length, mainSection.SizeOfRawData);
+
+ // Decrypt the code section..
+ var aes = new AesHelper(aesKey, aesIv);
+ aes.RebuildIv(aesIv);
+ codeSectionData = aes.Decrypt(codeSectionData, CipherMode.CBC, PaddingMode.None);
+ }
+ catch
+ {
+ this.Log(" --> Error trying to decrypt the files code section data!", LogMessageType.Error);
+ return false;
+ }
+ }
+
+ // Store the section data..
+ this.CodeSectionData = codeSectionData;
+
+ return true;
+ }
+
+ ///
+ /// Step #6
+ ///
+ /// Rebuild and save the unpacked file.
+ ///
+ ///
+ private bool Step6()
+ {
+ FileStream fStream = null;
+
+ try
+ {
+ // Rebuild the file sections..
+ this.File.RebuildSections();
+
+ // Open the unpacked file for writing..
+ var unpackedPath = this.File.FilePath + ".unpacked.exe";
+ fStream = new FileStream(unpackedPath, FileMode.Create, FileAccess.ReadWrite);
+
+ // Write the DOS header to the file..
+ fStream.WriteBytes(Pe32Helpers.GetStructureBytes(this.File.DosHeader));
+
+ // Write the DOS stub to the file..
+ if (this.File.DosStubSize > 0)
+ fStream.WriteBytes(this.File.DosStubData);
+
+ // Update the NT headers..
+ var ntHeaders = this.File.NtHeaders;
+ var lastSection = this.File.Sections[this.File.Sections.Count - 1];
+ var originalEntry = BitConverter.ToUInt32(this.PayloadData.Skip(this.SteamDrmpOffsets[2]).Take(4).ToArray(), 0);
+ ntHeaders.OptionalHeader.AddressOfEntryPoint = this.File.GetRvaFromVa(originalEntry);
+ ntHeaders.OptionalHeader.SizeOfImage = lastSection.VirtualAddress + lastSection.VirtualSize;
+ this.File.NtHeaders = ntHeaders;
+
+ // Write the NT headers to the file..
+ fStream.WriteBytes(Pe32Helpers.GetStructureBytes(ntHeaders));
+
+ // Write the sections to the file..
+ for (var x = 0; x < this.File.Sections.Count; x++)
+ {
+ var section = this.File.Sections[x];
+ var sectionData = this.File.SectionData[x];
+
+ // Write the section header to the file..
+ fStream.WriteBytes(Pe32Helpers.GetStructureBytes(section));
+
+ // Set the file pointer to the sections raw data..
+ var sectionOffset = fStream.Position;
+ fStream.Position = section.PointerToRawData;
+
+ // Write the sections raw data..
+ var sectionIndex = this.File.Sections.IndexOf(section);
+ if (sectionIndex == this.CodeSectionIndex)
+ fStream.WriteBytes(this.CodeSectionData ?? sectionData);
+ else
+ fStream.WriteBytes(sectionData);
+
+ // Reset the file offset..
+ fStream.Position = sectionOffset;
+ }
+
+ // Set the stream to the end of the file..
+ fStream.Position = fStream.Length;
+
+ // Write the overlay data if it exists..
+ if (this.File.OverlayData != null)
+ fStream.WriteBytes(this.File.OverlayData);
+
+ this.Log(" --> Unpacked file saved to disk!", LogMessageType.Success);
+ this.Log($" --> File Saved As: {unpackedPath}", LogMessageType.Success);
+
+ return true;
+ }
+ catch
+ {
+ this.Log(" --> Error trying to save unpacked file!", LogMessageType.Error);
+ return false;
+ }
+ finally
+ {
+ fStream?.Dispose();
+ }
+ }
+
+ ///
+ /// Disassembles the file to locate the needed DRM header information.
+ ///
+ ///
+ ///
+ ///
+ ///
+ private bool DisassembleFile(out int offset, out int size, out int xorKey)
+ {
+ // Prepare our needed variables..
+ Disassembler disasm = null;
+ var dataPointer = IntPtr.Zero;
+ var structOffset = 0;
+ var structSize = 0;
+ var structXorKey = 0;
+
+ // Determine the entry offset of the file..
+ var entryOffset = this.File.GetFileOffsetFromRva(this.File.NtHeaders.OptionalHeader.AddressOfEntryPoint);
+
+ try
+ {
+ // Copy the file data to memory for disassembling..
+ dataPointer = Marshal.AllocHGlobal(this.File.FileData.Length);
+ Marshal.Copy(this.File.FileData, 0, dataPointer, this.File.FileData.Length);
+
+ // Create an offset pointer to our .bind function start..
+ var startPointer = IntPtr.Add(dataPointer, (int)entryOffset);
+
+ // Create the disassembler..
+ Disassembler.Translator.IncludeAddress = true;
+ Disassembler.Translator.IncludeBinary = true;
+
+ disasm = new Disassembler(startPointer, 4096, ArchitectureMode.x86_32, entryOffset);
+
+ // Disassemble our function..
+ foreach (var inst in disasm.Disassemble().Where(inst => !inst.Error))
+ {
+ // If all values are found, return successfully..
+ if (structOffset > 0 && structSize > 0 && structXorKey > 0)
+ {
+ offset = structOffset;
+ size = structSize;
+ xorKey = structXorKey;
+ return true;
+ }
+
+ // Looks for: mov dword ptr [value], immediate
+ if (inst.Mnemonic == ud_mnemonic_code.UD_Imov && inst.Operands[0].Type == ud_type.UD_OP_MEM && inst.Operands[1].Type == ud_type.UD_OP_IMM)
+ {
+ if (structOffset == 0)
+ structOffset = inst.Operands[1].LvalSDWord - (int)this.File.NtHeaders.OptionalHeader.ImageBase;
+ else
+ structXorKey = inst.Operands[1].LvalSDWord;
+ }
+
+ // Looks for: mov reg, immediate
+ if (inst.Mnemonic == ud_mnemonic_code.UD_Imov && inst.Operands[0].Type == ud_type.UD_OP_REG && inst.Operands[1].Type == ud_type.UD_OP_IMM)
+ structSize = inst.Operands[1].LvalSDWord * 4;
+ }
+
+ offset = size = xorKey = 0;
+ return false;
+ }
+ catch
+ {
+ offset = size = xorKey = 0;
+ return false;
+ }
+ finally
+ {
+ disasm?.Dispose();
+ if (dataPointer != IntPtr.Zero)
+ Marshal.FreeHGlobal(dataPointer);
+ }
+ }
+
+ ///
+ /// Obtains the needed DRM offsets from the SteamDRMP.dll file.
+ ///
+ ///
+ ///
+ private List GetSteamDrmpOffsets(byte[] data)
+ {
+ var offsets = new List
+ {
+ BitConverter.ToInt32(data, 2), // .... 0 - Flags
+ BitConverter.ToInt32(data, 14), // ... 1 - Steam App Id
+ BitConverter.ToInt32(data, 26), // ... 2 - OEP
+ BitConverter.ToInt32(data, 38), // ... 3 - Code Section Virtual Address
+ BitConverter.ToInt32(data, 50), // ... 4 - Code Section Virtual Size (Encrypted Size)
+ BitConverter.ToInt32(data, 62) // .... 5 - Code Section AES Key
+ };
+
+ var aesIvOffset = BitConverter.ToInt32(data, 67);
+ offsets.Add(aesIvOffset); // ................. 6 - Code Section AES Iv
+ offsets.Add(aesIvOffset + 16); // ............ 7 - Code Section Stolen Bytes
+
+ return offsets;
+ }
+
+ ///
+ /// Gets or sets the Steamless options this file was requested to process with.
+ ///
+ private SteamlessOptions Options { get; set; }
+
+ ///
+ /// Gets or sets the file being processed.
+ ///
+ private Pe32File File { get; set; }
+
+ ///
+ /// Gets or sets the current xor key being used against the file data.
+ ///
+ private uint XorKey { get; set; }
+
+ ///
+ /// Gets or sets the DRM stub header.
+ ///
+ private SteamStub32Var20Header StubHeader { get; set; }
+
+ ///
+ /// Gets or sets the payload data.
+ ///
+ public byte[] PayloadData { get; set; }
+
+ ///
+ /// Gets or sets the SteamDRMP.dll data.
+ ///
+ public byte[] SteamDrmpData { get; set; }
+
+ ///
+ /// Gets or sets the list of SteamDRMP.dll offsets.
+ ///
+ public List SteamDrmpOffsets { get; set; }
+
+ ///
+ /// Gets or sets the index of the code section.
+ ///
+ private int CodeSectionIndex { get; set; }
+
+ ///
+ /// Gets or sets the decrypted code section data.
+ ///
+ private byte[] CodeSectionData { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/Steamless.Unpacker.Variant20.x86/Properties/AssemblyInfo.cs b/Steamless.Unpacker.Variant20.x86/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..17499f3
--- /dev/null
+++ b/Steamless.Unpacker.Variant20.x86/Properties/AssemblyInfo.cs
@@ -0,0 +1,40 @@
+/**
+ * Steamless - Copyright (c) 2015 - 2017 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.Unpacker.Variant20.x86")]
+[assembly: AssemblyDescription("Steamless SteamStub Variant v2.0 (x86) Unpacker")]
+[assembly: AssemblyConfiguration("Release")]
+[assembly: AssemblyCompany("atom0s")]
+[assembly: AssemblyProduct("Steamless.Unpacker.Variant20.x86")]
+[assembly: AssemblyCopyright("Copyright © atom0s 2015 - 2017")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+[assembly: ComVisible(false)]
+[assembly: Guid("a40154cd-a0fd-4371-8099-ce277e0989af")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
\ No newline at end of file
diff --git a/Steamless.Unpacker.Variant20.x86/SharpDisasm.dll b/Steamless.Unpacker.Variant20.x86/SharpDisasm.dll
new file mode 100644
index 0000000..950c59d
Binary files /dev/null and b/Steamless.Unpacker.Variant20.x86/SharpDisasm.dll differ
diff --git a/Steamless.Unpacker.Variant20.x86/Steamless.Unpacker.Variant20.x86.csproj b/Steamless.Unpacker.Variant20.x86/Steamless.Unpacker.Variant20.x86.csproj
new file mode 100644
index 0000000..f272880
--- /dev/null
+++ b/Steamless.Unpacker.Variant20.x86/Steamless.Unpacker.Variant20.x86.csproj
@@ -0,0 +1,60 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {A40154CD-A0FD-4371-8099-CE277E0989AF}
+ Library
+ Properties
+ Steamless.Unpacker.Variant20.x86
+ Steamless.Unpacker.Variant20.x86
+ v4.5.2
+ 512
+
+
+ x86
+ ..\Steamless\bin\x86\Debug\Plugins\
+ TRACE;DEBUG
+
+
+ x86
+ ..\Steamless\bin\x86\Release\Plugins\
+ true
+
+
+
+ .\SharpDisasm.dll
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {56c95629-3b34-47fe-b988-04274409294f}
+ Steamless.API
+ False
+
+
+
+
+
\ No newline at end of file
diff --git a/Steamless.Unpacker.Variant30.x86/Classes/SteamStubDrmFlags.cs b/Steamless.Unpacker.Variant30.x86/Classes/SteamStubDrmFlags.cs
new file mode 100644
index 0000000..80782c2
--- /dev/null
+++ b/Steamless.Unpacker.Variant30.x86/Classes/SteamStubDrmFlags.cs
@@ -0,0 +1,39 @@
+/**
+ * Steamless - Copyright (c) 2015 - 2017 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.Unpacker.Variant30.x86.Classes
+{
+ ///
+ /// Steam Stub Variant 3.0 DRM Flags
+ ///
+ public enum SteamStubDrmFlags
+ {
+ NoModuleVerification = 0x02,
+ NoEncryption = 0x04,
+ NoOwnershipCheck = 0x10,
+ NoDebuggerCheck = 0x20,
+ NoErrorDialog = 0x40
+ }
+}
\ No newline at end of file
diff --git a/Steamless.Unpacker.Variant30.x86/Classes/SteamStubHeader.cs b/Steamless.Unpacker.Variant30.x86/Classes/SteamStubHeader.cs
new file mode 100644
index 0000000..dd216cf
--- /dev/null
+++ b/Steamless.Unpacker.Variant30.x86/Classes/SteamStubHeader.cs
@@ -0,0 +1,81 @@
+/**
+ * Steamless - Copyright (c) 2015 - 2017 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.Unpacker.Variant30.x86.Classes
+{
+ using System.Runtime.InteropServices;
+
+ ///
+ /// SteamStub DRM Variant 3.0 Header
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ public struct SteamStub32Var30Header
+ {
+ public uint XorKey; // The base XOR key, if defined, to unpack the file with.
+ public uint Signature; // 0xC0DEC0DE signature to validate this header is proper.
+ public ulong ImageBase; // The base of the image that is protected.
+ public uint AddressOfEntryPoint; // The entry point that is set from the DRM.
+ public uint BindSectionOffset; // The starting offset to the bind section data. RVA(AddressOfEntryPoint - BindSectionOffset)
+ public uint Unknown0000; // [Cyanic: This field is most likely the .bind code size.]
+ public uint OriginalEntryPoint; // The original entry point of the binary before it was protected.
+ public uint Unknown0001; // [Cyanic: This field is most likely an offset to a string table.]
+ public uint PayloadSize; // The size of the payload data.
+ public uint DRMPDllOffset; // The offset to the SteamDRMP.dll file.
+ public uint DRMPDllSize; // The size of the SteamDRMP.dll file.
+ public uint SteamAppId; // The Steam Application ID of this game.
+ public uint Flags; // The DRM flags used while creating the protected executable.
+ public uint BindSectionVirtualSize; // The bind section virtual size.
+ public uint Unknown0002; // [Cyanic: This field is most likely a hash of some sort.]
+ public uint CodeSectionVirtualAddress; // The cpde section virtual address.
+ public uint CodeSectionRawSize; // The raw size of the code section.
+
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x20)]
+ public byte[] AES_Key; // The AES encryption key.
+
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x10)]
+ public byte[] AES_IV; // The AES encryption IV.
+
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x10)]
+ public byte[] CodeSectionStolenData; // The first 16 bytes of the code section stolen.
+
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x04)]
+ public uint[] EncryptionKeys; // Encryption keys used for decrypting SteamDRMP.dll file.
+
+ public uint Unknown0003; // [Cyanic: This field is most likely used to flag if the file has Tls data or not.]
+ public uint Unknown0004;
+ public uint Unknown0005;
+ public uint Unknown0006;
+ public uint Unknown0007;
+ public uint Unknown0008;
+ public uint GetModuleHandleA_RVA; // The RVA to GetModuleHandleA.
+ public uint GetModuleHandleW_RVA; // The RVA to GetModuleHandleW.
+ public uint LoadLibraryA_RVA; // The RVA to LoadLibraryA.
+ public uint LoadLibraryW_RVA; // The RVA to LoadLibraryW.
+ public uint GetProcAddress_RVA; // The RVA to GetProcAddress.
+ public uint Unknown0009;
+ public uint Unknown0010;
+ public uint Unknown0011;
+ }
+}
\ No newline at end of file
diff --git a/Steamless.Unpacker.Variant30.x86/Classes/SteamStubHelpers.cs b/Steamless.Unpacker.Variant30.x86/Classes/SteamStubHelpers.cs
new file mode 100644
index 0000000..59aa691
--- /dev/null
+++ b/Steamless.Unpacker.Variant30.x86/Classes/SteamStubHelpers.cs
@@ -0,0 +1,122 @@
+/**
+ * Steamless - Copyright (c) 2015 - 2017 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.Unpacker.Variant30.x86.Classes
+{
+ using System;
+
+ public static class SteamStubHelpers
+ {
+ ///
+ /// Xor decrypts the given data starting with the given key, if any.
+ ///
+ /// @note If no key is given (0) then the first key is read from the first
+ /// 4 bytes inside of the data given.
+ ///
+ /// The data to xor decode.
+ /// The size of the data to decode.
+ /// The starting xor key to decode with.
+ ///
+ public static uint SteamXor(ref byte[] data, uint size, uint key = 0)
+ {
+ var offset = (uint)0;
+
+ // Read the first key as the base xor key if we had none given..
+ if (key == 0)
+ {
+ offset += 4;
+ key = BitConverter.ToUInt32(data, 0);
+ }
+
+ // Decode the data..
+ for (var x = offset; x < size; x += 4)
+ {
+ var val = BitConverter.ToUInt32(data, (int)x);
+ Array.Copy(BitConverter.GetBytes(val ^ key), 0, data, x, 4);
+
+ key = val;
+ }
+
+ return key;
+ }
+
+ ///
+ /// The second pass of decryption for the SteamDRMP.dll file.
+ ///
+ /// @note The encryption method here is known as XTEA.
+ ///
+ /// The result value buffer to write our returns to.
+ /// The keys used for the decryption.
+ /// The first value to decrypt from.
+ /// The second value to decrypt from.
+ /// The number of passes to crypt the data with.
+ public static void SteamDrmpDecryptPass2(ref uint[] res, uint[] keys, uint v1, uint v2, uint n = 32)
+ {
+ const uint delta = 0x9E3779B9;
+ const uint mask = 0xFFFFFFFF;
+ var sum = (delta * n) & mask;
+
+ for (var x = 0; x < n; x++)
+ {
+ v2 = (v2 - (((v1 << 4 ^ v1 >> 5) + v1) ^ (sum + keys[sum >> 11 & 3]))) & mask;
+ sum = (sum - delta) & mask;
+ v1 = (v1 - (((v2 << 4 ^ v2 >> 5) + v2) ^ (sum + keys[sum & 3]))) & mask;
+ }
+
+ res[0] = v1;
+ res[1] = v2;
+ }
+
+ ///
+ /// The first pass of the decryption for the SteamDRMP.dll file.
+ ///
+ /// @note The encryption method here is known as XTEA. It is modded to include
+ /// some basic xor'ing.
+ ///
+ /// The data to decrypt.
+ /// The size of the data to decrypt.
+ /// The keys used for the decryption.
+ public static void SteamDrmpDecryptPass1(ref byte[] data, uint size, uint[] keys)
+ {
+ var v1 = (uint)0x55555555;
+ var v2 = (uint)0x55555555;
+
+ for (var x = 0; x < size; x += 8)
+ {
+ var d1 = BitConverter.ToUInt32(data, x + 0);
+ var d2 = BitConverter.ToUInt32(data, x + 4);
+
+ var res = new uint[2];
+ SteamDrmpDecryptPass2(ref res, keys, d1, d2);
+
+ Array.Copy(BitConverter.GetBytes(res[0] ^ v1), 0, data, x + 0, 4);
+ Array.Copy(BitConverter.GetBytes(res[1] ^ v2), 0, data, x + 4, 4);
+
+ v1 = d1;
+ v2 = d2;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Steamless.Unpacker.Variant30.x86/Main.cs b/Steamless.Unpacker.Variant30.x86/Main.cs
new file mode 100644
index 0000000..c556143
--- /dev/null
+++ b/Steamless.Unpacker.Variant30.x86/Main.cs
@@ -0,0 +1,496 @@
+/**
+ * Steamless - Copyright (c) 2015 - 2017 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.Unpacker.Variant30.x86
+{
+ using API;
+ using API.Crypto;
+ using API.Events;
+ using API.Extensions;
+ using API.Model;
+ using API.PE32;
+ using API.Services;
+ using Classes;
+ using System;
+ using System.IO;
+ using System.Security.Cryptography;
+
+ [SteamlessApiVersion(1, 0)]
+ public class Main : SteamlessPlugin
+ {
+ ///
+ /// Internal logging service instance.
+ ///
+ private LoggingService m_LoggingService;
+
+ ///
+ /// Gets the author of this plugin.
+ ///
+ public override string Author => "atom0s";
+
+ ///
+ /// Gets the name of this plugin.
+ ///
+ public override string Name => "SteamStub Variant 3.0 Unpacker (x86)";
+
+ ///
+ /// Gets the description of this plugin.
+ ///
+ public override string Description => "Unpacker for the 32bit SteamStub variant 3.0.";
+
+ ///
+ /// Gets the version of this plugin.
+ ///
+ public override Version Version => new Version(1, 0, 0, 0);
+
+ ///
+ /// Internal wrapper to log a message.
+ ///
+ ///
+ ///
+ private void Log(string msg, LogMessageType type)
+ {
+ this.m_LoggingService.OnAddLogMessage(this, new LogMessageEventArgs(msg, type));
+ }
+
+ ///
+ /// Initialize function called when this plugin is first loaded.
+ ///
+ ///
+ ///
+ public override bool Initialize(LoggingService logService)
+ {
+ this.m_LoggingService = logService;
+ return true;
+ }
+
+ ///
+ /// Processing function called when a file is being unpacked. Allows plugins to check the file
+ /// and see if it can handle the file for its intended purpose.
+ ///
+ ///
+ ///
+ public override bool CanProcessFile(string file)
+ {
+ try
+ {
+ // Load the file..
+ var f = new Pe32File(file);
+ if (!f.Parse() || f.IsFile64Bit() || !f.HasSection(".bind"))
+ return false;
+
+ // Obtain the bind section data..
+ var bind = f.GetSectionData(".bind");
+
+ // Attempt to locate the known v3.x signature..
+ var varient = Pe32Helpers.FindPattern(bind, "E8 00 00 00 00 50 53 51 52 56 57 55 8B 44 24 1C 2D 05 00 00 00 8B CC 83 E4 F0 51 51 51 50");
+ if (varient == 0) return false;
+
+ // Attempt to determine the varient version..
+ int headerSize;
+ var offset = Pe32Helpers.FindPattern(bind, "55 8B EC 81 EC ?? ?? ?? ?? 53 ?? ?? ?? ?? ?? 68");
+ if (offset == 0)
+ {
+ offset = Pe32Helpers.FindPattern(bind, "55 8B EC 81 EC ?? ?? ?? ?? 53 ?? ?? ?? ?? ?? 8D 83");
+ if (offset == 0)
+ return false;
+
+ headerSize = BitConverter.ToInt32(bind, (int)offset + 22);
+ }
+ else
+ headerSize = BitConverter.ToInt32(bind, (int)offset + 16);
+
+ return headerSize == 0xB0 || headerSize == 0xD0;
+ }
+ catch
+ {
+ return false;
+ }
+ }
+
+ ///
+ /// Processing function called to allow the plugin to process the file.
+ ///
+ ///
+ ///
+ ///
+ public override bool ProcessFile(string file, SteamlessOptions options)
+ {
+ // Initialize the class members..
+ this.Options = options;
+ this.CodeSectionData = null;
+ this.CodeSectionIndex = -1;
+ this.XorKey = 0;
+
+ // Parse the file..
+ this.File = new Pe32File(file);
+ if (!this.File.Parse())
+ return false;
+
+ // Announce we are being unpacked with this packer..
+ this.Log("File is packed with SteamStub Variant 3.0!", LogMessageType.Information);
+
+ this.Log("Step 1 - Read, decode and validate the SteamStub DRM header.", LogMessageType.Information);
+ if (!this.Step1())
+ return false;
+
+ this.Log("Step 2 - Read, decode and process the payload data.", LogMessageType.Information);
+ if (!this.Step2())
+ return false;
+
+ this.Log("Step 3 - Read, decode and dump the SteamDRMP.dll file.", LogMessageType.Information);
+ if (!this.Step3())
+ return false;
+
+ this.Log("Step 4 - Handle .bind section. Find code section.", LogMessageType.Information);
+ if (!this.Step4())
+ return false;
+
+ this.Log("Step 5 - Read, decrypt and process code section.", LogMessageType.Information);
+ if (!this.Step5())
+ return false;
+
+ this.Log("Step 6 - Rebuild and save the unpacked file.", LogMessageType.Information);
+ if (!this.Step6())
+ return false;
+
+ return true;
+ }
+
+ ///
+ /// Step #1
+ ///
+ /// Read, decode and validate the SteamStub DRM header.
+ ///
+ ///
+ private bool Step1()
+ {
+ // Obtain the DRM header data..
+ var fileOffset = this.File.GetFileOffsetFromRva(this.File.NtHeaders.OptionalHeader.AddressOfEntryPoint);
+ var headerData = new byte[0xD0];
+ Array.Copy(this.File.FileData, (int)(fileOffset - 0xD0), headerData, 0, 0xD0);
+
+ // Xor decode the header data..
+ this.XorKey = SteamStubHelpers.SteamXor(ref headerData, 0xD0);
+ this.StubHeader = Pe32Helpers.GetStructure(headerData);
+
+ // Validate the structure signature..
+ return this.StubHeader.Signature == 0xC0DEC0DE;
+ }
+
+ ///
+ /// Step #2
+ ///
+ /// Read, decode and process the payload data.
+ ///
+ ///
+ private bool Step2()
+ {
+ // Obtain the payload address and size..
+ var payloadAddr = this.File.GetFileOffsetFromRva(this.File.NtHeaders.OptionalHeader.AddressOfEntryPoint - this.StubHeader.BindSectionOffset);
+ var payloadSize = (this.StubHeader.PayloadSize + 0x0F) & 0xFFFFFFF0;
+
+ // Do nothing if there is no payload..
+ if (payloadSize == 0)
+ return true;
+
+ this.Log(" --> File has payload data!", LogMessageType.Debug);
+
+ // Obtain and decode the payload..
+ var payload = new byte[payloadSize];
+ Array.Copy(this.File.FileData, payloadAddr, payload, 0, payloadSize);
+ this.XorKey = SteamStubHelpers.SteamXor(ref payload, payloadSize, this.XorKey);
+
+ try
+ {
+ if (this.Options.DumpPayloadToDisk)
+ {
+ System.IO.File.WriteAllBytes(this.File.FilePath + ".payload", payload);
+ this.Log(" --> Saved payload to disk!", LogMessageType.Debug);
+ }
+ }
+ catch
+ {
+ // Do nothing here since it doesn't matter if this fails..
+ }
+
+ return true;
+ }
+
+ ///
+ /// Step #3
+ ///
+ /// Read, decode and dump the SteamDRMP.dll file.
+ ///
+ ///
+ private bool Step3()
+ {
+ // Ensure there is a dll to process..
+ if (this.StubHeader.DRMPDllSize == 0)
+ {
+ this.Log(" --> File does not contain a SteamDRMP.dll file.", LogMessageType.Debug);
+ return true;
+ }
+
+ this.Log(" --> File has SteamDRMP.dll file!", LogMessageType.Debug);
+
+ try
+ {
+ // Obtain the SteamDRMP.dll file address and data..
+ var drmpAddr = this.File.GetFileOffsetFromRva(this.File.NtHeaders.OptionalHeader.AddressOfEntryPoint - this.StubHeader.BindSectionOffset + this.StubHeader.DRMPDllOffset);
+ var drmpData = new byte[this.StubHeader.DRMPDllSize];
+ Array.Copy(this.File.FileData, drmpAddr, drmpData, 0, drmpData.Length);
+
+ // Decrypt the data (xtea decryption)..
+ SteamStubHelpers.SteamDrmpDecryptPass1(ref drmpData, this.StubHeader.DRMPDllSize, this.StubHeader.EncryptionKeys);
+
+ try
+ {
+ if (this.Options.DumpSteamDrmpToDisk)
+ {
+ var basePath = Path.GetDirectoryName(this.File.FilePath) ?? string.Empty;
+ System.IO.File.WriteAllBytes(Path.Combine(basePath, "SteamDRMP.dll"), drmpData);
+ this.Log(" --> Saved SteamDRMP.dll to disk!", LogMessageType.Debug);
+ }
+ }
+ catch
+ {
+ // Do nothing here since it doesn't matter if this fails..
+ }
+
+ return true;
+ }
+ catch
+ {
+ this.Log(" --> Error trying to decrypt the files SteamDRMP.dll data!", LogMessageType.Error);
+ return false;
+ }
+ }
+
+ ///
+ /// Step #4
+ ///
+ /// Remove the bind section if requested.
+ /// Find the code section.
+ ///
+ ///
+ private bool Step4()
+ {
+ // Remove the bind section if its not requested to be saved..
+ if (!this.Options.KeepBindSection)
+ {
+ // Obtain the .bind section..
+ var bindSection = this.File.GetSection(".bind");
+ if (!bindSection.IsValid)
+ return false;
+
+ // Remove the section..
+ this.File.RemoveSection(bindSection);
+
+ // Decrease the header section count..
+ var ntHeaders = this.File.NtHeaders;
+ ntHeaders.FileHeader.NumberOfSections--;
+ this.File.NtHeaders = ntHeaders;
+
+ this.Log(" --> .bind section was removed from the file.", LogMessageType.Debug);
+ }
+ else
+ this.Log(" --> .bind section was kept in the file.", LogMessageType.Debug);
+
+ // Skip finding the code section if the file is not encrypted..
+ if ((this.StubHeader.Flags & (uint)SteamStubDrmFlags.NoEncryption) == (uint)SteamStubDrmFlags.NoEncryption)
+ return true;
+
+ // Find the code section..
+ var codeSection = this.File.GetOwnerSection(this.StubHeader.CodeSectionVirtualAddress);
+ if (codeSection.PointerToRawData == 0 || codeSection.SizeOfRawData == 0)
+ return false;
+
+ // Store the code sections index..
+ this.CodeSectionIndex = this.File.GetSectionIndex(codeSection);
+
+ return true;
+ }
+
+ ///
+ /// Step #5
+ ///
+ /// Read, decrypt and process the code section.
+ ///
+ ///
+ private bool Step5()
+ {
+ // Skip decryption if the code section is not encrypted..
+ if ((this.StubHeader.Flags & (uint)SteamStubDrmFlags.NoEncryption) == (uint)SteamStubDrmFlags.NoEncryption)
+ {
+ this.Log(" --> Code section is not encrypted.", LogMessageType.Debug);
+ return true;
+ }
+
+ try
+ {
+ // Obtain the code section..
+ var codeSection = this.File.Sections[this.CodeSectionIndex];
+ this.Log($" --> {codeSection.SectionName} linked as main code section.", LogMessageType.Debug);
+ this.Log($" --> {codeSection.SectionName} section is encrypted.", LogMessageType.Debug);
+
+ // Obtain the code section data..
+ var codeSectionData = new byte[codeSection.SizeOfRawData + this.StubHeader.CodeSectionStolenData.Length];
+ Array.Copy(this.StubHeader.CodeSectionStolenData, 0, codeSectionData, 0, this.StubHeader.CodeSectionStolenData.Length);
+ Array.Copy(this.File.FileData, this.File.GetFileOffsetFromRva(codeSection.VirtualAddress), codeSectionData, this.StubHeader.CodeSectionStolenData.Length, codeSection.SizeOfRawData);
+
+ // Create the AES decryption helper..
+ var aes = new AesHelper(this.StubHeader.AES_Key, this.StubHeader.AES_IV);
+ aes.RebuildIv(this.StubHeader.AES_IV);
+
+ // Decrypt the code section data..
+ var data = aes.Decrypt(codeSectionData, CipherMode.CBC, PaddingMode.None);
+ if (data == null)
+ return false;
+
+ // Set the code section override data..
+ this.CodeSectionData = data;
+
+ return true;
+ }
+ catch
+ {
+ this.Log(" --> Error trying to decrypt the files code section data!", LogMessageType.Error);
+ return false;
+ }
+ }
+
+ ///
+ /// Step #6
+ ///
+ /// Rebuild and save the unpacked file.
+ ///
+ ///
+ private bool Step6()
+ {
+ FileStream fStream = null;
+
+ try
+ {
+ // Rebuild the file sections..
+ this.File.RebuildSections();
+
+ // Open the unpacked file for writing..
+ var unpackedPath = this.File.FilePath + ".unpacked.exe";
+ fStream = new FileStream(unpackedPath, FileMode.Create, FileAccess.ReadWrite);
+
+ // Write the DOS header to the file..
+ fStream.WriteBytes(Pe32Helpers.GetStructureBytes(this.File.DosHeader));
+
+ // Write the DOS stub to the file..
+ if (this.File.DosStubSize > 0)
+ fStream.WriteBytes(this.File.DosStubData);
+
+ // Update the entry point of the file..
+ var ntHeaders = this.File.NtHeaders;
+ ntHeaders.OptionalHeader.AddressOfEntryPoint = this.StubHeader.OriginalEntryPoint;
+ this.File.NtHeaders = ntHeaders;
+
+ // Write the NT headers to the file..
+ fStream.WriteBytes(Pe32Helpers.GetStructureBytes(ntHeaders));
+
+ // Write the sections to the file..
+ for (var x = 0; x < this.File.Sections.Count; x++)
+ {
+ var section = this.File.Sections[x];
+ var sectionData = this.File.SectionData[x];
+
+ // Write the section header to the file..
+ fStream.WriteBytes(Pe32Helpers.GetStructureBytes(section));
+
+ // Set the file pointer to the sections raw data..
+ var sectionOffset = fStream.Position;
+ fStream.Position = section.PointerToRawData;
+
+ // Write the sections raw data..
+ var sectionIndex = this.File.Sections.IndexOf(section);
+ if (sectionIndex == this.CodeSectionIndex)
+ fStream.WriteBytes(this.CodeSectionData ?? sectionData);
+ else
+ fStream.WriteBytes(sectionData);
+
+ // Reset the file offset..
+ fStream.Position = sectionOffset;
+ }
+
+ // Set the stream to the end of the file..
+ fStream.Position = fStream.Length;
+
+ // Write the overlay data if it exists..
+ if (this.File.OverlayData != null)
+ fStream.WriteBytes(this.File.OverlayData);
+
+ this.Log(" --> Unpacked file saved to disk!", LogMessageType.Success);
+ this.Log($" --> File Saved As: {unpackedPath}", LogMessageType.Success);
+
+ return true;
+ }
+ catch
+ {
+ this.Log(" --> Error trying to save unpacked file!", LogMessageType.Error);
+ return false;
+ }
+ finally
+ {
+ fStream?.Dispose();
+ }
+ }
+
+ ///
+ /// Gets or sets the Steamless options this file was requested to process with.
+ ///
+ private SteamlessOptions Options { get; set; }
+
+ ///
+ /// Gets or sets the file being processed.
+ ///
+ private Pe32File File { get; set; }
+
+ ///
+ /// Gets or sets the current xor key being used against the file data.
+ ///
+ private uint XorKey { get; set; }
+
+ ///
+ /// Gets or sets the DRM stub header.
+ ///
+ private SteamStub32Var30Header StubHeader { get; set; }
+
+ ///
+ /// Gets or sets the index of the code section.
+ ///
+ private int CodeSectionIndex { get; set; }
+
+ ///
+ /// Gets or sets the decrypted code section data.
+ ///
+ private byte[] CodeSectionData { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/Steamless.Unpacker.Variant30.x86/Properties/AssemblyInfo.cs b/Steamless.Unpacker.Variant30.x86/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..820340d
--- /dev/null
+++ b/Steamless.Unpacker.Variant30.x86/Properties/AssemblyInfo.cs
@@ -0,0 +1,40 @@
+/**
+ * Steamless - Copyright (c) 2015 - 2017 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.Unpacker.Variant30.x86")]
+[assembly: AssemblyDescription("Steamless SteamStub Variant v3.0 (x86) Unpacker")]
+[assembly: AssemblyConfiguration("Release")]
+[assembly: AssemblyCompany("atom0s")]
+[assembly: AssemblyProduct("Steamless.Unpacker.Variant30.x86")]
+[assembly: AssemblyCopyright("Copyright © atom0s 2015 - 2017")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+[assembly: ComVisible(false)]
+[assembly: Guid("b6bb7a32-ab23-4a25-8914-154879aad3fe")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
\ No newline at end of file
diff --git a/Steamless.Unpacker.Variant30.x86/Steamless.Unpacker.Variant30.x86.csproj b/Steamless.Unpacker.Variant30.x86/Steamless.Unpacker.Variant30.x86.csproj
new file mode 100644
index 0000000..91632ec
--- /dev/null
+++ b/Steamless.Unpacker.Variant30.x86/Steamless.Unpacker.Variant30.x86.csproj
@@ -0,0 +1,57 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {B6BB7A32-AB23-4A25-8914-154879AAD3FE}
+ Library
+ Properties
+ Steamless.Unpacker.Variant30.x86
+ Steamless.Unpacker.Variant30.x86
+ v4.5.2
+ 512
+
+
+ x86
+ ..\Steamless\bin\x86\Debug\Plugins\
+ DEBUG;TRACE
+
+
+ x86
+ ..\Steamless\bin\x86\Release\Plugins\
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {56c95629-3b34-47fe-b988-04274409294f}
+ Steamless.API
+ False
+
+
+
+
+
\ No newline at end of file
diff --git a/Steamless.Unpacker.Variant31.x86/Classes/SteamStubDrmFlags.cs b/Steamless.Unpacker.Variant31.x86/Classes/SteamStubDrmFlags.cs
new file mode 100644
index 0000000..8db25a6
--- /dev/null
+++ b/Steamless.Unpacker.Variant31.x86/Classes/SteamStubDrmFlags.cs
@@ -0,0 +1,39 @@
+/**
+ * Steamless - Copyright (c) 2015 - 2017 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.Unpacker.Variant31.x86.Classes
+{
+ ///
+ /// Steam Stub Variant 3.1 DRM Flags
+ ///
+ public enum SteamStubDrmFlags
+ {
+ NoModuleVerification = 0x02,
+ NoEncryption = 0x04,
+ NoOwnershipCheck = 0x10,
+ NoDebuggerCheck = 0x20,
+ NoErrorDialog = 0x40
+ }
+}
\ No newline at end of file
diff --git a/Steamless.Unpacker.Variant31.x86/Classes/SteamStubHeader.cs b/Steamless.Unpacker.Variant31.x86/Classes/SteamStubHeader.cs
new file mode 100644
index 0000000..34b2179
--- /dev/null
+++ b/Steamless.Unpacker.Variant31.x86/Classes/SteamStubHeader.cs
@@ -0,0 +1,75 @@
+/**
+ * Steamless - Copyright (c) 2015 - 2017 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.Unpacker.Variant31.x86.Classes
+{
+ using System.Runtime.InteropServices;
+
+ ///
+ /// SteamStub DRM Variant 3.1 Header
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ public struct SteamStub32Var31Header
+ {
+ public uint XorKey; // The base xor key, if defined, to unpack the file with.
+ public uint Signature; // The signature to ensure the xor decoding was successful.
+ public ulong ImageBase; // The base of the image that was protected.
+ public ulong AddressOfEntryPoint; // The entry point that is set from the DRM.
+ public uint BindSectionOffset; // The starting offset to the .bind section data. RVA(AddressOfEntryPoint - BindSectionOffset)
+ public uint Unknown0000; // [Cyanic: This field is most likely the .bind code size.]
+ public ulong OriginalEntryPoint; // The original entry point of the binary before it was protected.
+ public uint Unknown0001; // [Cyanic: This field is most likely an offset to a string table.]
+ public uint PayloadSize; // The size of the payload data.
+ public uint DRMPDllOffset; // The offset to the SteamDrmp.dll file.
+ public uint DRMPDllSize; // The size of the SteamDrmp.dll file.
+ public uint SteamAppId; // The Steam application id of this program.
+ public uint Flags; // The DRM flags used while protecting this program.
+ public uint BindSectionVirtualSize; // The .bind section virtual size.
+ public uint Unknown0002; // [Cyanic: This field is most likely a hash of some sort.]
+ public ulong CodeSectionVirtualAddress; // The code section virtual address.
+ public ulong CodeSectionRawSize; // The code section raw size.
+
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x20)]
+ public byte[] AES_Key; // The AES encryption key.
+
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x10)]
+ public byte[] AES_IV; // The AES encryption IV.
+
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x10)]
+ public byte[] CodeSectionStolenData; // The first 16 bytes of the code section stolen.
+
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x04)]
+ public uint[] EncryptionKeys; // Encryption keys used to decrypt the SteamDrmp.dll file.
+
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x08)]
+ public uint[] Unknown0003; // Unknown unused data.
+
+ public ulong GetModuleHandleA_Rva; // The rva to GetModuleHandleA.
+ public ulong GetModuleHandleW_Rva; // The rva to GetModuleHandleW.
+ public ulong LoadLibraryA_Rva; // The rva to LoadLibraryA.
+ public ulong LoadLibraryW_Rva; // The rva to LoadLibraryW.
+ public ulong GetProcAddress_Rva; // The rva to GetProcAddress.
+ }
+}
\ No newline at end of file
diff --git a/Steamless.Unpacker.Variant31.x86/Classes/SteamStubHelpers.cs b/Steamless.Unpacker.Variant31.x86/Classes/SteamStubHelpers.cs
new file mode 100644
index 0000000..d865f9c
--- /dev/null
+++ b/Steamless.Unpacker.Variant31.x86/Classes/SteamStubHelpers.cs
@@ -0,0 +1,122 @@
+/**
+ * Steamless - Copyright (c) 2015 - 2017 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.Unpacker.Variant31.x86.Classes
+{
+ using System;
+
+ public static class SteamStubHelpers
+ {
+ ///
+ /// Xor decrypts the given data starting with the given key, if any.
+ ///
+ /// @note If no key is given (0) then the first key is read from the first
+ /// 4 bytes inside of the data given.
+ ///
+ /// The data to xor decode.
+ /// The size of the data to decode.
+ /// The starting xor key to decode with.
+ ///
+ public static uint SteamXor(ref byte[] data, uint size, uint key = 0)
+ {
+ var offset = (uint)0;
+
+ // Read the first key as the base xor key if we had none given..
+ if (key == 0)
+ {
+ offset += 4;
+ key = BitConverter.ToUInt32(data, 0);
+ }
+
+ // Decode the data..
+ for (var x = offset; x < size; x += 4)
+ {
+ var val = BitConverter.ToUInt32(data, (int)x);
+ Array.Copy(BitConverter.GetBytes(val ^ key), 0, data, x, 4);
+
+ key = val;
+ }
+
+ return key;
+ }
+
+ ///
+ /// The second pass of decryption for the SteamDRMP.dll file.
+ ///
+ /// @note The encryption method here is known as XTEA.
+ ///
+ /// The result value buffer to write our returns to.
+ /// The keys used for the decryption.
+ /// The first value to decrypt from.
+ /// The second value to decrypt from.
+ /// The number of passes to crypt the data with.
+ public static void SteamDrmpDecryptPass2(ref uint[] res, uint[] keys, uint v1, uint v2, uint n = 32)
+ {
+ const uint delta = 0x9E3779B9;
+ const uint mask = 0xFFFFFFFF;
+ var sum = (delta * n) & mask;
+
+ for (var x = 0; x < n; x++)
+ {
+ v2 = (v2 - (((v1 << 4 ^ v1 >> 5) + v1) ^ (sum + keys[sum >> 11 & 3]))) & mask;
+ sum = (sum - delta) & mask;
+ v1 = (v1 - (((v2 << 4 ^ v2 >> 5) + v2) ^ (sum + keys[sum & 3]))) & mask;
+ }
+
+ res[0] = v1;
+ res[1] = v2;
+ }
+
+ ///
+ /// The first pass of the decryption for the SteamDRMP.dll file.
+ ///
+ /// @note The encryption method here is known as XTEA. It is modded to include
+ /// some basic xor'ing.
+ ///
+ /// The data to decrypt.
+ /// The size of the data to decrypt.
+ /// The keys used for the decryption.
+ public static void SteamDrmpDecryptPass1(ref byte[] data, uint size, uint[] keys)
+ {
+ var v1 = (uint)0x55555555;
+ var v2 = (uint)0x55555555;
+
+ for (var x = 0; x < size; x += 8)
+ {
+ var d1 = BitConverter.ToUInt32(data, x + 0);
+ var d2 = BitConverter.ToUInt32(data, x + 4);
+
+ var res = new uint[2];
+ SteamDrmpDecryptPass2(ref res, keys, d1, d2);
+
+ Array.Copy(BitConverter.GetBytes(res[0] ^ v1), 0, data, x + 0, 4);
+ Array.Copy(BitConverter.GetBytes(res[1] ^ v2), 0, data, x + 4, 4);
+
+ v1 = d1;
+ v2 = d2;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Steamless.Unpacker.Variant31.x86/Main.cs b/Steamless.Unpacker.Variant31.x86/Main.cs
new file mode 100644
index 0000000..cfadc18
--- /dev/null
+++ b/Steamless.Unpacker.Variant31.x86/Main.cs
@@ -0,0 +1,532 @@
+/**
+ * Steamless - Copyright (c) 2015 - 2017 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.Unpacker.Variant31.x86
+{
+ using API;
+ using API.Crypto;
+ using API.Events;
+ using API.Extensions;
+ using API.Model;
+ using API.PE32;
+ using API.Services;
+ using Classes;
+ using System;
+ using System.IO;
+ using System.Security.Cryptography;
+
+ [SteamlessApiVersion(1, 0)]
+ public class Main : SteamlessPlugin
+ {
+ ///
+ /// Internal logging service instance.
+ ///
+ private LoggingService m_LoggingService;
+
+ ///
+ /// Gets the author of this plugin.
+ ///
+ public override string Author => "atom0s";
+
+ ///
+ /// Gets the name of this plugin.
+ ///
+ public override string Name => "SteamStub Variant 3.1 Unpacker (x86)";
+
+ ///
+ /// Gets the description of this plugin.
+ ///
+ public override string Description => "Unpacker for the 32bit SteamStub variant 3.1.";
+
+ ///
+ /// Gets the version of this plugin.
+ ///
+ public override Version Version => new Version(1, 0, 0, 1);
+
+ ///
+ /// Internal wrapper to log a message.
+ ///
+ ///
+ ///
+ private void Log(string msg, LogMessageType type)
+ {
+ this.m_LoggingService.OnAddLogMessage(this, new LogMessageEventArgs(msg, type));
+ }
+
+ ///
+ /// Initialize function called when this plugin is first loaded.
+ ///
+ ///
+ ///
+ public override bool Initialize(LoggingService logService)
+ {
+ this.m_LoggingService = logService;
+ return true;
+ }
+
+ ///
+ /// Processing function called when a file is being unpacked. Allows plugins to check the file
+ /// and see if it can handle the file for its intended purpose.
+ ///
+ ///
+ ///
+ public override bool CanProcessFile(string file)
+ {
+ try
+ {
+ // Load the file..
+ var f = new Pe32File(file);
+ if (!f.Parse() || f.IsFile64Bit() || !f.HasSection(".bind"))
+ return false;
+
+ // Obtain the bind section data..
+ var bind = f.GetSectionData(".bind");
+
+ // Attempt to locate the known v3.x signature..
+ var varient = Pe32Helpers.FindPattern(bind, "E8 00 00 00 00 50 53 51 52 56 57 55 8B 44 24 1C 2D 05 00 00 00 8B CC 83 E4 F0 51 51 51 50");
+ if (varient == 0) return false;
+
+ // Attempt to determine the varient version..
+ int headerSize;
+ var offset = Pe32Helpers.FindPattern(bind, "55 8B EC 81 EC ?? ?? ?? ?? 53 ?? ?? ?? ?? ?? 68");
+ if (offset == 0)
+ {
+ offset = Pe32Helpers.FindPattern(bind, "55 8B EC 81 EC ?? ?? ?? ?? 53 ?? ?? ?? ?? ?? 8D 83");
+ if (offset == 0)
+ return false;
+
+ headerSize = BitConverter.ToInt32(bind, (int)offset + 22);
+ }
+ else
+ headerSize = BitConverter.ToInt32(bind, (int)offset + 16);
+
+ return headerSize == 0xF0;
+ }
+ catch
+ {
+ return false;
+ }
+ }
+
+ ///
+ /// Processing function called to allow the plugin to process the file.
+ ///
+ ///
+ ///
+ ///
+ public override bool ProcessFile(string file, SteamlessOptions options)
+ {
+ // Initialize the class members..
+ this.TlsAsOep = false;
+ this.TlsOepRva = 0;
+ this.Options = options;
+ this.CodeSectionData = null;
+ this.CodeSectionIndex = -1;
+ this.XorKey = 0;
+
+ // Parse the file..
+ this.File = new Pe32File(file);
+ if (!this.File.Parse())
+ return false;
+
+ // Announce we are being unpacked with this packer..
+ this.Log("File is packed with SteamStub Variant 3.1!", LogMessageType.Information);
+
+ this.Log("Step 1 - Read, decode and validate the SteamStub DRM header.", LogMessageType.Information);
+ if (!this.Step1())
+ return false;
+
+ this.Log("Step 2 - Read, decode and process the payload data.", LogMessageType.Information);
+ if (!this.Step2())
+ return false;
+
+ this.Log("Step 3 - Read, decode and dump the SteamDRMP.dll file.", LogMessageType.Information);
+ if (!this.Step3())
+ return false;
+
+ this.Log("Step 4 - Handle .bind section. Find code section.", LogMessageType.Information);
+ if (!this.Step4())
+ return false;
+
+ this.Log("Step 5 - Read, decrypt and process code section.", LogMessageType.Information);
+ if (!this.Step5())
+ return false;
+
+ this.Log("Step 6 - Rebuild and save the unpacked file.", LogMessageType.Information);
+ if (!this.Step6())
+ return false;
+
+ return true;
+ }
+
+ ///
+ /// Step #1
+ ///
+ /// Read, decode and validate the SteamStub DRM header.
+ ///
+ ///
+ private bool Step1()
+ {
+ // Obtain the DRM header data..
+ var fileOffset = this.File.GetFileOffsetFromRva(this.File.NtHeaders.OptionalHeader.AddressOfEntryPoint);
+ var headerData = new byte[0xF0];
+ Array.Copy(this.File.FileData, (int)(fileOffset - 0xF0), headerData, 0, 0xF0);
+
+ // Xor decode the header data..
+ this.XorKey = SteamStubHelpers.SteamXor(ref headerData, 0xF0);
+ this.StubHeader = Pe32Helpers.GetStructure(headerData);
+
+ // Validate the header signature..
+ if (this.StubHeader.Signature == 0xC0DEC0DF)
+ return true;
+
+ // Try again using the Tls callback (if any) as the OEP instead..
+ if (this.File.TlsCallbacks.Count == 0)
+ return false;
+
+ // Obtain the DRM header data..
+ fileOffset = this.File.GetRvaFromVa(this.File.TlsCallbacks[0]);
+ fileOffset = this.File.GetFileOffsetFromRva(fileOffset);
+ headerData = new byte[0xF0];
+ Array.Copy(this.File.FileData, (int)(fileOffset - 0xF0), headerData, 0, 0xF0);
+
+ // Xor decode the header data..
+ this.XorKey = SteamStubHelpers.SteamXor(ref headerData, 0xF0);
+ this.StubHeader = Pe32Helpers.GetStructure(headerData);
+
+ // Validate the header signature..
+ if (this.StubHeader.Signature != 0xC0DEC0DF)
+ return false;
+
+ // Tls was valid for the real oep..
+ this.TlsAsOep = true;
+ this.TlsOepRva = fileOffset;
+ return true;
+ }
+
+ ///
+ /// Step #2
+ ///
+ /// Read, decode and process the payload data.
+ ///
+ ///
+ private bool Step2()
+ {
+ // Obtain the payload address and size..
+ var payloadAddr = this.File.GetFileOffsetFromRva(this.TlsAsOep ? this.TlsOepRva : this.File.NtHeaders.OptionalHeader.AddressOfEntryPoint - this.StubHeader.BindSectionOffset);
+ var payloadSize = (this.StubHeader.PayloadSize + 0x0F) & 0xFFFFFFF0;
+
+ // Do nothing if there is no payload..
+ if (payloadSize == 0)
+ return true;
+
+ this.Log(" --> File has payload data!", LogMessageType.Debug);
+
+ // Obtain and decode the payload..
+ var payload = new byte[payloadSize];
+ Array.Copy(this.File.FileData, payloadAddr, payload, 0, payloadSize);
+ this.XorKey = SteamStubHelpers.SteamXor(ref payload, payloadSize, this.XorKey);
+
+ try
+ {
+ if (this.Options.DumpPayloadToDisk)
+ {
+ System.IO.File.WriteAllBytes(this.File.FilePath + ".payload", payload);
+ this.Log(" --> Saved payload to disk!", LogMessageType.Debug);
+ }
+ }
+ catch
+ {
+ // Do nothing here since it doesn't matter if this fails..
+ }
+
+ return true;
+ }
+
+ ///
+ /// Step #3
+ ///
+ /// Read, decode and dump the SteamDRMP.dll file.
+ ///
+ ///
+ private bool Step3()
+ {
+ // Ensure there is a dll to process..
+ if (this.StubHeader.DRMPDllSize == 0)
+ {
+ this.Log(" --> File does not contain a SteamDRMP.dll file.", LogMessageType.Debug);
+ return true;
+ }
+
+ this.Log(" --> File has SteamDRMP.dll file!", LogMessageType.Debug);
+
+ try
+ {
+ // Obtain the SteamDRMP.dll file address and data..
+ var drmpAddr = this.File.GetFileOffsetFromRva(this.TlsAsOep ? this.TlsOepRva : this.File.NtHeaders.OptionalHeader.AddressOfEntryPoint - this.StubHeader.BindSectionOffset + this.StubHeader.DRMPDllOffset);
+ var drmpData = new byte[this.StubHeader.DRMPDllSize];
+ Array.Copy(this.File.FileData, drmpAddr, drmpData, 0, drmpData.Length);
+
+ // Decrypt the data (xtea decryption)..
+ SteamStubHelpers.SteamDrmpDecryptPass1(ref drmpData, this.StubHeader.DRMPDllSize, this.StubHeader.EncryptionKeys);
+
+ try
+ {
+ if (this.Options.DumpSteamDrmpToDisk)
+ {
+ var basePath = Path.GetDirectoryName(this.File.FilePath) ?? string.Empty;
+ System.IO.File.WriteAllBytes(Path.Combine(basePath, "SteamDRMP.dll"), drmpData);
+ this.Log(" --> Saved SteamDRMP.dll to disk!", LogMessageType.Debug);
+ }
+ }
+ catch
+ {
+ // Do nothing here since it doesn't matter if this fails..
+ }
+
+ return true;
+ }
+ catch
+ {
+ this.Log(" --> Error trying to decrypt the files SteamDRMP.dll data!", LogMessageType.Error);
+ return false;
+ }
+ }
+
+ ///
+ /// Step #4
+ ///
+ /// Remove the bind section if requested.
+ /// Find the code section.
+ ///
+ ///
+ private bool Step4()
+ {
+ // Remove the bind section if its not requested to be saved..
+ if (!this.Options.KeepBindSection)
+ {
+ // Obtain the .bind section..
+ var bindSection = this.File.GetSection(".bind");
+ if (!bindSection.IsValid)
+ return false;
+
+ // Remove the section..
+ this.File.RemoveSection(bindSection);
+
+ // Decrease the header section count..
+ var ntHeaders = this.File.NtHeaders;
+ ntHeaders.FileHeader.NumberOfSections--;
+ this.File.NtHeaders = ntHeaders;
+
+ this.Log(" --> .bind section was removed from the file.", LogMessageType.Debug);
+ }
+ else
+ this.Log(" --> .bind section was kept in the file.", LogMessageType.Debug);
+
+ // Skip finding the code section if the file is not encrypted..
+ if ((this.StubHeader.Flags & (uint)SteamStubDrmFlags.NoEncryption) == (uint)SteamStubDrmFlags.NoEncryption)
+ return true;
+
+ // Find the code section..
+ var codeSection = this.File.GetOwnerSection(this.StubHeader.CodeSectionVirtualAddress);
+ if (codeSection.PointerToRawData == 0 || codeSection.SizeOfRawData == 0)
+ return false;
+
+ // Store the code sections index..
+ this.CodeSectionIndex = this.File.GetSectionIndex(codeSection);
+
+ return true;
+ }
+
+ ///
+ /// Step #5
+ ///
+ /// Read, decrypt and process the code section.
+ ///
+ ///
+ private bool Step5()
+ {
+ // Skip decryption if the code section is not encrypted..
+ if ((this.StubHeader.Flags & (uint)SteamStubDrmFlags.NoEncryption) == (uint)SteamStubDrmFlags.NoEncryption)
+ {
+ this.Log(" --> Code section is not encrypted.", LogMessageType.Debug);
+ return true;
+ }
+
+ try
+ {
+ // Obtain the code section..
+ var codeSection = this.File.Sections[this.CodeSectionIndex];
+ this.Log($" --> {codeSection.SectionName} linked as main code section.", LogMessageType.Debug);
+ this.Log($" --> {codeSection.SectionName} section is encrypted.", LogMessageType.Debug);
+
+ // Obtain the code section data..
+ var codeSectionData = new byte[codeSection.SizeOfRawData + this.StubHeader.CodeSectionStolenData.Length];
+ Array.Copy(this.StubHeader.CodeSectionStolenData, 0, codeSectionData, 0, this.StubHeader.CodeSectionStolenData.Length);
+ Array.Copy(this.File.FileData, this.File.GetFileOffsetFromRva(codeSection.VirtualAddress), codeSectionData, this.StubHeader.CodeSectionStolenData.Length, codeSection.SizeOfRawData);
+
+ // Create the AES decryption helper..
+ var aes = new AesHelper(this.StubHeader.AES_Key, this.StubHeader.AES_IV);
+ aes.RebuildIv(this.StubHeader.AES_IV);
+
+ // Decrypt the code section data..
+ var data = aes.Decrypt(codeSectionData, CipherMode.CBC, PaddingMode.None);
+ if (data == null)
+ return false;
+
+ // Set the code section override data..
+ this.CodeSectionData = data;
+
+ return true;
+ }
+ catch
+ {
+ this.Log(" --> Error trying to decrypt the files code section data!", LogMessageType.Error);
+ return false;
+ }
+ }
+
+ ///
+ /// Step #6
+ ///
+ /// Rebuild and save the unpacked file.
+ ///
+ ///
+ private bool Step6()
+ {
+ FileStream fStream = null;
+
+ try
+ {
+ // Rebuild the file sections..
+ this.File.RebuildSections();
+
+ // Open the unpacked file for writing..
+ var unpackedPath = this.File.FilePath + ".unpacked.exe";
+ fStream = new FileStream(unpackedPath, FileMode.Create, FileAccess.ReadWrite);
+
+ // Write the DOS header to the file..
+ fStream.WriteBytes(Pe32Helpers.GetStructureBytes(this.File.DosHeader));
+
+ // Write the DOS stub to the file..
+ if (this.File.DosStubSize > 0)
+ fStream.WriteBytes(this.File.DosStubData);
+
+ // Update the entry point of the file..
+ var ntHeaders = this.File.NtHeaders;
+ ntHeaders.OptionalHeader.AddressOfEntryPoint = (uint)this.StubHeader.OriginalEntryPoint;
+ this.File.NtHeaders = ntHeaders;
+
+ // Write the NT headers to the file..
+ fStream.WriteBytes(Pe32Helpers.GetStructureBytes(ntHeaders));
+
+ // Write the sections to the file..
+ for (var x = 0; x < this.File.Sections.Count; x++)
+ {
+ var section = this.File.Sections[x];
+ var sectionData = this.File.SectionData[x];
+
+ // Write the section header to the file..
+ fStream.WriteBytes(Pe32Helpers.GetStructureBytes(section));
+
+ // Set the file pointer to the sections raw data..
+ var sectionOffset = fStream.Position;
+ fStream.Position = section.PointerToRawData;
+
+ // Write the sections raw data..
+ var sectionIndex = this.File.Sections.IndexOf(section);
+ if (sectionIndex == this.CodeSectionIndex)
+ fStream.WriteBytes(this.CodeSectionData ?? sectionData);
+ else
+ fStream.WriteBytes(sectionData);
+
+ // Reset the file offset..
+ fStream.Position = sectionOffset;
+ }
+
+ // Set the stream to the end of the file..
+ fStream.Position = fStream.Length;
+
+ // Write the overlay data if it exists..
+ if (this.File.OverlayData != null)
+ fStream.WriteBytes(this.File.OverlayData);
+
+ this.Log(" --> Unpacked file saved to disk!", LogMessageType.Success);
+ this.Log($" --> File Saved As: {unpackedPath}", LogMessageType.Success);
+
+ return true;
+ }
+ catch
+ {
+ this.Log(" --> Error trying to save unpacked file!", LogMessageType.Error);
+ return false;
+ }
+ finally
+ {
+ fStream?.Dispose();
+ }
+ }
+
+ ///
+ /// Gets or sets if the Tls callback is being used as the Oep.
+ ///
+ private bool TlsAsOep { get; set; }
+
+ ///
+ /// Gets or sets the Tls Oep Rva if it is being used as the Oep.
+ ///
+ private uint TlsOepRva { get; set; }
+
+ ///
+ /// Gets or sets the Steamless options this file was requested to process with.
+ ///
+ private SteamlessOptions Options { get; set; }
+
+ ///
+ /// Gets or sets the file being processed.
+ ///
+ private Pe32File File { get; set; }
+
+ ///
+ /// Gets or sets the current xor key being used against the file data.
+ ///
+ private uint XorKey { get; set; }
+
+ ///
+ /// Gets or sets the DRM stub header.
+ ///
+ private SteamStub32Var31Header StubHeader { get; set; }
+
+ ///
+ /// Gets or sets the index of the code section.
+ ///
+ private int CodeSectionIndex { get; set; }
+
+ ///
+ /// Gets or sets the decrypted code section data.
+ ///
+ private byte[] CodeSectionData { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/Steamless.Unpacker.Variant31.x86/Properties/AssemblyInfo.cs b/Steamless.Unpacker.Variant31.x86/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..173a2ed
--- /dev/null
+++ b/Steamless.Unpacker.Variant31.x86/Properties/AssemblyInfo.cs
@@ -0,0 +1,40 @@
+/**
+ * Steamless - Copyright (c) 2015 - 2017 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.Unpacker.Variant31.x86")]
+[assembly: AssemblyDescription("Steamless SteamStub Variant v3.1 (x86) Unpacker")]
+[assembly: AssemblyConfiguration("Release")]
+[assembly: AssemblyCompany("atom0s")]
+[assembly: AssemblyProduct("Steamless.Unpacker.Variant31.x86")]
+[assembly: AssemblyCopyright("Copyright © atom0s 2015 - 2017")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+[assembly: ComVisible(false)]
+[assembly: Guid("0f2fae37-f898-4392-b4f6-711954beeb4f")]
+[assembly: AssemblyVersion("1.0.0.1")]
+[assembly: AssemblyFileVersion("1.0.0.1")]
\ No newline at end of file
diff --git a/Steamless.Unpacker.Variant31.x86/Steamless.Unpacker.Variant31.x86.csproj b/Steamless.Unpacker.Variant31.x86/Steamless.Unpacker.Variant31.x86.csproj
new file mode 100644
index 0000000..8b6857e
--- /dev/null
+++ b/Steamless.Unpacker.Variant31.x86/Steamless.Unpacker.Variant31.x86.csproj
@@ -0,0 +1,57 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {0F2FAE37-F898-4392-B4F6-711954BEEB4F}
+ Library
+ Properties
+ Steamless.Unpacker.Variant31.x86
+ Steamless.Unpacker.Variant31.x86
+ v4.5.2
+ 512
+
+
+ x86
+ ..\Steamless\bin\x86\Debug\Plugins\
+ DEBUG;TRACE
+
+
+ x86
+ ..\Steamless\bin\x86\Release\Plugins\
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {56c95629-3b34-47fe-b988-04274409294f}
+ Steamless.API
+ False
+
+
+
+
+
\ No newline at end of file
diff --git a/Steamless.sln b/Steamless.sln
new file mode 100644
index 0000000..40b2964
--- /dev/null
+++ b/Steamless.sln
@@ -0,0 +1,52 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 14
+VisualStudioVersion = 14.0.25420.1
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Steamless", "Steamless\Steamless.csproj", "{10AC8FDE-09D9-47B4-AA89-BADC40EECAAB}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Steamless.API", "Steamless.API\Steamless.API.csproj", "{56C95629-3B34-47FE-B988-04274409294F}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExamplePlugin", "ExamplePlugin\ExamplePlugin.csproj", "{97AC964A-E56F-415C-BAEA-D503E3D4D7B8}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Steamless.Unpacker.Variant30.x86", "Steamless.Unpacker.Variant30.x86\Steamless.Unpacker.Variant30.x86.csproj", "{B6BB7A32-AB23-4A25-8914-154879AAD3FE}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Steamless.Unpacker.Variant31.x86", "Steamless.Unpacker.Variant31.x86\Steamless.Unpacker.Variant31.x86.csproj", "{0F2FAE37-F898-4392-B4F6-711954BEEB4F}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Steamless.Unpacker.Variant20.x86", "Steamless.Unpacker.Variant20.x86\Steamless.Unpacker.Variant20.x86.csproj", "{A40154CD-A0FD-4371-8099-CE277E0989AF}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|x86 = Debug|x86
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {10AC8FDE-09D9-47B4-AA89-BADC40EECAAB}.Debug|x86.ActiveCfg = Debug|x86
+ {10AC8FDE-09D9-47B4-AA89-BADC40EECAAB}.Debug|x86.Build.0 = Debug|x86
+ {10AC8FDE-09D9-47B4-AA89-BADC40EECAAB}.Release|x86.ActiveCfg = Release|x86
+ {10AC8FDE-09D9-47B4-AA89-BADC40EECAAB}.Release|x86.Build.0 = Release|x86
+ {56C95629-3B34-47FE-B988-04274409294F}.Debug|x86.ActiveCfg = Debug|x86
+ {56C95629-3B34-47FE-B988-04274409294F}.Debug|x86.Build.0 = Debug|x86
+ {56C95629-3B34-47FE-B988-04274409294F}.Release|x86.ActiveCfg = Release|x86
+ {56C95629-3B34-47FE-B988-04274409294F}.Release|x86.Build.0 = Release|x86
+ {97AC964A-E56F-415C-BAEA-D503E3D4D7B8}.Debug|x86.ActiveCfg = Debug|x86
+ {97AC964A-E56F-415C-BAEA-D503E3D4D7B8}.Debug|x86.Build.0 = Debug|x86
+ {97AC964A-E56F-415C-BAEA-D503E3D4D7B8}.Release|x86.ActiveCfg = Release|x86
+ {97AC964A-E56F-415C-BAEA-D503E3D4D7B8}.Release|x86.Build.0 = Release|x86
+ {B6BB7A32-AB23-4A25-8914-154879AAD3FE}.Debug|x86.ActiveCfg = Debug|x86
+ {B6BB7A32-AB23-4A25-8914-154879AAD3FE}.Debug|x86.Build.0 = Debug|x86
+ {B6BB7A32-AB23-4A25-8914-154879AAD3FE}.Release|x86.ActiveCfg = Release|x86
+ {B6BB7A32-AB23-4A25-8914-154879AAD3FE}.Release|x86.Build.0 = Release|x86
+ {0F2FAE37-F898-4392-B4F6-711954BEEB4F}.Debug|x86.ActiveCfg = Debug|x86
+ {0F2FAE37-F898-4392-B4F6-711954BEEB4F}.Debug|x86.Build.0 = Debug|x86
+ {0F2FAE37-F898-4392-B4F6-711954BEEB4F}.Release|x86.ActiveCfg = Release|x86
+ {0F2FAE37-F898-4392-B4F6-711954BEEB4F}.Release|x86.Build.0 = Release|x86
+ {A40154CD-A0FD-4371-8099-CE277E0989AF}.Debug|x86.ActiveCfg = Debug|x86
+ {A40154CD-A0FD-4371-8099-CE277E0989AF}.Debug|x86.Build.0 = Debug|x86
+ {A40154CD-A0FD-4371-8099-CE277E0989AF}.Release|x86.ActiveCfg = Release|x86
+ {A40154CD-A0FD-4371-8099-CE277E0989AF}.Release|x86.Build.0 = Release|x86
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/Steamless/App.config b/Steamless/App.config
new file mode 100644
index 0000000..88fa402
--- /dev/null
+++ b/Steamless/App.config
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Steamless/App.xaml b/Steamless/App.xaml
new file mode 100644
index 0000000..30d33aa
--- /dev/null
+++ b/Steamless/App.xaml
@@ -0,0 +1,48 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Steamless/App.xaml.cs b/Steamless/App.xaml.cs
new file mode 100644
index 0000000..0841d28
--- /dev/null
+++ b/Steamless/App.xaml.cs
@@ -0,0 +1,79 @@
+/**
+ * Steamless - Copyright (c) 2015 - 2017 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
+{
+ using System;
+ using System.IO;
+ using System.Reflection;
+
+ ///
+ /// Interaction logic for App.xaml
+ ///
+ public partial class App
+ {
+ ///
+ /// Default Constructor
+ ///
+ public App()
+ {
+ // Override the assembly resolve event..
+ AppDomain.CurrentDomain.AssemblyResolve += OnAssemblyResolve;
+ }
+
+ ///
+ /// Assembly resolve override to allow loading of embedded modules.
+ ///
+ ///
+ ///
+ ///
+ private static Assembly OnAssemblyResolve(object sender, ResolveEventArgs args)
+ {
+ // Obtain the name of the assembly being loaded..
+ var name = args.Name.Contains(",") ? args.Name.Substring(0, args.Name.IndexOf(",", StringComparison.InvariantCultureIgnoreCase)) : args.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(args.Name).Name}.dll";
+ using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(fullName))
+ {
+ // If not embedded try to load from the plugin folder..
+ if (stream == null)
+ {
+ var file = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Plugins", name + ".dll");
+ return File.Exists(file) ? Assembly.Load(File.ReadAllBytes(file)) : null;
+ }
+
+ // Read and load the embedded resource..
+ var data = new byte[stream.Length];
+ stream.Read(data, 0, (int)stream.Length);
+ return Assembly.Load(data);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Steamless/Assets/Animations.xaml b/Steamless/Assets/Animations.xaml
new file mode 100644
index 0000000..a077f94
--- /dev/null
+++ b/Steamless/Assets/Animations.xaml
@@ -0,0 +1,58 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Steamless/Assets/Controls.CheckBox.xaml b/Steamless/Assets/Controls.CheckBox.xaml
new file mode 100644
index 0000000..849d762
--- /dev/null
+++ b/Steamless/Assets/Controls.CheckBox.xaml
@@ -0,0 +1,108 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Steamless/Assets/Controls.Scrollbars.xaml b/Steamless/Assets/Controls.Scrollbars.xaml
new file mode 100644
index 0000000..89f5bbe
--- /dev/null
+++ b/Steamless/Assets/Controls.Scrollbars.xaml
@@ -0,0 +1,448 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Steamless/Assets/Controls.xaml b/Steamless/Assets/Controls.xaml
new file mode 100644
index 0000000..e30e43b
--- /dev/null
+++ b/Steamless/Assets/Controls.xaml
@@ -0,0 +1,805 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Steamless/Assets/Theme.xaml b/Steamless/Assets/Theme.xaml
new file mode 100644
index 0000000..09408e5
--- /dev/null
+++ b/Steamless/Assets/Theme.xaml
@@ -0,0 +1,152 @@
+
+
+
+
+ #FFFF4A0D
+ #CCFF4A0D
+ #99FF4A0D
+ #66FF4A0D
+ #33FF4A0D
+
+
+ #FF000000
+ #FFFFFFFF
+ #A8A8A8
+ #FF333333
+ #FF7F7F7F
+ #FF9D9D9D
+ #FFA59F93
+ #FFB9B9B9
+ #FFCCCCCC
+ #FFD8D8D9
+ #FFE0E0E0
+ #5EC9C9C9
+ #FFF7F7F7
+
+
+ #33878787
+ #33959595
+ #4C000000
+ #4C000000
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #FF000000
+
+ White
+
+
+
+
\ No newline at end of file
diff --git a/Steamless/Assets/Window.xaml b/Steamless/Assets/Window.xaml
new file mode 100644
index 0000000..b52198e
--- /dev/null
+++ b/Steamless/Assets/Window.xaml
@@ -0,0 +1,99 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Steamless/Assets/icons.xaml b/Steamless/Assets/icons.xaml
new file mode 100644
index 0000000..175c027
--- /dev/null
+++ b/Steamless/Assets/icons.xaml
@@ -0,0 +1,1585 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Steamless/Assets/steam.ico b/Steamless/Assets/steam.ico
new file mode 100644
index 0000000..13ce382
Binary files /dev/null and b/Steamless/Assets/steam.ico differ
diff --git a/Steamless/Assets/steam.png b/Steamless/Assets/steam.png
new file mode 100644
index 0000000..dcb819d
Binary files /dev/null and b/Steamless/Assets/steam.png differ
diff --git a/Steamless/Classes/ControlsHelper.cs b/Steamless/Classes/ControlsHelper.cs
new file mode 100644
index 0000000..1e8efc3
--- /dev/null
+++ b/Steamless/Classes/ControlsHelper.cs
@@ -0,0 +1,55 @@
+/**
+ * Steamless - Copyright (c) 2015 - 2017 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.Classes
+{
+ using System.Windows;
+
+ ///
+ /// Contains helper functions for WPF controls.
+ ///
+ /// Credits to the functions within this class:
+ /// https://github.com/MahApps/MahApps.Metro
+ ///
+ public static class ControlsHelper
+ {
+ ///
+ /// This property can be used to set vertical scrollbar left side from the tabpanel (look at MetroAnimatedSingleRowTabControl)
+ ///
+ public static readonly DependencyProperty VerticalScrollBarOnLeftSideProperty =
+ DependencyProperty.RegisterAttached("VerticalScrollBarOnLeftSide", typeof(bool), typeof(ControlsHelper),
+ new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.Inherits));
+
+ public static bool GetVerticalScrollBarOnLeftSide(DependencyObject obj)
+ {
+ return (bool)obj.GetValue(VerticalScrollBarOnLeftSideProperty);
+ }
+
+ public static void SetVerticalScrollBarOnLeftSide(DependencyObject obj, bool value)
+ {
+ obj.SetValue(VerticalScrollBarOnLeftSideProperty, value);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Steamless/Classes/GridViewColumnWidthFromItemsBehavior.cs b/Steamless/Classes/GridViewColumnWidthFromItemsBehavior.cs
new file mode 100644
index 0000000..28db41d
--- /dev/null
+++ b/Steamless/Classes/GridViewColumnWidthFromItemsBehavior.cs
@@ -0,0 +1,100 @@
+/**
+ * Steamless - Copyright (c) 2015 - 2017 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.Classes
+{
+ using API.Events;
+ using System.Collections.Specialized;
+ using System.Globalization;
+ using System.Linq;
+ using System.Windows;
+ using System.Windows.Controls;
+ using System.Windows.Controls.Primitives;
+ using System.Windows.Media;
+
+ public static class GridViewColumnWidthFromItemsBehavior
+ {
+ public static readonly DependencyProperty GridViewColumnWidthFromItemsProperty =
+ DependencyProperty.RegisterAttached("Enabled", typeof(bool), typeof(GridViewColumnWidthFromItemsBehavior), new UIPropertyMetadata(false, OnGridViewColumnWidthFromItemsPropertyChanged));
+
+ public static bool GetEnabled(DependencyObject obj)
+ {
+ return (bool)obj.GetValue(GridViewColumnWidthFromItemsProperty);
+ }
+
+ public static void SetEnabled(DependencyObject obj, bool value)
+ {
+ obj.SetValue(GridViewColumnWidthFromItemsProperty, value);
+ }
+
+ private static void OnGridViewColumnWidthFromItemsPropertyChanged(DependencyObject dpo, DependencyPropertyChangedEventArgs e)
+ {
+ var lv = dpo as ListView;
+ if (lv != null)
+ {
+ if ((bool)e.NewValue)
+ lv.Loaded += OnListViewLoaded;
+ else
+ lv.Loaded -= OnListViewLoaded;
+ }
+ }
+
+ private static void OnListViewLoaded(object sender, RoutedEventArgs routedEventArgs)
+ {
+ var lv = sender as ListView;
+ var nc = ((INotifyCollectionChanged)lv?.Items);
+
+ if (nc == null)
+ return;
+
+ nc.CollectionChanged += (o, args) =>
+ {
+ if (lv.ItemContainerGenerator.Status != GeneratorStatus.ContainersGenerated)
+ return;
+
+ // Obtain the largest item width..
+ var width = lv.Items.OfType()
+ .Select(msg => new FormattedText(msg.Message, CultureInfo.CurrentCulture, FlowDirection.LeftToRight, new Typeface("Tahoma"), 11, Brushes.Black))
+ .Select(txt => txt.Width)
+ .Concat(new double[] { 0.0f })
+ .Max();
+
+ // Resize the message column..
+ var gv = lv.View as GridView;
+ if (gv != null)
+ gv.Columns[1].Width = width + 24.0f;
+
+ // Scroll to the last item..
+ if (lv.Items.Count > 0)
+ lv.ScrollIntoView(lv.Items[lv.Items.Count - 1]);
+ else
+ {
+ if (gv != null)
+ gv.Columns[1].Width = 600;
+ }
+ };
+ }
+ }
+}
\ No newline at end of file
diff --git a/Steamless/Embedded/GalaSoft.MvvmLight.Extras.dll b/Steamless/Embedded/GalaSoft.MvvmLight.Extras.dll
new file mode 100644
index 0000000..dff006f
Binary files /dev/null and b/Steamless/Embedded/GalaSoft.MvvmLight.Extras.dll differ
diff --git a/Steamless/Embedded/GalaSoft.MvvmLight.dll b/Steamless/Embedded/GalaSoft.MvvmLight.dll
new file mode 100644
index 0000000..6ca72d3
Binary files /dev/null and b/Steamless/Embedded/GalaSoft.MvvmLight.dll differ
diff --git a/Steamless/Embedded/Microsoft.Practices.ServiceLocation.dll b/Steamless/Embedded/Microsoft.Practices.ServiceLocation.dll
new file mode 100644
index 0000000..95bbd51
Binary files /dev/null and b/Steamless/Embedded/Microsoft.Practices.ServiceLocation.dll differ
diff --git a/Steamless/Embedded/Newtonsoft.Json.dll b/Steamless/Embedded/Newtonsoft.Json.dll
new file mode 100644
index 0000000..20dae62
Binary files /dev/null and b/Steamless/Embedded/Newtonsoft.Json.dll differ
diff --git a/Steamless/Embedded/System.Windows.Interactivity.dll b/Steamless/Embedded/System.Windows.Interactivity.dll
new file mode 100644
index 0000000..0419e95
Binary files /dev/null and b/Steamless/Embedded/System.Windows.Interactivity.dll differ
diff --git a/Steamless/Model/ApplicationState.cs b/Steamless/Model/ApplicationState.cs
new file mode 100644
index 0000000..50fd009
--- /dev/null
+++ b/Steamless/Model/ApplicationState.cs
@@ -0,0 +1,58 @@
+/**
+ * Steamless - Copyright (c) 2015 - 2017 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.Model
+{
+ public enum ApplicationState
+ {
+ ///
+ /// Initializing
+ ///
+ /// The state when the application is loading and/or updating.
+ ///
+ Initializing,
+
+ ///
+ /// Running
+ ///
+ /// The state when the application is done initializing and is running.
+ ///
+ Running,
+
+ ///
+ /// Closing
+ ///
+ /// The state when the launcher is closing.
+ ///
+ Closing,
+
+ ///
+ /// Closed
+ ///
+ /// The state when the launcher is closed.
+ ///
+ Closed
+ }
+}
\ No newline at end of file
diff --git a/Steamless/Model/AutomaticPlugin.cs b/Steamless/Model/AutomaticPlugin.cs
new file mode 100644
index 0000000..2fe970d
--- /dev/null
+++ b/Steamless/Model/AutomaticPlugin.cs
@@ -0,0 +1,100 @@
+/**
+ * Steamless - Copyright (c) 2015 - 2017 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.Model
+{
+ using API;
+ using API.Model;
+ using API.Services;
+ using System;
+ using System.Linq;
+ using System.Windows;
+ using ViewModel;
+
+ [SteamlessApiVersion(1, 0)]
+ internal class AutomaticPlugin : SteamlessPlugin
+ {
+ ///
+ /// Gets the author of this plugin.
+ ///
+ public override string Author => "Steamless Development Team";
+
+ ///
+ /// Gets the name of this plugin.
+ ///
+ public override string Name => "Automatic";
+
+ ///
+ /// Gets the description of this plugin.
+ ///
+ public override string Description => "Automatically finds which plugin to use for the given file.";
+
+ ///
+ /// Gets the version of this plugin.
+ ///
+ public override Version Version => new Version(1, 0, 0, 0);
+
+ ///
+ /// Initialize function called when this plugin is first loaded.
+ ///
+ ///
+ ///
+ public override bool Initialize(LoggingService logService)
+ {
+ return true;
+ }
+
+ ///
+ /// Processing function called when a file is being unpacked. Allows plugins to check the file
+ /// and see if it can handle the file for its intended purpose.
+ ///
+ ///
+ ///
+ public override bool CanProcessFile(string file)
+ {
+ return true;
+ }
+
+ ///
+ /// Processing function called to allow the plugin to process the file.
+ ///
+ ///
+ ///
+ ///
+ public override bool ProcessFile(string file, SteamlessOptions options)
+ {
+ // Obtain the view model locator..
+ var vml = Application.Current.FindResource("ViewModelLocator") as ViewModelLocator;
+
+ // Obtain the plugins..
+ var plugins = vml?.MainWindow.Plugins;
+ if (plugins == null || plugins.Count == 0)
+ return false;
+
+ // Query the plugin list for a plugin to process the file..
+ return (from p in plugins where p != this where p.CanProcessFile(file) select p.ProcessFile(file, options)).FirstOrDefault();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Steamless/Model/DataService.cs b/Steamless/Model/DataService.cs
new file mode 100644
index 0000000..62b8170
--- /dev/null
+++ b/Steamless/Model/DataService.cs
@@ -0,0 +1,146 @@
+/**
+ * Steamless - Copyright (c) 2015 - 2017 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.Model
+{
+ using API;
+ using API.Model;
+ using System;
+ using System.Collections.Generic;
+ using System.Diagnostics;
+ using System.IO;
+ using System.Linq;
+ using System.Reflection;
+ using System.Threading.Tasks;
+ using System.Windows;
+ using ViewModel;
+
+ public class DataService : IDataService
+ {
+ private static readonly Version SteamlessApiVersion = new Version(1, 0);
+
+ ///
+ /// Obtains the version of Steamless.
+ ///
+ ///
+ public Task GetSteamlessVersion()
+ {
+ return Task.Run(() =>
+ {
+ try
+ {
+ return Assembly.GetExecutingAssembly().EntryPoint.DeclaringType?.Assembly.GetName().Version ?? new Version(0, 0, 0, 0);
+ }
+ catch
+ {
+ return new Version(0, 0, 0, 0);
+ }
+ });
+ }
+
+ ///
+ /// Obtains a list of available Steamless plugins.
+ ///
+ ///
+ public Task> GetSteamlessPlugins()
+ {
+ return Task.Run(() =>
+ {
+ try
+ {
+ // Obtain the view model locator..
+ var vml = Application.Current.FindResource("ViewModelLocator") as ViewModelLocator;
+ if (vml == null)
+ throw new Exception("Failed to obtain ViewModelLocator.");
+
+ // 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)
+ {
+ Debug.WriteLine($"Failed to load plugin; could not find SteamlessPlugin base class. ({Path.GetFileName(dll)})");
+ continue;
+ }
+
+ // Locate the SteamlessApiVersion attribute on the base class..
+ var baseAttr = baseClass.GetCustomAttributes(typeof(SteamlessApiVersionAttribute), false);
+ if (baseAttr.Length == 0)
+ {
+ Debug.WriteLine($"Failed to load plugin; could not find SteamlessApiVersion attribute. ({Path.GetFileName(dll)})");
+ continue;
+ }
+
+ // Validate the interface version..
+ var apiVersion = (SteamlessApiVersionAttribute)baseAttr[0];
+ if (apiVersion.Version != SteamlessApiVersion)
+ {
+ Debug.WriteLine($"Failed to load plugin; invalid API version is being used. ({Path.GetFileName(dll)})");
+ continue;
+ }
+
+ // Create an instance of the plugin..
+ var plugin = (SteamlessPlugin)Activator.CreateInstance(baseClass);
+ if (!plugin.Initialize(vml.LoggingService))
+ {
+ Debug.WriteLine($"Failed to load plugin; plugin failed to initialize. ({Path.GetFileName(dll)})");
+ continue;
+ }
+
+ plugins.Add(plugin);
+ }
+ catch
+ {
+ Debug.WriteLine($"Failed to load DLL as a Steamless plugin: ({Path.GetFileName(dll)})");
+ }
+ }
+
+ // Order the plugins by their name..
+ return plugins.OrderBy(p => p.Name).ToList();
+ }
+ catch
+ {
+ return new List();
+ }
+ });
+ }
+ }
+}
\ No newline at end of file
diff --git a/Steamless/Model/IDataService.cs b/Steamless/Model/IDataService.cs
new file mode 100644
index 0000000..6f146a0
--- /dev/null
+++ b/Steamless/Model/IDataService.cs
@@ -0,0 +1,47 @@
+/**
+ * Steamless - Copyright (c) 2015 - 2017 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.Model
+{
+ using API.Model;
+ using System;
+ using System.Collections.Generic;
+ using System.Threading.Tasks;
+
+ public interface IDataService
+ {
+ ///
+ /// Obtains the version of Steamless.
+ ///
+ ///
+ Task GetSteamlessVersion();
+
+ ///
+ /// Obtains a list of available Steamless plugins.
+ ///
+ ///
+ Task> GetSteamlessPlugins();
+ }
+}
\ No newline at end of file
diff --git a/Steamless/Model/Tasks/BaseTask.cs b/Steamless/Model/Tasks/BaseTask.cs
new file mode 100644
index 0000000..7620ae3
--- /dev/null
+++ b/Steamless/Model/Tasks/BaseTask.cs
@@ -0,0 +1,87 @@
+/**
+ * Steamless - Copyright (c) 2015 - 2017 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.Model.Tasks
+{
+ using API.Model;
+ using System.Threading.Tasks;
+
+ public abstract class BaseTask : NotifiableModel
+ {
+ ///
+ /// Starts the task.
+ ///
+ public Task StartTask()
+ {
+ return Task.Run(async () =>
+ {
+ this.Completed = false;
+ await this.DoTask();
+ this.Completed = true;
+ });
+ }
+
+ ///
+ /// The tasks main function to execute when started.
+ ///
+ public abstract Task DoTask();
+
+ ///
+ /// Gets or sets the tasks completed state.
+ ///
+ public bool Completed
+ {
+ get { return this.Get("Completed"); }
+ set { this.Set("Completed", value); }
+ }
+
+ ///
+ /// Gets or sets the tasks progress.
+ ///
+ public double Progress
+ {
+ get { return this.Get("Progress"); }
+ set { this.Set("Progress", value); }
+ }
+
+ ///
+ /// Gets or sets the tasks total progress.
+ ///
+ public double ProgressTotal
+ {
+ get { return this.Get("ProgressTotal"); }
+ set { this.Set("ProgressTotal", value); }
+ }
+
+ ///
+ /// Gets or sets the text to display for this task.
+ ///
+ public string Text
+ {
+ get { return this.Get("Text"); }
+ set { this.Set("Text", value); }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Steamless/Model/Tasks/LoadPluginsTask.cs b/Steamless/Model/Tasks/LoadPluginsTask.cs
new file mode 100644
index 0000000..3d85c95
--- /dev/null
+++ b/Steamless/Model/Tasks/LoadPluginsTask.cs
@@ -0,0 +1,84 @@
+/**
+ * Steamless - Copyright (c) 2015 - 2017 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.Model.Tasks
+{
+ using API.Events;
+ using API.Model;
+ using System.Collections.ObjectModel;
+ using System.Linq;
+ using System.Threading.Tasks;
+ using System.Windows;
+ using ViewModel;
+
+ public class LoadPluginsTask : BaseTask
+ {
+ ///
+ /// Default Constructor
+ ///
+ public LoadPluginsTask()
+ {
+ this.Text = "Loading plugins...";
+ }
+
+ ///
+ /// The tasks main function to execute when started.
+ ///
+ public override Task DoTask()
+ {
+ return Task.Run(async () =>
+ {
+ // Obtain the view model locator..
+ var vml = Application.Current.FindResource("ViewModelLocator") as ViewModelLocator;
+ if (vml == null)
+ return;
+
+ vml.MainWindow.SelectedPluginIndex = -1;
+
+ // Obtain the list of plugins..
+ var plugins = await vml.DataService.GetSteamlessPlugins();
+
+ // Sort the plugins..
+ var sorted = plugins.OrderBy(p => p.Name).ToList();
+
+ // Print out the loaded plugins..
+ sorted.ForEach(p =>
+ {
+ Application.Current.Dispatcher.Invoke(() =>
+ {
+ vml.LoggingService.OnAddLogMessage(this, new LogMessageEventArgs($"Loaded plugin: {p.Name} - by {p.Author} (v.{p.Version})", LogMessageType.Success));
+ });
+ });
+
+ // Add the automatic plugin at the start of the list..
+ sorted.Insert(0, new AutomaticPlugin());
+
+ // Set the plugins..
+ vml.MainWindow.Plugins = new ObservableCollection(sorted);
+ vml.MainWindow.SelectedPluginIndex = 0;
+ });
+ }
+ }
+}
\ No newline at end of file
diff --git a/Steamless/Model/Tasks/StartSteamlessTask.cs b/Steamless/Model/Tasks/StartSteamlessTask.cs
new file mode 100644
index 0000000..9b5355d
--- /dev/null
+++ b/Steamless/Model/Tasks/StartSteamlessTask.cs
@@ -0,0 +1,52 @@
+/**
+ * Steamless - Copyright (c) 2015 - 2017 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.Model.Tasks
+{
+ using System.Threading;
+ using System.Threading.Tasks;
+
+ public class StartSteamlessTask : BaseTask
+ {
+ ///
+ /// Default Constructor
+ ///
+ public StartSteamlessTask()
+ {
+ this.Text = "Starting Steamless...";
+ }
+
+ ///
+ /// The tasks main function to execute when started.
+ ///
+ public override Task DoTask()
+ {
+ return Task.Run(() =>
+ {
+ Thread.Sleep(1000);
+ });
+ }
+ }
+}
\ No newline at end of file
diff --git a/Steamless/Model/Tasks/StatusTask.cs b/Steamless/Model/Tasks/StatusTask.cs
new file mode 100644
index 0000000..3b203d8
--- /dev/null
+++ b/Steamless/Model/Tasks/StatusTask.cs
@@ -0,0 +1,53 @@
+/**
+ * Steamless - Copyright (c) 2015 - 2017 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.Model.Tasks
+{
+ using System.Threading;
+ using System.Threading.Tasks;
+
+ public class StatusTask : BaseTask
+ {
+ ///
+ /// Default Constructor
+ ///
+ ///
+ public StatusTask(string msg)
+ {
+ this.Text = msg;
+ }
+
+ ///
+ /// The tasks main function to execute when started.
+ ///
+ public override Task DoTask()
+ {
+ return Task.Run(() =>
+ {
+ Thread.Sleep(1000);
+ });
+ }
+ }
+}
\ No newline at end of file
diff --git a/Steamless/Properties/AssemblyInfo.cs b/Steamless/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..c397b79
--- /dev/null
+++ b/Steamless/Properties/AssemblyInfo.cs
@@ -0,0 +1,41 @@
+/**
+ * Steamless - Copyright (c) 2015 - 2017 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;
+using System.Windows;
+
+[assembly: AssemblyTitle("Steamless")]
+[assembly: AssemblyDescription("Removes the SteamStub DRM protection from Steam applications.")]
+[assembly: AssemblyConfiguration("Release")]
+[assembly: AssemblyCompany("atom0s")]
+[assembly: AssemblyProduct("Steamless")]
+[assembly: AssemblyCopyright("Copyright © atom0s 2015 - 2017")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+[assembly: ComVisible(false)]
+[assembly: ThemeInfo(ResourceDictionaryLocation.None, ResourceDictionaryLocation.SourceAssembly)]
+[assembly: AssemblyVersion("3.0.0.1")]
+[assembly: AssemblyFileVersion("3.0.0.1")]
\ No newline at end of file
diff --git a/Steamless/Properties/Resources.Designer.cs b/Steamless/Properties/Resources.Designer.cs
new file mode 100644
index 0000000..c0c118a
--- /dev/null
+++ b/Steamless/Properties/Resources.Designer.cs
@@ -0,0 +1,71 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.42000
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace Steamless.Properties
+{
+
+
+ ///
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ ///
+ // This class was auto-generated by the StronglyTypedResourceBuilder
+ // class via a tool like ResGen or Visual Studio.
+ // To add or remove a member, edit your .ResX file then rerun ResGen
+ // with the /str option, or rebuild your VS project.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class Resources
+ {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal Resources()
+ {
+ }
+
+ ///
+ /// Returns the cached ResourceManager instance used by this class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager
+ {
+ get
+ {
+ if ((resourceMan == null))
+ {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Steamless.Properties.Resources", typeof(Resources).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ ///
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture
+ {
+ get
+ {
+ return resourceCulture;
+ }
+ set
+ {
+ resourceCulture = value;
+ }
+ }
+ }
+}
diff --git a/Steamless/Properties/Resources.resx b/Steamless/Properties/Resources.resx
new file mode 100644
index 0000000..af7dbeb
--- /dev/null
+++ b/Steamless/Properties/Resources.resx
@@ -0,0 +1,117 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/Steamless/Properties/Settings.Designer.cs b/Steamless/Properties/Settings.Designer.cs
new file mode 100644
index 0000000..456d33d
--- /dev/null
+++ b/Steamless/Properties/Settings.Designer.cs
@@ -0,0 +1,30 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.42000
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace Steamless.Properties
+{
+
+
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
+ internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
+ {
+
+ private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
+
+ public static Settings Default
+ {
+ get
+ {
+ return defaultInstance;
+ }
+ }
+ }
+}
diff --git a/Steamless/Properties/Settings.settings b/Steamless/Properties/Settings.settings
new file mode 100644
index 0000000..033d7a5
--- /dev/null
+++ b/Steamless/Properties/Settings.settings
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Steamless/Steamless.csproj b/Steamless/Steamless.csproj
new file mode 100644
index 0000000..e63e711
--- /dev/null
+++ b/Steamless/Steamless.csproj
@@ -0,0 +1,206 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {10AC8FDE-09D9-47B4-AA89-BADC40EECAAB}
+ WinExe
+ Properties
+ Steamless
+ Steamless
+ v4.5.2
+ 512
+ {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+ 4
+ true
+
+
+ x86
+ bin\x86\Debug\
+ TRACE;DEBUG
+
+
+ x86
+ bin\x86\Release\
+ true
+
+
+ Assets\steam.ico
+
+
+
+ Embedded\GalaSoft.MvvmLight.dll
+ False
+
+
+ Embedded\GalaSoft.MvvmLight.Extras.dll
+ False
+
+
+ Embedded\Microsoft.Practices.ServiceLocation.dll
+ False
+
+
+ Embedded\Newtonsoft.Json.dll
+ False
+
+
+
+
+
+
+
+ False
+ Embedded\System.Windows.Interactivity.dll
+ False
+
+
+
+
+
+
+
+
+ 4.0
+
+
+
+
+
+
+
+ MSBuild:Compile
+ Designer
+
+
+ App.xaml
+ Code
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ AboutView.xaml
+
+
+ MainView.xaml
+
+
+ MainWindow.xaml
+
+
+ SplashView.xaml
+
+
+
+
+ Code
+
+
+ True
+ True
+ Resources.resx
+
+
+ True
+ Settings.settings
+ True
+
+
+ ResXFileCodeGenerator
+ Resources.Designer.cs
+
+
+ Designer
+ MSBuild:Compile
+
+
+ MSBuild:Compile
+ Designer
+
+
+ SettingsSingleFileGenerator
+ Settings.Designer.cs
+
+
+
+
+
+
+
+
+ Designer
+ MSBuild:Compile
+
+
+ Designer
+ MSBuild:Compile
+
+
+ MSBuild:Compile
+ Designer
+
+
+ Designer
+ MSBuild:Compile
+
+
+ Designer
+ MSBuild:Compile
+
+
+ Designer
+ MSBuild:Compile
+
+
+ Designer
+ MSBuild:Compile
+
+
+ Designer
+ MSBuild:Compile
+
+
+ Designer
+ MSBuild:Compile
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {56c95629-3b34-47fe-b988-04274409294f}
+ Steamless.API
+ False
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Steamless/View/AboutView.xaml b/Steamless/View/AboutView.xaml
new file mode 100644
index 0000000..c4313f3
--- /dev/null
+++ b/Steamless/View/AboutView.xaml
@@ -0,0 +1,316 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Steamless is provided, as-is, for free. Donations are a way for users to show their support for my work.
+ I do not accept donations in the attempt to assist with pirating games or other illegal activities. Do
+ not contact me attempting to get help with pirating a game or any other illegal activity, I will not respond.
+
+
+
+
+
+ Steamless is released under the following license:
+
+ Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International
+
+ Unless otherwise separately undertaken by the Licensor, to the extent possible, the Licensor offers the Licensed Material
+ as-is and as-available, and makes no representations or warranties of any kind concerning the Licensed Material, whether
+ express, implied, statutory, or other. This includes, without limitation, warranties of title, merchantability, fitness
+ for a particular purpose, non-infringement, absence of latent or other defects, accuracy, or the presence or absence of
+ errors, whether or not known or discoverable. Where disclaimers of warranties are not allowed in full or in part, this
+ disclaimer may not apply to You.
+
+ Steamless is not intended for malicious use or for the use of obtaining or playing games illegally.
+
+ Steamless should only be used on games that you legally purchased and own.
+
+ Steamless is not associated with Steam or any of its partners / affiliates.
+
+ No code used within Steamless is taken from Valve or any of its partners / affiliates.
+
+ All work is original and done for educational purposes.
+
+ Steam © 2003 - 2016 Valve Corporation. All rights reserved.
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Steamless/View/AboutView.xaml.cs b/Steamless/View/AboutView.xaml.cs
new file mode 100644
index 0000000..e20fcb6
--- /dev/null
+++ b/Steamless/View/AboutView.xaml.cs
@@ -0,0 +1,41 @@
+/**
+ * Steamless - Copyright (c) 2015 - 2017 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.View
+{
+ ///
+ /// Interaction logic for AboutView.xaml
+ ///
+ public partial class AboutView
+ {
+ ///
+ /// Default Constructor
+ ///
+ public AboutView()
+ {
+ this.InitializeComponent();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Steamless/View/MainView.xaml b/Steamless/View/MainView.xaml
new file mode 100644
index 0000000..a87a4aa
--- /dev/null
+++ b/Steamless/View/MainView.xaml
@@ -0,0 +1,141 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Steamless/View/MainView.xaml.cs b/Steamless/View/MainView.xaml.cs
new file mode 100644
index 0000000..160b300
--- /dev/null
+++ b/Steamless/View/MainView.xaml.cs
@@ -0,0 +1,41 @@
+/**
+ * Steamless - Copyright (c) 2015 - 2017 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.View
+{
+ ///
+ /// Interaction logic for MainView.xaml
+ ///
+ public partial class MainView
+ {
+ ///
+ /// Default Constructor
+ ///
+ public MainView()
+ {
+ this.InitializeComponent();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Steamless/View/MainWindow.xaml b/Steamless/View/MainWindow.xaml
new file mode 100644
index 0000000..9436198
--- /dev/null
+++ b/Steamless/View/MainWindow.xaml
@@ -0,0 +1,189 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Steamless/View/MainWindow.xaml.cs b/Steamless/View/MainWindow.xaml.cs
new file mode 100644
index 0000000..16d2908
--- /dev/null
+++ b/Steamless/View/MainWindow.xaml.cs
@@ -0,0 +1,41 @@
+/**
+ * Steamless - Copyright (c) 2015 - 2017 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.View
+{
+ ///
+ /// Interaction logic for MainWindow.xaml
+ ///
+ public partial class MainWindow
+ {
+ ///
+ /// Default Constructor
+ ///
+ public MainWindow()
+ {
+ this.InitializeComponent();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Steamless/View/SplashView.xaml b/Steamless/View/SplashView.xaml
new file mode 100644
index 0000000..32c4498
--- /dev/null
+++ b/Steamless/View/SplashView.xaml
@@ -0,0 +1,151 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Steamless/View/SplashView.xaml.cs b/Steamless/View/SplashView.xaml.cs
new file mode 100644
index 0000000..0c31ffb
--- /dev/null
+++ b/Steamless/View/SplashView.xaml.cs
@@ -0,0 +1,41 @@
+/**
+ * Steamless - Copyright (c) 2015 - 2017 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.View
+{
+ ///
+ /// Interaction logic for SplashView.xaml
+ ///
+ public partial class SplashView
+ {
+ ///
+ /// Default Constructor
+ ///
+ public SplashView()
+ {
+ this.InitializeComponent();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Steamless/ViewModel/MainWindowViewModel.cs b/Steamless/ViewModel/MainWindowViewModel.cs
new file mode 100644
index 0000000..ecdd580
--- /dev/null
+++ b/Steamless/ViewModel/MainWindowViewModel.cs
@@ -0,0 +1,492 @@
+/**
+ * Steamless - Copyright (c) 2015 - 2017 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.ViewModel
+{
+ using API.Events;
+ using API.Model;
+ using API.Services;
+ using GalaSoft.MvvmLight.Command;
+ using Microsoft.Win32;
+ using Model;
+ using Model.Tasks;
+ using System;
+ using System.Collections.Concurrent;
+ using System.Collections.ObjectModel;
+ using System.Diagnostics;
+ using System.IO;
+ using System.Threading;
+ using System.Threading.Tasks;
+ using System.Windows;
+ using System.Windows.Documents;
+ using System.Windows.Input;
+
+ public class MainWindowViewModel : ViewModelBase
+ {
+ ///
+ /// Internal data service instance.
+ ///
+ private readonly IDataService m_DataService;
+
+ ///
+ /// Internal thread used to process tasks.
+ ///
+ private Thread m_TaskThread;
+
+ ///
+ /// Default Constructor
+ ///
+ ///
+ ///
+ public MainWindowViewModel(IDataService dataService, LoggingService logService)
+ {
+ // Store the data service instance..
+ this.m_DataService = dataService;
+
+ // Initialize the model..
+ this.State = ApplicationState.Initializing;
+ this.Tasks = new ConcurrentBag();
+ this.Options = new SteamlessOptions();
+ this.Log = new ObservableCollection();
+ this.ShowAboutView = false;
+ this.InputFilePath = string.Empty;
+
+ // Register command callbacks..
+ this.OnWindowCloseCommand = new RelayCommand(this.WindowClose);
+ this.OnWindowMinimizeCommand = new RelayCommand(WindowMinimize);
+ this.OnWindowMouseDownCommand = new RelayCommand(WindowMouseDown);
+ this.OnShowAboutViewCommand = new RelayCommand(() => this.ShowAboutView = !this.ShowAboutView);
+ this.OnOpenHyperlinkCommand = new RelayCommand