diff --git a/Dalamud.Bootstrap/BootstraperException.cs b/Dalamud.Bootstrap/BootstraperException.cs index 25984056c..7ae42f2bc 100644 --- a/Dalamud.Bootstrap/BootstraperException.cs +++ b/Dalamud.Bootstrap/BootstraperException.cs @@ -1,6 +1,4 @@ using System; -using System.Collections.Generic; -using System.Text; namespace Dalamud.Bootstrap { diff --git a/Dalamud.Bootstrap/GameProcess.cs b/Dalamud.Bootstrap/GameProcess.cs index fc23b5b9b..828a5683e 100644 --- a/Dalamud.Bootstrap/GameProcess.cs +++ b/Dalamud.Bootstrap/GameProcess.cs @@ -11,7 +11,15 @@ namespace Dalamud.Bootstrap { public sealed class GameProcess : IDisposable { - private const uint OpenProcessRights = 0; + private const uint OpenProcessRights = (uint) ( + PROCESS_ACCESS_RIGHTS.PROCESS_QUERY_INFORMATION | + PROCESS_ACCESS_RIGHTS.PROCESS_QUERY_LIMITED_INFORMATION | + PROCESS_ACCESS_RIGHTS.PROCESS_SUSPEND_RESUME | + PROCESS_ACCESS_RIGHTS.PROCESS_TERMINATE | + PROCESS_ACCESS_RIGHTS.PROCESS_VM_OPERATION | + PROCESS_ACCESS_RIGHTS.PROCESS_VM_READ | + PROCESS_ACCESS_RIGHTS.PROCESS_VM_WRITE + ); private IntPtr m_handle; @@ -41,7 +49,7 @@ namespace Dalamud.Bootstrap } } - private static IntPtr OpenProcessHandle(uint pid, uint access) + private static IntPtr OpenProcessHandleRaw(uint pid, uint access) { var handle = Kernel32.OpenProcess(access, false, pid); @@ -53,23 +61,38 @@ namespace Dalamud.Bootstrap return handle; } - public static GameProcess Open(uint pid) + private static IntPtr OpenProcessHandle(uint pid, uint access) { - var secHandle = OpenProcessHandle(pid, (uint)(PROCESS_ACCESS_RIGHTS.READ_CONTROL | PROCESS_ACCESS_RIGHTS.WRITE_DAC)); + var processDacHandle = OpenProcessHandleRaw(pid, (uint)(PROCESS_ACCESS_RIGHTS.READ_CONTROL | PROCESS_ACCESS_RIGHTS.WRITE_DAC)); try { - // We can get VM_WRITE this way - return RelaxProcessHandle(secHandle, OpenProcessRights, (_) => + return RelaxProcessHandle(processDacHandle, access, (_) => { - var handle = OpenProcessHandle(pid, OpenProcessRights); + var handle = OpenProcessHandleRaw(pid, access); - return new GameProcess(handle); + return handle; }); } finally { - Kernel32.CloseHandle(secHandle); + Kernel32.CloseHandle(processDacHandle); + } + } + + public static GameProcess Open(uint pid) + { + var handle = OpenProcessHandle(pid, OpenProcessRights); + + try + { + return new GameProcess(handle); + } + catch + { + // If something bad thing happens in .ctor we need to close the handle to avoid leak. + Kernel32.CloseHandle(handle); + throw; } } @@ -158,6 +181,38 @@ namespace Dalamud.Bootstrap } } + public static GameProcess Create(GameProcessCreationOptions options) + { + unsafe + { + SECURITY_ATTRIBUTES processAttr, threadAttr; + STARTUPINFOW startupInfo = default; + PROCESS_INFORMATION processInfo = default; + uint creationFlag; + + BuildCommandLine(options); + + if (!Kernel32.CreateProcessW( + options.ImagePath, + commandLine, + &processAttr, + &threadAttr, + false, + creationFlag, + /* env */, + currentDirectory, + &startupInfo, + &processInfo + )) + { + ProcessException.ThrowLastOsError(); + } + } + + + throw new NotImplementedException(); + } + /// /// Reads process memory. /// @@ -242,7 +297,13 @@ namespace Dalamud.Bootstrap { PROCESS_BASIC_INFORMATION info = default; - var status = Ntdll.NtQueryInformationProcess(m_handle, PROCESSINFOCLASS.ProcessBasicInformation, &info, sizeof(PROCESS_BASIC_INFORMATION), (IntPtr*)IntPtr.Zero); + var status = Ntdll.NtQueryInformationProcess( + m_handle, + PROCESSINFOCLASS.ProcessBasicInformation, + &info, + Marshal.SizeOf(), + (IntPtr*)IntPtr.Zero + ); if (!status.Success) { @@ -277,17 +338,17 @@ namespace Dalamud.Bootstrap /// public DateTime GetCreationTime() { - FILETIME creationTime, exitTime, kernelTime, userTime; - unsafe { + FILETIME creationTime, exitTime, kernelTime, userTime; + if (!Kernel32.GetProcessTimes(m_handle, &creationTime, &exitTime, &kernelTime, &userTime)) { ProcessException.ThrowLastOsError(); } - } - return creationTime.ToDateTime(); + return creationTime.ToDateTime(); + } } private string[] ParseCommandLineToArguments(ReadOnlySpan commandLine) diff --git a/Dalamud.Bootstrap/OS/Windows/Raw/Kernel32.cs b/Dalamud.Bootstrap/OS/Windows/Raw/Kernel32.cs index abd26dace..5d4cb3440 100644 --- a/Dalamud.Bootstrap/OS/Windows/Raw/Kernel32.cs +++ b/Dalamud.Bootstrap/OS/Windows/Raw/Kernel32.cs @@ -39,7 +39,18 @@ namespace Dalamud.Bootstrap.OS.Windows.Raw [DllImport(Name, CallingConvention = CallingConvention.Winapi, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Unicode)] [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool CreateProcessW(void* lpApplicationName, void* lpCommandLine, SECURITY_ATTRIBUTES* lpProcessAttributes, SECURITY_ATTRIBUTES* lpThreadAttributes, uint bInheritHandles, uint dwCreationFlags, void* lpEnvironment, void* lpCurrentDirectory, void* lpStartupInfo, void* lpProcessInformation); + public static extern bool CreateProcessW( + [MarshalAs(UnmanagedType.LPWStr)] string lpApplicationName, + [MarshalAs(UnmanagedType.LPWStr)] StringBuilder? lpCommandLine, + SECURITY_ATTRIBUTES* lpProcessAttributes, + SECURITY_ATTRIBUTES* lpThreadAttributes, + [MarshalAs(UnmanagedType.Bool)] bool bInheritHandles, + uint dwCreationFlags, + void* lpEnvironment, + [MarshalAs(UnmanagedType.LPWStr)] string lpCurrentDirectory, + STARTUPINFOW* lpStartupInfo, + PROCESS_INFORMATION* lpProcessInformation + ); [DllImport(Name, CallingConvention = CallingConvention.Winapi, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] diff --git a/Dalamud.Bootstrap/OS/Windows/Raw/Structures.cs b/Dalamud.Bootstrap/OS/Windows/Raw/Structures.cs index 16cb4ccfe..4badc0a60 100644 --- a/Dalamud.Bootstrap/OS/Windows/Raw/Structures.cs +++ b/Dalamud.Bootstrap/OS/Windows/Raw/Structures.cs @@ -115,8 +115,7 @@ namespace Dalamud.Bootstrap.OS.Windows.Raw public SECURITY_DESCRIPTOR* SecurityDescriptor; - [MarshalAs(UnmanagedType.Bool)] - public bool InheritHandle; + public uint InheritHandle; } [StructLayout(LayoutKind.Sequential)] @@ -176,4 +175,36 @@ namespace Dalamud.Bootstrap.OS.Windows.Raw public ushort AceCount; public ushort Sbz2; } + + [StructLayout(LayoutKind.Sequential)] + internal struct STARTUPINFOW + { + public uint cb; + public IntPtr lpReserved; + public IntPtr lpDesktop; + public IntPtr lpTitle; + public uint dwX; + public uint dwY; + public uint dwXSize; + public uint dwYSize; + public uint dwXCountChars; + public uint dwYCountChars; + public uint dwFillAttribute; + public uint dwFlags; + public ushort wShowWindow; + public ushort cbReserved2; + public IntPtr lpReserved2; + public IntPtr hStdInput; + public IntPtr hStdOutput; + public IntPtr hStdError; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct PROCESS_INFORMATION + { + public IntPtr hProcess; + public IntPtr hThread; + public uint dwProcessId; + public uint dwThreadId; + } }