using Daybreak.Injector; using Daybreak.Shared.Models; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; static void PrintUsage() { Console.WriteLine("======================================================"); Console.WriteLine("Usage: Daybreak.Injector [mode] "); Console.WriteLine("Modes: "); Console.WriteLine("- winapi"); Console.WriteLine("- stub"); Console.WriteLine("- launch"); Console.WriteLine("- resume"); Console.WriteLine("- resolve"); Console.WriteLine("Examples:"); Console.WriteLine("1) Daybreak.Injector winapi 1234 C:\\path\\to\\dll.dll"); Console.WriteLine("2) Daybreak.Injector stub 1234 entryPoint C:\\path\\to\\dll.dll"); Console.WriteLine("3) Daybreak.Injector launch true C:\\path\\to\\dll.dll arg1 arg2 arg3"); Console.WriteLine("4) Daybreak.Injector resume 1234"); Console.WriteLine("5) Daybreak.Injector resolve \"Z:\\path\\to\\Gw.exe\""); Console.WriteLine("======================================================"); } static bool TryParseInjectWinApiArgs( string[] args, [NotNullWhen(true)] out Process? process, [NotNullWhen(true)] out string? dllPath, out InjectorResponses.InjectResult exitCode) { process = default; dllPath = default; if (!int.TryParse(args[1], out var processId)) { PrintUsage(); exitCode = InjectorResponses.InjectResult.InvalidProcess; return false; } if (args.Length < 3) { PrintUsage(); exitCode = InjectorResponses.InjectResult.InvalidArgs; return false; } dllPath = Path.GetFullPath(args[2]); process = Process.GetProcessById(processId); if (process is null) { Console.WriteLine($"Process {processId} could not be found"); exitCode = InjectorResponses.InjectResult.InvalidProcess; return false; } if (!File.Exists(dllPath)) { Console.WriteLine($"DLL path {dllPath} could not be found"); exitCode = InjectorResponses.InjectResult.InvalidDllPath; return false; } exitCode = 0; return true; } static bool TryParseInjectStubArgs( string[] args, [NotNullWhen(true)] out Process? process, [NotNullWhen(true)] out string? dllPath, [NotNullWhen(true)] out string? entryPoint, out InjectorResponses.InjectResult exitCode) { process = default; dllPath = default; entryPoint = default; if (!int.TryParse(args[1], out var processId)) { PrintUsage(); exitCode = InjectorResponses.InjectResult.InvalidProcess; return false; } if (args.Length < 4) { PrintUsage(); exitCode = InjectorResponses.InjectResult.InvalidArgs; return false; } entryPoint = args[2]; dllPath = Path.GetFullPath(args[3]); process = Process.GetProcessById(processId); if (process is null) { Console.WriteLine($"Process {processId} could not be found"); exitCode = InjectorResponses.InjectResult.InvalidProcess; return false; } if (!File.Exists(dllPath)) { Console.WriteLine($"DLL path {dllPath} could not be found"); exitCode = InjectorResponses.InjectResult.InvalidDllPath; return false; } exitCode = 0; return true; } static bool TryParseLaunchArgs( string[] args, [NotNullWhen(true)] out string? gwPath, [NotNullWhen(true)] out string? gwArgs, [NotNullWhen(true)] out bool? elevated, out InjectorResponses.LaunchResult exitCode) { gwPath = default; gwArgs = default; elevated = default; if (args.Length < 3) { PrintUsage(); exitCode = InjectorResponses.LaunchResult.InvalidArgs; return false; } gwPath = Path.GetFullPath(args[2]); if (!bool.TryParse(args[1], out var parsedElevated)) { PrintUsage(); exitCode = InjectorResponses.LaunchResult.InvalidElevated; return false; } elevated = parsedElevated; gwArgs = args.Length > 3 ? string.Join(" ", args.Skip(3)) : string.Empty; if (!File.Exists(gwPath)) { Console.WriteLine($"Guild Wars path {gwPath} could not be found"); exitCode = InjectorResponses.LaunchResult.InvalidPath; return false; } exitCode = 0; return true; } static bool TryParseThreadResumeArgs( string[] args, [NotNullWhen(true)] out IntPtr? threadHwnd, out InjectorResponses.ResumeResult exitCode) { threadHwnd = default; if (args.Length < 2) { PrintUsage(); exitCode = InjectorResponses.ResumeResult.InvalidArgs; return false; } if (!IntPtr.TryParse(args[1], out var threadInt)) { PrintUsage(); exitCode = InjectorResponses.ResumeResult.InvalidThreadHandle; return false; } threadHwnd = threadInt; exitCode = InjectorResponses.ResumeResult.Success; return true; } static bool TryParseResolveArgs( string[] args, [NotNullWhen(true)] out string? executablePath, out InjectorResponses.ResolveResult exitCode) { executablePath = default; if (args.Length < 2 || string.IsNullOrWhiteSpace(args[1])) { PrintUsage(); exitCode = InjectorResponses.ResolveResult.InvalidArgs; return false; } executablePath = args[1]; exitCode = InjectorResponses.ResolveResult.Success; return true; } if (args.Length < 1) { PrintUsage(); return (int)InjectorResponses.GenericResults.InvalidArgs; } var mode = args[0]; switch (mode) { case "winapi": { if (!TryParseInjectWinApiArgs(args, out var process, out var dllPath, out var parseResult)) { Console.WriteLine($"ExitCode: {(int)parseResult}"); return (int)parseResult; } Console.WriteLine($"Starting WinAPI injection. Process {process.Id}. DllPath: {dllPath}"); var result = (int)ProcessInjector.InjectWithApi(process, dllPath); Console.WriteLine($"ExitCode: {result}"); return result; } case "stub": { if (!TryParseInjectStubArgs(args, out var process, out var dllPath, out var entryPoint, out var parseResult)) { Console.WriteLine($"ExitCode: {(int)parseResult}"); return (int)parseResult; } Console.WriteLine($"Starting stub injection. Process {process.Id}. EntryPoint {entryPoint}. DllPath: {dllPath}"); var result = StubInjector.Inject(process, dllPath, entryPoint, out var exitCode); if (result is not InjectorResponses.InjectResult.Success) { Console.WriteLine($"ExitCode: {(int)result}"); return (int)result; } Console.WriteLine($"Stub returned {exitCode}"); Console.WriteLine($"ExitCode: {exitCode}"); return exitCode; } case "launch": { if (!TryParseLaunchArgs(args, out var gwPath, out var gwArgs, out var elevated, out var parseResult)) { Console.WriteLine($"ExitCode: {(int)parseResult}"); return (int)parseResult; } Console.WriteLine($"Launching Guild Wars. Path {gwPath}. Elevated {elevated}. Args {gwArgs}"); var result = ProcessLauncher.LaunchGuildWars(gwPath, gwArgs, elevated.Value, out var threadHandle, out var processId); Console.WriteLine($"ThreadHandle: {threadHandle}"); Console.WriteLine($"ProcessId: {processId}"); Console.WriteLine($"ExitCode: {(int)result}"); return (int)result; } case "resume": { if (!TryParseThreadResumeArgs(args, out var threadHwnd, out var parseResult)) { Console.WriteLine($"ExitCode: {(int)parseResult}"); return (int)parseResult; } Console.WriteLine($"Resuming thread {threadHwnd.Value}"); var result = (int) ThreadResumer.Resume(threadHwnd.Value); Console.WriteLine($"ExitCode: {result}"); return result; } case "resolve": { if (!TryParseResolveArgs(args, out var executablePath, out var parseResult)) { Console.WriteLine($"ExitCode: {(int)parseResult}"); return (int)parseResult; } Console.WriteLine($"Resolving Wine PID for {executablePath}"); var result = ProcessResolver.Resolve(executablePath, out var processId); if (result is InjectorResponses.ResolveResult.Success) { Console.WriteLine($"ProcessId: {processId}"); } Console.WriteLine($"ExitCode: {(int)result}"); return (int)result; } default: PrintUsage(); Console.WriteLine($"ExitCode: {(int)InjectorResponses.GenericResults.InvalidMode}"); return (int)InjectorResponses.GenericResults.InvalidMode; }