From 38c6ceeaab97fab70e034ec1b303aa5c905b9b86 Mon Sep 17 00:00:00 2001 From: Fabian Date: Thu, 10 Nov 2022 18:35:27 +0100 Subject: [PATCH] Update to .NET 7 --- README.md | 8 +- nuget.config | 9 -- src/Arctium.WoW.Launcher.csproj | 131 +++++++++++----------- src/IO/WinMemory.cs | 18 +-- src/LaunchOptions.cs | 4 +- src/Launcher.cs | 31 ++--- src/Program.cs | 46 ++++---- src/Structures/LargeInteger.cs | 2 +- src/Structures/MemoryBasicInformation.cs | 2 +- src/Structures/ProcessBasicInformation.cs | 2 +- src/Structures/ProcessInformation.cs | 2 +- src/Structures/StartupInfo.cs | 2 +- 12 files changed, 119 insertions(+), 138 deletions(-) delete mode 100644 nuget.config diff --git a/README.md b/README.md index 948f0f7..b49f0a4 100644 --- a/README.md +++ b/README.md @@ -11,8 +11,8 @@ Please see our Open Source project [Documentation Repo](https://github.com/Arcti You can find signed binary releases at [Releases](https://github.com/Arctium/WoW-Launcher/releases) ### Supported Game Versions (Windows x86 64 bit) -* Dragonflight: 10.0.0, 10.0.2 -* Shadowlands: 9.1.0, 9.1.5, 9.2.0, 9.2.5, 9.2.7 (default) +* Dragonflight: 10.0.0, 10.0.2 (implicit) +* Shadowlands: 9.1.0, 9.1.5, 9.2.0, 9.2.5, 9.2.7 (implicit) * Classic: 2.5.2, 2.5.3, 2.5.4, 3.4.0 (--version Classic) * Classic Era: 1.14.x (--version ClassicEra) @@ -24,13 +24,13 @@ You can find signed binary releases at [Releases](https://github.com/Arctium/WoW ## Building ### Build Prerequisites -* [.NET Core SDK 6.0.0 or later](https://dotnet.microsoft.com/download/dotnet/6.0) +* [.NET Core SDK 7.0.0 or later](https://dotnet.microsoft.com/download/dotnet/7.0) * Optional for native builds: C++ workload through Visual Studio 2022 or latest C++ build tools ### Build Instructions Windows (native) * Available runtime identifiers/platforms: win-x64/x64, win-arm64/ARM64 * Available release configurations: Release, ReleaseSilentMode, ReleaseCustomFiles, ReleaseCustomFilesSilentMode -* Execute `dotnet publish -r RuntimeIdentifier -c Configuration -p:platform="Platform" --self-contained` +* Execute `dotnet publish -r RuntimeIdentifier -c Configuration -p:platform="Platform"` * Native output is placed in `build\Configuration\bin\native` ## Usage diff --git a/nuget.config b/nuget.config deleted file mode 100644 index fe3b040..0000000 --- a/nuget.config +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/src/Arctium.WoW.Launcher.csproj b/src/Arctium.WoW.Launcher.csproj index 36ba636..440a417 100644 --- a/src/Arctium.WoW.Launcher.csproj +++ b/src/Arctium.WoW.Launcher.csproj @@ -1,77 +1,76 @@  + + ../build/$(Configuration)/bin + Arctium WoW Launcher + logo.ico + Exe + net7.0 + True + False + False + disable + preview + 10.0.0.0 + 10.0.0.0 + Arctium + x64;ARM64 + enable + $(DefineConstants);$(Platform) + Debug;Release;ReleaseSilentMode;ReleaseCustomFiles;ReleaseCustomFilesSilentMode - - ../build/$(Configuration)/bin - Arctium WoW Launcher - logo.ico - Exe - net6.0 - False - False - False - disable - preview - 9.0.0.0 - 9.0.0.0 - Arctium - x64;ARM64 - enable - $(DefineConstants);$(Platform) - Debug;Release;ReleaseSilentMode;ReleaseCustomFiles;ReleaseCustomFilesSilentMode + + true + false + false + false + true + false + true + false + true + true + Speed + false + - - false - false - false - + + win-x64 + - - win-x64 - + + win-arm64 + - - win-arm64 - + + $(DefineConstants);$(Platform);CUSTOM_FILES + - - $(DefineConstants);$(Platform);CUSTOM_FILES - + + none + false + - - none - false - + + $(DefineConstants);$(Platform);CUSTOM_FILES + none + false + - - $(DefineConstants);$(Platform);CUSTOM_FILES - none - false - + + WinExe + none + false + - - WinExe - none - false - - - - WinExe - $(DefineConstants);$(Platform);CUSTOM_FILES - none - false - - - - - - - - - - - - - - + + WinExe + $(DefineConstants);$(Platform);CUSTOM_FILES + none + false + + + + + diff --git a/src/IO/WinMemory.cs b/src/IO/WinMemory.cs index 4adfe02..3fa4474 100644 --- a/src/IO/WinMemory.cs +++ b/src/IO/WinMemory.cs @@ -142,7 +142,7 @@ class WinMemory Console.WriteLine("Press any key to exit..."); Console.ReadKey(); - Program.CancellationTokenSource.Cancel(); + Launcher.CancellationTokenSource.Cancel(); } while (Read(patchOffset, patch.Length)?.SequenceEqual(patch) == false) @@ -163,7 +163,7 @@ class WinMemory public Task QueuePatch(long patchOffset, byte[] patch, string patchName) { - Program.CancellationTokenSource.Token.ThrowIfCancellationRequested(); + Launcher.CancellationTokenSource.Token.ThrowIfCancellationRequested(); Console.WriteLine($"[{patchName}] Adding..."); @@ -198,7 +198,7 @@ class WinMemory Console.WriteLine("Press any key to exit..."); Console.ReadKey(); - Program.CancellationTokenSource.Cancel(); + Launcher.CancellationTokenSource.Cancel(); return Task.CompletedTask; } @@ -234,12 +234,12 @@ class WinMemory // Apply our patches. foreach (var p in patchList) { - var address = p.Value.Item1; + var address = p.Value.Address; if (address == 0) continue; - var patch = p.Value.Item2; + var patch = p.Value.Data; // We are in a different section here. if (address > Data.Length) @@ -311,7 +311,7 @@ class WinMemory { try { - if (NtQueryInformationProcess(processHandle, 0, ref peb, peb.Size, out int sizeInfoReturned) == NtStatus.Success) + if (NtQueryInformationProcess(processHandle, 0, ref peb, ProcessBasicInformation.Size, out int sizeInfoReturned) == NtStatus.Success) return Read(peb.PebBaseAddress + 0x10); } catch (Exception ex) @@ -323,19 +323,19 @@ class WinMemory } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool IsShortJump(byte[] instructions, int startIndex = 0) + public static bool IsShortJump(byte[] instructions, int startIndex = 0) { return instructions[startIndex] >= 0x70 && instructions[startIndex] < 0x7F; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool IsJump(byte[] instructions, int startIndex = 0) + public static bool IsJump(byte[] instructions, int startIndex = 0) { return instructions[startIndex] == 0x0F && instructions[startIndex + 1] >= 0x80 && instructions[startIndex + 1] <= 0x8F; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool IsUnconditionalJump(byte[] instructions, int startIndex = 0) + public static bool IsUnconditionalJump(byte[] instructions, int startIndex = 0) { return instructions[startIndex] == 0xE9 || instructions[startIndex] == 0xEB; } diff --git a/src/LaunchOptions.cs b/src/LaunchOptions.cs index 38923be..b706a43 100644 --- a/src/LaunchOptions.cs +++ b/src/LaunchOptions.cs @@ -1,7 +1,6 @@ // Copyright (c) Arctium. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using System.CommandLine; using System.CommandLine.Builder; using System.CommandLine.Parsing; @@ -22,7 +21,7 @@ static class LaunchOptions .UseSuggestDirective() .Build(); - public static RootCommand RootCommand = new("Arctium\0WoW\0Launcher") + public static RootCommand RootCommand = new("Arctium WoW Launcher") { Version, GamePath, @@ -38,4 +37,3 @@ static class LaunchOptions return rootCommand; } } - diff --git a/src/Launcher.cs b/src/Launcher.cs index 1d679cc..c1693fe 100644 --- a/src/Launcher.cs +++ b/src/Launcher.cs @@ -9,6 +9,8 @@ namespace Arctium.WoW.Launcher; class Launcher { + public static CancellationTokenSource CancellationTokenSource => new(); + public static string PrepareGameLaunch(ParseResult commandLineResult) { var gameVersion = commandLineResult.GetValueForOption(LaunchOptions.Version); @@ -24,7 +26,6 @@ class Launcher GameVersion.ClassicEra => ("_classic_era_", "WowClassic-arm64.exe", new[] { 1 }, 40347), #endif _ => throw new NotImplementedException("Invalid game version specified."), - }; Console.ForegroundColor = ConsoleColor.Yellow; @@ -58,7 +59,7 @@ class Launcher Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine($"[Error] No {gameVersion} client found."); - return String.Empty; + return string.Empty; } var gameClientBuild = GetVersionValueFromClient(gameBinaryPath).Build; @@ -69,7 +70,7 @@ class Launcher Console.WriteLine($"Your found client version {gameClientBuild} is not supported."); Console.WriteLine($"The minimum required build is {MinGameBuild}"); - return String.Empty; + return string.Empty; } // Delete the cache folder by default. @@ -99,11 +100,11 @@ class Launcher Console.ForegroundColor = ConsoleColor.White; Console.WriteLine("Starting WoW client..."); - var createSuccess = NativeWindows.CreateProcess(null, $"{appPath} {gameCommandLine}", 0, 0, false, 4U, 0, new FileInfo(appPath)?.DirectoryName, ref startupInfo, out processInfo); + var createSuccess = NativeWindows.CreateProcess(null, $"{appPath} {gameCommandLine}", 0, 0, false, 4, 0, new FileInfo(appPath)?.DirectoryName, ref startupInfo, out processInfo); // On some systems we have to launch the game with the application name used. if (!createSuccess) - createSuccess = NativeWindows.CreateProcess(appPath, $" {gameCommandLine}", 0, 0, false, 4U, 0, null, ref startupInfo, out processInfo); + createSuccess = NativeWindows.CreateProcess(appPath, $" {gameCommandLine}", 0, 0, false, 4, 0, null, ref startupInfo, out processInfo); // Start process with suspend flags. if (createSuccess) @@ -149,7 +150,7 @@ class Launcher memory.PatchMemory(Patterns.Common.Portal, Patches.Common.Portal, "Login Portal"), memory.PatchMemory(Patterns.Common.VersionUrl, versionPatch, "Version URL"), memory.PatchMemory(Patterns.Windows.LauncherLogin, Patches.Windows.LauncherLogin, "Launcher Login Registry") - }, Program.CancellationTokenSource.Token); + }, CancellationTokenSource.Token); NativeWindows.NtResumeProcess(processInfo.ProcessHandle); @@ -178,8 +179,8 @@ class Launcher { memory.QueuePatch(Patterns.Windows.CertBundle, Patches.Windows.CertBundle, "CertBundle"), memory.QueuePatch(Patterns.Windows.CertCommonName, Patches.Windows.CertCommonName, "CertCommonName", 5) - }, Program.CancellationTokenSource.Token); - #if CUSTOM_FILES + }, CancellationTokenSource.Token); +#if CUSTOM_FILES Task.WaitAll(new[] { memory.QueuePatch(Patterns.Windows.LoadByFileId, Patches.Windows.NoJump, "LoadByFileId", 6), @@ -188,7 +189,7 @@ class Launcher (clientVersion is (10, _, _, _)) ? memory.QueuePatch(Patterns.Windows.LoadByFilePathAlternate, Patches.Windows.NoJump, "LoadByFilePath", 3) : memory.QueuePatch(Patterns.Windows.LoadByFilePath, Patches.Windows.NoJump, "LoadByFilePath", 3) - }, Program.CancellationTokenSource.Token); + }, CancellationTokenSource.Token); var (idAlloc, stringAlloc) = ModLoader.LoadFileMappings(processInfo.ProcessHandle); @@ -197,7 +198,7 @@ class Launcher if (!ModLoader.HookClient(memory, processInfo.ProcessHandle, idAlloc, stringAlloc)) return false; } - #endif +#endif #elif ARM64 Task.WaitAll(new[] @@ -281,14 +282,14 @@ class Launcher Buffer.BlockCopy(memory.Data, instructionStart, instructions, 0, 6); // Skip unconditional jumps. - if (memory.IsUnconditionalJump(instructions)) + if (WinMemory.IsUnconditionalJump(instructions)) continue; var operandValue = 0; - if (memory.IsShortJump(instructions)) + if (WinMemory.IsShortJump(instructions)) operandValue = instructions[1] + 2; - else if (memory.IsJump(instructions)) + else if (WinMemory.IsJump(instructions)) operandValue = BitConverter.ToInt32(instructions, 2) + 6; else throw new InvalidDataException("Invalid operand value."); @@ -299,7 +300,7 @@ class Launcher // Find all references of real code parts inside the remap check functions. Parallel.For(lastAddress, memory.Data.Length, i => { - if (memory.IsJump(memory.Data, i)) + if (WinMemory.IsJump(memory.Data, i)) { var jumpOperand = BitConverter.ToInt32(memory.Data, i + 2); var jumpSize = (int)jumpToValue - i - 6; @@ -313,7 +314,7 @@ class Launcher tempPatches.TryAdd($"Jump{i}", (i, jumpBytes)); } } - else if (memory.IsShortJump(memory.Data, i)) + else if (WinMemory.IsShortJump(memory.Data, i)) { var jumpOperand = memory.Data[i + 1]; var jumpSize = (int)jumpToValue - i - 2; diff --git a/src/Program.cs b/src/Program.cs index 6033ec0..da3a958 100644 --- a/src/Program.cs +++ b/src/Program.cs @@ -1,42 +1,34 @@ // Copyright (c) Arctium. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using System.CommandLine.Invocation; using System.CommandLine.Parsing; - +using Arctium.WoW.Launcher; using static Arctium.WoW.Launcher.Misc.Helpers; -namespace Arctium.WoW.Launcher; +// "Arctium" should not be removed from the final binary name. +if (!Process.GetCurrentProcess().ProcessName.ToLowerInvariant().Contains("arctium")) + WaitAndExit(); -class Program +PrintHeader("WoW Client Launcher"); + +LaunchOptions.RootCommand.SetHandler(context => { - public static CancellationTokenSource CancellationTokenSource { get; private set; } + var appPath = Launcher.PrepareGameLaunch(context.ParseResult); + var gameCommandLine = string.Join(" ", context.ParseResult.UnmatchedTokens); - static async Task Main(string[] args) - { - CancellationTokenSource = new CancellationTokenSource(); + if (string.IsNullOrEmpty(appPath) || !Launcher.LaunchGame(appPath, gameCommandLine)) + WaitAndExit(5000); +}); - PrintHeader("WoW Client Launcher"); +await LaunchOptions.Instance.InvokeAsync(args); - 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)) - WaitAndExit(5000); - }); +static void WaitAndExit(int ms = 2000) +{ + Console.ForegroundColor = ConsoleColor.Gray; + Console.WriteLine($"Closing in {ms / 1000} seconds..."); - await LaunchOptions.Instance.InvokeAsync(args); - } + Thread.Sleep(ms); - public static void WaitAndExit(int ms = 2000) - { - Console.ForegroundColor = ConsoleColor.Gray; - Console.WriteLine($"Closing in {ms / 1000} seconds..."); - - Thread.Sleep(ms); - - Environment.Exit(0); - } + Environment.Exit(0); } diff --git a/src/Structures/LargeInteger.cs b/src/Structures/LargeInteger.cs index 359058c..a0eb5f5 100644 --- a/src/Structures/LargeInteger.cs +++ b/src/Structures/LargeInteger.cs @@ -13,5 +13,5 @@ struct LargeInteger [FieldOffset(4)] public int High; - public int Size => Marshal.SizeOf(typeof(LargeInteger)); + public static int Size => Marshal.SizeOf(); } diff --git a/src/Structures/MemoryBasicInformation.cs b/src/Structures/MemoryBasicInformation.cs index a036848..83c8928 100644 --- a/src/Structures/MemoryBasicInformation.cs +++ b/src/Structures/MemoryBasicInformation.cs @@ -14,5 +14,5 @@ struct MemoryBasicInformation public MemProtection Protect; public MemType Type; - public static int Size => Marshal.SizeOf(typeof(MemoryBasicInformation)); + public static int Size => Marshal.SizeOf(); } diff --git a/src/Structures/ProcessBasicInformation.cs b/src/Structures/ProcessBasicInformation.cs index dff743e..84a1e07 100644 --- a/src/Structures/ProcessBasicInformation.cs +++ b/src/Structures/ProcessBasicInformation.cs @@ -13,5 +13,5 @@ struct ProcessBasicInformation public nint UniqueProcessId; public nint InheritedFromUniqueProcessId; - public int Size => Marshal.SizeOf(typeof(ProcessBasicInformation)); + public static int Size => Marshal.SizeOf(); } diff --git a/src/Structures/ProcessInformation.cs b/src/Structures/ProcessInformation.cs index 8c1e584..8fac950 100644 --- a/src/Structures/ProcessInformation.cs +++ b/src/Structures/ProcessInformation.cs @@ -10,5 +10,5 @@ struct ProcessInformation public uint ProcessId; public uint ThreadId; - public int Size => Marshal.SizeOf(typeof(ProcessInformation)); + public static int Size => Marshal.SizeOf(); } diff --git a/src/Structures/StartupInfo.cs b/src/Structures/StartupInfo.cs index 96f69ff..1a74e7c 100644 --- a/src/Structures/StartupInfo.cs +++ b/src/Structures/StartupInfo.cs @@ -24,5 +24,5 @@ struct StartupInfo public nint StdOutputHandle; public nint StdErrorHandle; - public int Size => Marshal.SizeOf(typeof(StartupInfo)); + public static int Size => Marshal.SizeOf(); }