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