Added new command line options to specify custom versions & cdns urls.

Also fall back to default data when these are not reachable.
This commit is contained in:
Fabian
2023-07-22 02:14:28 +02:00
parent 3df4f47f50
commit cc60049b6a
7 changed files with 82 additions and 22 deletions

View File

@@ -16,6 +16,10 @@ static class LaunchOptions
public static Option<bool> KeepCache = new("--keepcache", () => true);
public static Option<bool> UseStaticAuthSeed = new("--staticseed");
public static Option<bool> DevMode = new("--dev", () => true);
public static Option<string> VersionUrl = new("--versionurl");
public static Option<string> CdnsUrl = new("--cdnsurl");
public static Option<string> ProductName = new("--product", () => "wow");
public static Option<string> CdnRegion = new("--region", () => "EU");
// Game command line options.
public static Option<string> GameConfig = new("-config", () => "Config.wtf");
@@ -36,6 +40,10 @@ static class LaunchOptions
KeepCache,
UseStaticAuthSeed,
DevMode,
VersionUrl,
CdnsUrl,
ProductName,
CdnRegion,
GameConfig
};

View File

@@ -98,7 +98,7 @@ static class Launcher
else
{
var config = File.ReadAllText(configPath);
portal = ParsePortal(config);
LaunchOptions.IsDevModeAllowed = IsDevModeAllowed(ipFilter, portal.IPAddress);
@@ -113,7 +113,7 @@ static class Launcher
Console.WriteLine($"Developer mode: {(devModeEnabled ? "Enabled" : "Disabled")}");
Console.WriteLine();
Console.ForegroundColor = ConsoleColor.Gray;
// Check for valid certificate when dev mode is disabled.
if (!devModeEnabled)
{
@@ -138,7 +138,7 @@ static class Launcher
},
null
);
sslStream.AuthenticateAsClient(portal.HostName);
}
catch (SocketException)
@@ -166,6 +166,38 @@ static class Launcher
public static bool LaunchGame(string appPath, string gameCommandLine, ParseResult commandLineResult)
{
// Build the version URL from the game binary build.
var clientVersion = GetVersionValueFromClient(appPath);
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine($"Client Build {clientVersion}");
Console.WriteLine($"Client Path '{appPath}'");
Console.WriteLine();
Console.ResetColor();
// Assign the region and product dependent version url to check it's online status.
var versionUrl = commandLineResult.GetValueForOption(LaunchOptions.VersionUrl)
?? Patches.Common.GetVersionUrl(clientVersion.Build, commandLineResult.GetValueForOption(LaunchOptions.CdnRegion),
commandLineResult.GetValueForOption(LaunchOptions.ProductName));
if (!CheckUrl(versionUrl, fallbackUrl: Patterns.Common.VersionUrl).GetAwaiter().GetResult())
versionUrl = Patterns.Common.VersionUrl;
else
// Assign the region and product independent version url.
versionUrl = commandLineResult.GetValueForOption(LaunchOptions.VersionUrl) ?? Patches.Common.GetVersionUrl(clientVersion.Build);
var cdnsUrl = commandLineResult.GetValueForOption(LaunchOptions.CdnsUrl) ?? Patches.Common.CdnsUrl;
if (!CheckUrl(cdnsUrl, fallbackUrl: Patterns.Common.CdnsUrl).GetAwaiter().GetResult())
cdnsUrl = Patterns.Common.CdnsUrl;
Console.ForegroundColor = ConsoleColor.Cyan;
Console.WriteLine("Game CDN connection info:");
Console.WriteLine($"Version file: {versionUrl}");
Console.WriteLine($"CDNs file: {cdnsUrl}");
Console.WriteLine();
Console.ResetColor();
var startupInfo = new StartupInfo();
var processInfo = new ProcessInformation();
@@ -204,17 +236,6 @@ static class Launcher
byte[] certBundleData = Convert.FromBase64String(Patches.Common.CertBundleData);
// Build the version URL from the game binary build.
var clientVersion = GetVersionValueFromClient(appPath);
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine();
Console.WriteLine($"Client Build {clientVersion}");
Console.WriteLine($"Client Path '{appPath}'");
Console.WriteLine();
Console.ResetColor();
byte[] versionPatch = Patches.Common.GetVersionUrl(clientVersion.Build);
// Refresh the client data before patching.
memory.RefreshMemoryData((int)gameAppData.Length);
@@ -232,6 +253,7 @@ static class Launcher
}, CancellationTokenSource.Token);
}
// Wait for all direct memory patch tasks to complete,
Task.WaitAll(new[]
{
@@ -243,8 +265,8 @@ static class Launcher
: memory.PatchMemory(Patterns.Common.CryptoRsaModulus, Patches.Common.RsaModulus, "GameCrypto RsaModulus"),
memory.PatchMemory(Patterns.Common.Portal, Patches.Common.Portal, "Login Portal"),
memory.PatchMemory(Patterns.Common.VersionUrl, versionPatch, "Version URL"),
memory.PatchMemory(Patterns.Common.CdnsUrl, Patches.Common.CdnsUrl, "CDNs URL"),
memory.PatchMemory(Patterns.Common.VersionUrl.ToPattern(), Encoding.UTF8.GetBytes(versionUrl), "Version URL"),
memory.PatchMemory(Patterns.Common.CdnsUrl.ToPattern(), Encoding.UTF8.GetBytes(cdnsUrl), "CDNs URL"),
memory.PatchMemory(Patterns.Windows.LauncherLogin, Patches.Windows.LauncherLogin, "Launcher Login Registry")
}, CancellationTokenSource.Token);

View File

@@ -8,6 +8,15 @@ namespace Arctium.WoW.Launcher.Misc;
static class Helpers
{
public static bool IsDebugBuild()
{
#if DEBUG
return true;
#else
return false;
#endif
}
public static (int Major, int Minor, int Revision, int Build) GetVersionValueFromClient(string fileName)
{
var fileVersionInfo = FileVersionInfo.GetVersionInfo(fileName);
@@ -90,4 +99,25 @@ static class Helpers
return (string.Empty, string.Empty, port);
}
}
public static async Task<bool> CheckUrl(string url, string fallbackUrl)
{
using var httpClient = new HttpClient { Timeout = TimeSpan.FromSeconds(5) };
try
{
var result = await httpClient.GetAsync(url);
if (!result.IsSuccessStatusCode)
Console.WriteLine($"{url} not reachable. Falling back to {fallbackUrl}");
return result.IsSuccessStatusCode;
}
catch (Exception)
{
Console.WriteLine($"{url} not reachable. Falling back to {fallbackUrl}");
return false;
}
}
}

View File

@@ -29,7 +29,7 @@ class ModLoader
var hookAddress = memory.Data.FindPattern(Patterns.Windows.CustomFileIdHook);
if (hookAddress == 0)
return false;
throw new InvalidDataException("CustomFileIdHook");
// Read original data from the hook function.
var originalBytes = memory.Read(memory.BaseAddress + hookAddress, 13);

View File

@@ -43,8 +43,8 @@ static class Common
public static byte[] CryptoEdPublicKey = { 0x02, 0x59, 0x6F, 0x0D, 0x0C, 0x06, 0x1A, 0x8B, 0x30, 0x74, 0x59, 0x88, 0xFD, 0x72, 0xC5, 0x9E,
0x29, 0xEC, 0x36, 0x7F, 0xB0, 0xF3, 0x41, 0xF2, 0x8E, 0x0F, 0x08, 0xD0, 0x37, 0xBA, 0xFC, 0x69 };
public static byte[] GetVersionUrl(int build) => Encoding.UTF8.GetBytes($"ngdp.arctium.io/%s/%s/{build}/versions");
public static byte[] CdnsUrl => Encoding.UTF8.GetBytes("http://ngdp.arctium.io/customs/wow/cdns");
public static string GetVersionUrl(int build, string region = "%s", string product = "%s") => $"http://ngdp.arctium.io/{region}/{product}/{build}/versions";
public static string CdnsUrl => "http://ngdp.arctium.io/customs/wow/cdns";
public static byte[] Portal = new byte[Patterns.Common.Portal.Length];
// Our own ca_bundle.txt.signed file.

View File

@@ -11,8 +11,7 @@ static class Common
public static short[] CryptoEdPublicKey = { 0x15, 0xD6, 0x18, 0xBD, 0x7D, 0xB5, 0x77, 0xBD };
public static short[] CertBundle = "{\"Created\":".ToPattern();
public static short[] VersionUrl = "%s.patch.battle.net:1119/%s/versions".ToPattern();
public static short[] CdnsUrl = "http://%s.patch.battle.net:1119/%s/cdns".ToPattern();
public static string VersionUrl = "http://%s.patch.battle.net:1119/%s/versions";
public static string CdnsUrl = "http://%s.patch.battle.net:1119/%s/cdns";
public static short[] Portal = ".actual.battle.net\0".ToPattern();
public static short[] CommandLineHelp = "World of Warcraft usage".ToPattern();
}

View File

@@ -3,6 +3,7 @@
using System.CommandLine.Parsing;
using Arctium.WoW.Launcher;
using static Arctium.WoW.Launcher.Misc.Helpers;
// "Arctium" should not be removed from the final binary name.