Files
Daybreak/Daybreak.Injector/Program.cs
T
2026-06-30 17:09:16 +02:00

290 lines
8.9 KiB
C#

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] <params>");
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;
}