Skip to content

Commit

Permalink
Allow opening process/thread objects with specific access rights.
Browse files Browse the repository at this point in the history
Remove use of Win32 OpenProcess() in Vezel.Ruptura.Injection.

Part of #30.
  • Loading branch information
alexrp committed Jul 15, 2022
1 parent 180dfb8 commit ee171d3
Show file tree
Hide file tree
Showing 7 changed files with 57 additions and 21 deletions.
2 changes: 1 addition & 1 deletion src/hosting/InjectedProgramContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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.");
Expand Down
1 change: 0 additions & 1 deletion src/injection/NativeMethods.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ CreateProcessW
CreateRemoteThreadEx
IsWow64Process2
K32GetModuleBaseNameW
OpenProcess

WIN32_ERROR

Expand Down
18 changes: 5 additions & 13 deletions src/injection/TargetProcess.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
22 changes: 22 additions & 0 deletions src/system/ProcessAccess.cs
Original file line number Diff line number Diff line change
@@ -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,
}
9 changes: 6 additions & 3 deletions src/system/ProcessObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
17 changes: 17 additions & 0 deletions src/system/ThreadAccess.cs
Original file line number Diff line number Diff line change
@@ -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,
}
9 changes: 6 additions & 3 deletions src/system/ThreadObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down

0 comments on commit ee171d3

Please sign in to comment.