private bool Start(string appPath) { var startupInfo = new StartupInfo(); var processInfo = new ProcessInformation(); try { Logger.Instance.WriteLine($"Starting WoW ....", LogLevel.Debug); // Start process with suspend flags. if (NativeWindows.CreateProcess(null, $"{appPath}", IntPtr.Zero, IntPtr.Zero, false, 4U, IntPtr.Zero, null, ref startupInfo, out processInfo)) { var memory = new WinMemory(processInfo.ProcessHandle); var modulusOffset = IntPtr.Zero; // Get RSA modulus offset from file. modulusOffset = File.ReadAllBytes(appPath).FindPattern(Patterns.Common.Modulus, memory.BaseAddress.ToInt64()).ToIntPtr(); var sectionOffset = memory.Read(modulusOffset, 0x2000).FindPattern(Patterns.Common.Modulus); modulusOffset = (modulusOffset.ToInt64() + sectionOffset).ToIntPtr(); // Be sure that the modulus is written before the client is initialized. while (memory.Read(modulusOffset, 1)[0] != Patches.Common.Modulus[0]) { memory.Write(modulusOffset, Patches.Common.Modulus); } // Resume the process to initialize it. NativeWindows.NtResumeProcess(processInfo.ProcessHandle); var mbi = new MemoryBasicInformation(); // Wait for the memory region to be initialized. while (NativeWindows.VirtualQueryEx(processInfo.ProcessHandle, memory.BaseAddress, out mbi, mbi.Size) == 0 || mbi.RegionSize.ToInt32() <= 0x1000) { } if (mbi.BaseAddress != IntPtr.Zero) { // Get the memory content. var binary = new byte[0]; // Wait for client initialization. var initOffset = memory?.Read(mbi.BaseAddress, mbi.RegionSize.ToInt32())?.FindPattern(Store.InitializePattern) ?? 0; while (initOffset == 0) { initOffset = memory?.Read(mbi.BaseAddress, mbi.RegionSize.ToInt32())?.FindPattern(Store.InitializePattern) ?? 0; Logger.Instance.WriteLine($"Waiting initialization ...", LogLevel.Debug); } initOffset += BitConverter.ToUInt32(memory.Read((long)initOffset + memory.BaseAddress.ToInt64() + 2, 4), 0) + 10; while (memory?.Read((long)initOffset + memory.BaseAddress.ToInt64(), 1)?[0] == null || memory?.Read((long)initOffset + memory.BaseAddress.ToInt64(), 1)?[0] == 0) { binary = memory.Read(mbi.BaseAddress, mbi.RegionSize.ToInt32()); } // Suspend the process and handle the patches. NativeWindows.NtSuspendProcess(processInfo.ProcessHandle); //! Re-read the memory region for each pattern search. var certBundleOffset = memory.Read(mbi.BaseAddress, mbi.RegionSize.ToInt32()).FindPattern(Store.CertificateBundle); var signatureOffset = memory.Read(mbi.BaseAddress, mbi.RegionSize.ToInt32()).FindPattern(Store.SignatureBundle); if (certBundleOffset == 0 || signatureOffset == 0) { Logger.Instance.WriteLine("Can't find all patterns.", LogLevel.Error); Logger.Instance.WriteLine($"CertBundle: {certBundleOffset == 0}", LogLevel.Error); Logger.Instance.WriteLine($"Signature: {signatureOffset == 0}", LogLevel.Error); } // Add the patches to the patch list. PatchList.Add("CertBundle", Tuple.Create(certBundleOffset, Store.CertificatePatch)); PatchList.Add("Signature", Tuple.Create(signatureOffset, Store.SignaturePatch)); NativeWindows.NtResumeProcess(processInfo.ProcessHandle); if (memory.RemapAndPatch(PatchList)) { Logger.Instance.WriteLine($"Executeable successfully patched!", LogLevel.Debug); binary = null; return(true); } else { binary = null; Logger.Instance.WriteLine("Error while launching the client.", LogLevel.Error); NativeWindows.TerminateProcess(processInfo.ProcessHandle, 0); return(false); } } } } catch (Exception ex) { Logger.Instance.WriteLine(ex.ToString(), LogLevel.Error); NativeWindows.TerminateProcess(processInfo.ProcessHandle, 0); return(false); } return(false); }
static void StartWindows() { Process process = null; try { var startupInfo = new StartupInfo(); var processInfo = new ProcessInformation(); // App info var curDir = Directory.GetCurrentDirectory(); var appPath = ""; // Check for existing WoW binaries. if (File.Exists($"{ curDir}\\WoW-64.exe")) { appPath = $"{curDir}\\WoW-64.exe"; } else if (File.Exists($"{curDir}\\WoWT-64.exe")) { appPath = $"{curDir}\\WoWT-64.exe"; } else if (File.Exists($"{curDir}\\WoWB-64.exe")) { appPath = $"{curDir}\\WoWB-64.exe"; } if (!File.Exists(appPath)) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("Please copy the launcher to your WoW directory."); WaitAndExit(); } var baseDirectory = Path.GetDirectoryName(curDir); // Write the cert bundle. if (!File.Exists($"{curDir}/ca_bundle.txt.signed")) { File.WriteAllBytes($"{curDir}/ca_bundle.txt.signed", Convert.FromBase64String(Patches.Common.CertBundleData)); } Console.ForegroundColor = ConsoleColor.White; Console.WriteLine("Starting WoW client..."); if (NativeWindows.CreateProcess(appPath, $"-console -console", IntPtr.Zero, IntPtr.Zero, false, 4U, IntPtr.Zero, null, ref startupInfo, out processInfo)) { process = Process.GetProcessById((int)processInfo.ProcessId); // Wait for process initialization. while (process == null) { process = Process.GetProcessById((int)processInfo.ProcessId); } var memory = new Memory(process.Handle); // Get RSA modulus offset from file. var modulusOffset = File.ReadAllBytes(appPath).FindPattern(Patterns.Common.Modulus, memory.BaseAddress.ToInt64()).ToIntPtr(); var sectionOffset = memory.Read(modulusOffset, 0x2000).FindPattern(Patterns.Common.Modulus); modulusOffset = (modulusOffset.ToInt64() + sectionOffset).ToIntPtr(); // Be sure that the modulus is written before the client is initialized. while (memory.Read(modulusOffset, 1)[0] != Patches.Common.Modulus[0]) { memory.Write(modulusOffset, Patches.Common.Modulus); } Memory.ResumeThreads(process); var mbi = new MemoryBasicInformation(); // Wait for the memory region to be initialized. while (NativeWindows.VirtualQueryEx(process.Handle, memory.BaseAddress, out mbi, mbi.Size) == 0 || mbi.RegionSize.ToInt32() <= 0x1000) { } if (mbi.BaseAddress != IntPtr.Zero) { // Get the memory content. var binary = memory.Read(mbi.BaseAddress, mbi.RegionSize.ToInt32()); var initOffset = IntPtr.Zero; // Search while not initialized. while ((initOffset = binary.FindPattern(initPattern, memory.BaseAddress.ToInt64()).ToIntPtr()) == IntPtr.Zero) { binary = memory.Read(mbi.BaseAddress, mbi.RegionSize.ToInt32()); } // Re-read the memory region for each pattern search. var connectOffset = memory.Read(mbi.BaseAddress, mbi.RegionSize.ToInt32()).FindPattern(connectPattern, memory.BaseAddress.ToInt64()); var certBundleOffset = memory.Read(mbi.BaseAddress, mbi.RegionSize.ToInt32()).FindPattern(certBundlePattern, memory.BaseAddress.ToInt64()); var signatureOffset = memory.Read(mbi.BaseAddress, mbi.RegionSize.ToInt32()).FindPattern(signaturePattern, memory.BaseAddress.ToInt64()); if (initOffset == IntPtr.Zero || modulusOffset == IntPtr.Zero || connectOffset == 0 || certBundleOffset == 0 || signatureOffset == 0) { Console.WriteLine($"0x{initOffset.ToInt64():X}"); Console.WriteLine($"0x{modulusOffset.ToInt64():X}"); Console.WriteLine($"0x{connectOffset:X}"); Console.WriteLine($"0x{certBundleOffset:X}"); Console.WriteLine($"0x{signatureOffset:X}"); process.Dispose(); process.Kill(); WaitAndExit(); } if (memory.RemapViewBase()) { memory.Write(connectOffset, connectPatch); memory.Write(certBundleOffset, certBundlePatch); memory.Write(signatureOffset, signaturePatch); Console.WriteLine("Done :) "); Console.ForegroundColor = ConsoleColor.Green; Console.WriteLine("You can login now."); binary = null; WaitAndExit(); } else { binary = null; Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("Error while launching the client."); process.Dispose(); process.Kill(); WaitAndExit(); } } } } catch (Exception) { process?.Dispose(); process?.Kill(); WaitAndExit(); } }