diff --git a/Steamless.Unpacker.Variant20.x86/Classes/SteamStubDrmFlags.cs b/Steamless.Unpacker.Variant20.x86/Classes/SteamStubDrmFlags.cs
new file mode 100644
index 0000000..750f9a5
--- /dev/null
+++ b/Steamless.Unpacker.Variant20.x86/Classes/SteamStubDrmFlags.cs
@@ -0,0 +1,66 @@
+/**
+ * Steamless - Copyright (c) 2015 - 2020 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
+ {
+ ///
+ /// None.
+ ///
+ None = 0x00,
+
+ ///
+ /// Flag that states that the stub will hash check the stub code and header data.
+ ///
+ UseValidation = 0x01,
+
+ ///
+ /// Flag that states that the stub will validate the file via WinVerifyTrust if able.
+ ///
+ UseWinVerifyTrustValidation = 0x02,
+
+ ///
+ /// Flag that states that the stub will decode/decrypt the code section.
+ ///
+ UseEncodedCodeSection = 0x04,
+
+ ///
+ /// Flag that states that the stub will check for active thread count of the current process during the stubs processing
+ /// to check for any injected threads. (If the count is not 1, the check fails.)
+ ///
+ UseThreadCheckValidation = 0x08,
+
+ ///
+ /// Flag that states that the stub will create and check some data against a mapped memory view of the modded startup information.
+ ///
+ /// This uses the SteamAppID and Unknown0000 of the header.
+ ///
+ UseMemoryMappedValidation = 0x10
+ }
+}
\ 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..b02e6ea
--- /dev/null
+++ b/Steamless.Unpacker.Variant20.x86/Classes/SteamStubHeader.cs
@@ -0,0 +1,59 @@
+/**
+ * Steamless - Copyright (c) 2015 - 2020 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 XorKey1; // Xor key used to encode the header data.
+ public uint XorKey2; // Xor key used to encode the header data.
+ public uint GetModuleHandleA_idata; // The address of GetModuleHandleA inside of the .idata section.
+ public uint GetProcAddress_idata; // The address of GetProcAddress inside of the .idata section.
+ public uint GetModuleHandleW_idata; // The address of GetModuleHandleW inside of the .idata section.
+ public uint GetProcAddress_bind; // The address of the .bind sections custom GetProcAddress instance.
+ public uint Flags; // Protection flags used with the file.
+ public uint Unknown0000; // Unknown (Was 0xEC227021 when testing.) (Only used if (Flags & 0x10) is set. Used in part of a hash check.)
+ public uint BindSectionVirtualAddress; // The virtual address to the .bind section.
+ public uint BindSectionCodeSize; // The size of the code stub inside of the .bind section.
+ public uint ValidationHash; // Hash that is calculated based on the .bind code section and .bind stub header data. (Only used if (Flags & 1) is set.)
+ public uint OEP; // The original file OEP to be invoked after the stub has finished.
+ public uint CodeSectionVirtualAddress; // The virtual address to the code section. (.text) (Was 0x0401000 when testing. Possibly original OEP?)
+ public uint CodeSectionSize; // The size of the code section.
+ public uint CodeSectionXorKey; // The starting key to xor decode against. (Only used if (Flags & 4) is set.)
+ public uint SteamAppID; // The steam application id of the packed file.
+
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x0C)]
+ public byte[] SteamAppIDString; // The SteamAppID of the packed file, in string format.
+
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x36C)]
+ 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..41ff2d1
--- /dev/null
+++ b/Steamless.Unpacker.Variant20.x86/Classes/SteamStubHelpers.cs
@@ -0,0 +1,65 @@
+/**
+ * Steamless - Copyright (c) 2015 - 2020 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;
+ }
+ }
+}
\ 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..01b69f8
--- /dev/null
+++ b/Steamless.Unpacker.Variant20.x86/Main.cs
@@ -0,0 +1,510 @@
+/**
+ * Steamless - Copyright (c) 2015 - 2020 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.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.Reflection;
+ using System.Runtime.InteropServices;
+
+ [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 => Assembly.GetExecutingAssembly().GetName().Version;
+
+ ///
+ /// 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.0 signature..
+ return Pe32Helpers.FindPattern(bind, "53 51 52 56 57 55 8B EC 81 EC 00 10 00 00 BE") > 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.UseFallbackDrmpOffsets = false;
+ 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, decrypt and process the main code section.", LogMessageType.Information);
+ if (!this.Step2())
+ return false;
+
+ this.Log("Step 3 - Prepare the file sections.", LogMessageType.Information);
+ if (!this.Step3())
+ return false;
+
+ this.Log("Step 4 - Rebuild and save the unpacked file.", LogMessageType.Information);
+ if (!this.Step4())
+ 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;
+
+ // Disassemble the file to locate the needed DRM information..
+ if (!this.DisassembleFile(out var structOffset, out var structSize, out var structXorKey))
+ return false;
+
+ // Obtain the DRM header data..
+ var headerData = new byte[structSize];
+ Array.Copy(this.File.FileData, this.File.GetFileOffsetFromRva(structOffset), headerData, 0, structSize);
+
+ // Xor decode the header data..
+ this.XorKey = SteamStubHelpers.SteamXor(ref headerData, (uint)headerData.Length, 0);
+
+ // Create the stub header..
+ this.StubHeader = Pe32Helpers.GetStructure(headerData);
+
+ return true;
+ }
+
+ ///
+ /// Step #2
+ ///
+ /// Read, decrypt and process the main code section.
+ ///
+ ///
+ private bool Step2()
+ {
+ /**
+ * TODO:
+ *
+ * Should we add custom checks here that mimic the validations of the stub based on the header flags?
+ *
+ * 0x01 - Hash check validation of the .bind code and stub header.
+ * 0x02 - WinTrustVerify validation of the file.
+ *
+ * These would just be for warnings to let users know if the file was broken/tampered, but unpacking should
+ * still complete if it can.
+ */
+
+ // Determine the code section RVA..
+ var codeSectionRVA = this.File.NtHeaders.OptionalHeader.BaseOfCode;
+ if (this.StubHeader.CodeSectionVirtualAddress != 0)
+ codeSectionRVA = this.File.GetRvaFromVa(this.StubHeader.CodeSectionVirtualAddress);
+
+ // Get the code section..
+ var codeSection = this.File.GetOwnerSection(codeSectionRVA);
+ if (codeSection.PointerToRawData == 0 || codeSection.SizeOfRawData == 0)
+ return false;
+
+ this.CodeSectionIndex = this.File.GetSectionIndex(codeSection);
+
+ // Get the code section data..
+ var codeSectionData = new byte[codeSection.SizeOfRawData];
+ Array.Copy(this.File.FileData, this.File.GetFileOffsetFromRva(codeSection.VirtualAddress), codeSectionData, 0, codeSection.SizeOfRawData);
+
+ // Skip the code section encoding if we do not need to process it..
+ if ((this.StubHeader.Flags & (uint)DrmFlags.UseEncodedCodeSection) == 0)
+ return true;
+
+ // Decode the code section data..
+ var key = this.StubHeader.CodeSectionXorKey;
+ var offset = 0;
+ for (var x = this.StubHeader.CodeSectionSize >> 2; x > 0; --x)
+ {
+ var val1 = BitConverter.ToUInt32(codeSectionData, offset);
+ var val2 = val1 ^ key;
+ key = val1;
+
+ Array.Copy(BitConverter.GetBytes(val2), 0, codeSectionData, offset, 4);
+
+ offset += 4;
+ }
+
+ // Store the section data..
+ this.CodeSectionData = codeSectionData;
+
+ return true;
+ }
+
+ ///
+ /// Step #3
+ ///
+ /// Prepare the file sections.
+ ///
+ ///
+ private bool Step3()
+ {
+ // 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);
+
+ try
+ {
+ // Rebuild the file sections..
+ this.File.RebuildSections();
+ }
+ catch
+ {
+ return false;
+ }
+
+
+ return true;
+ }
+
+ ///
+ /// Step #4
+ ///
+ /// Rebuild and save the unpacked file.
+ ///
+ ///
+ private bool Step4()
+ {
+ FileStream fStream = null;
+
+ try
+ {
+ // 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];
+ ntHeaders.OptionalHeader.AddressOfEntryPoint = this.File.GetRvaFromVa(this.StubHeader.OEP);
+ 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 uint offset, out uint size, out uint xorKey)
+ {
+ // Prepare our needed variables..
+ Disassembler disasm = null;
+ var dataPointer = IntPtr.Zero;
+ uint structOffset = 0;
+ uint structSize = 0;
+ uint 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 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)
+ {
+ if (structOffset == 0)
+ {
+ structOffset = inst.Operands[1].LvalUDWord - this.File.NtHeaders.OptionalHeader.ImageBase;
+ continue;
+ }
+ }
+
+ // 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].LvalUDWord * 4;
+ structXorKey = 1;
+ }
+ }
+
+ offset = size = xorKey = 0;
+ return false;
+ }
+ catch
+ {
+ offset = size = xorKey = 0;
+ return false;
+ }
+ finally
+ {
+ disasm?.Dispose();
+ if (dataPointer != IntPtr.Zero)
+ Marshal.FreeHGlobal(dataPointer);
+ }
+ }
+
+ ///
+ /// 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 dynamic 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 if the offsets should be read using fallback values.
+ ///
+ private bool UseFallbackDrmpOffsets { 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..a298ffe
--- /dev/null
+++ b/Steamless.Unpacker.Variant20.x86/Properties/AssemblyInfo.cs
@@ -0,0 +1,40 @@
+/**
+ * Steamless - Copyright (c) 2015 - 2020 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 2.0 (x86) Unpacker")]
+[assembly: AssemblyConfiguration("Release")]
+[assembly: AssemblyCompany("atom0s")]
+[assembly: AssemblyProduct("Steamless.Unpacker.Variant20.x86")]
+[assembly: AssemblyCopyright("Copyright © atom0s 2015 - 2020")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+[assembly: ComVisible(false)]
+[assembly: Guid("4f11f26d-2946-467f-a4e9-9e2a619a1fd3")]
+[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..bbddf49
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..87a08af
--- /dev/null
+++ b/Steamless.Unpacker.Variant20.x86/Steamless.Unpacker.Variant20.x86.csproj
@@ -0,0 +1,55 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {4F11F26D-2946-467F-A4E9-9E2A619A1FD3}
+ Library
+ Properties
+ Steamless.Unpacker.Variant20.x86
+ Steamless.Unpacker.Variant20.x86
+ v4.5.2
+ 512
+ true
+
+
+
+ x86
+ ..\Steamless\bin\x86\Debug\Plugins\
+ TRACE;DEBUG
+
+
+ x86
+ ..\Steamless\bin\x86\Release\Plugins\
+ true
+
+
+
+ False
+ .\SharpDisasm.dll
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {56c95629-3b34-47fe-b988-04274409294f}
+ Steamless.API
+
+
+
+
\ No newline at end of file
diff --git a/Steamless.sln b/Steamless.sln
index 7bd50a5..129e611 100644
--- a/Steamless.sln
+++ b/Steamless.sln
@@ -19,6 +19,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Steamless.Unpacker.Variant3
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Steamless.Unpacker.Variant30.x64", "Steamless.Unpacker.Variant30.x64\Steamless.Unpacker.Variant30.x64.csproj", "{03621EAD-77A7-4208-AFDF-4B8292230A71}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Steamless.Unpacker.Variant20.x86", "Steamless.Unpacker.Variant20.x86\Steamless.Unpacker.Variant20.x86.csproj", "{4F11F26D-2946-467F-A4E9-9E2A619A1FD3}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x86 = Debug|x86
@@ -57,6 +59,10 @@ Global
{03621EAD-77A7-4208-AFDF-4B8292230A71}.Debug|x86.Build.0 = Debug|x86
{03621EAD-77A7-4208-AFDF-4B8292230A71}.Release|x86.ActiveCfg = Release|x86
{03621EAD-77A7-4208-AFDF-4B8292230A71}.Release|x86.Build.0 = Release|x86
+ {4F11F26D-2946-467F-A4E9-9E2A619A1FD3}.Debug|x86.ActiveCfg = Debug|x86
+ {4F11F26D-2946-467F-A4E9-9E2A619A1FD3}.Debug|x86.Build.0 = Debug|x86
+ {4F11F26D-2946-467F-A4E9-9E2A619A1FD3}.Release|x86.ActiveCfg = Release|x86
+ {4F11F26D-2946-467F-A4E9-9E2A619A1FD3}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE