diff --git a/trunk/CHANGELOG.txt b/trunk/CHANGELOG.txt
index bdd9a1015..98dde5455 100644
--- a/trunk/CHANGELOG.txt
+++ b/trunk/CHANGELOG.txt
@@ -4,6 +4,7 @@ Process Hacker
* NEW/IMPROVED:
* KProcessHacker can now perform process memory reading/writing
by itself and does not require MmCopyVirtualMemory
+ * KProcessHacker can now bypass all handle-opening protections
* Better highlighting
* Shows function file and line numbers where available
* FIXED:
diff --git a/trunk/KProcessHacker/i386/kprocesshacker.sys b/trunk/KProcessHacker/i386/kprocesshacker.sys
index 18999754e..e946e436f 100644
Binary files a/trunk/KProcessHacker/i386/kprocesshacker.sys and b/trunk/KProcessHacker/i386/kprocesshacker.sys differ
diff --git a/trunk/KProcessHacker/include/kph.h b/trunk/KProcessHacker/include/kph.h
index 343b1aca1..57931a8a5 100644
--- a/trunk/KProcessHacker/include/kph.h
+++ b/trunk/KProcessHacker/include/kph.h
@@ -199,6 +199,12 @@ NTSTATUS KphSetContextThread(
KPROCESSOR_MODE AccessMode
);
+NTSTATUS KphSetHandleGrantedAccess(
+ PEPROCESS Process,
+ HANDLE Handle,
+ ACCESS_MASK GrantedAccess
+ );
+
NTSTATUS KphSuspendProcess(
HANDLE ProcessHandle
);
diff --git a/trunk/KProcessHacker/include/kprocesshacker.h b/trunk/KProcessHacker/include/kprocesshacker.h
index cadf47c9b..740285de0 100644
--- a/trunk/KProcessHacker/include/kprocesshacker.h
+++ b/trunk/KProcessHacker/include/kprocesshacker.h
@@ -68,7 +68,7 @@
#define KPH_GETTHREADID KPH_CTL_CODE(24)
#define KPH_TERMINATETHREAD KPH_CTL_CODE(25)
#define KPH_GETFEATURES KPH_CTL_CODE(26)
-#define KPH_RESERVED2 KPH_CTL_CODE(27)
+#define KPH_SETHANDLEGRANTEDACCESS KPH_CTL_CODE(27)
#define KPH_ASSIGNIMPERSONATIONTOKEN KPH_CTL_CODE(28)
#define GET_BIT(integer, bit) (((integer) >> (bit)) & 0x1)
diff --git a/trunk/KProcessHacker/include/ob.h b/trunk/KProcessHacker/include/ob.h
index 26730415f..a7353450b 100644
--- a/trunk/KProcessHacker/include/ob.h
+++ b/trunk/KProcessHacker/include/ob.h
@@ -29,6 +29,11 @@
#define OBJECT_TO_OBJECT_HEADER(o) \
CONTAINING_RECORD((o), OBJECT_HEADER, Body)
+#define OBJ_PROTECT_CLOSE 0x00000001L
+#define OBJ_INHERIT 0x00000002L
+#define OBJ_AUDIT_OBJECT_CLOSE 0x00000004L
+#define OBJ_HANDLE_ATTRIBUTES (OBJ_PROTECT_CLOSE | OBJ_INHERIT | OBJ_AUDIT_OBJECT_CLOSE)
+
/* FUNCTION DEFS */
NTSTATUS NTAPI ObOpenObjectByName(
diff --git a/trunk/KProcessHacker/include/version.h b/trunk/KProcessHacker/include/version.h
index b040f33e4..6d4053a9f 100644
--- a/trunk/KProcessHacker/include/version.h
+++ b/trunk/KProcessHacker/include/version.h
@@ -96,6 +96,7 @@ EXT ULONG OffEpObjectTable;
EXT ULONG OffEpProtectedProcessOff;
EXT ULONG OffEpProtectedProcessBit;
EXT ULONG OffEpRundownProtect;
+EXT ULONG OffOhBody;
EXT ULONG OffOtiGenericMapping;
/* Functions
diff --git a/trunk/KProcessHacker/kprocesshacker.c b/trunk/KProcessHacker/kprocesshacker.c
index 2810e71bf..4f1e8ceca 100644
--- a/trunk/KProcessHacker/kprocesshacker.c
+++ b/trunk/KProcessHacker/kprocesshacker.c
@@ -233,6 +233,8 @@ PCHAR GetIoControlName(ULONG ControlCode)
return "KphTerminateThread";
else if (ControlCode == KPH_GETFEATURES)
return "Get Features";
+ else if (ControlCode == KPH_SETHANDLEGRANTEDACCESS)
+ return "KphSetHandleGrantedAccess";
else if (ControlCode == KPH_ASSIGNIMPERSONATIONTOKEN)
return "KphAssignImpersonationToken";
else
@@ -1155,6 +1157,32 @@ NTSTATUS KphDispatchDeviceControl(PDEVICE_OBJECT DeviceObject, PIRP Irp)
}
break;
+ /* KphSetHandleGrantedAccess
+ *
+ * Sets the granted access for a handle.
+ */
+ case KPH_SETHANDLEGRANTEDACCESS:
+ {
+ struct
+ {
+ HANDLE Handle;
+ ACCESS_MASK GrantedAccess;
+ } *args = dataBuffer;
+
+ if (inLength < sizeof(*args))
+ {
+ status = STATUS_BUFFER_TOO_SMALL;
+ goto IoControlEnd;
+ }
+
+ status = KphSetHandleGrantedAccess(
+ PsGetCurrentProcess(),
+ args->Handle,
+ args->GrantedAccess
+ );
+ }
+ break;
+
/* KphAssignImpersonationToken
*
* Assigns an impersonation token to a thread.
diff --git a/trunk/KProcessHacker/ob.c b/trunk/KProcessHacker/ob.c
index 24b2e220d..82308341e 100644
--- a/trunk/KProcessHacker/ob.c
+++ b/trunk/KProcessHacker/ob.c
@@ -138,11 +138,58 @@ BOOLEAN KphEnumProcessHandleTable(
handleTable,
EnumHandleProcedure,
Context,
- Handle);
+ Handle
+ );
ObDereferenceProcessHandleTable(Process);
+
return result;
}
+/* KphpSetHandleGrantedAccessEnumCallback
+ *
+ * The callback for KphEnumProcessHandleTable, used by
+ * KphSetHandleGrantedAccess.
+ */
+BOOLEAN KphpSetHandleGrantedAccessEnumCallback(
+ PHANDLE_TABLE_ENTRY HandleTableEntry,
+ HANDLE Handle,
+ PSET_HANDLE_GRANTED_ACCESS_DATA Context
+ )
+{
+ if (Handle != Context->Handle)
+ return FALSE;
+
+ HandleTableEntry->GrantedAccess = Context->GrantedAccess;
+
+ return TRUE;
+}
+
+/* KphSetHandleGrantedAccess
+ *
+ * Sets the granted access of a handle.
+ */
+NTSTATUS KphSetHandleGrantedAccess(
+ PEPROCESS Process,
+ HANDLE Handle,
+ ACCESS_MASK GrantedAccess
+ )
+{
+ BOOLEAN result;
+ SET_HANDLE_GRANTED_ACCESS_DATA context;
+
+ context.Handle = Handle;
+ context.GrantedAccess = GrantedAccess;
+
+ result = KphEnumProcessHandleTable(
+ Process,
+ KphpSetHandleGrantedAccessEnumCallback,
+ &context,
+ NULL
+ );
+
+ return result ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
+}
+
/* ObDereferenceProcessHandleTable
*
* Allows the process to terminate.
diff --git a/trunk/KProcessHacker/version.c b/trunk/KProcessHacker/version.c
index 149461e12..073c73fa0 100644
--- a/trunk/KProcessHacker/version.c
+++ b/trunk/KProcessHacker/version.c
@@ -119,6 +119,7 @@ NTSTATUS KvInit()
OffEpProtectedProcessBit = 0;
OffEpRundownProtect = 0x80;
OffOtiGenericMapping = 0x60 + 0x8;
+ OffOhBody = 0x18;
/* We are scanning for PspTerminateProcess which has
the same signature as PsTerminateProcess because
@@ -181,6 +182,7 @@ NTSTATUS KvInit()
OffEpProtectedProcessOff = 0x224;
OffEpProtectedProcessBit = 0xb;
OffEpRundownProtect = 0x98;
+ OffOhBody = 0x18;
INIT_SCAN(
PsTerminateProcessScan,
@@ -231,6 +233,7 @@ NTSTATUS KvInit()
OffEpProtectedProcessBit = 0xb;
OffEpRundownProtect = 0xb0;
OffOtiGenericMapping = 0x28 + 0xc;
+ OffOhBody = 0x18;
INIT_SCAN(
PsTerminateProcessScan,
diff --git a/trunk/ProcessHacker.Native/KProcessHacker.cs b/trunk/ProcessHacker.Native/KProcessHacker.cs
index d3dce23ab..35618b036 100644
--- a/trunk/ProcessHacker.Native/KProcessHacker.cs
+++ b/trunk/ProcessHacker.Native/KProcessHacker.cs
@@ -75,7 +75,7 @@ namespace ProcessHacker.Native
KphGetThreadId,
KphTerminateThread,
GetFeatures,
- Reserved2,
+ KphSetHandleGrantedAccess,
KphAssignImpersonationToken
}
@@ -463,6 +463,16 @@ namespace ProcessHacker.Native
_fileHandle.IoControl(CtlCode(Control.KphSetContextThread), inData, 8, null, 0);
}
+ public void KphSetHandleGrantedAccess(IntPtr handle, int grantedAccess)
+ {
+ byte* inData = stackalloc byte[8];
+
+ *(int*)inData = handle.ToInt32();
+ *(int*)(inData + 4) = grantedAccess;
+
+ _fileHandle.IoControl(CtlCode(Control.KphSetHandleGrantedAccess), inData, 8, null, 0);
+ }
+
public void KphSuspendProcess(ProcessHandle processHandle)
{
int processHandleInt = processHandle;
diff --git a/trunk/ProcessHacker.Native/Objects/JobObjectHandle.cs b/trunk/ProcessHacker.Native/Objects/JobObjectHandle.cs
index 253e25ee5..fc9fa9a6c 100644
--- a/trunk/ProcessHacker.Native/Objects/JobObjectHandle.cs
+++ b/trunk/ProcessHacker.Native/Objects/JobObjectHandle.cs
@@ -78,7 +78,17 @@ namespace ProcessHacker.Native.Objects
/// The desired access to the job object.
public JobObjectHandle(ProcessHandle processHandle, JobObjectAccess access)
{
- this.Handle = new IntPtr(KProcessHacker.Instance.KphOpenProcessJob(processHandle, access));
+ try
+ {
+ this.Handle = new IntPtr(KProcessHacker.Instance.KphOpenProcessJob(processHandle, access));
+ }
+ catch (WindowsException)
+ {
+ // Use KPH to set the handle's granted access.
+ this.Handle = new IntPtr(KProcessHacker.Instance.KphOpenProcessJob(processHandle,
+ (JobObjectAccess)StandardRights.Synchronize));
+ KProcessHacker.Instance.KphSetHandleGrantedAccess(this.Handle, (int)access);
+ }
if (this.Handle == IntPtr.Zero)
Win32.ThrowLastError();
diff --git a/trunk/ProcessHacker.Native/Objects/ProcessHandle.cs b/trunk/ProcessHacker.Native/Objects/ProcessHandle.cs
index befd4ed0c..cbbbf8c9f 100644
--- a/trunk/ProcessHacker.Native/Objects/ProcessHandle.cs
+++ b/trunk/ProcessHacker.Native/Objects/ProcessHandle.cs
@@ -129,10 +129,28 @@ namespace ProcessHacker.Native.Objects
/// The desired access to the process.
public ProcessHandle(int pid, ProcessAccess access)
{
+ // If we have KPH, use it.
if (KProcessHacker.Instance != null)
- this.Handle = new IntPtr(KProcessHacker.Instance.KphOpenProcess(pid, access));
+ {
+ try
+ {
+ this.Handle = new IntPtr(KProcessHacker.Instance.KphOpenProcess(pid, access));
+ }
+ catch (WindowsException)
+ {
+ // This would only happen if the process is DRM-protected or if
+ // some part of ObReferenceObjectByHandle is hooked. We can
+ // open the process with SYNCHRONIZE access and set the granted access
+ // using KPH.
+ this.Handle = new IntPtr(KProcessHacker.Instance.KphOpenProcess(pid,
+ (ProcessAccess)StandardRights.Synchronize));
+ KProcessHacker.Instance.KphSetHandleGrantedAccess(this.Handle, (int)access);
+ }
+ }
else
+ {
this.Handle = Win32.OpenProcess(access, false, pid);
+ }
if (this.Handle == IntPtr.Zero)
Win32.ThrowLastError();
diff --git a/trunk/ProcessHacker.Native/Objects/ThreadHandle.cs b/trunk/ProcessHacker.Native/Objects/ThreadHandle.cs
index 53f316c2a..9aae8d135 100644
--- a/trunk/ProcessHacker.Native/Objects/ThreadHandle.cs
+++ b/trunk/ProcessHacker.Native/Objects/ThreadHandle.cs
@@ -73,9 +73,23 @@ namespace ProcessHacker.Native.Objects
public ThreadHandle(int tid, ThreadAccess access)
{
if (KProcessHacker.Instance != null)
- this.Handle = new IntPtr(KProcessHacker.Instance.KphOpenThread((int)tid, access));
+ {
+ try
+ {
+ this.Handle = new IntPtr(KProcessHacker.Instance.KphOpenThread(tid, access));
+ }
+ catch (WindowsException)
+ {
+ // Open the thread with minimum access (SYNCHRONIZE) and set the granted access.
+ this.Handle = new IntPtr(KProcessHacker.Instance.KphOpenThread(tid,
+ (ThreadAccess)StandardRights.Synchronize));
+ KProcessHacker.Instance.KphSetHandleGrantedAccess(this.Handle, (int)access);
+ }
+ }
else
+ {
this.Handle = Win32.OpenThread(access, false, tid);
+ }
if (this.Handle == IntPtr.Zero)
Win32.ThrowLastError();