mirror of
https://github.com/atom0s/Steamless.git
synced 2024-12-19 23:07:41 +01:00
Add support for the real stub 2.0 variant. (This is a first-go at this version. I only have 1 sample with this version of the stub so it is solely based on this one exe. The full stub has been reversed for this file though. You can find more about that in issue #37)
This commit is contained in:
parent
82d763940a
commit
769232fc65
8 changed files with 801 additions and 0 deletions
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Steam Stub Variant 2.0 DRM Flags
|
||||||
|
/// </summary>
|
||||||
|
public enum DrmFlags
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// None.
|
||||||
|
/// </summary>
|
||||||
|
None = 0x00,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Flag that states that the stub will hash check the stub code and header data.
|
||||||
|
/// </summary>
|
||||||
|
UseValidation = 0x01,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Flag that states that the stub will validate the file via WinVerifyTrust if able.
|
||||||
|
/// </summary>
|
||||||
|
UseWinVerifyTrustValidation = 0x02,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Flag that states that the stub will decode/decrypt the code section.
|
||||||
|
/// </summary>
|
||||||
|
UseEncodedCodeSection = 0x04,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 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.)
|
||||||
|
/// </summary>
|
||||||
|
UseThreadCheckValidation = 0x08,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 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.
|
||||||
|
/// </summary>
|
||||||
|
UseMemoryMappedValidation = 0x10
|
||||||
|
}
|
||||||
|
}
|
59
Steamless.Unpacker.Variant20.x86/Classes/SteamStubHeader.cs
Normal file
59
Steamless.Unpacker.Variant20.x86/Classes/SteamStubHeader.cs
Normal file
|
@ -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;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// SteamStub DRM Variant 2.0 Header
|
||||||
|
/// </summary>
|
||||||
|
[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.
|
||||||
|
}
|
||||||
|
}
|
65
Steamless.Unpacker.Variant20.x86/Classes/SteamStubHelpers.cs
Normal file
65
Steamless.Unpacker.Variant20.x86/Classes/SteamStubHelpers.cs
Normal file
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 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.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="data">The data to xor decode.</param>
|
||||||
|
/// <param name="size">The size of the data to decode.</param>
|
||||||
|
/// <param name="key">The starting xor key to decode with.</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
510
Steamless.Unpacker.Variant20.x86/Main.cs
Normal file
510
Steamless.Unpacker.Variant20.x86/Main.cs
Normal file
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Internal logging service instance.
|
||||||
|
/// </summary>
|
||||||
|
private LoggingService m_LoggingService;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the author of this plugin.
|
||||||
|
/// </summary>
|
||||||
|
public override string Author => "atom0s";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the name of this plugin.
|
||||||
|
/// </summary>
|
||||||
|
public override string Name => "SteamStub Variant 2.0 Unpacker (x86)";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the description of this plugin.
|
||||||
|
/// </summary>
|
||||||
|
public override string Description => "Unpacker for the 32bit SteamStub variant 2.0.";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the version of this plugin.
|
||||||
|
/// </summary>
|
||||||
|
public override Version Version => Assembly.GetExecutingAssembly().GetName().Version;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Internal wrapper to log a message.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="msg"></param>
|
||||||
|
/// <param name="type"></param>
|
||||||
|
private void Log(string msg, LogMessageType type)
|
||||||
|
{
|
||||||
|
this.m_LoggingService.OnAddLogMessage(this, new LogMessageEventArgs(msg, type));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initialize function called when this plugin is first loaded.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="logService"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public override bool Initialize(LoggingService logService)
|
||||||
|
{
|
||||||
|
this.m_LoggingService = logService;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 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.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="file"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Processing function called to allow the plugin to process the file.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="file"></param>
|
||||||
|
/// <param name="options"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
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<int>();
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Step #1
|
||||||
|
///
|
||||||
|
/// Read, disassemble and decode the SteamStub DRM header.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
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<SteamStub32Var20Header>(headerData);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Step #2
|
||||||
|
///
|
||||||
|
/// Read, decrypt and process the main code section.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Step #3
|
||||||
|
///
|
||||||
|
/// Prepare the file sections.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Step #4
|
||||||
|
///
|
||||||
|
/// Rebuild and save the unpacked file.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Disassembles the file to locate the needed DRM header information.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="offset"></param>
|
||||||
|
/// <param name="size"></param>
|
||||||
|
/// <param name="xorKey"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the Steamless options this file was requested to process with.
|
||||||
|
/// </summary>
|
||||||
|
private SteamlessOptions Options { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the file being processed.
|
||||||
|
/// </summary>
|
||||||
|
private Pe32File File { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the current xor key being used against the file data.
|
||||||
|
/// </summary>
|
||||||
|
private uint XorKey { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the DRM stub header.
|
||||||
|
/// </summary>
|
||||||
|
private dynamic StubHeader { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the payload data.
|
||||||
|
/// </summary>
|
||||||
|
public byte[] PayloadData { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the SteamDRMP.dll data.
|
||||||
|
/// </summary>
|
||||||
|
public byte[] SteamDrmpData { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the list of SteamDRMP.dll offsets.
|
||||||
|
/// </summary>
|
||||||
|
public List<int> SteamDrmpOffsets { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets if the offsets should be read using fallback values.
|
||||||
|
/// </summary>
|
||||||
|
private bool UseFallbackDrmpOffsets { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the index of the code section.
|
||||||
|
/// </summary>
|
||||||
|
private int CodeSectionIndex { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the decrypted code section data.
|
||||||
|
/// </summary>
|
||||||
|
private byte[] CodeSectionData { get; set; }
|
||||||
|
}
|
||||||
|
}
|
40
Steamless.Unpacker.Variant20.x86/Properties/AssemblyInfo.cs
Normal file
40
Steamless.Unpacker.Variant20.x86/Properties/AssemblyInfo.cs
Normal file
|
@ -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")]
|
BIN
Steamless.Unpacker.Variant20.x86/SharpDisasm.dll
Normal file
BIN
Steamless.Unpacker.Variant20.x86/SharpDisasm.dll
Normal file
Binary file not shown.
|
@ -0,0 +1,55 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
|
<ProjectGuid>{4F11F26D-2946-467F-A4E9-9E2A619A1FD3}</ProjectGuid>
|
||||||
|
<OutputType>Library</OutputType>
|
||||||
|
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||||
|
<RootNamespace>Steamless.Unpacker.Variant20.x86</RootNamespace>
|
||||||
|
<AssemblyName>Steamless.Unpacker.Variant20.x86</AssemblyName>
|
||||||
|
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
|
||||||
|
<FileAlignment>512</FileAlignment>
|
||||||
|
<Deterministic>true</Deterministic>
|
||||||
|
<TargetFrameworkProfile />
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
|
||||||
|
<PlatformTarget>x86</PlatformTarget>
|
||||||
|
<OutputPath>..\Steamless\bin\x86\Debug\Plugins\</OutputPath>
|
||||||
|
<DefineConstants>TRACE;DEBUG</DefineConstants>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
|
||||||
|
<PlatformTarget>x86</PlatformTarget>
|
||||||
|
<OutputPath>..\Steamless\bin\x86\Release\Plugins\</OutputPath>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="SharpDisasm, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
|
<SpecificVersion>False</SpecificVersion>
|
||||||
|
<HintPath>.\SharpDisasm.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.Core" />
|
||||||
|
<Reference Include="System.Xml.Linq" />
|
||||||
|
<Reference Include="System.Data.DataSetExtensions" />
|
||||||
|
<Reference Include="Microsoft.CSharp" />
|
||||||
|
<Reference Include="System.Data" />
|
||||||
|
<Reference Include="System.Net.Http" />
|
||||||
|
<Reference Include="System.Xml" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="Classes\SteamStubDrmFlags.cs" />
|
||||||
|
<Compile Include="Classes\SteamStubHeader.cs" />
|
||||||
|
<Compile Include="Classes\SteamStubHelpers.cs" />
|
||||||
|
<Compile Include="Main.cs" />
|
||||||
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Steamless.API\Steamless.API.csproj">
|
||||||
|
<Project>{56c95629-3b34-47fe-b988-04274409294f}</Project>
|
||||||
|
<Name>Steamless.API</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
|
</Project>
|
|
@ -19,6 +19,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Steamless.Unpacker.Variant3
|
||||||
EndProject
|
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}"
|
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
|
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
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|x86 = Debug|x86
|
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}.Debug|x86.Build.0 = Debug|x86
|
||||||
{03621EAD-77A7-4208-AFDF-4B8292230A71}.Release|x86.ActiveCfg = Release|x86
|
{03621EAD-77A7-4208-AFDF-4B8292230A71}.Release|x86.ActiveCfg = Release|x86
|
||||||
{03621EAD-77A7-4208-AFDF-4B8292230A71}.Release|x86.Build.0 = 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
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|
Loading…
Reference in a new issue