mirror of
https://github.com/atom0s/Steamless.git
synced 2024-12-19 23:07:41 +01:00
Steamless.Unpacker.Variant30.x86
- Fixed issue with header size not unpacking properly for certain files. - Fixed issue with TLS callbacks not being unpacked properly when present. Steamless.Unpacker.Variant30.x64 - Added support for 64bit version of SteamStub Variant 3.0. Steamless.Unpacker.Variant31.x64 - Added support for 64bit version of SteamStub Variant 3.1
This commit is contained in:
parent
a7fa5bb337
commit
8c88ba51c3
15 changed files with 1811 additions and 30 deletions
|
@ -0,0 +1,39 @@
|
|||
/**
|
||||
* Steamless - Copyright (c) 2015 - 2017 atom0s [atom0s@live.com]
|
||||
*
|
||||
* This work is licensed under the Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License.
|
||||
* To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/4.0/ or send a letter to
|
||||
* Creative Commons, PO Box 1866, Mountain View, CA 94042, USA.
|
||||
*
|
||||
* By using Steamless, you agree to the above license and its terms.
|
||||
*
|
||||
* Attribution - You must give appropriate credit, provide a link to the license and indicate if changes were
|
||||
* made. You must do so in any reasonable manner, but not in any way that suggests the licensor
|
||||
* endorses you or your use.
|
||||
*
|
||||
* Non-Commercial - You may not use the material (Steamless) for commercial purposes.
|
||||
*
|
||||
* No-Derivatives - If you remix, transform, or build upon the material (Steamless), you may not distribute the
|
||||
* modified material. You are, however, allowed to submit the modified works back to the original
|
||||
* Steamless project in attempt to have it added to the original project.
|
||||
*
|
||||
* You may not apply legal terms or technological measures that legally restrict others
|
||||
* from doing anything the license permits.
|
||||
*
|
||||
* No warranties are given.
|
||||
*/
|
||||
|
||||
namespace Steamless.Unpacker.Variant30.x64.Classes
|
||||
{
|
||||
/// <summary>
|
||||
/// Steam Stub Variant 3.0 DRM Flags
|
||||
/// </summary>
|
||||
public enum SteamStubDrmFlags
|
||||
{
|
||||
NoModuleVerification = 0x02,
|
||||
NoEncryption = 0x04,
|
||||
NoOwnershipCheck = 0x10,
|
||||
NoDebuggerCheck = 0x20,
|
||||
NoErrorDialog = 0x40
|
||||
}
|
||||
}
|
81
Steamless.Unpacker.Variant30.x64/Classes/SteamStubHeader.cs
Normal file
81
Steamless.Unpacker.Variant30.x64/Classes/SteamStubHeader.cs
Normal file
|
@ -0,0 +1,81 @@
|
|||
/**
|
||||
* Steamless - Copyright (c) 2015 - 2017 atom0s [atom0s@live.com]
|
||||
*
|
||||
* This work is licensed under the Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License.
|
||||
* To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/4.0/ or send a letter to
|
||||
* Creative Commons, PO Box 1866, Mountain View, CA 94042, USA.
|
||||
*
|
||||
* By using Steamless, you agree to the above license and its terms.
|
||||
*
|
||||
* Attribution - You must give appropriate credit, provide a link to the license and indicate if changes were
|
||||
* made. You must do so in any reasonable manner, but not in any way that suggests the licensor
|
||||
* endorses you or your use.
|
||||
*
|
||||
* Non-Commercial - You may not use the material (Steamless) for commercial purposes.
|
||||
*
|
||||
* No-Derivatives - If you remix, transform, or build upon the material (Steamless), you may not distribute the
|
||||
* modified material. You are, however, allowed to submit the modified works back to the original
|
||||
* Steamless project in attempt to have it added to the original project.
|
||||
*
|
||||
* You may not apply legal terms or technological measures that legally restrict others
|
||||
* from doing anything the license permits.
|
||||
*
|
||||
* No warranties are given.
|
||||
*/
|
||||
|
||||
namespace Steamless.Unpacker.Variant30.x64.Classes
|
||||
{
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
/// <summary>
|
||||
/// SteamStub DRM Variant 3.0 x64 Header
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct SteamStub64Var30Header
|
||||
{
|
||||
public uint XorKey; // The base XOR key, if defined, to unpack the file with.
|
||||
public uint Signature; // 0xC0DEC0DE signature to validate this header is proper.
|
||||
public ulong ImageBase; // The base of the image that is protected.
|
||||
public uint AddressOfEntryPoint; // The entry point that is set from the DRM.
|
||||
public uint BindSectionOffset; // The starting offset to the bind section data. RVA(AddressOfEntryPoint - BindSectionOffset)
|
||||
public uint Unknown0000; // [Cyanic: This field is most likely the .bind code size.]
|
||||
public uint OriginalEntryPoint; // The original entry point of the binary before it was protected.
|
||||
public uint Unknown0001; // [Cyanic: This field is most likely an offset to a string table.]
|
||||
public uint PayloadSize; // The size of the payload data.
|
||||
public uint DRMPDllOffset; // The offset to the SteamDRMP.dll file.
|
||||
public uint DRMPDllSize; // The size of the SteamDRMP.dll file.
|
||||
public uint SteamAppId; // The Steam Application ID of this game.
|
||||
public uint Flags; // The DRM flags used while creating the protected executable.
|
||||
public uint BindSectionVirtualSize; // The bind section virtual size.
|
||||
public uint Unknown0002; // [Cyanic: This field is most likely a hash of some sort.]
|
||||
public uint CodeSectionVirtualAddress; // The cpde section virtual address.
|
||||
public uint CodeSectionRawSize; // The raw size of the code section.
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x20)]
|
||||
public byte[] AES_Key; // The AES encryption key.
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x10)]
|
||||
public byte[] AES_IV; // The AES encryption IV.
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x10)]
|
||||
public byte[] CodeSectionStolenData; // The first 16 bytes of the code section stolen.
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x04)]
|
||||
public uint[] EncryptionKeys; // Encryption keys used for decrypting SteamDRMP.dll file.
|
||||
|
||||
public uint Unknown0003; // [Cyanic: This field is most likely used to flag if the file has Tls data or not.]
|
||||
public uint Unknown0004;
|
||||
public uint Unknown0005;
|
||||
public uint Unknown0006;
|
||||
public uint Unknown0007;
|
||||
public uint Unknown0008;
|
||||
public uint GetModuleHandleA_RVA; // The RVA to GetModuleHandleA.
|
||||
public uint GetModuleHandleW_RVA; // The RVA to GetModuleHandleW.
|
||||
public uint LoadLibraryA_RVA; // The RVA to LoadLibraryA.
|
||||
public uint LoadLibraryW_RVA; // The RVA to LoadLibraryW.
|
||||
public uint GetProcAddress_RVA; // The RVA to GetProcAddress.
|
||||
public uint Unknown0009;
|
||||
public uint Unknown0010;
|
||||
public uint Unknown0011;
|
||||
}
|
||||
}
|
122
Steamless.Unpacker.Variant30.x64/Classes/SteamStubHelpers.cs
Normal file
122
Steamless.Unpacker.Variant30.x64/Classes/SteamStubHelpers.cs
Normal file
|
@ -0,0 +1,122 @@
|
|||
/**
|
||||
* Steamless - Copyright (c) 2015 - 2017 atom0s [atom0s@live.com]
|
||||
*
|
||||
* This work is licensed under the Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License.
|
||||
* To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/4.0/ or send a letter to
|
||||
* Creative Commons, PO Box 1866, Mountain View, CA 94042, USA.
|
||||
*
|
||||
* By using Steamless, you agree to the above license and its terms.
|
||||
*
|
||||
* Attribution - You must give appropriate credit, provide a link to the license and indicate if changes were
|
||||
* made. You must do so in any reasonable manner, but not in any way that suggests the licensor
|
||||
* endorses you or your use.
|
||||
*
|
||||
* Non-Commercial - You may not use the material (Steamless) for commercial purposes.
|
||||
*
|
||||
* No-Derivatives - If you remix, transform, or build upon the material (Steamless), you may not distribute the
|
||||
* modified material. You are, however, allowed to submit the modified works back to the original
|
||||
* Steamless project in attempt to have it added to the original project.
|
||||
*
|
||||
* You may not apply legal terms or technological measures that legally restrict others
|
||||
* from doing anything the license permits.
|
||||
*
|
||||
* No warranties are given.
|
||||
*/
|
||||
|
||||
namespace Steamless.Unpacker.Variant30.x64.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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The second pass of decryption for the SteamDRMP.dll file.
|
||||
///
|
||||
/// @note The encryption method here is known as XTEA.
|
||||
/// </summary>
|
||||
/// <param name="res">The result value buffer to write our returns to.</param>
|
||||
/// <param name="keys">The keys used for the decryption.</param>
|
||||
/// <param name="v1">The first value to decrypt from.</param>
|
||||
/// <param name="v2">The second value to decrypt from.</param>
|
||||
/// <param name="n">The number of passes to crypt the data with.</param>
|
||||
public static void SteamDrmpDecryptPass2(ref uint[] res, uint[] keys, uint v1, uint v2, uint n = 32)
|
||||
{
|
||||
const uint delta = 0x9E3779B9;
|
||||
const uint mask = 0xFFFFFFFF;
|
||||
var sum = (delta * n) & mask;
|
||||
|
||||
for (var x = 0; x < n; x++)
|
||||
{
|
||||
v2 = (v2 - (((v1 << 4 ^ v1 >> 5) + v1) ^ (sum + keys[sum >> 11 & 3]))) & mask;
|
||||
sum = (sum - delta) & mask;
|
||||
v1 = (v1 - (((v2 << 4 ^ v2 >> 5) + v2) ^ (sum + keys[sum & 3]))) & mask;
|
||||
}
|
||||
|
||||
res[0] = v1;
|
||||
res[1] = v2;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The first pass of the decryption for the SteamDRMP.dll file.
|
||||
///
|
||||
/// @note The encryption method here is known as XTEA. It is modded to include
|
||||
/// some basic xor'ing.
|
||||
/// </summary>
|
||||
/// <param name="data">The data to decrypt.</param>
|
||||
/// <param name="size">The size of the data to decrypt.</param>
|
||||
/// <param name="keys">The keys used for the decryption.</param>
|
||||
public static void SteamDrmpDecryptPass1(ref byte[] data, uint size, uint[] keys)
|
||||
{
|
||||
var v1 = (uint)0x55555555;
|
||||
var v2 = (uint)0x55555555;
|
||||
|
||||
for (var x = 0; x < size; x += 8)
|
||||
{
|
||||
var d1 = BitConverter.ToUInt32(data, x + 0);
|
||||
var d2 = BitConverter.ToUInt32(data, x + 4);
|
||||
|
||||
var res = new uint[2];
|
||||
SteamDrmpDecryptPass2(ref res, keys, d1, d2);
|
||||
|
||||
Array.Copy(BitConverter.GetBytes(res[0] ^ v1), 0, data, x + 0, 4);
|
||||
Array.Copy(BitConverter.GetBytes(res[1] ^ v2), 0, data, x + 4, 4);
|
||||
|
||||
v1 = d1;
|
||||
v2 = d2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
518
Steamless.Unpacker.Variant30.x64/Main.cs
Normal file
518
Steamless.Unpacker.Variant30.x64/Main.cs
Normal file
|
@ -0,0 +1,518 @@
|
|||
/**
|
||||
* Steamless - Copyright (c) 2015 - 2017 atom0s [atom0s@live.com]
|
||||
*
|
||||
* This work is licensed under the Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License.
|
||||
* To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/4.0/ or send a letter to
|
||||
* Creative Commons, PO Box 1866, Mountain View, CA 94042, USA.
|
||||
*
|
||||
* By using Steamless, you agree to the above license and its terms.
|
||||
*
|
||||
* Attribution - You must give appropriate credit, provide a link to the license and indicate if changes were
|
||||
* made. You must do so in any reasonable manner, but not in any way that suggests the licensor
|
||||
* endorses you or your use.
|
||||
*
|
||||
* Non-Commercial - You may not use the material (Steamless) for commercial purposes.
|
||||
*
|
||||
* No-Derivatives - If you remix, transform, or build upon the material (Steamless), you may not distribute the
|
||||
* modified material. You are, however, allowed to submit the modified works back to the original
|
||||
* Steamless project in attempt to have it added to the original project.
|
||||
*
|
||||
* You may not apply legal terms or technological measures that legally restrict others
|
||||
* from doing anything the license permits.
|
||||
*
|
||||
* No warranties are given.
|
||||
*/
|
||||
|
||||
namespace Steamless.Unpacker.Variant30.x64
|
||||
{
|
||||
using API;
|
||||
using API.Crypto;
|
||||
using API.Events;
|
||||
using API.Extensions;
|
||||
using API.Model;
|
||||
using API.PE64;
|
||||
using API.Services;
|
||||
using Classes;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
[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 3.0 Unpacker (x64)";
|
||||
|
||||
/// <summary>
|
||||
/// Gets the description of this plugin.
|
||||
/// </summary>
|
||||
public override string Description => "Unpacker for the 64bit SteamStub variant 3.0.";
|
||||
|
||||
/// <summary>
|
||||
/// Gets the version of this plugin.
|
||||
/// </summary>
|
||||
public override Version Version => new Version(1, 0, 0, 0);
|
||||
|
||||
/// <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>
|
||||
/// Gets the SteamStub header size from the given file.
|
||||
/// </summary>
|
||||
/// <param name="f"></param>
|
||||
/// <returns></returns>
|
||||
private uint GetHeaderSize(Pe64File f)
|
||||
{
|
||||
// Obtain the bind section data..
|
||||
var bind = f.GetSectionData(".bind");
|
||||
|
||||
// Attempt to locate the known v3.x signature..
|
||||
var varient = Pe64Helpers.FindPattern(bind, "E8 00 00 00 00 50 53 51 52 56 57 55 41 50");
|
||||
if (varient == 0) return 0;
|
||||
|
||||
// Attempt to determine the varient version..
|
||||
var offset = Pe64Helpers.FindPattern(bind, "48 8D 91 ?? ?? ?? ?? 48"); // 3.0
|
||||
if (offset == 0)
|
||||
offset = Pe64Helpers.FindPattern(bind, "48 8D 91 ?? ?? ?? ?? 41"); // 3.1
|
||||
|
||||
// Ensure a pattern was found..
|
||||
if (offset == 0) return 0;
|
||||
|
||||
// Read the header size.. (The header size is only 32bit!)
|
||||
return (uint)Math.Abs(BitConverter.ToInt32(bind, (int)offset + 3));
|
||||
}
|
||||
|
||||
/// <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 Pe64File(file);
|
||||
if (!f.Parse() || !f.IsFile64Bit() || !f.HasSection(".bind"))
|
||||
return false;
|
||||
|
||||
// Check for the known 3.0 header sizes..
|
||||
var headerSize = this.GetHeaderSize(f);
|
||||
return headerSize == 0xB0 || headerSize == 0xD0;
|
||||
}
|
||||
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.TlsAsOep = false;
|
||||
this.TlsOepRva = 0;
|
||||
this.Options = options;
|
||||
this.CodeSectionData = null;
|
||||
this.CodeSectionIndex = -1;
|
||||
this.XorKey = 0;
|
||||
|
||||
// Parse the file..
|
||||
this.File = new Pe64File(file);
|
||||
if (!this.File.Parse())
|
||||
return false;
|
||||
|
||||
// Announce we are being unpacked with this packer..
|
||||
this.Log("File is packed with SteamStub Variant 3.0!", LogMessageType.Information);
|
||||
|
||||
this.Log("Step 1 - Read, decode and validate the SteamStub DRM header.", LogMessageType.Information);
|
||||
if (!this.Step1())
|
||||
return false;
|
||||
|
||||
this.Log("Step 2 - Read, decode and process the payload data.", LogMessageType.Information);
|
||||
if (!this.Step2())
|
||||
return false;
|
||||
|
||||
this.Log("Step 3 - Read, decode and dump the SteamDRMP.dll file.", LogMessageType.Information);
|
||||
if (!this.Step3())
|
||||
return false;
|
||||
|
||||
this.Log("Step 4 - Handle .bind section. Find code section.", LogMessageType.Information);
|
||||
if (!this.Step4())
|
||||
return false;
|
||||
|
||||
this.Log("Step 5 - Read, decrypt and process code section.", LogMessageType.Information);
|
||||
if (!this.Step5())
|
||||
return false;
|
||||
|
||||
this.Log("Step 6 - Rebuild and save the unpacked file.", LogMessageType.Information);
|
||||
if (!this.Step6())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Step #1
|
||||
///
|
||||
/// Read, decode and validate the SteamStub DRM header.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private bool Step1()
|
||||
{
|
||||
// Obtain the header size..
|
||||
var headerSize = this.GetHeaderSize(this.File);
|
||||
|
||||
// Obtain the DRM header data..
|
||||
var fileOffset = this.File.GetFileOffsetFromRva(this.File.NtHeaders.OptionalHeader.AddressOfEntryPoint);
|
||||
var headerData = new byte[headerSize];
|
||||
Array.Copy(this.File.FileData, (long)(fileOffset - headerSize), headerData, 0, headerSize);
|
||||
|
||||
// Xor decode the header data..
|
||||
this.XorKey = SteamStubHelpers.SteamXor(ref headerData, headerSize);
|
||||
this.StubHeader = Pe64Helpers.GetStructure<SteamStub64Var30Header>(headerData);
|
||||
|
||||
// Validate the structure signature..
|
||||
return this.StubHeader.Signature == 0xC0DEC0DE;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Step #2
|
||||
///
|
||||
/// Read, decode and process the payload data.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private bool Step2()
|
||||
{
|
||||
// Obtain the payload address and size..
|
||||
var payloadAddr = this.File.GetFileOffsetFromRva(this.File.NtHeaders.OptionalHeader.AddressOfEntryPoint - this.StubHeader.BindSectionOffset);
|
||||
var payloadSize = (this.StubHeader.PayloadSize + 0x0F) & 0xFFFFFFF0;
|
||||
|
||||
// Do nothing if there is no payload..
|
||||
if (payloadSize == 0)
|
||||
return true;
|
||||
|
||||
this.Log(" --> File has payload data!", LogMessageType.Debug);
|
||||
|
||||
// Obtain and decode the payload..
|
||||
var payload = new byte[payloadSize];
|
||||
Array.Copy(this.File.FileData, (long)payloadAddr, payload, 0, payloadSize);
|
||||
this.XorKey = SteamStubHelpers.SteamXor(ref payload, payloadSize, this.XorKey);
|
||||
|
||||
try
|
||||
{
|
||||
if (this.Options.DumpPayloadToDisk)
|
||||
{
|
||||
System.IO.File.WriteAllBytes(this.File.FilePath + ".payload", payload);
|
||||
this.Log(" --> Saved payload to disk!", LogMessageType.Debug);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Do nothing here since it doesn't matter if this fails..
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Step #3
|
||||
///
|
||||
/// Read, decode and dump the SteamDRMP.dll file.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private bool Step3()
|
||||
{
|
||||
// Ensure there is a dll to process..
|
||||
if (this.StubHeader.DRMPDllSize == 0)
|
||||
{
|
||||
this.Log(" --> File does not contain a SteamDRMP.dll file.", LogMessageType.Debug);
|
||||
return true;
|
||||
}
|
||||
|
||||
this.Log(" --> File has SteamDRMP.dll file!", LogMessageType.Debug);
|
||||
|
||||
try
|
||||
{
|
||||
// Obtain the SteamDRMP.dll file address and data..
|
||||
var drmpAddr = this.File.GetFileOffsetFromRva(this.File.NtHeaders.OptionalHeader.AddressOfEntryPoint - this.StubHeader.BindSectionOffset + this.StubHeader.DRMPDllOffset);
|
||||
var drmpData = new byte[this.StubHeader.DRMPDllSize];
|
||||
Array.Copy(this.File.FileData, (long)drmpAddr, drmpData, 0, drmpData.Length);
|
||||
|
||||
// Decrypt the data (xtea decryption)..
|
||||
SteamStubHelpers.SteamDrmpDecryptPass1(ref drmpData, this.StubHeader.DRMPDllSize, this.StubHeader.EncryptionKeys);
|
||||
|
||||
try
|
||||
{
|
||||
if (this.Options.DumpSteamDrmpToDisk)
|
||||
{
|
||||
var basePath = Path.GetDirectoryName(this.File.FilePath) ?? string.Empty;
|
||||
System.IO.File.WriteAllBytes(Path.Combine(basePath, "SteamDRMP.dll"), drmpData);
|
||||
this.Log(" --> Saved SteamDRMP.dll to disk!", LogMessageType.Debug);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Do nothing here since it doesn't matter if this fails..
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
this.Log(" --> Error trying to decrypt the files SteamDRMP.dll data!", LogMessageType.Error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Step #4
|
||||
///
|
||||
/// Remove the bind section if requested.
|
||||
/// Find the code section.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private bool Step4()
|
||||
{
|
||||
// Remove the bind section if its not requested to be saved..
|
||||
if (!this.Options.KeepBindSection)
|
||||
{
|
||||
// Obtain the .bind section..
|
||||
var bindSection = this.File.GetSection(".bind");
|
||||
if (!bindSection.IsValid)
|
||||
return false;
|
||||
|
||||
// Remove the section..
|
||||
this.File.RemoveSection(bindSection);
|
||||
|
||||
// Decrease the header section count..
|
||||
var ntHeaders = this.File.NtHeaders;
|
||||
ntHeaders.FileHeader.NumberOfSections--;
|
||||
this.File.NtHeaders = ntHeaders;
|
||||
|
||||
this.Log(" --> .bind section was removed from the file.", LogMessageType.Debug);
|
||||
}
|
||||
else
|
||||
this.Log(" --> .bind section was kept in the file.", LogMessageType.Debug);
|
||||
|
||||
// Skip finding the code section if the file is not encrypted..
|
||||
if ((this.StubHeader.Flags & (uint)SteamStubDrmFlags.NoEncryption) == (uint)SteamStubDrmFlags.NoEncryption)
|
||||
return true;
|
||||
|
||||
// Find the code section..
|
||||
var codeSection = this.File.GetOwnerSection(this.StubHeader.CodeSectionVirtualAddress);
|
||||
if (codeSection.PointerToRawData == 0 || codeSection.SizeOfRawData == 0)
|
||||
return false;
|
||||
|
||||
// Store the code sections index..
|
||||
this.CodeSectionIndex = this.File.GetSectionIndex(codeSection);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Step #5
|
||||
///
|
||||
/// Read, decrypt and process the code section.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private bool Step5()
|
||||
{
|
||||
// Skip decryption if the code section is not encrypted..
|
||||
if ((this.StubHeader.Flags & (uint)SteamStubDrmFlags.NoEncryption) == (uint)SteamStubDrmFlags.NoEncryption)
|
||||
{
|
||||
this.Log(" --> Code section is not encrypted.", LogMessageType.Debug);
|
||||
return true;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// Obtain the code section..
|
||||
var codeSection = this.File.Sections[this.CodeSectionIndex];
|
||||
this.Log($" --> {codeSection.SectionName} linked as main code section.", LogMessageType.Debug);
|
||||
this.Log($" --> {codeSection.SectionName} section is encrypted.", LogMessageType.Debug);
|
||||
|
||||
// Obtain the code section data..
|
||||
var codeSectionData = new byte[codeSection.SizeOfRawData + this.StubHeader.CodeSectionStolenData.Length];
|
||||
Array.Copy(this.StubHeader.CodeSectionStolenData, (long)0, codeSectionData, 0, this.StubHeader.CodeSectionStolenData.Length);
|
||||
Array.Copy(this.File.FileData, (long)this.File.GetFileOffsetFromRva(codeSection.VirtualAddress), codeSectionData, this.StubHeader.CodeSectionStolenData.Length, codeSection.SizeOfRawData);
|
||||
|
||||
// Create the AES decryption helper..
|
||||
var aes = new AesHelper(this.StubHeader.AES_Key, this.StubHeader.AES_IV);
|
||||
aes.RebuildIv(this.StubHeader.AES_IV);
|
||||
|
||||
// Decrypt the code section data..
|
||||
var data = aes.Decrypt(codeSectionData, CipherMode.CBC, PaddingMode.None);
|
||||
if (data == null)
|
||||
return false;
|
||||
|
||||
// Set the code section override data..
|
||||
this.CodeSectionData = data;
|
||||
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
this.Log(" --> Error trying to decrypt the files code section data!", LogMessageType.Error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Step #6
|
||||
///
|
||||
/// Rebuild and save the unpacked file.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private bool Step6()
|
||||
{
|
||||
FileStream fStream = null;
|
||||
|
||||
try
|
||||
{
|
||||
// Rebuild the file sections..
|
||||
this.File.RebuildSections();
|
||||
|
||||
// Open the unpacked file for writing..
|
||||
var unpackedPath = this.File.FilePath + ".unpacked.exe";
|
||||
fStream = new FileStream(unpackedPath, FileMode.Create, FileAccess.ReadWrite);
|
||||
|
||||
// Write the DOS header to the file..
|
||||
fStream.WriteBytes(Pe64Helpers.GetStructureBytes(this.File.DosHeader));
|
||||
|
||||
// Write the DOS stub to the file..
|
||||
if (this.File.DosStubSize > 0)
|
||||
fStream.WriteBytes(this.File.DosStubData);
|
||||
|
||||
// Update the entry point of the file..
|
||||
var ntHeaders = this.File.NtHeaders;
|
||||
ntHeaders.OptionalHeader.AddressOfEntryPoint = this.StubHeader.OriginalEntryPoint;
|
||||
this.File.NtHeaders = ntHeaders;
|
||||
|
||||
// Write the NT headers to the file..
|
||||
fStream.WriteBytes(Pe64Helpers.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(Pe64Helpers.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>
|
||||
/// Gets or sets if the Tls callback is being used as the Oep.
|
||||
/// </summary>
|
||||
private bool TlsAsOep { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Tls Oep Rva if it is being used as the Oep.
|
||||
/// </summary>
|
||||
private ulong TlsOepRva { get; set; }
|
||||
|
||||
/// <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 Pe64File 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 SteamStub64Var30Header StubHeader { 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.Variant30.x64/Properties/AssemblyInfo.cs
Normal file
40
Steamless.Unpacker.Variant30.x64/Properties/AssemblyInfo.cs
Normal file
|
@ -0,0 +1,40 @@
|
|||
/**
|
||||
* Steamless - Copyright (c) 2015 - 2017 atom0s [atom0s@live.com]
|
||||
*
|
||||
* This work is licensed under the Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License.
|
||||
* To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/4.0/ or send a letter to
|
||||
* Creative Commons, PO Box 1866, Mountain View, CA 94042, USA.
|
||||
*
|
||||
* By using Steamless, you agree to the above license and its terms.
|
||||
*
|
||||
* Attribution - You must give appropriate credit, provide a link to the license and indicate if changes were
|
||||
* made. You must do so in any reasonable manner, but not in any way that suggests the licensor
|
||||
* endorses you or your use.
|
||||
*
|
||||
* Non-Commercial - You may not use the material (Steamless) for commercial purposes.
|
||||
*
|
||||
* No-Derivatives - If you remix, transform, or build upon the material (Steamless), you may not distribute the
|
||||
* modified material. You are, however, allowed to submit the modified works back to the original
|
||||
* Steamless project in attempt to have it added to the original project.
|
||||
*
|
||||
* You may not apply legal terms or technological measures that legally restrict others
|
||||
* from doing anything the license permits.
|
||||
*
|
||||
* No warranties are given.
|
||||
*/
|
||||
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
[assembly: AssemblyTitle("Steamless.Unpacker.Variant30.x64")]
|
||||
[assembly: AssemblyDescription("Steamless SteamStub Variant v3.0 (x64) Unpacker")]
|
||||
[assembly: AssemblyConfiguration("Release")]
|
||||
[assembly: AssemblyCompany("atom0s")]
|
||||
[assembly: AssemblyProduct("Steamless.Unpacker.Variant30.x64")]
|
||||
[assembly: AssemblyCopyright("Copyright © atom0s 2015 - 2017")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
[assembly: ComVisible(false)]
|
||||
[assembly: Guid("03621ead-77a7-4208-afdf-4b8292230a71")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
|
@ -0,0 +1,55 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" 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>{03621EAD-77A7-4208-AFDF-4B8292230A71}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>Steamless.Unpacker.Variant30.x64</RootNamespace>
|
||||
<AssemblyName>Steamless.Unpacker.Variant30.x64</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<OutputPath>..\Steamless\bin\x86\Debug\Plugins\</OutputPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<OutputPath>..\Steamless\bin\x86\Release\Plugins\</OutputPath>
|
||||
<Optimize>true</Optimize>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<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" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
|
@ -63,7 +63,7 @@ namespace Steamless.Unpacker.Variant30.x86
|
|||
/// <summary>
|
||||
/// Gets the version of this plugin.
|
||||
/// </summary>
|
||||
public override Version Version => new Version(1, 0, 0, 0);
|
||||
public override Version Version => new Version(1, 0, 0, 1);
|
||||
|
||||
/// <summary>
|
||||
/// Internal wrapper to log a message.
|
||||
|
@ -86,6 +86,37 @@ namespace Steamless.Unpacker.Variant30.x86
|
|||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the SteamStub header size from the given file.
|
||||
/// </summary>
|
||||
/// <param name="f"></param>
|
||||
/// <returns></returns>
|
||||
private uint GetHeaderSize(Pe32File f)
|
||||
{
|
||||
// Obtain the bind section data..
|
||||
var bind = f.GetSectionData(".bind");
|
||||
|
||||
// Attempt to locate the known v3.x signature..
|
||||
var varient = Pe32Helpers.FindPattern(bind, "E8 00 00 00 00 50 53 51 52 56 57 55 8B 44 24 1C 2D 05 00 00 00 8B CC 83 E4 F0 51 51 51 50");
|
||||
if (varient == 0) return 0;
|
||||
|
||||
// Attempt to determine the varient version..
|
||||
uint headerSize;
|
||||
var offset = Pe32Helpers.FindPattern(bind, "55 8B EC 81 EC ?? ?? ?? ?? 53 ?? ?? ?? ?? ?? 68");
|
||||
if (offset == 0)
|
||||
{
|
||||
offset = Pe32Helpers.FindPattern(bind, "55 8B EC 81 EC ?? ?? ?? ?? 53 ?? ?? ?? ?? ?? 8D 83");
|
||||
if (offset == 0)
|
||||
return 0;
|
||||
|
||||
headerSize = (uint)BitConverter.ToInt32(bind, (int)offset + 22);
|
||||
}
|
||||
else
|
||||
headerSize = (uint)BitConverter.ToInt32(bind, (int)offset + 16);
|
||||
|
||||
return headerSize;
|
||||
}
|
||||
|
||||
/// <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.
|
||||
|
@ -101,27 +132,8 @@ namespace Steamless.Unpacker.Variant30.x86
|
|||
if (!f.Parse() || f.IsFile64Bit() || !f.HasSection(".bind"))
|
||||
return false;
|
||||
|
||||
// Obtain the bind section data..
|
||||
var bind = f.GetSectionData(".bind");
|
||||
|
||||
// Attempt to locate the known v3.x signature..
|
||||
var varient = Pe32Helpers.FindPattern(bind, "E8 00 00 00 00 50 53 51 52 56 57 55 8B 44 24 1C 2D 05 00 00 00 8B CC 83 E4 F0 51 51 51 50");
|
||||
if (varient == 0) return false;
|
||||
|
||||
// Attempt to determine the varient version..
|
||||
int headerSize;
|
||||
var offset = Pe32Helpers.FindPattern(bind, "55 8B EC 81 EC ?? ?? ?? ?? 53 ?? ?? ?? ?? ?? 68");
|
||||
if (offset == 0)
|
||||
{
|
||||
offset = Pe32Helpers.FindPattern(bind, "55 8B EC 81 EC ?? ?? ?? ?? 53 ?? ?? ?? ?? ?? 8D 83");
|
||||
if (offset == 0)
|
||||
return false;
|
||||
|
||||
headerSize = BitConverter.ToInt32(bind, (int)offset + 22);
|
||||
}
|
||||
else
|
||||
headerSize = BitConverter.ToInt32(bind, (int)offset + 16);
|
||||
|
||||
// Check for the known 3.0 header sizes..
|
||||
var headerSize = this.GetHeaderSize(f);
|
||||
return headerSize == 0xB0 || headerSize == 0xD0;
|
||||
}
|
||||
catch
|
||||
|
@ -139,6 +151,8 @@ namespace Steamless.Unpacker.Variant30.x86
|
|||
public override bool ProcessFile(string file, SteamlessOptions options)
|
||||
{
|
||||
// Initialize the class members..
|
||||
this.TlsAsOep = false;
|
||||
this.TlsOepRva = 0;
|
||||
this.Options = options;
|
||||
this.CodeSectionData = null;
|
||||
this.CodeSectionIndex = -1;
|
||||
|
@ -187,17 +201,44 @@ namespace Steamless.Unpacker.Variant30.x86
|
|||
/// <returns></returns>
|
||||
private bool Step1()
|
||||
{
|
||||
// Obtain the header size..
|
||||
var headerSize = this.GetHeaderSize(this.File);
|
||||
|
||||
// Obtain the DRM header data..
|
||||
var fileOffset = this.File.GetFileOffsetFromRva(this.File.NtHeaders.OptionalHeader.AddressOfEntryPoint);
|
||||
var headerData = new byte[0xD0];
|
||||
Array.Copy(this.File.FileData, (int)(fileOffset - 0xD0), headerData, 0, 0xD0);
|
||||
var headerData = new byte[headerSize];
|
||||
Array.Copy(this.File.FileData, (int)(fileOffset - headerSize), headerData, 0, headerSize);
|
||||
|
||||
// Xor decode the header data..
|
||||
this.XorKey = SteamStubHelpers.SteamXor(ref headerData, 0xD0);
|
||||
this.XorKey = SteamStubHelpers.SteamXor(ref headerData, headerSize);
|
||||
this.StubHeader = Pe32Helpers.GetStructure<SteamStub32Var30Header>(headerData);
|
||||
|
||||
// Validate the structure signature..
|
||||
return this.StubHeader.Signature == 0xC0DEC0DE;
|
||||
if (this.StubHeader.Signature == 0xC0DEC0DE)
|
||||
return true;
|
||||
|
||||
// Try again using the Tls callback (if any) as the OEP instead..
|
||||
if (this.File.TlsCallbacks.Count == 0)
|
||||
return false;
|
||||
|
||||
// Obtain the DRM header data..
|
||||
fileOffset = this.File.GetRvaFromVa(this.File.TlsCallbacks[0]);
|
||||
fileOffset = this.File.GetFileOffsetFromRva(fileOffset);
|
||||
headerData = new byte[headerSize];
|
||||
Array.Copy(this.File.FileData, (int)(fileOffset - headerSize), headerData, 0, headerSize);
|
||||
|
||||
// Xor decode the header data..
|
||||
this.XorKey = SteamStubHelpers.SteamXor(ref headerData, headerSize);
|
||||
this.StubHeader = Pe32Helpers.GetStructure<SteamStub32Var30Header>(headerData);
|
||||
|
||||
// Validate the structure signature..
|
||||
if (this.StubHeader.Signature == 0xC0DEC0DE)
|
||||
return true;
|
||||
|
||||
// Tls was valid for the real oep..
|
||||
this.TlsAsOep = true;
|
||||
this.TlsOepRva = fileOffset;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -209,7 +250,7 @@ namespace Steamless.Unpacker.Variant30.x86
|
|||
private bool Step2()
|
||||
{
|
||||
// Obtain the payload address and size..
|
||||
var payloadAddr = this.File.GetFileOffsetFromRva(this.File.NtHeaders.OptionalHeader.AddressOfEntryPoint - this.StubHeader.BindSectionOffset);
|
||||
var payloadAddr = this.File.GetFileOffsetFromRva(this.TlsAsOep ? this.TlsOepRva : this.File.NtHeaders.OptionalHeader.AddressOfEntryPoint - this.StubHeader.BindSectionOffset);
|
||||
var payloadSize = (this.StubHeader.PayloadSize + 0x0F) & 0xFFFFFFF0;
|
||||
|
||||
// Do nothing if there is no payload..
|
||||
|
@ -259,7 +300,7 @@ namespace Steamless.Unpacker.Variant30.x86
|
|||
try
|
||||
{
|
||||
// Obtain the SteamDRMP.dll file address and data..
|
||||
var drmpAddr = this.File.GetFileOffsetFromRva(this.File.NtHeaders.OptionalHeader.AddressOfEntryPoint - this.StubHeader.BindSectionOffset + this.StubHeader.DRMPDllOffset);
|
||||
var drmpAddr = this.File.GetFileOffsetFromRva(this.TlsAsOep ? this.TlsOepRva : this.File.NtHeaders.OptionalHeader.AddressOfEntryPoint - this.StubHeader.BindSectionOffset + this.StubHeader.DRMPDllOffset);
|
||||
var drmpData = new byte[this.StubHeader.DRMPDllSize];
|
||||
Array.Copy(this.File.FileData, drmpAddr, drmpData, 0, drmpData.Length);
|
||||
|
||||
|
@ -463,6 +504,16 @@ namespace Steamless.Unpacker.Variant30.x86
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets if the Tls callback is being used as the Oep.
|
||||
/// </summary>
|
||||
private bool TlsAsOep { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Tls Oep Rva if it is being used as the Oep.
|
||||
/// </summary>
|
||||
private uint TlsOepRva { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Steamless options this file was requested to process with.
|
||||
/// </summary>
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
/**
|
||||
* Steamless - Copyright (c) 2015 - 2017 atom0s [atom0s@live.com]
|
||||
*
|
||||
* This work is licensed under the Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License.
|
||||
* To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/4.0/ or send a letter to
|
||||
* Creative Commons, PO Box 1866, Mountain View, CA 94042, USA.
|
||||
*
|
||||
* By using Steamless, you agree to the above license and its terms.
|
||||
*
|
||||
* Attribution - You must give appropriate credit, provide a link to the license and indicate if changes were
|
||||
* made. You must do so in any reasonable manner, but not in any way that suggests the licensor
|
||||
* endorses you or your use.
|
||||
*
|
||||
* Non-Commercial - You may not use the material (Steamless) for commercial purposes.
|
||||
*
|
||||
* No-Derivatives - If you remix, transform, or build upon the material (Steamless), you may not distribute the
|
||||
* modified material. You are, however, allowed to submit the modified works back to the original
|
||||
* Steamless project in attempt to have it added to the original project.
|
||||
*
|
||||
* You may not apply legal terms or technological measures that legally restrict others
|
||||
* from doing anything the license permits.
|
||||
*
|
||||
* No warranties are given.
|
||||
*/
|
||||
|
||||
namespace Steamless.Unpacker.Variant31.x64.Classes
|
||||
{
|
||||
/// <summary>
|
||||
/// Steam Stub Variant 3.1 DRM Flags
|
||||
/// </summary>
|
||||
public enum SteamStubDrmFlags
|
||||
{
|
||||
NoModuleVerification = 0x02,
|
||||
NoEncryption = 0x04,
|
||||
NoOwnershipCheck = 0x10,
|
||||
NoDebuggerCheck = 0x20,
|
||||
NoErrorDialog = 0x40
|
||||
}
|
||||
}
|
75
Steamless.Unpacker.Variant31.x64/Classes/SteamStubHeader.cs
Normal file
75
Steamless.Unpacker.Variant31.x64/Classes/SteamStubHeader.cs
Normal file
|
@ -0,0 +1,75 @@
|
|||
/**
|
||||
* Steamless - Copyright (c) 2015 - 2017 atom0s [atom0s@live.com]
|
||||
*
|
||||
* This work is licensed under the Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License.
|
||||
* To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/4.0/ or send a letter to
|
||||
* Creative Commons, PO Box 1866, Mountain View, CA 94042, USA.
|
||||
*
|
||||
* By using Steamless, you agree to the above license and its terms.
|
||||
*
|
||||
* Attribution - You must give appropriate credit, provide a link to the license and indicate if changes were
|
||||
* made. You must do so in any reasonable manner, but not in any way that suggests the licensor
|
||||
* endorses you or your use.
|
||||
*
|
||||
* Non-Commercial - You may not use the material (Steamless) for commercial purposes.
|
||||
*
|
||||
* No-Derivatives - If you remix, transform, or build upon the material (Steamless), you may not distribute the
|
||||
* modified material. You are, however, allowed to submit the modified works back to the original
|
||||
* Steamless project in attempt to have it added to the original project.
|
||||
*
|
||||
* You may not apply legal terms or technological measures that legally restrict others
|
||||
* from doing anything the license permits.
|
||||
*
|
||||
* No warranties are given.
|
||||
*/
|
||||
|
||||
namespace Steamless.Unpacker.Variant31.x64.Classes
|
||||
{
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
/// <summary>
|
||||
/// SteamStub DRM Variant 3.1 x64 Header
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct SteamStub64Var31Header
|
||||
{
|
||||
public uint XorKey; // The base xor key, if defined, to unpack the file with.
|
||||
public uint Signature; // The signature to ensure the xor decoding was successful.
|
||||
public ulong ImageBase; // The base of the image that was protected.
|
||||
public ulong AddressOfEntryPoint; // The entry point that is set from the DRM.
|
||||
public uint BindSectionOffset; // The starting offset to the .bind section data. RVA(AddressOfEntryPoint - BindSectionOffset)
|
||||
public uint Unknown0000; // [Cyanic: This field is most likely the .bind code size.]
|
||||
public ulong OriginalEntryPoint; // The original entry point of the binary before it was protected.
|
||||
public uint Unknown0001; // [Cyanic: This field is most likely an offset to a string table.]
|
||||
public uint PayloadSize; // The size of the payload data.
|
||||
public uint DRMPDllOffset; // The offset to the SteamDrmp.dll file.
|
||||
public uint DRMPDllSize; // The size of the SteamDrmp.dll file.
|
||||
public uint SteamAppId; // The Steam application id of this program.
|
||||
public uint Flags; // The DRM flags used while protecting this program.
|
||||
public uint BindSectionVirtualSize; // The .bind section virtual size.
|
||||
public uint Unknown0002; // [Cyanic: This field is most likely a hash of some sort.]
|
||||
public ulong CodeSectionVirtualAddress; // The code section virtual address.
|
||||
public ulong CodeSectionRawSize; // The code section raw size.
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x20)]
|
||||
public byte[] AES_Key; // The AES encryption key.
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x10)]
|
||||
public byte[] AES_IV; // The AES encryption IV.
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x10)]
|
||||
public byte[] CodeSectionStolenData; // The first 16 bytes of the code section stolen.
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x04)]
|
||||
public uint[] EncryptionKeys; // Encryption keys used to decrypt the SteamDrmp.dll file.
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x08)]
|
||||
public uint[] Unknown0003; // Unknown unused data.
|
||||
|
||||
public ulong GetModuleHandleA_Rva; // The rva to GetModuleHandleA.
|
||||
public ulong GetModuleHandleW_Rva; // The rva to GetModuleHandleW.
|
||||
public ulong LoadLibraryA_Rva; // The rva to LoadLibraryA.
|
||||
public ulong LoadLibraryW_Rva; // The rva to LoadLibraryW.
|
||||
public ulong GetProcAddress_Rva; // The rva to GetProcAddress.
|
||||
}
|
||||
}
|
122
Steamless.Unpacker.Variant31.x64/Classes/SteamStubHelpers.cs
Normal file
122
Steamless.Unpacker.Variant31.x64/Classes/SteamStubHelpers.cs
Normal file
|
@ -0,0 +1,122 @@
|
|||
/**
|
||||
* Steamless - Copyright (c) 2015 - 2017 atom0s [atom0s@live.com]
|
||||
*
|
||||
* This work is licensed under the Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License.
|
||||
* To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/4.0/ or send a letter to
|
||||
* Creative Commons, PO Box 1866, Mountain View, CA 94042, USA.
|
||||
*
|
||||
* By using Steamless, you agree to the above license and its terms.
|
||||
*
|
||||
* Attribution - You must give appropriate credit, provide a link to the license and indicate if changes were
|
||||
* made. You must do so in any reasonable manner, but not in any way that suggests the licensor
|
||||
* endorses you or your use.
|
||||
*
|
||||
* Non-Commercial - You may not use the material (Steamless) for commercial purposes.
|
||||
*
|
||||
* No-Derivatives - If you remix, transform, or build upon the material (Steamless), you may not distribute the
|
||||
* modified material. You are, however, allowed to submit the modified works back to the original
|
||||
* Steamless project in attempt to have it added to the original project.
|
||||
*
|
||||
* You may not apply legal terms or technological measures that legally restrict others
|
||||
* from doing anything the license permits.
|
||||
*
|
||||
* No warranties are given.
|
||||
*/
|
||||
|
||||
namespace Steamless.Unpacker.Variant31.x64.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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The second pass of decryption for the SteamDRMP.dll file.
|
||||
///
|
||||
/// @note The encryption method here is known as XTEA.
|
||||
/// </summary>
|
||||
/// <param name="res">The result value buffer to write our returns to.</param>
|
||||
/// <param name="keys">The keys used for the decryption.</param>
|
||||
/// <param name="v1">The first value to decrypt from.</param>
|
||||
/// <param name="v2">The second value to decrypt from.</param>
|
||||
/// <param name="n">The number of passes to crypt the data with.</param>
|
||||
public static void SteamDrmpDecryptPass2(ref uint[] res, uint[] keys, uint v1, uint v2, uint n = 32)
|
||||
{
|
||||
const uint delta = 0x9E3779B9;
|
||||
const uint mask = 0xFFFFFFFF;
|
||||
var sum = (delta * n) & mask;
|
||||
|
||||
for (var x = 0; x < n; x++)
|
||||
{
|
||||
v2 = (v2 - (((v1 << 4 ^ v1 >> 5) + v1) ^ (sum + keys[sum >> 11 & 3]))) & mask;
|
||||
sum = (sum - delta) & mask;
|
||||
v1 = (v1 - (((v2 << 4 ^ v2 >> 5) + v2) ^ (sum + keys[sum & 3]))) & mask;
|
||||
}
|
||||
|
||||
res[0] = v1;
|
||||
res[1] = v2;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The first pass of the decryption for the SteamDRMP.dll file.
|
||||
///
|
||||
/// @note The encryption method here is known as XTEA. It is modded to include
|
||||
/// some basic xor'ing.
|
||||
/// </summary>
|
||||
/// <param name="data">The data to decrypt.</param>
|
||||
/// <param name="size">The size of the data to decrypt.</param>
|
||||
/// <param name="keys">The keys used for the decryption.</param>
|
||||
public static void SteamDrmpDecryptPass1(ref byte[] data, uint size, uint[] keys)
|
||||
{
|
||||
var v1 = (uint)0x55555555;
|
||||
var v2 = (uint)0x55555555;
|
||||
|
||||
for (var x = 0; x < size; x += 8)
|
||||
{
|
||||
var d1 = BitConverter.ToUInt32(data, x + 0);
|
||||
var d2 = BitConverter.ToUInt32(data, x + 4);
|
||||
|
||||
var res = new uint[2];
|
||||
SteamDrmpDecryptPass2(ref res, keys, d1, d2);
|
||||
|
||||
Array.Copy(BitConverter.GetBytes(res[0] ^ v1), 0, data, x + 0, 4);
|
||||
Array.Copy(BitConverter.GetBytes(res[1] ^ v2), 0, data, x + 4, 4);
|
||||
|
||||
v1 = d1;
|
||||
v2 = d2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
531
Steamless.Unpacker.Variant31.x64/Main.cs
Normal file
531
Steamless.Unpacker.Variant31.x64/Main.cs
Normal file
|
@ -0,0 +1,531 @@
|
|||
/**
|
||||
* Steamless - Copyright (c) 2015 - 2017 atom0s [atom0s@live.com]
|
||||
*
|
||||
* This work is licensed under the Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License.
|
||||
* To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/4.0/ or send a letter to
|
||||
* Creative Commons, PO Box 1866, Mountain View, CA 94042, USA.
|
||||
*
|
||||
* By using Steamless, you agree to the above license and its terms.
|
||||
*
|
||||
* Attribution - You must give appropriate credit, provide a link to the license and indicate if changes were
|
||||
* made. You must do so in any reasonable manner, but not in any way that suggests the licensor
|
||||
* endorses you or your use.
|
||||
*
|
||||
* Non-Commercial - You may not use the material (Steamless) for commercial purposes.
|
||||
*
|
||||
* No-Derivatives - If you remix, transform, or build upon the material (Steamless), you may not distribute the
|
||||
* modified material. You are, however, allowed to submit the modified works back to the original
|
||||
* Steamless project in attempt to have it added to the original project.
|
||||
*
|
||||
* You may not apply legal terms or technological measures that legally restrict others
|
||||
* from doing anything the license permits.
|
||||
*
|
||||
* No warranties are given.
|
||||
*/
|
||||
|
||||
namespace Steamless.Unpacker.Variant31.x64
|
||||
{
|
||||
using API;
|
||||
using API.Crypto;
|
||||
using API.Events;
|
||||
using API.Extensions;
|
||||
using API.Model;
|
||||
using API.PE64;
|
||||
using API.Services;
|
||||
using Classes;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
[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 3.1 Unpacker (x64)";
|
||||
|
||||
/// <summary>
|
||||
/// Gets the description of this plugin.
|
||||
/// </summary>
|
||||
public override string Description => "Unpacker for the 64bit SteamStub variant 3.1.";
|
||||
|
||||
/// <summary>
|
||||
/// Gets the version of this plugin.
|
||||
/// </summary>
|
||||
public override Version Version => new Version(1, 0, 0, 0);
|
||||
|
||||
/// <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 Pe64File(file);
|
||||
if (!f.Parse() || !f.IsFile64Bit() || !f.HasSection(".bind"))
|
||||
return false;
|
||||
|
||||
// Obtain the bind section data..
|
||||
var bind = f.GetSectionData(".bind");
|
||||
|
||||
// Attempt to locate the known v3.x signature..
|
||||
var varient = Pe64Helpers.FindPattern(bind, "E8 00 00 00 00 50 53 51 52 56 57 55 41 50");
|
||||
if (varient == 0) return false;
|
||||
|
||||
// Attempt to determine the varient version..
|
||||
var offset = Pe64Helpers.FindPattern(bind, "48 8D 91 ?? ?? ?? ?? 48"); // 3.0
|
||||
if (offset == 0)
|
||||
offset = Pe64Helpers.FindPattern(bind, "48 8D 91 ?? ?? ?? ?? 41"); // 3.1
|
||||
|
||||
// Ensure a pattern was found..
|
||||
if (offset == 0)
|
||||
return false;
|
||||
|
||||
// Read the header size.. (The header size is only 32bit!)
|
||||
var headerSize = Math.Abs(BitConverter.ToInt32(bind, (int)offset + 3));
|
||||
|
||||
// Check for the known 3.1 header size..
|
||||
return headerSize == 0xF0;
|
||||
}
|
||||
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.TlsAsOep = false;
|
||||
this.TlsOepRva = 0;
|
||||
this.Options = options;
|
||||
this.CodeSectionData = null;
|
||||
this.CodeSectionIndex = -1;
|
||||
this.XorKey = 0;
|
||||
|
||||
// Parse the file..
|
||||
this.File = new Pe64File(file);
|
||||
if (!this.File.Parse())
|
||||
return false;
|
||||
|
||||
// Announce we are being unpacked with this packer..
|
||||
this.Log("File is packed with SteamStub Variant 3.1 (x64)!", LogMessageType.Information);
|
||||
|
||||
this.Log("Step 1 - Read, decode and validate the SteamStub DRM header.", LogMessageType.Information);
|
||||
if (!this.Step1())
|
||||
return false;
|
||||
|
||||
this.Log("Step 2 - Read, decode and process the payload data.", LogMessageType.Information);
|
||||
if (!this.Step2())
|
||||
return false;
|
||||
|
||||
this.Log("Step 3 - Read, decode and dump the SteamDRMP.dll file.", LogMessageType.Information);
|
||||
if (!this.Step3())
|
||||
return false;
|
||||
|
||||
this.Log("Step 4 - Handle .bind section. Find code section.", LogMessageType.Information);
|
||||
if (!this.Step4())
|
||||
return false;
|
||||
|
||||
this.Log("Step 5 - Read, decrypt and process code section.", LogMessageType.Information);
|
||||
if (!this.Step5())
|
||||
return false;
|
||||
|
||||
this.Log("Step 6 - Rebuild and save the unpacked file.", LogMessageType.Information);
|
||||
if (!this.Step6())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Step #1
|
||||
///
|
||||
/// Read, decode and validate the SteamStub DRM header.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private bool Step1()
|
||||
{
|
||||
// Obtain the DRM header data..
|
||||
var fileOffset = this.File.GetFileOffsetFromRva(this.File.NtHeaders.OptionalHeader.AddressOfEntryPoint);
|
||||
var headerData = new byte[0xF0];
|
||||
Array.Copy(this.File.FileData, (long)(fileOffset - 0xF0), headerData, 0, 0xF0);
|
||||
|
||||
// Xor decode the header data..
|
||||
this.XorKey = SteamStubHelpers.SteamXor(ref headerData, 0xF0);
|
||||
this.StubHeader = Pe64Helpers.GetStructure<SteamStub64Var31Header>(headerData);
|
||||
|
||||
// Validate the header signature..
|
||||
if (this.StubHeader.Signature == 0xC0DEC0DF)
|
||||
return true;
|
||||
|
||||
// Try again using the Tls callback (if any) as the OEP instead..
|
||||
if (this.File.TlsCallbacks.Count == 0)
|
||||
return false;
|
||||
|
||||
// Obtain the DRM header data..
|
||||
fileOffset = this.File.GetRvaFromVa(this.File.TlsCallbacks[0]);
|
||||
fileOffset = this.File.GetFileOffsetFromRva(fileOffset);
|
||||
headerData = new byte[0xF0];
|
||||
Array.Copy(this.File.FileData, (long)(fileOffset - 0xF0), headerData, 0, 0xF0);
|
||||
|
||||
// Xor decode the header data..
|
||||
this.XorKey = SteamStubHelpers.SteamXor(ref headerData, 0xF0);
|
||||
this.StubHeader = Pe64Helpers.GetStructure<SteamStub64Var31Header>(headerData);
|
||||
|
||||
// Validate the header signature..
|
||||
if (this.StubHeader.Signature != 0xC0DEC0DF)
|
||||
return false;
|
||||
|
||||
// Tls was valid for the real oep..
|
||||
this.TlsAsOep = true;
|
||||
this.TlsOepRva = fileOffset;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Step #2
|
||||
///
|
||||
/// Read, decode and process the payload data.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private bool Step2()
|
||||
{
|
||||
// Obtain the payload address and size..
|
||||
var payloadAddr = this.File.GetFileOffsetFromRva(this.TlsAsOep ? this.TlsOepRva : this.File.NtHeaders.OptionalHeader.AddressOfEntryPoint - this.StubHeader.BindSectionOffset);
|
||||
var payloadSize = (this.StubHeader.PayloadSize + 0x0F) & 0xFFFFFFF0;
|
||||
|
||||
// Do nothing if there is no payload..
|
||||
if (payloadSize == 0)
|
||||
return true;
|
||||
|
||||
this.Log(" --> File has payload data!", LogMessageType.Debug);
|
||||
|
||||
// Obtain and decode the payload..
|
||||
var payload = new byte[payloadSize];
|
||||
Array.Copy(this.File.FileData, (long)payloadAddr, payload, 0, payloadSize);
|
||||
this.XorKey = SteamStubHelpers.SteamXor(ref payload, payloadSize, this.XorKey);
|
||||
|
||||
try
|
||||
{
|
||||
if (this.Options.DumpPayloadToDisk)
|
||||
{
|
||||
System.IO.File.WriteAllBytes(this.File.FilePath + ".payload", payload);
|
||||
this.Log(" --> Saved payload to disk!", LogMessageType.Debug);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Do nothing here since it doesn't matter if this fails..
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Step #3
|
||||
///
|
||||
/// Read, decode and dump the SteamDRMP.dll file.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private bool Step3()
|
||||
{
|
||||
// Ensure there is a dll to process..
|
||||
if (this.StubHeader.DRMPDllSize == 0)
|
||||
{
|
||||
this.Log(" --> File does not contain a SteamDRMP.dll file.", LogMessageType.Debug);
|
||||
return true;
|
||||
}
|
||||
|
||||
this.Log(" --> File has SteamDRMP.dll file!", LogMessageType.Debug);
|
||||
|
||||
try
|
||||
{
|
||||
// Obtain the SteamDRMP.dll file address and data..
|
||||
var drmpAddr = this.File.GetFileOffsetFromRva(this.TlsAsOep ? this.TlsOepRva : this.File.NtHeaders.OptionalHeader.AddressOfEntryPoint - this.StubHeader.BindSectionOffset + this.StubHeader.DRMPDllOffset);
|
||||
var drmpData = new byte[this.StubHeader.DRMPDllSize];
|
||||
Array.Copy(this.File.FileData, (long)drmpAddr, drmpData, 0, drmpData.Length);
|
||||
|
||||
// Decrypt the data (xtea decryption)..
|
||||
SteamStubHelpers.SteamDrmpDecryptPass1(ref drmpData, this.StubHeader.DRMPDllSize, this.StubHeader.EncryptionKeys);
|
||||
|
||||
try
|
||||
{
|
||||
if (this.Options.DumpSteamDrmpToDisk)
|
||||
{
|
||||
var basePath = Path.GetDirectoryName(this.File.FilePath) ?? string.Empty;
|
||||
System.IO.File.WriteAllBytes(Path.Combine(basePath, "SteamDRMP.dll"), drmpData);
|
||||
this.Log(" --> Saved SteamDRMP.dll to disk!", LogMessageType.Debug);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Do nothing here since it doesn't matter if this fails..
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
this.Log(" --> Error trying to decrypt the files SteamDRMP.dll data!", LogMessageType.Error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Step #4
|
||||
///
|
||||
/// Remove the bind section if requested.
|
||||
/// Find the code section.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private bool Step4()
|
||||
{
|
||||
// Remove the bind section if its not requested to be saved..
|
||||
if (!this.Options.KeepBindSection)
|
||||
{
|
||||
// Obtain the .bind section..
|
||||
var bindSection = this.File.GetSection(".bind");
|
||||
if (!bindSection.IsValid)
|
||||
return false;
|
||||
|
||||
// Remove the section..
|
||||
this.File.RemoveSection(bindSection);
|
||||
|
||||
// Decrease the header section count..
|
||||
var ntHeaders = this.File.NtHeaders;
|
||||
ntHeaders.FileHeader.NumberOfSections--;
|
||||
this.File.NtHeaders = ntHeaders;
|
||||
|
||||
this.Log(" --> .bind section was removed from the file.", LogMessageType.Debug);
|
||||
}
|
||||
else
|
||||
this.Log(" --> .bind section was kept in the file.", LogMessageType.Debug);
|
||||
|
||||
// Skip finding the code section if the file is not encrypted..
|
||||
if ((this.StubHeader.Flags & (uint)SteamStubDrmFlags.NoEncryption) == (uint)SteamStubDrmFlags.NoEncryption)
|
||||
return true;
|
||||
|
||||
// Find the code section..
|
||||
var codeSection = this.File.GetOwnerSection(this.StubHeader.CodeSectionVirtualAddress);
|
||||
if (codeSection.PointerToRawData == 0 || codeSection.SizeOfRawData == 0)
|
||||
return false;
|
||||
|
||||
// Store the code sections index..
|
||||
this.CodeSectionIndex = this.File.GetSectionIndex(codeSection);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Step #5
|
||||
///
|
||||
/// Read, decrypt and process the code section.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private bool Step5()
|
||||
{
|
||||
// Skip decryption if the code section is not encrypted..
|
||||
if ((this.StubHeader.Flags & (uint)SteamStubDrmFlags.NoEncryption) == (uint)SteamStubDrmFlags.NoEncryption)
|
||||
{
|
||||
this.Log(" --> Code section is not encrypted.", LogMessageType.Debug);
|
||||
return true;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// Obtain the code section..
|
||||
var codeSection = this.File.Sections[this.CodeSectionIndex];
|
||||
this.Log($" --> {codeSection.SectionName} linked as main code section.", LogMessageType.Debug);
|
||||
this.Log($" --> {codeSection.SectionName} section is encrypted.", LogMessageType.Debug);
|
||||
|
||||
// Obtain the code section data..
|
||||
var codeSectionData = new byte[codeSection.SizeOfRawData + this.StubHeader.CodeSectionStolenData.Length];
|
||||
Array.Copy(this.StubHeader.CodeSectionStolenData, (long)0, codeSectionData, 0, this.StubHeader.CodeSectionStolenData.Length);
|
||||
Array.Copy(this.File.FileData, (long)this.File.GetFileOffsetFromRva(codeSection.VirtualAddress), codeSectionData, this.StubHeader.CodeSectionStolenData.Length, codeSection.SizeOfRawData);
|
||||
|
||||
// Create the AES decryption helper..
|
||||
var aes = new AesHelper(this.StubHeader.AES_Key, this.StubHeader.AES_IV);
|
||||
aes.RebuildIv(this.StubHeader.AES_IV);
|
||||
|
||||
// Decrypt the code section data..
|
||||
var data = aes.Decrypt(codeSectionData, CipherMode.CBC, PaddingMode.None);
|
||||
if (data == null)
|
||||
return false;
|
||||
|
||||
// Set the code section override data..
|
||||
this.CodeSectionData = data;
|
||||
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
this.Log(" --> Error trying to decrypt the files code section data!", LogMessageType.Error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Step #6
|
||||
///
|
||||
/// Rebuild and save the unpacked file.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private bool Step6()
|
||||
{
|
||||
FileStream fStream = null;
|
||||
|
||||
try
|
||||
{
|
||||
// Rebuild the file sections..
|
||||
this.File.RebuildSections();
|
||||
|
||||
// Open the unpacked file for writing..
|
||||
var unpackedPath = this.File.FilePath + ".unpacked.exe";
|
||||
fStream = new FileStream(unpackedPath, FileMode.Create, FileAccess.ReadWrite);
|
||||
|
||||
// Write the DOS header to the file..
|
||||
fStream.WriteBytes(Pe64Helpers.GetStructureBytes(this.File.DosHeader));
|
||||
|
||||
// Write the DOS stub to the file..
|
||||
if (this.File.DosStubSize > 0)
|
||||
fStream.WriteBytes(this.File.DosStubData);
|
||||
|
||||
// Update the entry point of the file..
|
||||
var ntHeaders = this.File.NtHeaders;
|
||||
ntHeaders.OptionalHeader.AddressOfEntryPoint = (uint)this.StubHeader.OriginalEntryPoint;
|
||||
this.File.NtHeaders = ntHeaders;
|
||||
|
||||
// Write the NT headers to the file..
|
||||
fStream.WriteBytes(Pe64Helpers.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(Pe64Helpers.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>
|
||||
/// Gets or sets if the Tls callback is being used as the Oep.
|
||||
/// </summary>
|
||||
private bool TlsAsOep { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Tls Oep Rva if it is being used as the Oep.
|
||||
/// </summary>
|
||||
private ulong TlsOepRva { get; set; }
|
||||
|
||||
/// <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 Pe64File 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 SteamStub64Var31Header StubHeader { 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.Variant31.x64/Properties/AssemblyInfo.cs
Normal file
40
Steamless.Unpacker.Variant31.x64/Properties/AssemblyInfo.cs
Normal file
|
@ -0,0 +1,40 @@
|
|||
/**
|
||||
* Steamless - Copyright (c) 2015 - 2017 atom0s [atom0s@live.com]
|
||||
*
|
||||
* This work is licensed under the Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License.
|
||||
* To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-nd/4.0/ or send a letter to
|
||||
* Creative Commons, PO Box 1866, Mountain View, CA 94042, USA.
|
||||
*
|
||||
* By using Steamless, you agree to the above license and its terms.
|
||||
*
|
||||
* Attribution - You must give appropriate credit, provide a link to the license and indicate if changes were
|
||||
* made. You must do so in any reasonable manner, but not in any way that suggests the licensor
|
||||
* endorses you or your use.
|
||||
*
|
||||
* Non-Commercial - You may not use the material (Steamless) for commercial purposes.
|
||||
*
|
||||
* No-Derivatives - If you remix, transform, or build upon the material (Steamless), you may not distribute the
|
||||
* modified material. You are, however, allowed to submit the modified works back to the original
|
||||
* Steamless project in attempt to have it added to the original project.
|
||||
*
|
||||
* You may not apply legal terms or technological measures that legally restrict others
|
||||
* from doing anything the license permits.
|
||||
*
|
||||
* No warranties are given.
|
||||
*/
|
||||
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
[assembly: AssemblyTitle("Steamless.Unpacker.Variant31.x64")]
|
||||
[assembly: AssemblyDescription("Steamless SteamStub Variant v3.1 (x64) Unpacker")]
|
||||
[assembly: AssemblyConfiguration("Release")]
|
||||
[assembly: AssemblyCompany("atom0s")]
|
||||
[assembly: AssemblyProduct("Steamless.Unpacker.Variant31.x64")]
|
||||
[assembly: AssemblyCopyright("Copyright © atom0s 2015 - 2017")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
[assembly: ComVisible(false)]
|
||||
[assembly: Guid("05f540fb-d14b-4966-8de2-591b76361cf0")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
|
@ -0,0 +1,56 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" 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>{05F540FB-D14B-4966-8DE2-591B76361CF0}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>Steamless.Unpacker.Variant31.x64</RootNamespace>
|
||||
<AssemblyName>Steamless.Unpacker.Variant31.x64</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
</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="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" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
|
@ -36,5 +36,5 @@ using System.Runtime.InteropServices;
|
|||
[assembly: AssemblyCulture("")]
|
||||
[assembly: ComVisible(false)]
|
||||
[assembly: Guid("0f2fae37-f898-4392-b4f6-711954beeb4f")]
|
||||
[assembly: AssemblyVersion("1.0.0.1")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.1")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
|
@ -15,6 +15,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Steamless.Unpacker.Variant3
|
|||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Steamless.Unpacker.Variant20.x86", "Steamless.Unpacker.Variant20.x86\Steamless.Unpacker.Variant20.x86.csproj", "{A40154CD-A0FD-4371-8099-CE277E0989AF}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Steamless.Unpacker.Variant31.x64", "Steamless.Unpacker.Variant31.x64\Steamless.Unpacker.Variant31.x64.csproj", "{05F540FB-D14B-4966-8DE2-591B76361CF0}"
|
||||
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
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x86 = Debug|x86
|
||||
|
@ -45,6 +49,14 @@ Global
|
|||
{A40154CD-A0FD-4371-8099-CE277E0989AF}.Debug|x86.Build.0 = Debug|x86
|
||||
{A40154CD-A0FD-4371-8099-CE277E0989AF}.Release|x86.ActiveCfg = Release|x86
|
||||
{A40154CD-A0FD-4371-8099-CE277E0989AF}.Release|x86.Build.0 = Release|x86
|
||||
{05F540FB-D14B-4966-8DE2-591B76361CF0}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{05F540FB-D14B-4966-8DE2-591B76361CF0}.Debug|x86.Build.0 = Debug|x86
|
||||
{05F540FB-D14B-4966-8DE2-591B76361CF0}.Release|x86.ActiveCfg = Release|x86
|
||||
{05F540FB-D14B-4966-8DE2-591B76361CF0}.Release|x86.Build.0 = Release|x86
|
||||
{03621EAD-77A7-4208-AFDF-4B8292230A71}.Debug|x86.ActiveCfg = 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.Build.0 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
Loading…
Reference in a new issue