From 341897c01a4d4dbc9f9d9dd325f1ec7a194d56f7 Mon Sep 17 00:00:00 2001 From: Fabian Date: Sun, 13 Nov 2022 18:29:33 +0100 Subject: [PATCH] Patch in a static auth seed to remove the need of updating them on new builds: - Only works with --staticseed launch arg. - Works on all supported game versions. - Use the following auth seed on your server: 179D3DC3235629D07113A9B3867F97A7 --- src/LaunchOptions.cs | 4 +- src/Launcher.cs | 83 +++++++++++++++++++++++++++++++---------- src/Patches/Windows.cs | 1 + src/Patterns/Windows.cs | 3 ++ src/Program.cs | 2 +- 5 files changed, 71 insertions(+), 22 deletions(-) diff --git a/src/LaunchOptions.cs b/src/LaunchOptions.cs index b706a43..551de1e 100644 --- a/src/LaunchOptions.cs +++ b/src/LaunchOptions.cs @@ -12,6 +12,7 @@ static class LaunchOptions public static Option GamePath = new("--path"); public static Option GameBinary = new("--binary"); public static Option KeepCache = new("--keepcache", () => true); + public static Option UseStaticAuthSeed = new("--staticseed"); public static Parser Instance => new CommandLineBuilder(ConfigureCommandLine(RootCommand)) .UseHelp() @@ -26,7 +27,8 @@ static class LaunchOptions Version, GamePath, GameBinary, - KeepCache + KeepCache, + UseStaticAuthSeed }; static Command ConfigureCommandLine(Command rootCommand) diff --git a/src/Launcher.cs b/src/Launcher.cs index c1693fe..9c7dae2 100644 --- a/src/Launcher.cs +++ b/src/Launcher.cs @@ -90,7 +90,7 @@ class Launcher return gameBinaryPath; } - public static bool LaunchGame(string appPath, string gameCommandLine) + public static bool LaunchGame(string appPath, string gameCommandLine, bool useStaticAuthSeed) { var startupInfo = new StartupInfo(); var processInfo = new ProcessInformation(); @@ -135,6 +135,9 @@ class Launcher // Refresh the client data before patching. memory.RefreshMemoryData((int)gameAppData.Length); + // We need to cache this here since we are using our RSA modulus as auth seed. + var modulusOffset = memory.Data.FindPattern(Patterns.Common.SignatureModulus); + // Wait for all direct memory patch tasks to complete, Task.WaitAll(new[] { @@ -154,25 +157,7 @@ class Launcher NativeWindows.NtResumeProcess(processInfo.ProcessHandle); - // Wait for client initialization. - var initOffset = memory?.Read(mbi.BaseAddress, (int)mbi.RegionSize)?.FindPattern(Patterns.Windows.Init) ?? 0; - - while (initOffset == 0) - { - initOffset = memory?.Read(mbi.BaseAddress, (int)mbi.RegionSize)?.FindPattern(Patterns.Windows.Init) ?? 0; - - Console.WriteLine("Waiting for client initialization..."); - } - - initOffset += BitConverter.ToUInt32(memory.Read(initOffset + memory.BaseAddress + 2, 4), 0) + 10; - - while (memory?.Read(initOffset + memory.BaseAddress, 1)?[0] == null || - memory?.Read(initOffset + memory.BaseAddress, 1)?[0] == 0) - memory.Data = memory.Read(mbi.BaseAddress, (int)mbi.RegionSize); - - PrepareAntiCrash(memory, ref mbi, ref processInfo); - - memory.RefreshMemoryData((int)mbi.RegionSize); + WaitForUnpack(ref processInfo, memory, ref mbi); #if x64 Task.WaitAll(new[] @@ -180,6 +165,21 @@ class Launcher memory.QueuePatch(Patterns.Windows.CertBundle, Patches.Windows.CertBundle, "CertBundle"), memory.QueuePatch(Patterns.Windows.CertCommonName, Patches.Windows.CertCommonName, "CertCommonName", 5) }, CancellationTokenSource.Token); + + if (useStaticAuthSeed) + { + Console.ForegroundColor = ConsoleColor.Cyan; + Console.WriteLine("Static auth seed used. Be sure that the server you are connecting to supports it."); + Console.ResetColor(); + + // Generates a patch for the auth seed so we don't have to update them on each build. + var authSeedFunctionOffset = GenerateAuthSeedFunctionPatch(memory, modulusOffset); + + Task.WaitAll(new[] + { + memory.QueuePatch(authSeedFunctionOffset, Patches.Windows.AuthSeed, "CustomAuthSeedFunction") + }, CancellationTokenSource.Token); + } #if CUSTOM_FILES Task.WaitAll(new[] { @@ -248,6 +248,49 @@ class Launcher return false; } + static long GenerateAuthSeedFunctionPatch(WinMemory memory, long modulusOffset) + { + var authSeedLoadOffset = memory.Data.FindPattern(Patterns.Windows.AuthSeed); + + if (authSeedLoadOffset == 0) + throw new InvalidDataException("authSeedLoadOffset"); + + var leaStartOffset = authSeedLoadOffset + 9; + var leaValue = Unsafe.ReadUnaligned(ref memory.Data[leaStartOffset + 3]); + var authSeedWrapperOffset = leaStartOffset + leaValue + 7; + var jmpValue = Unsafe.ReadUnaligned(ref memory.Data[authSeedWrapperOffset + 6]); + var authSeedFunctionOffset = authSeedWrapperOffset + 5 + jmpValue + 5; + + // Write the modulus offset to our custom get seed functions. + // Resulting static auth seed is: 179D3DC3235629D07113A9B3867F97A7 + Unsafe.WriteUnaligned(ref Patches.Windows.AuthSeed[3], (uint)(modulusOffset - authSeedFunctionOffset - 7)); + + return authSeedFunctionOffset; + } + + static void WaitForUnpack(ref ProcessInformation processInfo, WinMemory memory, ref MemoryBasicInformation mbi) + { + // Wait for client initialization. + var initOffset = memory?.Read(mbi.BaseAddress, (int)mbi.RegionSize)?.FindPattern(Patterns.Windows.Init) ?? 0; + + while (initOffset == 0) + { + initOffset = memory?.Read(mbi.BaseAddress, (int)mbi.RegionSize)?.FindPattern(Patterns.Windows.Init) ?? 0; + + Console.WriteLine("Waiting for client initialization..."); + } + + initOffset += BitConverter.ToUInt32(memory.Read(initOffset + memory.BaseAddress + 2, 4), 0) + 10; + + while (memory?.Read(initOffset + memory.BaseAddress, 1)?[0] == null || + memory?.Read(initOffset + memory.BaseAddress, 1)?[0] == 0) + memory.Data = memory.Read(mbi.BaseAddress, (int)mbi.RegionSize); + + PrepareAntiCrash(memory, ref mbi, ref processInfo); + + memory.RefreshMemoryData((int)mbi.RegionSize); + } + static void PrepareAntiCrash(WinMemory memory, ref MemoryBasicInformation mbi, ref ProcessInformation processInfo) { memory.RefreshMemoryData((int)mbi.RegionSize); diff --git a/src/Patches/Windows.cs b/src/Patches/Windows.cs index 493daa0..aa9c90a 100644 --- a/src/Patches/Windows.cs +++ b/src/Patches/Windows.cs @@ -11,6 +11,7 @@ static class Windows public static byte[] CertCommonName = { 0xB0, 0x01 }; public static byte[] ShortJump = { 0xEB }; public static byte[] NoJump = { 0x00, 0x00, 0x00, 0x00 }; + public static byte[] AuthSeed = { 0x0F, 0x28, 0x05, 0xEF, 0xBE, 0xAD, 0xDE, 0x0F, 0x11, 0x02, 0xC3 }; #elif ARM64 public static byte[] Integrity = { }; public static byte[] Branch = { 0xB5 }; diff --git a/src/Patterns/Windows.cs b/src/Patterns/Windows.cs index 7efce46..129adc9 100644 --- a/src/Patterns/Windows.cs +++ b/src/Patterns/Windows.cs @@ -17,6 +17,9 @@ static class Windows public static short[] CertBundle = { 0x75, 0x06, 0x48, -1, -1, 0x60, 0x5F, 0xC3 }; public static short[] CertCommonName = { 0x80, -1, 0x2A, 0x75, -1, 0x32, 0xC0, 0x48 }; + // Auth seed function. + public static short[] AuthSeed = { 0x57, 0x6F, 0x57, 0x00, 0xE8, -1, -1, -1, -1, 0x48, 0x8D }; + // Custom files (mods). public static short[] LoadByFileId = { 0x41, -1, -1, 0x01, 0x0F, 0x84, -1, 0x00, 0x00, 0x00, 0x48, 0x8B, -1, -1, -1, -1, -1, 0x8B }; public static short[] LoadByFilePath = { 0x01, 0x0F, 0x84, -1, -1, -1, -1, 0x48, 0x8B, -1, -1, -1, -1, -1, 0x44, 0x89, -1, -1, -1, 0x48, 0x85, 0xC9 }; diff --git a/src/Program.cs b/src/Program.cs index da3a958..a2d1cb0 100644 --- a/src/Program.cs +++ b/src/Program.cs @@ -16,7 +16,7 @@ LaunchOptions.RootCommand.SetHandler(context => var appPath = Launcher.PrepareGameLaunch(context.ParseResult); var gameCommandLine = string.Join(" ", context.ParseResult.UnmatchedTokens); - if (string.IsNullOrEmpty(appPath) || !Launcher.LaunchGame(appPath, gameCommandLine)) + if (string.IsNullOrEmpty(appPath) || !Launcher.LaunchGame(appPath, gameCommandLine, context.ParseResult.HasOption(LaunchOptions.UseStaticAuthSeed))) WaitAndExit(5000); });