diff --git a/src/hosting/InjectedProgramContext.cs b/src/hosting/InjectedProgramContext.cs index 31cec6d..085911b 100644 --- a/src/hosting/InjectedProgramContext.cs +++ b/src/hosting/InjectedProgramContext.cs @@ -63,7 +63,7 @@ public void WakeUp() { _ = _mainThreadId != 0 ? true : throw new InvalidOperationException("This process was not created suspended."); - using var thread = ThreadObject.OpenId((int)_mainThreadId); + using var thread = ThreadObject.OpenId((int)_mainThreadId, null); if (thread.Resume() == 0) throw new InvalidOperationException("The process appears to have been resumed already."); diff --git a/src/injection/NativeMethods.txt b/src/injection/NativeMethods.txt index 8d62f8e..7dbbb79 100644 --- a/src/injection/NativeMethods.txt +++ b/src/injection/NativeMethods.txt @@ -2,7 +2,6 @@ CreateProcessW CreateRemoteThreadEx IsWow64Process2 K32GetModuleBaseNameW -OpenProcess WIN32_ERROR diff --git a/src/injection/TargetProcess.cs b/src/injection/TargetProcess.cs index 1cf8269..637b063 100644 --- a/src/injection/TargetProcess.cs +++ b/src/injection/TargetProcess.cs @@ -109,19 +109,11 @@ public static TargetProcess Open(int id) // I am not sure why we can get away with not using PROCESS_CREATE_THREAD (CreateRemoteThread) and // PROCESS_QUERY_LIMITED_INFORMATION (IsWow64Process2), but apparently we can. The below rights are the absolute // minimum needed for successful injection (tested on Windows 11 22H2). - using var handle = Win32.OpenProcess_SafeHandle( - PROCESS_ACCESS_RIGHTS.PROCESS_VM_OPERATION | - PROCESS_ACCESS_RIGHTS.PROCESS_VM_READ | - PROCESS_ACCESS_RIGHTS.PROCESS_VM_WRITE, - false, - (uint)id); - - var obj = ProcessObject.OpenHandle(handle.DangerousGetHandle()); - - // Transfer handle ownership to the process object. - handle.SetHandleAsInvalid(); - - return new(id, obj, null); + return new( + id, + ProcessObject.OpenId( + id, ProcessAccess.OperateMemory | ProcessAccess.ReadMemory | ProcessAccess.WriteMemory), + null); } public void Dispose() diff --git a/src/system/ProcessAccess.cs b/src/system/ProcessAccess.cs new file mode 100644 index 0000000..bad3ae0 --- /dev/null +++ b/src/system/ProcessAccess.cs @@ -0,0 +1,22 @@ +using Windows.Win32.System.Threading; + +namespace Vezel.Ruptura.System; + +[Flags] +public enum ProcessAccess : uint +{ + Terminate = PROCESS_ACCESS_RIGHTS.PROCESS_TERMINATE, + CreateThread = PROCESS_ACCESS_RIGHTS.PROCESS_CREATE_THREAD, + OperateMemory = PROCESS_ACCESS_RIGHTS.PROCESS_VM_OPERATION, + ReadMemory = PROCESS_ACCESS_RIGHTS.PROCESS_VM_READ, + WriteMemory = PROCESS_ACCESS_RIGHTS.PROCESS_VM_WRITE, + DuplicateHandle = PROCESS_ACCESS_RIGHTS.PROCESS_DUP_HANDLE, + CreateProcess = PROCESS_ACCESS_RIGHTS.PROCESS_CREATE_PROCESS, + SetQuota = PROCESS_ACCESS_RIGHTS.PROCESS_SET_QUOTA, + SetInfo = PROCESS_ACCESS_RIGHTS.PROCESS_SET_INFORMATION, + GetInfo = PROCESS_ACCESS_RIGHTS.PROCESS_QUERY_INFORMATION, + SuspendResume = PROCESS_ACCESS_RIGHTS.PROCESS_SUSPEND_RESUME, + GetLimitedInfo = PROCESS_ACCESS_RIGHTS.PROCESS_QUERY_LIMITED_INFORMATION, + SetLimitedInfo = PROCESS_ACCESS_RIGHTS.PROCESS_SET_LIMITED_INFORMATION, + Synchronize = PROCESS_ACCESS_RIGHTS.PROCESS_SYNCHRONIZE, +} diff --git a/src/system/ProcessObject.cs b/src/system/ProcessObject.cs index 0b54cd0..359fe4d 100644 --- a/src/system/ProcessObject.cs +++ b/src/system/ProcessObject.cs @@ -46,16 +46,19 @@ public static ProcessObject OpenHandle(nint handle) return Win32.GetHandleInformation((HANDLE)handle, &unused) ? new(handle) : throw new Win32Exception(); } - public static ProcessObject OpenId(int id) + public static ProcessObject OpenId(int id, ProcessAccess? access) { - return Win32.OpenProcess(PROCESS_ACCESS_RIGHTS.PROCESS_ALL_ACCESS, false, (uint)id) is { IsNull: false } handle + return Win32.OpenProcess( + access is ProcessAccess acc ? (PROCESS_ACCESS_RIGHTS)acc : PROCESS_ACCESS_RIGHTS.PROCESS_ALL_ACCESS, + false, + (uint)id) is { IsNull: false } handle ? new(handle) : throw new Win32Exception(); } public static ProcessObject OpenCurrent() { - return OpenId(CurrentId); + return OpenId(CurrentId, null); } public static void FlushWriteBuffers() diff --git a/src/system/ThreadAccess.cs b/src/system/ThreadAccess.cs new file mode 100644 index 0000000..a14585c --- /dev/null +++ b/src/system/ThreadAccess.cs @@ -0,0 +1,17 @@ +using Windows.Win32.System.Threading; + +namespace Vezel.Ruptura.System; + +[Flags] +public enum ThreadAccess : uint +{ + Terminate = THREAD_ACCESS_RIGHTS.THREAD_TERMINATE, + SuspendResume = THREAD_ACCESS_RIGHTS.THREAD_SUSPEND_RESUME, + GetContext = THREAD_ACCESS_RIGHTS.THREAD_GET_CONTEXT, + SetContext = THREAD_ACCESS_RIGHTS.THREAD_SET_CONTEXT, + SetInfo = THREAD_ACCESS_RIGHTS.THREAD_SET_INFORMATION, + GetInfo = THREAD_ACCESS_RIGHTS.THREAD_QUERY_INFORMATION, + SetLimitedInfo = THREAD_ACCESS_RIGHTS.THREAD_SET_LIMITED_INFORMATION, + GetLimitedInfo = THREAD_ACCESS_RIGHTS.THREAD_QUERY_LIMITED_INFORMATION, + Synchronize = THREAD_ACCESS_RIGHTS.THREAD_SYNCHRONIZE, +} diff --git a/src/system/ThreadObject.cs b/src/system/ThreadObject.cs index b8b642e..7e36117 100644 --- a/src/system/ThreadObject.cs +++ b/src/system/ThreadObject.cs @@ -73,16 +73,19 @@ public static ThreadObject OpenHandle(nint handle) return Win32.GetHandleInformation((HANDLE)handle, &unused) ? new(handle) : throw new Win32Exception(); } - public static ThreadObject OpenId(int id) + public static ThreadObject OpenId(int id, ThreadAccess? access) { - return Win32.OpenThread(THREAD_ACCESS_RIGHTS.THREAD_ALL_ACCESS, false, (uint)id) is { IsNull: false } handle + return Win32.OpenThread( + access is ThreadAccess acc ? (THREAD_ACCESS_RIGHTS)acc : THREAD_ACCESS_RIGHTS.THREAD_ALL_ACCESS, + false, + (uint)id) is { IsNull: false } handle ? new(handle) : throw new Win32Exception(); } public static ThreadObject OpenCurrent() { - return OpenId(CurrentId); + return OpenId(CurrentId, null); } public static void GetStackBounds(out void* low, out void* high)