mirror of
https://github.com/araxiaonline/WoW-Launcher.git
synced 2026-06-13 01:22:21 -04:00
Cleanup
This commit is contained in:
@@ -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
|
||||
}
|
||||
@@ -10,16 +10,16 @@ class WinMemory
|
||||
{
|
||||
public byte[] Data { get; set; }
|
||||
|
||||
public nint ProcessHandle { get; }
|
||||
public nint BaseAddress { get; }
|
||||
|
||||
ProcessBasicInformation peb;
|
||||
|
||||
readonly Dictionary<string, (long Address, byte[] Data)> patchList;
|
||||
ProcessBasicInformation _peb;
|
||||
|
||||
readonly nint _processHandle;
|
||||
readonly Dictionary<string, (long Address, byte[] Data)> _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<string, (long Address, byte[] Data)>();
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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<bool> 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
|
||||
{
|
||||
|
||||
@@ -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<char> cidr)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace Arctium.WoW.Launcher;
|
||||
#if x64
|
||||
class ModLoader
|
||||
{
|
||||
static readonly HashSet<uint> loadedFileIds = new();
|
||||
static readonly HashSet<uint> _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 _);
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user