From 1396634079e6a012a7d0020e545c0d5befc87a19 Mon Sep 17 00:00:00 2001 From: Fabian Date: Tue, 25 Jul 2023 03:48:20 +0200 Subject: [PATCH] Cleanup --- src/Constants/BinaryTypes.cs | 13 ------- src/IO/WinMemory.cs | 71 ++++++++++++++++++------------------ src/Launcher.cs | 57 +++++++++++++++-------------- src/Misc/Extensions.cs | 15 ++++---- src/Misc/Helpers.cs | 6 ++- src/Misc/IPFilter.cs | 7 +--- src/Misc/NativeWindows.cs | 4 +- src/ModLoader.cs | 21 ++++------- src/Program.cs | 3 +- 9 files changed, 89 insertions(+), 108 deletions(-) delete mode 100644 src/Constants/BinaryTypes.cs diff --git a/src/Constants/BinaryTypes.cs b/src/Constants/BinaryTypes.cs deleted file mode 100644 index bbef045..0000000 --- a/src/Constants/BinaryTypes.cs +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (c) Arctium. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -namespace Arctium.WoW.Launcher.Constants; - -enum BinaryTypes : uint -{ - None = 0000000000, - Pe32 = 0x0000014C, - Pe64 = 0x00008664, - Mach32 = 0xFEEDFACE, - Mach64 = 0xFEEDFACF -} diff --git a/src/IO/WinMemory.cs b/src/IO/WinMemory.cs index 1668aa4..c80bead 100644 --- a/src/IO/WinMemory.cs +++ b/src/IO/WinMemory.cs @@ -10,16 +10,16 @@ class WinMemory { public byte[] Data { get; set; } - public nint ProcessHandle { get; } public nint BaseAddress { get; } - ProcessBasicInformation peb; - - readonly Dictionary patchList; + ProcessBasicInformation _peb; + + readonly nint _processHandle; + readonly Dictionary _patchList; public WinMemory(ProcessInformation processInformation, long binaryLength) { - ProcessHandle = processInformation.ProcessHandle; + _processHandle = processInformation.ProcessHandle; if (processInformation.ProcessHandle == 0) throw new InvalidOperationException("No valid process found."); @@ -31,7 +31,7 @@ class WinMemory Data = Read(BaseAddress, (int)binaryLength); - patchList = new(); + _patchList = new Dictionary(); } public void RefreshMemoryData(int size) @@ -53,7 +53,7 @@ class WinMemory { var buffer = new byte[8]; - if (ReadProcessMemory(ProcessHandle, address, buffer, buffer.Length, out var dummy)) + if (ReadProcessMemory(_processHandle, address, buffer, buffer.Length, out var dummy)) return buffer.ToNint(); } @@ -73,7 +73,7 @@ class WinMemory { var buffer = new byte[size]; - if (ReadProcessMemory(ProcessHandle, address, buffer, size, out var dummy)) + if (ReadProcessMemory(_processHandle, address, buffer, size, out var dummy)) return buffer; } @@ -87,10 +87,10 @@ class WinMemory public byte[] Read(long address, int size) => Read((nint)address, size); - public int ReadDataLength(nint address, string seperator) + public int ReadDataLength(nint address, string separator) { var length = 0L; - var seperatorBytes = Encoding.UTF8.GetBytes(seperator).Select(b => (short)b).ToArray(); + var seperatorBytes = Encoding.UTF8.GetBytes(separator).Select(b => (short)b).ToArray(); var dataLength = 1000; // Read in batches here. @@ -112,12 +112,12 @@ class WinMemory { try { - VirtualProtectEx(ProcessHandle, address, (uint)data.Length, (uint)newProtection, out var oldProtect); + VirtualProtectEx(_processHandle, address, (uint)data.Length, (uint)newProtection, out var oldProtect); - WriteProcessMemory(ProcessHandle, address, data, data.Length, out var written); + WriteProcessMemory(_processHandle, address, data, data.Length, out _); - FlushInstructionCache(ProcessHandle, address, (uint)data.Length); - VirtualProtectEx(ProcessHandle, address, (uint)data.Length, oldProtect, out oldProtect); + FlushInstructionCache(_processHandle, address, (uint)data.Length); + VirtualProtectEx(_processHandle, address, (uint)data.Length, oldProtect, out oldProtect); } catch (Exception ex) @@ -174,7 +174,7 @@ class WinMemory { Console.WriteLine($"[{patchName}] Adding..."); - patchList[patchName] = (patchOffset, patch); + _patchList[patchName] = (patchOffset, patch); Console.Write($"[{patchName}]"); Console.ForegroundColor = ConsoleColor.Green; @@ -183,7 +183,7 @@ class WinMemory Console.WriteLine(); } else - patchList[patchName] = (patchOffset, patch); + _patchList[patchName] = (patchOffset, patch); return Task.CompletedTask; } @@ -209,10 +209,10 @@ class WinMemory return QueuePatch(patchOffset + offsetBase, patch, patchName, printInfo); } - public bool RemapAndPatch(nint viewAddress, int viewSize) + bool RemapAndPatch(nint viewAddress, int viewSize) { // Suspend before remapping to prevent crashes. - NtSuspendProcess(ProcessHandle); + NtSuspendProcess(_processHandle); Data = Read(viewAddress, viewSize); @@ -224,13 +224,13 @@ class WinMemory try { if (NtCreateSection(ref newViewHandle, 0xF001F, 0, ref maxSize, 0x40u, 0x8000000 | 0x400000, 0) == NtStatus.Success && - NtUnmapViewOfSection(ProcessHandle, viewAddress) == NtStatus.Success) + NtUnmapViewOfSection(_processHandle, viewAddress) == NtStatus.Success) { var viewBase = viewAddress; // Map the view with original protections. - var result = NtMapViewOfSection(newViewHandle, ProcessHandle, ref viewBase, 0, (ulong)viewSize, out var viewOffset, - out var newViewSize, 2, 0, (int)MemProtection.ExecuteRead); + var result = NtMapViewOfSection(newViewHandle, _processHandle, ref viewBase, 0, (ulong)viewSize, out _, + out _, 2, 0, (int)MemProtection.ExecuteRead); if (result == NtStatus.Success) { @@ -240,23 +240,24 @@ class WinMemory nint viewBase2 = 0; // Create a writable view to write our patches through to preserve the original protections. - result = NtMapViewOfSection(newViewHandle, ProcessHandle, ref viewBase2, 0, (uint)viewSize, out var viewOffset2, - out var newViewSize2, 2, 0, (int)MemProtection.ReadWrite); + result = NtMapViewOfSection(newViewHandle, _processHandle, ref viewBase2, 0, (uint)viewSize, out _, + out _, 2, 0, (int)MemProtection.ReadWrite); if (result == NtStatus.Success) { // Write our patched data trough the writable view to the memory. - if (WriteProcessMemory(ProcessHandle, viewBase2, Data, viewSize, out var dummy)) + if (WriteProcessMemory(_processHandle, viewBase2, Data, viewSize, out var dummy)) { // Unmap them writeable view, it's not longer needed. - NtUnmapViewOfSection(ProcessHandle, viewBase2); + NtUnmapViewOfSection(_processHandle, viewBase2); // Check if the allocation protections is the right one. - if (VirtualQueryEx(ProcessHandle, BaseAddress, out MemoryBasicInformation mbi, MemoryBasicInformation.Size) != 0 && mbi.AllocationProtect == MemProtection.ExecuteRead) + if (VirtualQueryEx(_processHandle, BaseAddress, out MemoryBasicInformation mbi, MemoryBasicInformation.Size) != 0 + && mbi.AllocationProtect == MemProtection.ExecuteRead) { // Also check if we can change the page protection. - if (!VirtualProtectEx(ProcessHandle, BaseAddress, 0x4000, (uint)MemProtection.ReadWrite, out var oldProtect)) - NtResumeProcess(ProcessHandle); + if (!VirtualProtectEx(_processHandle, BaseAddress, 0x4000, (uint)MemProtection.ReadWrite, out _)) + NtResumeProcess(_processHandle); return true; } @@ -275,14 +276,14 @@ class WinMemory else Console.WriteLine("Error while creating the view backup."); - NtResumeProcess(ProcessHandle); + NtResumeProcess(_processHandle); return false; } void ApplyPatches(bool remap) { - foreach (var p in patchList) + foreach (var p in _patchList) { var address = p.Value.Address; @@ -297,7 +298,7 @@ class WinMemory if (address < BaseAddress) address += BaseAddress; - Write(address, patch, MemProtection.ReadWrite); + Write(address, patch); continue; } @@ -314,11 +315,11 @@ class WinMemory { if (!remap) { - ApplyPatches(remap); + ApplyPatches(false); return true; } - if (VirtualQueryEx(ProcessHandle, BaseAddress, out MemoryBasicInformation mbi, MemoryBasicInformation.Size) != 0) + if (VirtualQueryEx(_processHandle, BaseAddress, out var mbi, MemoryBasicInformation.Size) != 0) return RemapAndPatch(mbi.BaseAddress, (int)mbi.RegionSize); return false; @@ -329,8 +330,8 @@ class WinMemory { try { - if (NtQueryInformationProcess(processHandle, 0, ref peb, ProcessBasicInformation.Size, out int sizeInfoReturned) == NtStatus.Success) - return Read(peb.PebBaseAddress + 0x10); + if (NtQueryInformationProcess(processHandle, 0, ref _peb, ProcessBasicInformation.Size, out _) == NtStatus.Success) + return Read(_peb.PebBaseAddress + 0x10); } catch (Exception ex) { diff --git a/src/Launcher.cs b/src/Launcher.cs index b7ecfed..1d69519 100644 --- a/src/Launcher.cs +++ b/src/Launcher.cs @@ -5,7 +5,7 @@ using System.CommandLine.Parsing; using System.Net.Security; using System.Net.Sockets; using System.Security.Authentication; -using System.Security.Cryptography.X509Certificates; + using static Arctium.WoW.Launcher.Misc.Helpers; namespace Arctium.WoW.Launcher; @@ -17,7 +17,7 @@ static class Launcher public static string PrepareGameLaunch(ParseResult commandLineResult, IPFilter ipFilter) { var gameVersion = commandLineResult.GetValueForOption(LaunchOptions.Version); - var (SubFolder, BinaryName, MajorGameVersion, MinGameBuild) = gameVersion switch + var (subFolder, binaryName, majorGameVersion, minGameBuild) = gameVersion switch { #if x64 GameVersion.Retail => ("_retail_", "Wow.exe", new[] { 9, 10 }, 37862), @@ -38,26 +38,26 @@ static class Launcher Console.ResetColor(); var currentFolder = AppDomain.CurrentDomain.BaseDirectory; - var gameFolder = $"{currentFolder}/{SubFolder}"; + var gameFolder = $"{currentFolder}/{subFolder}"; if (commandLineResult.HasOption(LaunchOptions.GameBinary)) - BinaryName = commandLineResult.GetValueForOption(LaunchOptions.GameBinary); + binaryName = commandLineResult.GetValueForOption(LaunchOptions.GameBinary); - var gameBinaryPath = $"{gameFolder}/{BinaryName}"; + var gameBinaryPath = $"{gameFolder}/{binaryName}"; if (commandLineResult.HasOption(LaunchOptions.GamePath)) { gameFolder = commandLineResult.GetValueForOption(LaunchOptions.GamePath); - gameBinaryPath = $"{gameFolder}/{BinaryName}"; + gameBinaryPath = $"{gameFolder}/{binaryName}"; } else if (!File.Exists(gameBinaryPath)) { // Also support game installations without branch sub folders. gameFolder = currentFolder; - gameBinaryPath = $"{gameFolder}/{BinaryName}"; + gameBinaryPath = $"{gameFolder}/{binaryName}"; } - if (!File.Exists(gameBinaryPath) || !MajorGameVersion.Contains(GetVersionValueFromClient(gameBinaryPath).Major)) + if (!File.Exists(gameBinaryPath) || !majorGameVersion.Contains(GetVersionValueFromClient(gameBinaryPath).Major)) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine($"[Error] No {gameVersion} client found."); @@ -67,11 +67,11 @@ static class Launcher var gameClientBuild = GetVersionValueFromClient(gameBinaryPath).Build; - if (gameClientBuild < MinGameBuild && gameClientBuild != 0) + if (gameClientBuild < minGameBuild && gameClientBuild != 0) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine($"Your found client version {gameClientBuild} is not supported."); - Console.WriteLine($"The minimum required build is {MinGameBuild}"); + Console.WriteLine($"The minimum required build is {minGameBuild}"); return string.Empty; } @@ -119,22 +119,25 @@ static class Launcher { try { - var tcpClient = new TcpClient(portal.HostName, portal.Port); - var sslStream = new SslStream(tcpClient.GetStream(), false, - (object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) => + using var tcpClient = new TcpClient(portal.HostName, portal.Port); + + // Cancel after 5 seconds. + tcpClient.ReceiveTimeout = 5000; + tcpClient.SendTimeout = 5000; + + using var sslStream = new SslStream(tcpClient.GetStream(), false, + (_, _, _, sslPolicyErrors) => { - if (sslPolicyErrors == SslPolicyErrors.None) - { - Console.ForegroundColor = ConsoleColor.Green; - Console.WriteLine($"Certificate for server '{portal.HostName}' successfully validated."); - Console.WriteLine(); - Console.ResetColor(); - - return true; - } - // Redirect to the trusted cert warning. - throw new AuthenticationException(); + if (sslPolicyErrors != SslPolicyErrors.None) + throw new AuthenticationException(); + + Console.ForegroundColor = ConsoleColor.Green; + Console.WriteLine($"Certificate for server '{portal.HostName}' successfully validated."); + Console.WriteLine(); + Console.ResetColor(); + + return true; }, null ); @@ -272,13 +275,11 @@ static class Launcher NativeWindows.NtResumeProcess(processInfo.ProcessHandle); - var antiCrash = false; - // Enable anti crash in dev mode, custom file mode or static auth seed mode. #if CUSTOM_FILES - antiCrash = true; + var antiCrash = true; #else - antiCrash = legacyCertMode || commandLineResult.HasOption(LaunchOptions.UseStaticAuthSeed) || + var antiCrash = legacyCertMode || commandLineResult.HasOption(LaunchOptions.UseStaticAuthSeed) || commandLineResult.GetValueForOption(LaunchOptions.DevMode) && LaunchOptions.IsDevModeAllowed; #endif diff --git a/src/Misc/Extensions.cs b/src/Misc/Extensions.cs index 38d3bfd..c3943e5 100644 --- a/src/Misc/Extensions.cs +++ b/src/Misc/Extensions.cs @@ -60,17 +60,16 @@ static class Extensions { match = data.FindPattern(pattern, match, 0); - if (match != 0) - { - if (!matchList.Contains(match)) - matchList.Add(match); - - match += pattern.Length; - } + if (match == 0) + continue; + + matchList.Add(match); + + match += pattern.Length; } while ((matchList.Count < maxMatches || match < maxOffset) && match != 0); - return matchList; + return matchList; } public static short[] ToPattern(this string data) => Encoding.UTF8.GetBytes(data).Select(b => (short)b).ToArray(); diff --git a/src/Misc/Helpers.cs b/src/Misc/Helpers.cs index 54d31ed..f29afb0 100644 --- a/src/Misc/Helpers.cs +++ b/src/Misc/Helpers.cs @@ -85,7 +85,7 @@ static class Helpers if (IPAddress.TryParse(portalString, out var ipAddress)) return (ipAddress.ToString(), portalString, port); - var ipv4Address = Dns.GetHostAddresses(portalString).FirstOrDefault(a => a.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork); + var ipv4Address = Dns.GetHostAddresses(portalString).FirstOrDefault(a => a.AddressFamily == AddressFamily.InterNetwork); if (ipv4Address == null) throw new Exception("No IPv4 address found for the provided hostname."); @@ -102,7 +102,9 @@ static class Helpers public static async Task CheckUrl(string url, string fallbackUrl) { - using var httpClient = new HttpClient { Timeout = TimeSpan.FromSeconds(5) }; + using var httpClient = new HttpClient(); + + httpClient.Timeout = TimeSpan.FromSeconds(5); try { diff --git a/src/Misc/IPFilter.cs b/src/Misc/IPFilter.cs index 600ad26..f06b2cc 100644 --- a/src/Misc/IPFilter.cs +++ b/src/Misc/IPFilter.cs @@ -7,12 +7,7 @@ namespace Arctium.WoW.Launcher.Misc; public class IPFilter { - readonly ICollection<(IPAddress, IPAddress)> _ipRanges; - - public IPFilter() - { - _ipRanges = new List<(IPAddress, IPAddress)>(); - } + readonly List<(IPAddress, IPAddress)> _ipRanges = new(); public void AddCidrRange(ReadOnlySpan cidr) { diff --git a/src/Misc/NativeWindows.cs b/src/Misc/NativeWindows.cs index cd40c59..56b1ecd 100644 --- a/src/Misc/NativeWindows.cs +++ b/src/Misc/NativeWindows.cs @@ -51,10 +51,10 @@ static class NativeWindows public static extern NtStatus NtUnmapViewOfSection(nint processHandle, nint baseAddress); [DllImport("ntdll.dll", SetLastError = true)] - public static extern nint NtResumeProcess(nint ProcessHandle); + public static extern nint NtResumeProcess(nint processHandle); [DllImport("ntdll.dll", SetLastError = true)] - public static extern nint NtSuspendProcess(nint ProcessHandle); + public static extern nint NtSuspendProcess(nint processHandle); [DllImport("ntdll.dll", SetLastError = true)] public static extern nint NtClose(nint handle); diff --git a/src/ModLoader.cs b/src/ModLoader.cs index 5715d16..5e653b5 100644 --- a/src/ModLoader.cs +++ b/src/ModLoader.cs @@ -6,7 +6,7 @@ namespace Arctium.WoW.Launcher; #if x64 class ModLoader { - static readonly HashSet loadedFileIds = new(); + static readonly HashSet _loadedFileIds = new(); public static bool HookClient(WinMemory memory, nint processHandle, nint idAlloc, nint stringAlloc) { @@ -38,7 +38,7 @@ class ModLoader memory.QueuePatch(hookAddress, hookInstructions, "CustomFileIdHook"); // Copy count bytes. - Buffer.BlockCopy(BitConverter.GetBytes(loadedFileIds.Count), 0, asm, 35, 4); + Buffer.BlockCopy(BitConverter.GetBytes(_loadedFileIds.Count), 0, asm, 35, 4); // Copy mapping ptr bytes. Buffer.BlockCopy(BitConverter.GetBytes(idAlloc), 0, asm, 12, 8); @@ -121,7 +121,7 @@ class ModLoader return default; } - static bool GetFileMappingData(List<(byte[] fileId, byte[] path, uint StringPos)> loadedMappings, out uint count, ref uint stringLength, string mappingFile) + static void GetFileMappingData(List<(byte[] fileId, byte[] path, uint StringPos)> loadedMappings, out uint count, ref uint stringLength, string mappingFile) { var mappings = File.ReadAllLines(mappingFile).Where(s => s.Trim() != "") .Select(s => s.ToLowerInvariant().Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries)) @@ -145,13 +145,13 @@ class ModLoader { var id = uint.Parse(fileId); - if (loadedFileIds.Contains(id)) + if (_loadedFileIds.Contains(id)) { Console.WriteLine($"Skipping overlapping file '{id} - {f}'."); continue; } - loadedFileIds.Add(id); + _loadedFileIds.Add(id); loadedMappings.Add((BitConverter.GetBytes(id), pathBytes, stringLength)); @@ -160,11 +160,6 @@ class ModLoader } count = (uint)loadedMappings.Count; - - if (loadedMappings.Count == 0) - return false; - - return true; } static (nint, nint) AllocateFileMapping(nint handle, List<(byte[] fileId, byte[] path, uint StringPos)> loadedMappings, uint count, uint stringLength) @@ -176,11 +171,11 @@ class ModLoader Parallel.For(0, loadedMappings.Count, m => { - var (fileId, path, StringPos) = loadedMappings[m]; + var (fileId, path, stringPos) = loadedMappings[m]; Buffer.BlockCopy(fileId, 0, idAllocData, m * 12, fileId.Length); - Buffer.BlockCopy(BitConverter.GetBytes(stringAlloc + StringPos), 0, idAllocData, (m * 12) + 4, 8); - Buffer.BlockCopy(path, 0, stringAllocData, (int)StringPos, path.Length); + Buffer.BlockCopy(BitConverter.GetBytes(stringAlloc + stringPos), 0, idAllocData, (m * 12) + 4, 8); + Buffer.BlockCopy(path, 0, stringAllocData, (int)stringPos, path.Length); }); NativeWindows.WriteProcessMemory(handle, idAlloc, idAllocData, idAllocData.Length, out var _); diff --git a/src/Program.cs b/src/Program.cs index b51e36a..9e5f563 100644 --- a/src/Program.cs +++ b/src/Program.cs @@ -7,7 +7,7 @@ using Arctium.WoW.Launcher; using static Arctium.WoW.Launcher.Misc.Helpers; // "Arctium" should not be removed from the final binary name. -if (!Process.GetCurrentProcess().ProcessName.ToLowerInvariant().Contains("arctium")) +if (!Process.GetCurrentProcess().ProcessName.Contains("arctium", StringComparison.InvariantCultureIgnoreCase)) WaitAndExit(); PrintHeader("WoW Client Launcher"); @@ -28,6 +28,7 @@ LaunchOptions.RootCommand.SetHandler(context => }); await LaunchOptions.Instance.InvokeAsync(args); +return; void CreateDevIPFilter(out IPFilter ipFilter) {