diff --git a/Steamless.Unpacker.Variant30.x64/Classes/SteamStubHeader.cs b/Steamless.Unpacker.Variant30.x64/Classes/SteamStubHeader.cs
index 0a3751d..201933b 100644
--- a/Steamless.Unpacker.Variant30.x64/Classes/SteamStubHeader.cs
+++ b/Steamless.Unpacker.Variant30.x64/Classes/SteamStubHeader.cs
@@ -63,7 +63,7 @@ namespace Steamless.Unpacker.Variant30.x64.Classes
[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 HasTlsCallback; // Flag that states if the file was protected with a TlsCallback present.
public uint Unknown0004;
public uint Unknown0005;
public uint Unknown0006;
diff --git a/Steamless.Unpacker.Variant30.x64/Main.cs b/Steamless.Unpacker.Variant30.x64/Main.cs
index 79a440a..d544050 100644
--- a/Steamless.Unpacker.Variant30.x64/Main.cs
+++ b/Steamless.Unpacker.Variant30.x64/Main.cs
@@ -35,6 +35,7 @@ namespace Steamless.Unpacker.Variant30.x64
using Classes;
using System;
using System.IO;
+ using System.Linq;
using System.Reflection;
using System.Security.Cryptography;
@@ -189,6 +190,48 @@ namespace Steamless.Unpacker.Variant30.x64
return true;
}
+ ///
+ /// Rebuilds the file TlsCallback information and repairs the proper OEP.
+ ///
+ ///
+ private bool RebuildTlsCallbackInformation()
+ {
+ // Ensure the modified main TlsCallback is within the .bind section..
+ var section = this.File.GetOwnerSection(this.File.GetRvaFromVa(this.File.TlsCallbacks[0]));
+ if (!section.IsValid || string.Compare(section.SectionName, ".bind", System.Globalization.CultureInfo.InvariantCulture, System.Globalization.CompareOptions.IgnoreCase) != 0)
+ return false;
+
+ // Obtain the section that holds the Tls directory information..
+ var addr = this.File.GetFileOffsetFromRva(this.File.GetRvaFromVa(this.File.TlsDirectory.AddressOfCallBacks));
+ var tlsd = this.File.GetOwnerSection(addr);
+
+ if (!tlsd.IsValid)
+ return false;
+
+ addr -= tlsd.PointerToRawData;
+
+ // Restore the true original TlsCallback address..
+ var callback = BitConverter.GetBytes(this.File.NtHeaders.OptionalHeader.ImageBase + this.StubHeader.OriginalEntryPoint);
+ Array.Copy(callback, 0, this.File.GetSectionData(this.File.GetSectionIndex(tlsd)), (int)addr, callback.Length);
+
+ // Find the original entry point function..
+ var entry = this.File.GetFileOffsetFromRva(this.File.NtHeaders.OptionalHeader.AddressOfEntryPoint);
+ var data = this.File.FileData.Skip((int)entry).Take(0x100).ToArray();
+
+ // Find the XOR key from within the function..
+ var res = Pe64Helpers.FindPattern(data, "48 81 EA ?? ?? ?? ?? 8B 12 81 F2");
+ if (res == 0)
+ return false;
+
+ // Decrypt and recalculate the true OEP address..
+ var key = (ulong)(this.StubHeader.XorKey ^ BitConverter.ToInt32(data, (int)res + 0x0B));
+ var off = (ulong)((this.File.NtHeaders.OptionalHeader.ImageBase + this.File.NtHeaders.OptionalHeader.AddressOfEntryPoint) + key);
+
+ // Store the proper OEP..
+ this.TlsOepOverride = (uint)(off - this.File.NtHeaders.OptionalHeader.ImageBase);
+ return true;
+ }
+
///
/// Step #1
///
@@ -234,7 +277,13 @@ namespace Steamless.Unpacker.Variant30.x64
// Tls was valid for the real oep..
this.TlsAsOep = true;
this.TlsOepRva = this.File.GetRvaFromVa(this.File.TlsCallbacks[0]);
- return true;
+
+ // Is the TlsCallback replacing the OEP..
+ if (this.StubHeader.HasTlsCallback != 1 || this.File.TlsCallbacks[0] == 0)
+ return true;
+
+ // Rebuild the file Tls callback information..
+ return this.RebuildTlsCallbackInformation();
}
///
@@ -447,7 +496,10 @@ namespace Steamless.Unpacker.Variant30.x64
// Update the entry point of the file..
var ntHeaders = this.File.NtHeaders;
- ntHeaders.OptionalHeader.AddressOfEntryPoint = this.StubHeader.OriginalEntryPoint;
+ if (this.StubHeader.HasTlsCallback != 1)
+ ntHeaders.OptionalHeader.AddressOfEntryPoint = this.StubHeader.OriginalEntryPoint;
+ else
+ ntHeaders.OptionalHeader.AddressOfEntryPoint = this.TlsOepOverride;
this.File.NtHeaders = ntHeaders;
// Write the NT headers to the file..
@@ -510,6 +562,11 @@ namespace Steamless.Unpacker.Variant30.x64
///
private ulong TlsOepRva { get; set; }
+ ///
+ /// Gets or sets the Tls Oep override value to use when the stub has set the HasTlsCallback flag.
+ ///
+ private uint TlsOepOverride { get; set; }
+
///
/// Gets or sets the Steamless options this file was requested to process with.
///