diff --git a/Dalamud.Bootstrap/Bootstrapper.cs b/Dalamud.Bootstrap/Bootstrapper.cs index 2f1788833..bf84f26b9 100644 --- a/Dalamud.Bootstrap/Bootstrapper.cs +++ b/Dalamud.Bootstrap/Bootstrapper.cs @@ -54,65 +54,36 @@ namespace Dalamud.Bootstrap // delegate Step 3 to 5 to Launch() maybe? // Acquire the process handle and read the command line - using var process = Process.Open(pid); + using var process = GameProcess.Open(pid); var exePath = process.GetImageFilePath(); var argument = ReadArgumentFromProcess(process); + var encryptedArgument = EncryptArgument(argument.ToString()); - var newTick = (uint)Environment.TickCount; - var newKey = newTick & 0xFFFF_0000; // only the high nibble is used - var newArgument = argument - .Remove("T") - .Add("T", $"{newTick}") - .ToString(); - var encryptedArgument = new EncryptedArgument(newArgument, newKey); - // TODO: launch new exe with the argument from encryptedArgument.ToString() // TODO: we also need to figure out where the exe is located // This is just for poc purpose. - System.Diagnostics.Process.Start(exePath, encryptedArgument.ToString()); - process.Terminate(); + //process.Terminate(); } - private static uint RecoverKey(Process gameProcess) + private static string EncryptArgument(string argument) { - var createdTime = gameProcess.GetCreationTime(); - - var currentDt = DateTime.Now; - var currentTick = Environment.TickCount; + // for testing purpose + return argument; - var delta = currentDt - createdTime; - var createdTick = (uint)currentTick - (uint)delta.TotalMilliseconds; + // + // var tick = (uint)Environment.TickCount; + // var key = tick & 0xFFFF_0000; // only the high nibble is used - // only the high nibble is used. - return createdTick & 0xFFFF_0000; + // var encryptedArgument = new EncryptedArgument(argument, key); + // return encryptedArgument.ToString(); } - - private static ArgumentBuilder ReadArgumentFromProcess(Process process) - { - var arguments = process.ReadArguments(); - - if (arguments.Length < 2) - { - throw new BootstrapException($"Process id {process.GetPid()} does not have any arguments to parse."); - } - - var argument = arguments[1]; - - if (EncryptedArgument.TryParse(argument, out var encryptedArgument)) - { - var key = RecoverKey(process); - argument = encryptedArgument.Decrypt(key); - } - - return ArgumentBuilder.Parse(argument); - } - + /// /// Injects Dalamud into the process. See remarks for process state prerequisites. /// diff --git a/Dalamud.Bootstrap/GameProcess.cs b/Dalamud.Bootstrap/GameProcess.cs new file mode 100644 index 000000000..5140c541f --- /dev/null +++ b/Dalamud.Bootstrap/GameProcess.cs @@ -0,0 +1,83 @@ +using System; +using Dalamud.Bootstrap.SqexArg; +using Dalamud.Bootstrap.Windows; + +namespace Dalamud.Bootstrap +{ + internal sealed class GameProcess : IDisposable + { + private Process m_process; + + public GameProcess(Process process) + { + m_process = process; + } + + public static GameProcess Open(uint pid) + { + const PROCESS_ACCESS_RIGHT access = PROCESS_ACCESS_RIGHT.PROCESS_VM_OPERATION + | PROCESS_ACCESS_RIGHT.PROCESS_VM_READ + // | PROCESS_ACCESS_RIGHT.PROCESS_VM_WRITE // we don't need it for now + | PROCESS_ACCESS_RIGHT.PROCESS_QUERY_LIMITED_INFORMATION + | PROCESS_ACCESS_RIGHT.PROCESS_QUERY_INFORMATION + | PROCESS_ACCESS_RIGHT.PROCESS_CREATE_THREAD + | PROCESS_ACCESS_RIGHT.PROCESS_TERMINATE; + + // TODO: unfuck VM_WRITE + + var process = Process.Open(pid, access); + + return new GameProcess(process); + } + + public void Dispose() + { + m_process?.Dispose(); + m_process = null!; + } + + /// + /// Recovers a key used in encrypting process arguments. + /// + /// A key recovered from the time when the process was created. + /// + /// This is possible because the key to encrypt arguments is just a high nibble value from GetTickCount() at the time when the process was created. + /// (Thanks Wintermute!) + /// + private uint GetArgumentEncryptionKey() + { + var createdTime = m_process.GetCreationTime(); + + // Get current tick + var currentDt = DateTime.Now; + var currentTick = Environment.TickCount; + + // We know that GetTickCount() is just a system uptime in milliseconds. + var delta = currentDt - createdTime; + var createdTick = (uint)currentTick - (uint)delta.TotalMilliseconds; + + // only the high nibble is used. + return createdTick & 0xFFFF_0000; + } + + public ArgumentBuilder ReadArguments() + { + var arguments = m_process.ReadArguments(); + + if (arguments.Length < 2) + { + throw new BootstrapException($"Process id {m_process.GetPid()} have no arguments to parse."); + } + + var argument = arguments[1]; + + if (EncryptedArgument.TryParse(argument, out var encryptedArgument)) + { + var key = GetArgumentEncryptionKey(); + argument = encryptedArgument.Decrypt(key); + } + + return ArgumentBuilder.Parse(argument); + } + } +} diff --git a/Dalamud.Bootstrap/Windows/Process.cs b/Dalamud.Bootstrap/Windows/Process.cs index fbfc3b20f..e7bfc3d21 100644 --- a/Dalamud.Bootstrap/Windows/Process.cs +++ b/Dalamud.Bootstrap/Windows/Process.cs @@ -8,7 +8,7 @@ using System.Text; namespace Dalamud.Bootstrap { /// - /// TODO + /// A class that provides a wrapper over operations on Win32 process. /// internal sealed partial class Process : IDisposable { @@ -29,16 +29,8 @@ namespace Dalamud.Bootstrap m_handle = null!; } - public static Process Open(uint pid) + public static Process Open(uint pid, PROCESS_ACCESS_RIGHT access) { - const PROCESS_ACCESS_RIGHT access = PROCESS_ACCESS_RIGHT.PROCESS_VM_OPERATION - | PROCESS_ACCESS_RIGHT.PROCESS_VM_READ - // | PROCESS_ACCESS_RIGHT.PROCESS_VM_WRITE // we don't need it for now - | PROCESS_ACCESS_RIGHT.PROCESS_QUERY_LIMITED_INFORMATION - | PROCESS_ACCESS_RIGHT.PROCESS_QUERY_INFORMATION - | PROCESS_ACCESS_RIGHT.PROCESS_CREATE_THREAD - | PROCESS_ACCESS_RIGHT.PROCESS_TERMINATE; - var handle = Win32.OpenProcess((uint) access, false, pid); if (handle.IsInvalid) diff --git a/Dalamud.Injector/Program.cs b/Dalamud.Injector/Program.cs index 41ed53458..25569445b 100644 --- a/Dalamud.Injector/Program.cs +++ b/Dalamud.Injector/Program.cs @@ -10,18 +10,6 @@ namespace Dalamud.Injector { private static void Main(string[] args) { - var pid = 12336u; - var binDirectory = ""; - var rootDirectory = ""; - - var boot = new Bootstrapper(new BootstrapperOptions - { - BinaryDirectory = "", - RootDirectory = "", - }); - - boot.Relaunch(pid); - Parser.Default.ParseArguments(args) .WithParsed(Inject) .WithParsed(Launch);