From 6eaaa3deb889cce55bb45230d1739b03fc55085a Mon Sep 17 00:00:00 2001 From: wj32 Date: Sat, 9 May 2009 11:57:47 +0000 Subject: [PATCH] * added KphSetHandleGrantedAccess; KPH can finally bypass all protected process restrictions git-svn-id: svn://svn.code.sf.net/p/processhacker/code@1254 21ef857c-d57f-4fe0-8362-d861dc6d29cd --- trunk/CHANGELOG.txt | 1 + trunk/KProcessHacker/i386/kprocesshacker.sys | Bin 17920 -> 17920 bytes trunk/KProcessHacker/include/kph.h | 6 +++ trunk/KProcessHacker/include/kprocesshacker.h | 2 +- trunk/KProcessHacker/include/ob.h | 5 ++ trunk/KProcessHacker/include/version.h | 1 + trunk/KProcessHacker/kprocesshacker.c | 28 ++++++++++ trunk/KProcessHacker/ob.c | 49 +++++++++++++++++- trunk/KProcessHacker/version.c | 3 ++ trunk/ProcessHacker.Native/KProcessHacker.cs | 12 ++++- .../Objects/JobObjectHandle.cs | 12 ++++- .../Objects/ProcessHandle.cs | 20 ++++++- .../Objects/ThreadHandle.cs | 16 +++++- 13 files changed, 149 insertions(+), 6 deletions(-) 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 18999754e0d1e84d7d14c1f4d8608eb33a75f1c3..e946e436f1dd783c618b07495f98bcd8f1f532c9 100644 GIT binary patch delta 5011 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 bv#>?jCcG@{6k3JXgguCJMMwUuH&y=&J6r=@ delta 4706 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 QR!k;cJ##9ar(nhX1J>kX{Qv*} 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();