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();