diff --git a/trunk/CHANGELOG.txt b/trunk/CHANGELOG.txt index 4b814ea84..761fcc1b3 100644 --- a/trunk/CHANGELOG.txt +++ b/trunk/CHANGELOG.txt @@ -4,6 +4,7 @@ Process Hacker * NEW/IMPROVED: * POSIX process support, including command lines and highlighting + * Hidden processes scanner can now detect FUTo * Ability to set DEP status of processes in other sessions * Automatic tree text coloring, allowing for dark highlighting colors diff --git a/trunk/KProcessHacker/hook.c b/trunk/KProcessHacker/hook.c index d34e7a4e2..e2cd60cf3 100644 --- a/trunk/KProcessHacker/hook.c +++ b/trunk/KProcessHacker/hook.c @@ -30,13 +30,13 @@ typedef struct _MAPPED_MDL } MAPPED_MDL, *PMAPPED_MDL; NTSTATUS KphpCreateMappedMdl( - PVOID Address, - ULONG Length, - PMAPPED_MDL MappedMdl + __in PVOID Address, + __in ULONG Length, + __out PMAPPED_MDL MappedMdl ); VOID KphpFreeMappedMdl( - PMAPPED_MDL MappedMdl + __in PMAPPED_MDL MappedMdl ); static KPH_PROCESSOR_LOCK HookProcessorLock; @@ -57,9 +57,9 @@ NTSTATUS KphHookInit() * Initializes a hook structure. */ VOID KphInitializeHook( - PKPH_HOOK Hook, - PVOID Function, - PVOID Target + __out PKPH_HOOK Hook, + __in PVOID Function, + __in PVOID Target ) { memset(Hook, 0, sizeof(KPH_HOOK)); @@ -76,7 +76,7 @@ VOID KphInitializeHook( * IRQL: <= APC_LEVEL */ NTSTATUS KphHook( - PKPH_HOOK Hook + __inout PKPH_HOOK Hook ) { NTSTATUS status = STATUS_SUCCESS; @@ -131,7 +131,7 @@ NTSTATUS KphHook( * IRQL: <= APC_LEVEL */ NTSTATUS KphUnhook( - PKPH_HOOK Hook + __inout PKPH_HOOK Hook ) { NTSTATUS status = STATUS_SUCCESS; @@ -176,13 +176,13 @@ NTSTATUS KphUnhook( * AccessMode: If this argument is unavailable, specify KernelMode. */ NTSTATUS NTAPI KphObOpenCall( - PKPH_OB_OPEN_HOOK ObOpenHook, - OB_OPEN_REASON OpenReason, - KPROCESSOR_MODE AccessMode, - PEPROCESS Process, - PVOID Object, - ACCESS_MASK GrantedAccess, - ULONG HandleCount + __in PKPH_OB_OPEN_HOOK ObOpenHook, + __in OB_OPEN_REASON OpenReason, + __in KPROCESSOR_MODE AccessMode, + __in PEPROCESS Process, + __in PVOID Object, + __in ACCESS_MASK GrantedAccess, + __in ULONG HandleCount ) { /* If there wasn't any original open procedure, exit. */ @@ -220,10 +220,10 @@ NTSTATUS NTAPI KphObOpenCall( } VOID KphInitializeObOpenHook( - PKPH_OB_OPEN_HOOK ObOpenHook, - POBJECT_TYPE ObjectType, - PVOID Target51, - PVOID Target60 + __inout PKPH_OB_OPEN_HOOK ObOpenHook, + __in POBJECT_TYPE ObjectType, + __in PVOID Target51, + __in PVOID Target60 ) { memset(ObOpenHook, 0, sizeof(KPH_OB_OPEN_HOOK)); @@ -240,7 +240,7 @@ VOID KphInitializeObOpenHook( * IRQL: <= APC_LEVEL */ NTSTATUS KphObOpenHook( - PKPH_OB_OPEN_HOOK ObOpenHook + __inout PKPH_OB_OPEN_HOOK ObOpenHook ) { NTSTATUS status = STATUS_SUCCESS; @@ -310,7 +310,7 @@ NTSTATUS KphObOpenHook( * IRQL: <= APC_LEVEL */ NTSTATUS KphObOpenUnhook( - PKPH_OB_OPEN_HOOK ObOpenHook + __inout PKPH_OB_OPEN_HOOK ObOpenHook ) { NTSTATUS status = STATUS_SUCCESS; @@ -359,9 +359,9 @@ NTSTATUS KphObOpenUnhook( * IRQL: Any */ NTSTATUS KphpCreateMappedMdl( - PVOID Address, - ULONG Length, - PMAPPED_MDL MappedMdl + __in PVOID Address, + __in ULONG Length, + __out PMAPPED_MDL MappedMdl ) { PMDL mdl; @@ -403,7 +403,7 @@ NTSTATUS KphpCreateMappedMdl( * IRQL: Any */ VOID KphpFreeMappedMdl( - PMAPPED_MDL MappedMdl + __in PMAPPED_MDL MappedMdl ) { if (MappedMdl->Mdl != NULL) diff --git a/trunk/KProcessHacker/i386/kprocesshacker.sys b/trunk/KProcessHacker/i386/kprocesshacker.sys index 0ba031e8d..cb52e38d4 100644 Binary files a/trunk/KProcessHacker/i386/kprocesshacker.sys and b/trunk/KProcessHacker/i386/kprocesshacker.sys differ diff --git a/trunk/KProcessHacker/include/ex.h b/trunk/KProcessHacker/include/ex.h index 8c130abb7..80c5b3307 100644 --- a/trunk/KProcessHacker/include/ex.h +++ b/trunk/KProcessHacker/include/ex.h @@ -35,10 +35,10 @@ typedef BOOLEAN (NTAPI *PEX_ENUM_HANDLE_CALLBACK)( ); BOOLEAN NTAPI ExEnumHandleTable( - struct _HANDLE_TABLE *HandleTable, - PEX_ENUM_HANDLE_CALLBACK EnumHandleProcedure, - PVOID Context, - PHANDLE Handle + __in struct _HANDLE_TABLE *HandleTable, + __in PEX_ENUM_HANDLE_CALLBACK EnumHandleProcedure, + __inout PVOID Context, + __out_opt PHANDLE Handle ); typedef NTSTATUS (NTAPI *_ExpGetProcessInformation)( diff --git a/trunk/KProcessHacker/include/hook.h b/trunk/KProcessHacker/include/hook.h index 25e666cc3..ecc4bc499 100644 --- a/trunk/KProcessHacker/include/hook.h +++ b/trunk/KProcessHacker/include/hook.h @@ -67,42 +67,42 @@ typedef struct _KPH_OB_OPEN_HOOK NTSTATUS KphHookInit(); VOID KphInitializeHook( - PKPH_HOOK Hook, - PVOID Function, - PVOID Target + __out PKPH_HOOK Hook, + __in PVOID Function, + __in PVOID Target ); NTSTATUS KphHook( - PKPH_HOOK Hook + __inout PKPH_HOOK Hook ); NTSTATUS KphUnhook( - PKPH_HOOK Hook + __inout PKPH_HOOK Hook ); NTSTATUS NTAPI KphObOpenCall( - PKPH_OB_OPEN_HOOK ObOpenHook, - OB_OPEN_REASON OpenReason, - KPROCESSOR_MODE AccessMode, - PEPROCESS Process, - PVOID Object, - ACCESS_MASK GrantedAccess, - ULONG HandleCount + __in PKPH_OB_OPEN_HOOK ObOpenHook, + __in OB_OPEN_REASON OpenReason, + __in KPROCESSOR_MODE AccessMode, + __in PEPROCESS Process, + __in PVOID Object, + __in ACCESS_MASK GrantedAccess, + __in ULONG HandleCount ); VOID KphInitializeObOpenHook( - PKPH_OB_OPEN_HOOK ObOpenHook, - POBJECT_TYPE ObjectType, - PVOID Target51, - PVOID Target60 + __inout PKPH_OB_OPEN_HOOK ObOpenHook, + __in POBJECT_TYPE ObjectType, + __in PVOID Target51, + __in PVOID Target60 ); NTSTATUS KphObOpenHook( - PKPH_OB_OPEN_HOOK ObOpenHook + __inout PKPH_OB_OPEN_HOOK ObOpenHook ); NTSTATUS KphObOpenUnhook( - PKPH_OB_OPEN_HOOK ObOpenHook + __inout PKPH_OB_OPEN_HOOK ObOpenHook ); #endif diff --git a/trunk/KProcessHacker/include/kph.h b/trunk/KProcessHacker/include/kph.h index 88152152a..1d2c07004 100644 --- a/trunk/KProcessHacker/include/kph.h +++ b/trunk/KProcessHacker/include/kph.h @@ -64,247 +64,262 @@ PVOID GetSystemRoutineAddress( WCHAR *Name ); -NTSTATUS OpenProcess( - PHANDLE ProcessHandle, - ULONG DesiredAccess, - HANDLE ProcessId - ); - VOID KphAttachProcess( - PEPROCESS Process, - PKPH_ATTACH_STATE AttachState + __in PEPROCESS Process, + __out PKPH_ATTACH_STATE AttachState ); NTSTATUS KphAttachProcessHandle( - HANDLE ProcessHandle, - PKPH_ATTACH_STATE AttachState + __in HANDLE ProcessHandle, + __out PKPH_ATTACH_STATE AttachState ); NTSTATUS KphAttachProcessId( - HANDLE ProcessId, - PKPH_ATTACH_STATE AttachState + __in HANDLE ProcessId, + __out PKPH_ATTACH_STATE AttachState ); VOID KphDetachProcess( - PKPH_ATTACH_STATE AttachState + __in PKPH_ATTACH_STATE AttachState + ); + +NTSTATUS OpenProcess( + __out PHANDLE ProcessHandle, + __in ACCESS_MASK DesiredAccess, + __in HANDLE ProcessId ); NTSTATUS SetProcessToken( - HANDLE sourcePid, - HANDLE targetPid + __in HANDLE sourcePid, + __in HANDLE targetPid ); /* KProcessHacker */ BOOLEAN KphAcquireProcessRundownProtection( - PEPROCESS Process + __in PEPROCESS Process ); NTSTATUS KphAssignImpersonationToken( - HANDLE ThreadHandle, - HANDLE TokenHandle + __in HANDLE ThreadHandle, + __in HANDLE TokenHandle ); NTSTATUS KphDuplicateObject( - HANDLE SourceProcessHandle, - HANDLE SourceHandle, - HANDLE TargetProcessHandle, - PHANDLE TargetHandle, - ACCESS_MASK DesiredAccess, - ULONG HandleAttributes, - ULONG Options, - KPROCESSOR_MODE AccessMode + __in HANDLE SourceProcessHandle, + __in HANDLE SourceHandle, + __in_opt HANDLE TargetProcessHandle, + __out_opt PHANDLE TargetHandle, + __in ACCESS_MASK DesiredAccess, + __in ULONG HandleAttributes, + __in ULONG Options, + __in KPROCESSOR_MODE AccessMode ); BOOLEAN KphEnumProcessHandleTable( - PEPROCESS Process, - PEX_ENUM_HANDLE_CALLBACK EnumHandleProcedure, - PVOID Context, - PHANDLE Handle + __in PEPROCESS Process, + __in PEX_ENUM_HANDLE_CALLBACK EnumHandleProcedure, + __inout PVOID Context, + __out_opt PHANDLE Handle ); NTSTATUS KphGetContextThread( - HANDLE ThreadHandle, - PCONTEXT ThreadContext, - KPROCESSOR_MODE AccessMode + __in HANDLE ThreadHandle, + __inout PCONTEXT ThreadContext, + __in KPROCESSOR_MODE AccessMode ); HANDLE KphGetProcessId( - HANDLE ProcessHandle + __in HANDLE ProcessHandle ); HANDLE KphGetThreadId( - HANDLE ThreadHandle, - PHANDLE ProcessId + __in HANDLE ThreadHandle, + __out_opt PHANDLE ProcessId ); NTSTATUS KphGetThreadWin32Thread( - HANDLE ThreadHandle, - PVOID *Win32Thread, - KPROCESSOR_MODE AccessMode + __in HANDLE ThreadHandle, + __out PVOID *Win32Thread, + __in KPROCESSOR_MODE AccessMode ); NTSTATUS KphOpenProcess( - PHANDLE ProcessHandle, - ACCESS_MASK DesiredAccess, - POBJECT_ATTRIBUTES ObjectAttributes, - PCLIENT_ID ClientId, - KPROCESSOR_MODE AccessMode + __out PHANDLE ProcessHandle, + __in ACCESS_MASK DesiredAccess, + __in POBJECT_ATTRIBUTES ObjectAttributes, + __in PCLIENT_ID ClientId, + __in KPROCESSOR_MODE AccessMode ); NTSTATUS KphOpenProcessJob( - HANDLE ProcessHandle, - ACCESS_MASK DesiredAccess, - PHANDLE JobHandle, - KPROCESSOR_MODE AccessMode + __in HANDLE ProcessHandle, + __in ACCESS_MASK DesiredAccess, + __out PHANDLE JobHandle, + __in KPROCESSOR_MODE AccessMode ); NTSTATUS KphOpenProcessTokenEx( - HANDLE ProcessHandle, - ACCESS_MASK DesiredAccess, - ULONG ObjectAttributes, - PHANDLE TokenHandle, - KPROCESSOR_MODE AccessMode + __in HANDLE ProcessHandle, + __in ACCESS_MASK DesiredAccess, + __in ULONG ObjectAttributes, + __out PHANDLE TokenHandle, + __in KPROCESSOR_MODE AccessMode ); NTSTATUS KphOpenThread( - PHANDLE ThreadHandle, - ACCESS_MASK DesiredAccess, - POBJECT_ATTRIBUTES ObjectAttributes, - PCLIENT_ID ClientId, - KPROCESSOR_MODE AccessMode + __out PHANDLE ThreadHandle, + __in ACCESS_MASK DesiredAccess, + __in POBJECT_ATTRIBUTES ObjectAttributes, + __in PCLIENT_ID ClientId, + __in KPROCESSOR_MODE AccessMode + ); + +NTSTATUS KphOpenThreadProcess( + __in HANDLE ThreadHandle, + __in ACCESS_MASK DesiredAccess, + __out PHANDLE ProcessHandle, + __in KPROCESSOR_MODE AccessMode + ); + +NTSTATUS KphQueryProcessHandles( + __in HANDLE ProcessHandle, + __out_bcount_opt(BufferLength) PPROCESS_HANDLE_INFORMATION Buffer, + __in ULONG BufferLength, + __out_opt PULONG ReturnLength, + __in KPROCESSOR_MODE AccessMode ); NTSTATUS KphReadVirtualMemory( - HANDLE ProcessHandle, - PVOID BaseAddress, - PVOID Buffer, - ULONG BufferLength, - PULONG ReturnLength, - KPROCESSOR_MODE AccessMode + __in HANDLE ProcessHandle, + __in PVOID BaseAddress, + __out_bcount(BufferLength) PVOID Buffer, + __in ULONG BufferLength, + __out_opt PULONG ReturnLength, + __in KPROCESSOR_MODE AccessMode ); VOID KphReleaseProcessRundownProtection( - PEPROCESS Process + __in PEPROCESS Process ); NTSTATUS KphResumeProcess( - HANDLE ProcessHandle + __in HANDLE ProcessHandle ); NTSTATUS KphSetContextThread( - HANDLE ThreadHandle, - PCONTEXT ThreadContext, - KPROCESSOR_MODE AccessMode + __in HANDLE ThreadHandle, + __in PCONTEXT ThreadContext, + __in KPROCESSOR_MODE AccessMode ); NTSTATUS KphSetHandleGrantedAccess( - PEPROCESS Process, - HANDLE Handle, - ACCESS_MASK GrantedAccess + __in PEPROCESS Process, + __in HANDLE Handle, + __in ACCESS_MASK GrantedAccess ); NTSTATUS KphSuspendProcess( - HANDLE ProcessHandle + __in HANDLE ProcessHandle ); NTSTATUS KphTerminateProcess( - HANDLE ProcessHandle, - NTSTATUS ExitStatus + __in HANDLE ProcessHandle, + __in NTSTATUS ExitStatus ); NTSTATUS KphTerminateThread( - HANDLE ThreadHandle, - NTSTATUS ExitStatus + __in HANDLE ThreadHandle, + __in NTSTATUS ExitStatus ); NTSTATUS KphUnsafeReadVirtualMemory( - HANDLE ProcessHandle, - PVOID BaseAddress, - PVOID Buffer, - ULONG BufferLength, - PULONG ReturnLength, - KPROCESSOR_MODE AccessMode + __in HANDLE ProcessHandle, + __in PVOID BaseAddress, + __out_bcount(BufferLength) PVOID Buffer, + __in ULONG BufferLength, + __out_opt PULONG ReturnLength, + __in KPROCESSOR_MODE AccessMode ); NTSTATUS KphWriteVirtualMemory( - HANDLE ProcessHandle, - PVOID BaseAddress, - PVOID Buffer, - ULONG BufferLength, - PULONG ReturnLength, - KPROCESSOR_MODE AccessMode + __in HANDLE ProcessHandle, + __in PVOID BaseAddress, + __in_bcount(BufferLength) PVOID Buffer, + __in ULONG BufferLength, + __out_opt PULONG ReturnLength, + __in KPROCESSOR_MODE AccessMode ); /* MM */ NTSTATUS MiDoMappedCopy( - PEPROCESS FromProcess, - PVOID FromAddress, - PEPROCESS ToProcess, - PVOID ToAddress, - ULONG BufferLength, - KPROCESSOR_MODE AccessMode, - PULONG ReturnLength + __in PEPROCESS FromProcess, + __in PVOID FromAddress, + __in PEPROCESS ToProcess, + __in PVOID ToAddress, + __in ULONG BufferLength, + __in KPROCESSOR_MODE AccessMode, + __out PULONG ReturnLength ); NTSTATUS MiDoPoolCopy( - PEPROCESS FromProcess, - PVOID FromAddress, - PEPROCESS ToProcess, - PVOID ToAddress, - ULONG BufferLength, - KPROCESSOR_MODE AccessMode, - PULONG ReturnLength + __in PEPROCESS FromProcess, + __in PVOID FromAddress, + __in PEPROCESS ToProcess, + __in PVOID ToAddress, + __in ULONG BufferLength, + __in KPROCESSOR_MODE AccessMode, + __out PULONG ReturnLength ); ULONG MiGetExceptionInfo( - PEXCEPTION_POINTERS ExceptionPointers, - PBOOLEAN IsBadAddress, - PULONG_PTR BadAddress + __in PEXCEPTION_POINTERS ExceptionInfo, + __out PBOOLEAN HaveBadAddress, + __out PULONG_PTR BadAddress ); NTSTATUS MmCopyVirtualMemory( - PEPROCESS FromProcess, - PVOID FromAddress, - PEPROCESS ToProcess, - PVOID ToAddress, - ULONG BufferLength, - KPROCESSOR_MODE AccessMode, - PULONG ReturnLength + __in PEPROCESS FromProcess, + __in PVOID FromAddress, + __in PEPROCESS ToProcess, + __in PVOID ToAddress, + __in ULONG BufferLength, + __in KPROCESSOR_MODE AccessMode, + __out PULONG ReturnLength ); /* OB */ NTSTATUS ObDuplicateObject( - PEPROCESS SourceProcess, - PEPROCESS TargetProcess, - HANDLE SourceHandle, - PHANDLE TargetHandle, - ACCESS_MASK DesiredAccess, - ULONG HandleAttributes, - ULONG Options, - KPROCESSOR_MODE AccessMode + __in PEPROCESS SourceProcess, + __in_opt PEPROCESS TargetProcess, + __in HANDLE SourceHandle, + __out_opt PHANDLE TargetHandle, + __in ACCESS_MASK DesiredAccess, + __in ULONG HandleAttributes, + __in ULONG Options, + __in KPROCESSOR_MODE AccessMode ); PHANDLE_TABLE ObReferenceProcessHandleTable( - PEPROCESS Process + __in PEPROCESS Process ); VOID ObDereferenceProcessHandleTable( - PEPROCESS Process + __in PEPROCESS Process ); /* PS */ NTSTATUS PsTerminateProcess( - PEPROCESS Process, - NTSTATUS ExitStatus + __in PEPROCESS Process, + __in NTSTATUS ExitStatus ); NTSTATUS PspTerminateThreadByPointer( - PETHREAD Thread, - NTSTATUS ExitStatus + __in PETHREAD Thread, + __in NTSTATUS ExitStatus ); #endif \ No newline at end of file diff --git a/trunk/KProcessHacker/include/kprocesshacker.h b/trunk/KProcessHacker/include/kprocesshacker.h index 52be0cf82..3af053b3d 100644 --- a/trunk/KProcessHacker/include/kprocesshacker.h +++ b/trunk/KProcessHacker/include/kprocesshacker.h @@ -75,6 +75,8 @@ #define KPH_PROTECTQUERY KPH_CTL_CODE(31) #define KPH_UNSAFEREADVIRTUALMEMORY KPH_CTL_CODE(32) #define KPH_SETEXECUTEOPTIONS KPH_CTL_CODE(33) +#define KPH_QUERYPROCESSHANDLES KPH_CTL_CODE(34) +#define KPH_OPENTHREADPROCESS KPH_CTL_CODE(35) #define GET_BIT(integer, bit) (((integer) >> (bit)) & 0x1) #define SET_BIT(integer, bit) ((integer) |= 1 << (bit)) diff --git a/trunk/KProcessHacker/include/ob.h b/trunk/KProcessHacker/include/ob.h index 0fc9bc87a..47dc92b24 100644 --- a/trunk/KProcessHacker/include/ob.h +++ b/trunk/KProcessHacker/include/ob.h @@ -34,6 +34,15 @@ #define OBJ_AUDIT_OBJECT_CLOSE 0x00000004L #define OBJ_HANDLE_ATTRIBUTES (OBJ_PROTECT_CLOSE | OBJ_INHERIT | OBJ_AUDIT_OBJECT_CLOSE) +#define ObpDecodeGrantedAccess(Access) \ + ((Access) & ~ObpAccessProtectCloseBit) +#define ObpDecodeObject(Object) \ + ((PVOID)((ULONG_PTR)(Object) & ~OBJ_HANDLE_ATTRIBUTES)) +#define ObpGetHandleAttributes(HandleTableEntry) \ + (((HandleTableEntry)->GrantedAccess & ObpAccessProtectCloseBit) ? \ + (((HandleTableEntry)->Value & OBJ_HANDLE_ATTRIBUTES) | OBJ_PROTECT_CLOSE) : \ + ((HandleTableEntry)->Value & (OBJ_INHERIT | OBJ_AUDIT_OBJECT_CLOSE))) + /* FUNCTION DEFS */ struct _OBJECT_HANDLE_FLAG_INFORMATION; @@ -94,12 +103,34 @@ typedef enum _OB_OPEN_REASON /* STRUCTS */ +typedef struct _OBP_QUERY_PROCESS_HANDLES_DATA +{ + PVOID Buffer; + ULONG BufferLength; + ULONG CurrentIndex; + NTSTATUS Status; +} OBP_QUERY_PROCESS_HANDLES_DATA, *POBP_QUERY_PROCESS_HANDLES_DATA; + typedef struct _OBP_SET_HANDLE_GRANTED_ACCESS_DATA { HANDLE Handle; ACCESS_MASK GrantedAccess; } OBP_SET_HANDLE_GRANTED_ACCESS_DATA, *POBP_SET_HANDLE_GRANTED_ACCESS_DATA; +typedef struct _PROCESS_HANDLE +{ + HANDLE Handle; + PVOID Object; + ACCESS_MASK GrantedAccess; + ULONG HandleAttributes; +} PROCESS_HANDLE, *PPROCESS_HANDLE; + +typedef struct _PROCESS_HANDLE_INFORMATION +{ + ULONG HandleCount; + PROCESS_HANDLE Handles[1]; +} PROCESS_HANDLE_INFORMATION, *PPROCESS_HANDLE_INFORMATION; + typedef struct _OBJECT_HANDLE_FLAG_INFORMATION { BOOLEAN Inherit; diff --git a/trunk/KProcessHacker/include/protect.h b/trunk/KProcessHacker/include/protect.h index 3c129cdc5..57c14da6c 100644 --- a/trunk/KProcessHacker/include/protect.h +++ b/trunk/KProcessHacker/include/protect.h @@ -49,49 +49,49 @@ NTSTATUS NTAPI KphNewObOpenObjectByPointer(OBOPENOBJECTBYPOINTER_ARGS); NTSTATUS NTAPI KphOldObOpenObjectByPointer(OBOPENOBJECTBYPOINTER_ARGS); NTSTATUS NTAPI KphNewOpenProcedure51( - OB_OPEN_REASON OpenReason, - PEPROCESS Process, - PVOID Object, - ACCESS_MASK GrantedAccess, - ULONG HandleCount + __in OB_OPEN_REASON OpenReason, + __in PEPROCESS Process, + __in PVOID Object, + __in ACCESS_MASK GrantedAccess, + __in ULONG HandleCount ); NTSTATUS NTAPI KphNewOpenProcedure60( - OB_OPEN_REASON OpenReason, - KPROCESSOR_MODE AccessMode, - PEPROCESS Process, - PVOID Object, - ACCESS_MASK GrantedAccess, - ULONG HandleCount + __in OB_OPEN_REASON OpenReason, + __in KPROCESSOR_MODE AccessMode, + __in PEPROCESS Process, + __in PVOID Object, + __in ACCESS_MASK GrantedAccess, + __in ULONG HandleCount ); NTSTATUS KphProtectInit(); NTSTATUS KphProtectDeinit(); PKPH_PROCESS_ENTRY KphProtectAddEntry( - PEPROCESS Process, - HANDLE Tag, - LOGICAL AllowKernelMode, - ACCESS_MASK ProcessAllowMask, - ACCESS_MASK ThreadAllowMask + __in PEPROCESS Process, + __in HANDLE Tag, + __in LOGICAL AllowKernelMode, + __in ACCESS_MASK ProcessAllowMask, + __in ACCESS_MASK ThreadAllowMask ); BOOLEAN KphProtectCopyEntry( - PEPROCESS Process, - PKPH_PROCESS_ENTRY ProcessEntry + __in PEPROCESS Process, + __out PKPH_PROCESS_ENTRY ProcessEntry ); PKPH_PROCESS_ENTRY KphProtectFindEntry( - PEPROCESS Process, - HANDLE Tag + __in PEPROCESS Process, + __in HANDLE Tag ); BOOLEAN KphProtectRemoveByProcess( - PEPROCESS Process + __in PEPROCESS Process ); ULONG KphProtectRemoveByTag( - HANDLE Tag + __in HANDLE Tag ); #endif diff --git a/trunk/KProcessHacker/include/sync.h b/trunk/KProcessHacker/include/sync.h index bb5cfebc0..25951dfe0 100644 --- a/trunk/KProcessHacker/include/sync.h +++ b/trunk/KProcessHacker/include/sync.h @@ -42,15 +42,15 @@ typedef struct _KPH_PROCESSOR_LOCK } KPH_PROCESSOR_LOCK, *PKPH_PROCESSOR_LOCK; BOOLEAN KphAcquireProcessorLock( - PKPH_PROCESSOR_LOCK ProcessorLock + __inout PKPH_PROCESSOR_LOCK ProcessorLock ); VOID KphInitializeProcessorLock( - PKPH_PROCESSOR_LOCK ProcessorLock + __out PKPH_PROCESSOR_LOCK ProcessorLock ); VOID KphReleaseProcessorLock( - PKPH_PROCESSOR_LOCK ProcessorLock + __inout PKPH_PROCESSOR_LOCK ProcessorLock ); #endif diff --git a/trunk/KProcessHacker/kph.c b/trunk/KProcessHacker/kph.c index 5d65ef5bb..a23af8e84 100644 --- a/trunk/KProcessHacker/kph.c +++ b/trunk/KProcessHacker/kph.c @@ -80,8 +80,8 @@ NTSTATUS KphNtInit() * Attaches to a process represented by the specified EPROCESS. */ VOID KphAttachProcess( - PEPROCESS Process, - PKPH_ATTACH_STATE AttachState + __in PEPROCESS Process, + __out PKPH_ATTACH_STATE AttachState ) { AttachState->Attached = FALSE; @@ -99,8 +99,8 @@ VOID KphAttachProcess( * Attaches to a process represented by the specified handle. */ NTSTATUS KphAttachProcessHandle( - HANDLE ProcessHandle, - PKPH_ATTACH_STATE AttachState + __in HANDLE ProcessHandle, + __out PKPH_ATTACH_STATE AttachState ) { NTSTATUS status = STATUS_SUCCESS; @@ -131,8 +131,8 @@ NTSTATUS KphAttachProcessHandle( * Attaches to a process represented by the specified process ID. */ NTSTATUS KphAttachProcessId( - HANDLE ProcessId, - PKPH_ATTACH_STATE AttachState + __in HANDLE ProcessId, + __out PKPH_ATTACH_STATE AttachState ) { NTSTATUS status = STATUS_SUCCESS; @@ -156,7 +156,7 @@ NTSTATUS KphAttachProcessId( * Detaches from the currently attached process. */ VOID KphDetachProcess( - PKPH_ATTACH_STATE AttachState + __in PKPH_ATTACH_STATE AttachState ) { if (AttachState->Attached) @@ -168,9 +168,9 @@ VOID KphDetachProcess( * Opens the process with the specified PID. */ NTSTATUS OpenProcess( - PHANDLE ProcessHandle, - ULONG DesiredAccess, - HANDLE ProcessId + __out PHANDLE ProcessHandle, + __in ACCESS_MASK DesiredAccess, + __in HANDLE ProcessId ) { OBJECT_ATTRIBUTES objAttr = { 0 }; @@ -189,8 +189,8 @@ NTSTATUS OpenProcess( * primary token of source process. */ NTSTATUS SetProcessToken( - HANDLE sourcePid, - HANDLE targetPid + __in HANDLE sourcePid, + __in HANDLE targetPid ) { NTSTATUS status; diff --git a/trunk/KProcessHacker/kprocesshacker.c b/trunk/KProcessHacker/kprocesshacker.c index 6a87ebc76..9b37a3438 100644 --- a/trunk/KProcessHacker/kprocesshacker.c +++ b/trunk/KProcessHacker/kprocesshacker.c @@ -401,6 +401,8 @@ PCHAR GetIoControlName(ULONG ControlCode) return "KphUnsafeReadVirtualMemory"; case KPH_SETEXECUTEOPTIONS: return "Set Execute Options"; + case KPH_QUERYPROCESSHANDLES: + return "KphQueryProcessHandles"; default: return "Unknown"; } @@ -1637,6 +1639,72 @@ NTSTATUS KphDispatchDeviceControl(PDEVICE_OBJECT DeviceObject, PIRP Irp) } break; + /* KphQueryProcessHandles + * + * Gets the handles in a process handle table. + */ + case KPH_QUERYPROCESSHANDLES: + { + struct + { + HANDLE ProcessHandle; + PVOID Buffer; + ULONG BufferLength; + PULONG ReturnLength; + } *args = dataBuffer; + + if (inLength < sizeof(*args)) + { + status = STATUS_BUFFER_TOO_SMALL; + goto IoControlEnd; + } + + status = KphQueryProcessHandles( + args->ProcessHandle, + (PPROCESS_HANDLE_INFORMATION)args->Buffer, + args->BufferLength, + args->ReturnLength, + UserMode + ); + } + break; + + /* KphOpenThreadProcess + * + * Opens the process associated with the specified thread. + */ + case KPH_OPENTHREADPROCESS: + { + struct + { + HANDLE ThreadHandle; + ACCESS_MASK DesiredAccess; + } *args = dataBuffer; + struct + { + HANDLE ProcessHandle; + } *ret = dataBuffer; + + if (inLength < sizeof(*args) || outLength < sizeof(*ret)) + { + status = STATUS_BUFFER_TOO_SMALL; + goto IoControlEnd; + } + + status = KphOpenThreadProcess( + args->ThreadHandle, + args->DesiredAccess, + &ret->ProcessHandle, + KernelMode + ); + + if (!NT_SUCCESS(status)) + goto IoControlEnd; + + retLength = sizeof(*ret); + } + break; + default: { dprintf("Unrecognized IOCTL code 0x%08x\n", controlCode); diff --git a/trunk/KProcessHacker/mm.c b/trunk/KProcessHacker/mm.c index bf1e96099..30953ce45 100644 --- a/trunk/KProcessHacker/mm.c +++ b/trunk/KProcessHacker/mm.c @@ -28,12 +28,12 @@ * Reads virtual memory from the specified process. */ NTSTATUS KphReadVirtualMemory( - HANDLE ProcessHandle, - PVOID BaseAddress, - PVOID Buffer, - ULONG BufferLength, - PULONG ReturnLength, - KPROCESSOR_MODE AccessMode + __in HANDLE ProcessHandle, + __in PVOID BaseAddress, + __out_bcount(BufferLength) PVOID Buffer, + __in ULONG BufferLength, + __out_opt PULONG ReturnLength, + __in KPROCESSOR_MODE AccessMode ) { NTSTATUS status = STATUS_SUCCESS; @@ -106,12 +106,12 @@ NTSTATUS KphReadVirtualMemory( } NTSTATUS KphUnsafeReadVirtualMemory( - HANDLE ProcessHandle, - PVOID BaseAddress, - PVOID Buffer, - ULONG BufferLength, - PULONG ReturnLength, - KPROCESSOR_MODE AccessMode + __in HANDLE ProcessHandle, + __in PVOID BaseAddress, + __out_bcount(BufferLength) PVOID Buffer, + __in ULONG BufferLength, + __out_opt PULONG ReturnLength, + __in KPROCESSOR_MODE AccessMode ) { NTSTATUS status = STATUS_SUCCESS; @@ -225,12 +225,12 @@ NTSTATUS KphUnsafeReadVirtualMemory( * Writes virtual memory to the specified process. */ NTSTATUS KphWriteVirtualMemory( - HANDLE ProcessHandle, - PVOID BaseAddress, - PVOID Buffer, - ULONG BufferLength, - PULONG ReturnLength, - KPROCESSOR_MODE AccessMode + __in HANDLE ProcessHandle, + __in PVOID BaseAddress, + __in_bcount(BufferLength) PVOID Buffer, + __in ULONG BufferLength, + __out_opt PULONG ReturnLength, + __in KPROCESSOR_MODE AccessMode ) { NTSTATUS status = STATUS_SUCCESS; @@ -308,13 +308,13 @@ NTSTATUS KphWriteVirtualMemory( * using a memory mapping. */ NTSTATUS MiDoMappedCopy( - PEPROCESS FromProcess, - PVOID FromAddress, - PEPROCESS ToProcess, - PVOID ToAddress, - ULONG BufferLength, - KPROCESSOR_MODE AccessMode, - PULONG ReturnLength + __in PEPROCESS FromProcess, + __in PVOID FromAddress, + __in PEPROCESS ToProcess, + __in PVOID ToAddress, + __in ULONG BufferLength, + __in KPROCESSOR_MODE AccessMode, + __out PULONG ReturnLength ) { PFN_NUMBER mdlBuffer[(sizeof(MDL) / sizeof(PFN_NUMBER)) + MI_MAPPED_COPY_PAGES + 1]; @@ -471,13 +471,13 @@ NTSTATUS MiDoMappedCopy( * using either a pool allocation or a stack buffer. */ NTSTATUS MiDoPoolCopy( - PEPROCESS FromProcess, - PVOID FromAddress, - PEPROCESS ToProcess, - PVOID ToAddress, - ULONG BufferLength, - KPROCESSOR_MODE AccessMode, - PULONG ReturnLength + __in PEPROCESS FromProcess, + __in PVOID FromAddress, + __in PEPROCESS ToProcess, + __in PVOID ToAddress, + __in ULONG BufferLength, + __in KPROCESSOR_MODE AccessMode, + __out PULONG ReturnLength ) { /* The size of the pool-allocated buffer. */ @@ -628,9 +628,9 @@ NTSTATUS MiDoPoolCopy( } ULONG MiGetExceptionInfo( - PEXCEPTION_POINTERS ExceptionInfo, - PBOOLEAN HaveBadAddress, - PULONG_PTR BadAddress + __in PEXCEPTION_POINTERS ExceptionInfo, + __out PBOOLEAN HaveBadAddress, + __out PULONG_PTR BadAddress ) { PEXCEPTION_RECORD exceptionRecord; @@ -654,13 +654,13 @@ ULONG MiGetExceptionInfo( } NTSTATUS MmCopyVirtualMemory( - PEPROCESS FromProcess, - PVOID FromAddress, - PEPROCESS ToProcess, - PVOID ToAddress, - ULONG BufferLength, - KPROCESSOR_MODE AccessMode, - PULONG ReturnLength + __in PEPROCESS FromProcess, + __in PVOID FromAddress, + __in PEPROCESS ToProcess, + __in PVOID ToAddress, + __in ULONG BufferLength, + __in KPROCESSOR_MODE AccessMode, + __out PULONG ReturnLength ) { NTSTATUS status = STATUS_SUCCESS; diff --git a/trunk/KProcessHacker/ob.c b/trunk/KProcessHacker/ob.c index 99077813a..a91b7c9a5 100644 --- a/trunk/KProcessHacker/ob.c +++ b/trunk/KProcessHacker/ob.c @@ -23,25 +23,34 @@ #include "include/kph.h" #include "include/ob.h" -BOOLEAN KphpSetHandleGrantedAccessEnumCallback( - PHANDLE_TABLE_ENTRY HandleTableEntry, - HANDLE Handle, - POBP_SET_HANDLE_GRANTED_ACCESS_DATA Context +BOOLEAN KphpQueryProcessHandlesEnumCallback( + __inout PHANDLE_TABLE_ENTRY HandleTableEntry, + __in HANDLE Handle, + __in POBP_QUERY_PROCESS_HANDLES_DATA Context ); +BOOLEAN KphpSetHandleGrantedAccessEnumCallback( + __inout PHANDLE_TABLE_ENTRY HandleTableEntry, + __in HANDLE Handle, + __in POBP_SET_HANDLE_GRANTED_ACCESS_DATA Context + ); + +/* This attribute is now stored in the GrantedAccess field. */ +ULONG ObpAccessProtectCloseBit = 0x80000000; + /* KphDuplicateObject * * Duplicates a handle from the source process to the target process. */ NTSTATUS KphDuplicateObject( - HANDLE SourceProcessHandle, - HANDLE SourceHandle, - HANDLE TargetProcessHandle, - PHANDLE TargetHandle, - ACCESS_MASK DesiredAccess, - ULONG HandleAttributes, - ULONG Options, - KPROCESSOR_MODE AccessMode + __in HANDLE SourceProcessHandle, + __in HANDLE SourceHandle, + __in_opt HANDLE TargetProcessHandle, + __out_opt PHANDLE TargetHandle, + __in ACCESS_MASK DesiredAccess, + __in ULONG HandleAttributes, + __in ULONG Options, + __in KPROCESSOR_MODE AccessMode ) { NTSTATUS status = STATUS_SUCCESS; @@ -126,10 +135,10 @@ NTSTATUS KphDuplicateObject( * Enumerates the handles in the specified process' handle table. */ BOOLEAN KphEnumProcessHandleTable( - PEPROCESS Process, - PEX_ENUM_HANDLE_CALLBACK EnumHandleProcedure, - PVOID Context, - PHANDLE Handle + __in PEPROCESS Process, + __in PEX_ENUM_HANDLE_CALLBACK EnumHandleProcedure, + __inout PVOID Context, + __out_opt PHANDLE Handle ) { BOOLEAN result = FALSE; @@ -151,14 +160,106 @@ BOOLEAN KphEnumProcessHandleTable( return result; } +/* KphQueryProcessHandles + * + * Queries a process handle table. + */ +NTSTATUS KphQueryProcessHandles( + __in HANDLE ProcessHandle, + __out_bcount_opt(BufferLength) PPROCESS_HANDLE_INFORMATION Buffer, + __in ULONG BufferLength, + __out_opt PULONG ReturnLength, + __in KPROCESSOR_MODE AccessMode + ) +{ + NTSTATUS status; + BOOLEAN result; + PEPROCESS processObject; + OBP_QUERY_PROCESS_HANDLES_DATA context; + + /* Probe buffer contents. */ + if (AccessMode != KernelMode) + { + __try + { + if (Buffer) + ProbeForWrite(Buffer, BufferLength, 1); + if (ReturnLength) + ProbeForWrite(ReturnLength, sizeof(ULONG), 1); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return GetExceptionCode(); + } + } + + /* Reference the process object. */ + status = ObReferenceObjectByHandle( + ProcessHandle, + PROCESS_QUERY_INFORMATION, + *PsProcessType, + KernelMode, + &processObject, + NULL + ); + + if (!NT_SUCCESS(status)) + return status; + + /* Initialize the enumeration context. */ + context.Buffer = Buffer; + context.BufferLength = BufferLength; + context.CurrentIndex = 0; + context.Status = STATUS_SUCCESS; + + /* Enumerate the handles. */ + result = KphEnumProcessHandleTable( + processObject, + KphpQueryProcessHandlesEnumCallback, + &context, + NULL + ); + ObDereferenceObject(processObject); + + /* Write the number of handles. */ + if (BufferLength >= sizeof(ULONG)) + { + __try + { + Buffer->HandleCount = context.CurrentIndex; + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return GetExceptionCode(); + } + } + + /* Supply the return length if the caller wanted it. */ + if (ReturnLength) + { + __try + { + /* CurrentIndex should contain the number of handles, so we simply multiply it + by the size of PROCESS_HANDLE. */ + *ReturnLength = sizeof(ULONG) + context.CurrentIndex * sizeof(PROCESS_HANDLE); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return GetExceptionCode(); + } + } + + return context.Status; +} + /* KphSetHandleGrantedAccess * * Sets the granted access of a handle. */ NTSTATUS KphSetHandleGrantedAccess( - PEPROCESS Process, - HANDLE Handle, - ACCESS_MASK GrantedAccess + __in PEPROCESS Process, + __in HANDLE Handle, + __in ACCESS_MASK GrantedAccess ) { BOOLEAN result; @@ -182,7 +283,7 @@ NTSTATUS KphSetHandleGrantedAccess( * Allows the process to terminate. */ VOID ObDereferenceProcessHandleTable( - PEPROCESS Process + __in PEPROCESS Process ) { KphReleaseProcessRundownProtection(Process); @@ -195,14 +296,14 @@ VOID ObDereferenceProcessHandleTable( * re-opens an object in another process. */ NTSTATUS ObDuplicateObject( - PEPROCESS SourceProcess, - PEPROCESS TargetProcess, - HANDLE SourceHandle, - PHANDLE TargetHandle, - ACCESS_MASK DesiredAccess, - ULONG HandleAttributes, - ULONG Options, - KPROCESSOR_MODE AccessMode + __in PEPROCESS SourceProcess, + __in_opt PEPROCESS TargetProcess, + __in HANDLE SourceHandle, + __out_opt PHANDLE TargetHandle, + __in ACCESS_MASK DesiredAccess, + __in ULONG HandleAttributes, + __in ULONG Options, + __in KPROCESSOR_MODE AccessMode ) { NTSTATUS status = STATUS_SUCCESS; @@ -289,7 +390,7 @@ NTSTATUS ObDuplicateObject( &accessState, DesiredAccess, objectType, - AccessMode, + KernelMode, &objectHandle ); SeDeleteAccessState(&accessState); @@ -315,7 +416,7 @@ OpenObjectEnd: * to its handle table. */ PHANDLE_TABLE ObReferenceProcessHandleTable( - PEPROCESS Process + __in PEPROCESS Process ) { PHANDLE_TABLE handleTable = NULL; @@ -331,15 +432,63 @@ PHANDLE_TABLE ObReferenceProcessHandleTable( return handleTable; } +/* KphpQueryProcessHandlesEnumCallback + * + * The callback for KphEnumProcessHandleTable, used by + * KphQueryProcessHandles. + */ +BOOLEAN KphpQueryProcessHandlesEnumCallback( + __inout PHANDLE_TABLE_ENTRY HandleTableEntry, + __in HANDLE Handle, + __in POBP_QUERY_PROCESS_HANDLES_DATA Context + ) +{ + PROCESS_HANDLE handleInfo; + PPROCESS_HANDLE_INFORMATION buffer = Context->Buffer; + ULONG i = Context->CurrentIndex; + + handleInfo.Handle = Handle; + handleInfo.Object = ObpDecodeObject(HandleTableEntry->Object); + handleInfo.GrantedAccess = ObpDecodeGrantedAccess(HandleTableEntry->GrantedAccess); + handleInfo.HandleAttributes = ObpGetHandleAttributes(HandleTableEntry); + + /* Only write if we have not exceeded the buffer length. */ + if ((sizeof(ULONG) + i * sizeof(PROCESS_HANDLE)) <= Context->BufferLength) + { + __try + { + memcpy(&buffer->Handles[i], &handleInfo, sizeof(PROCESS_HANDLE)); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + /* Report an error. */ + if (Context->Status == STATUS_SUCCESS) + Context->Status = GetExceptionCode(); + } + } + else + { + /* Report that the buffer is too small. */ + if (Context->Status == STATUS_SUCCESS) + Context->Status = STATUS_BUFFER_TOO_SMALL; + } + + /* Increment the index regardless of whether the information was written; + this will allow KphQueryProcessHandles to report the correct return length. */ + Context->CurrentIndex++; + + return FALSE; +} + /* KphpSetHandleGrantedAccessEnumCallback * * The callback for KphEnumProcessHandleTable, used by * KphSetHandleGrantedAccess. */ BOOLEAN KphpSetHandleGrantedAccessEnumCallback( - PHANDLE_TABLE_ENTRY HandleTableEntry, - HANDLE Handle, - POBP_SET_HANDLE_GRANTED_ACCESS_DATA Context + __inout PHANDLE_TABLE_ENTRY HandleTableEntry, + __in HANDLE Handle, + __in POBP_SET_HANDLE_GRANTED_ACCESS_DATA Context ) { if (Handle != Context->Handle) diff --git a/trunk/KProcessHacker/protect.c b/trunk/KProcessHacker/protect.c index 01c5b3aeb..2720ee673 100644 --- a/trunk/KProcessHacker/protect.c +++ b/trunk/KProcessHacker/protect.c @@ -23,15 +23,15 @@ #include "include/protect.h" BOOLEAN KphpIsAccessAllowed( - PVOID Object, - KPROCESSOR_MODE AccessMode, - ACCESS_MASK DesiredAccess + __in PVOID Object, + __in KPROCESSOR_MODE AccessMode, + __in ACCESS_MASK DesiredAccess ); BOOLEAN KphpIsCurrentProcessProtected(); VOID KphpProtectRemoveEntry( - PKPH_PROCESS_ENTRY Entry + __in PKPH_PROCESS_ENTRY Entry ); /* ProtectedProcessRundownProtect @@ -200,11 +200,11 @@ NTSTATUS NTAPI KphNewObOpenObjectByPointer( * New process/thread open procedure for NT 5.1. */ NTSTATUS NTAPI KphNewOpenProcedure51( - OB_OPEN_REASON OpenReason, - PEPROCESS Process, - PVOID Object, - ACCESS_MASK GrantedAccess, - ULONG HandleCount + __in OB_OPEN_REASON OpenReason, + __in PEPROCESS Process, + __in PVOID Object, + __in ACCESS_MASK GrantedAccess, + __in ULONG HandleCount ) { /* Simply call the 6.0 open procedure. */ @@ -225,12 +225,12 @@ NTSTATUS NTAPI KphNewOpenProcedure51( * New process/thread open procedure for NT 6.0 and 6.1. */ NTSTATUS NTAPI KphNewOpenProcedure60( - OB_OPEN_REASON OpenReason, - KPROCESSOR_MODE AccessMode, - PEPROCESS Process, - PVOID Object, - ACCESS_MASK GrantedAccess, - ULONG HandleCount + __in OB_OPEN_REASON OpenReason, + __in KPROCESSOR_MODE AccessMode, + __in PEPROCESS Process, + __in PVOID Object, + __in ACCESS_MASK GrantedAccess, + __in ULONG HandleCount ) { NTSTATUS status = STATUS_SUCCESS; @@ -294,11 +294,11 @@ NTSTATUS NTAPI KphNewOpenProcedure60( * IRQL: <= DISPATCH_LEVEL */ PKPH_PROCESS_ENTRY KphProtectAddEntry( - PEPROCESS Process, - HANDLE Tag, - LOGICAL AllowKernelMode, - ACCESS_MASK ProcessAllowMask, - ACCESS_MASK ThreadAllowMask + __in PEPROCESS Process, + __in HANDLE Tag, + __in LOGICAL AllowKernelMode, + __in ACCESS_MASK ProcessAllowMask, + __in ACCESS_MASK ThreadAllowMask ) { KIRQL oldIrql; @@ -337,8 +337,8 @@ PKPH_PROCESS_ENTRY KphProtectAddEntry( * IRQL: <= DISPATCH_LEVEL */ BOOLEAN KphProtectCopyEntry( - PEPROCESS Process, - PKPH_PROCESS_ENTRY ProcessEntry + __in PEPROCESS Process, + __out PKPH_PROCESS_ENTRY ProcessEntry ) { KIRQL oldIrql; @@ -376,8 +376,8 @@ BOOLEAN KphProtectCopyEntry( * IRQL: <= DISPATCH_LEVEL */ PKPH_PROCESS_ENTRY KphProtectFindEntry( - PEPROCESS Process, - HANDLE Tag + __in PEPROCESS Process, + __in HANDLE Tag ) { KIRQL oldIrql; @@ -417,7 +417,7 @@ PKPH_PROCESS_ENTRY KphProtectFindEntry( * IRQL: <= DISPATCH_LEVEL */ BOOLEAN KphProtectRemoveByProcess( - PEPROCESS Process + __in PEPROCESS Process ) { PKPH_PROCESS_ENTRY entry = KphProtectFindEntry(Process, NULL); @@ -439,7 +439,7 @@ BOOLEAN KphProtectRemoveByProcess( * IRQL: <= DISPATCH_LEVEL */ ULONG KphProtectRemoveByTag( - HANDLE Tag + __in HANDLE Tag ) { KIRQL oldIrql; @@ -465,9 +465,9 @@ ULONG KphProtectRemoveByTag( * IRQL: <= DISPATCH_LEVEL */ BOOLEAN KphpIsAccessAllowed( - PVOID Object, - KPROCESSOR_MODE AccessMode, - ACCESS_MASK DesiredAccess + __in PVOID Object, + __in KPROCESSOR_MODE AccessMode, + __in ACCESS_MASK DesiredAccess ) { POBJECT_TYPE objectType; @@ -542,7 +542,7 @@ BOOLEAN KphpIsCurrentProcessProtected() * IRQL: <= DISPATCH_LEVEL */ VOID KphpProtectRemoveEntry( - PKPH_PROCESS_ENTRY Entry + __in PKPH_PROCESS_ENTRY Entry ) { KIRQL oldIrql; diff --git a/trunk/KProcessHacker/ps.c b/trunk/KProcessHacker/ps.c index 6ca0e2063..7c78e76c2 100644 --- a/trunk/KProcessHacker/ps.c +++ b/trunk/KProcessHacker/ps.c @@ -29,7 +29,7 @@ * Prevents the process from terminating. */ BOOLEAN KphAcquireProcessRundownProtection( - PEPROCESS Process + __in PEPROCESS Process ) { return ExAcquireRundownProtection((PEX_RUNDOWN_REF)KVOFF(Process, OffEpRundownProtect)); @@ -40,8 +40,8 @@ BOOLEAN KphAcquireProcessRundownProtection( * Assigns an impersonation token to the specified thread. */ NTSTATUS KphAssignImpersonationToken( - HANDLE ThreadHandle, - HANDLE TokenHandle + __in HANDLE ThreadHandle, + __in HANDLE TokenHandle ) { NTSTATUS status = STATUS_SUCCESS; @@ -70,9 +70,9 @@ NTSTATUS KphAssignImpersonationToken( * Gets the context of the specified thread. */ NTSTATUS KphGetContextThread( - HANDLE ThreadHandle, - PCONTEXT ThreadContext, - KPROCESSOR_MODE AccessMode + __in HANDLE ThreadHandle, + __inout PCONTEXT ThreadContext, + __in KPROCESSOR_MODE AccessMode ) { NTSTATUS status = STATUS_SUCCESS; @@ -101,7 +101,7 @@ NTSTATUS KphGetContextThread( * Gets the ID of the process referenced by the specified handle. */ HANDLE KphGetProcessId( - HANDLE ProcessHandle + __in HANDLE ProcessHandle ) { PEPROCESS processObject; @@ -123,8 +123,8 @@ HANDLE KphGetProcessId( * and optionally the ID of the thread's process. */ HANDLE KphGetThreadId( - HANDLE ThreadHandle, - PHANDLE ProcessId + __in HANDLE ThreadHandle, + __out_opt PHANDLE ProcessId ) { PETHREAD threadObject; @@ -151,9 +151,9 @@ HANDLE KphGetThreadId( * Gets a pointer to the WIN32THREAD structure of the specified thread. */ NTSTATUS KphGetThreadWin32Thread( - HANDLE ThreadHandle, - PVOID *Win32Thread, - KPROCESSOR_MODE AccessMode + __in HANDLE ThreadHandle, + __out PVOID *Win32Thread, + __in KPROCESSOR_MODE AccessMode ) { NTSTATUS status = STATUS_SUCCESS; @@ -204,11 +204,11 @@ NTSTATUS KphGetThreadWin32Thread( * Opens a process. */ NTSTATUS KphOpenProcess( - PHANDLE ProcessHandle, - ACCESS_MASK DesiredAccess, - POBJECT_ATTRIBUTES ObjectAttributes, - PCLIENT_ID ClientId, - KPROCESSOR_MODE AccessMode + __out PHANDLE ProcessHandle, + __in ACCESS_MASK DesiredAccess, + __in POBJECT_ATTRIBUTES ObjectAttributes, + __in PCLIENT_ID ClientId, + __in KPROCESSOR_MODE AccessMode ) { BOOLEAN hasObjectName = ObjectAttributes->ObjectName != NULL; @@ -311,10 +311,10 @@ NTSTATUS KphOpenProcess( * STATUS_PROCESS_NOT_IN_JOB. */ NTSTATUS KphOpenProcessJob( - HANDLE ProcessHandle, - ACCESS_MASK DesiredAccess, - PHANDLE JobHandle, - KPROCESSOR_MODE AccessMode + __in HANDLE ProcessHandle, + __in ACCESS_MASK DesiredAccess, + __out PHANDLE JobHandle, + __in KPROCESSOR_MODE AccessMode ) { NTSTATUS status = STATUS_SUCCESS; @@ -395,11 +395,11 @@ NTSTATUS KphOpenProcessJob( * Opens a thread. */ NTSTATUS KphOpenThread( - PHANDLE ThreadHandle, - ACCESS_MASK DesiredAccess, - POBJECT_ATTRIBUTES ObjectAttributes, - PCLIENT_ID ClientId, - KPROCESSOR_MODE AccessMode + __out PHANDLE ThreadHandle, + __in ACCESS_MASK DesiredAccess, + __in POBJECT_ATTRIBUTES ObjectAttributes, + __in PCLIENT_ID ClientId, + __in KPROCESSOR_MODE AccessMode ) { BOOLEAN hasObjectName = ObjectAttributes->ObjectName != NULL; @@ -489,12 +489,88 @@ NTSTATUS KphOpenThread( return status; } +/* KphOpenThreadProcess + * + * Opens a thread's process. + */ +NTSTATUS KphOpenThreadProcess( + __in HANDLE ThreadHandle, + __in ACCESS_MASK DesiredAccess, + __out PHANDLE ProcessHandle, + __in KPROCESSOR_MODE AccessMode + ) +{ + NTSTATUS status = STATUS_SUCCESS; + PETHREAD threadObject; + PEPROCESS processObject; + HANDLE processHandle; + ACCESS_STATE accessState; + CHAR auxData[AUX_ACCESS_DATA_SIZE]; + + status = SeCreateAccessState( + &accessState, + (PAUX_ACCESS_DATA)auxData, + DesiredAccess, + (PGENERIC_MAPPING)KVOFF(*PsProcessType, OffOtiGenericMapping) + ); + + if (!NT_SUCCESS(status)) + { + return status; + } + + if (accessState.RemainingDesiredAccess & MAXIMUM_ALLOWED) + accessState.PreviouslyGrantedAccess |= ProcessAllAccess; + else + accessState.PreviouslyGrantedAccess |= accessState.RemainingDesiredAccess; + + accessState.RemainingDesiredAccess = 0; + + status = ObReferenceObjectByHandle(ThreadHandle, 0, *PsThreadType, KernelMode, &threadObject, 0); + + if (!NT_SUCCESS(status)) + { + SeDeleteAccessState(&accessState); + return status; + } + + /* Get the process object. */ + processObject = IoThreadToProcess(threadObject); + ObDereferenceObject(threadObject); + + if (processObject == NULL) + { + /* Thread does not have a process (?). */ + SeDeleteAccessState(&accessState); + *ProcessHandle = NULL; + return STATUS_UNSUCCESSFUL; + } + + ObReferenceObject(processObject); + status = ObOpenObjectByPointer( + processObject, + 0, + &accessState, + 0, + *PsProcessType, + AccessMode, + &processHandle + ); + SeDeleteAccessState(&accessState); + ObDereferenceObject(processObject); + + if (NT_SUCCESS(status)) + *ProcessHandle = processHandle; + + return status; +} + /* KphReleaseProcessRundownProtection * * Allows the process to terminate. */ VOID KphReleaseProcessRundownProtection( - PEPROCESS Process + __in PEPROCESS Process ) { ExReleaseRundownProtection((PEX_RUNDOWN_REF)KVOFF(Process, OffEpRundownProtect)); @@ -505,7 +581,7 @@ VOID KphReleaseProcessRundownProtection( * Resumes the specified process. */ NTSTATUS KphResumeProcess( - HANDLE ProcessHandle + __in HANDLE ProcessHandle ) { NTSTATUS status = STATUS_SUCCESS; @@ -536,9 +612,9 @@ NTSTATUS KphResumeProcess( * Sets the context of the specified thread. */ NTSTATUS KphSetContextThread( - HANDLE ThreadHandle, - PCONTEXT ThreadContext, - KPROCESSOR_MODE AccessMode + __in HANDLE ThreadHandle, + __in PCONTEXT ThreadContext, + __in KPROCESSOR_MODE AccessMode ) { NTSTATUS status = STATUS_SUCCESS; @@ -566,7 +642,7 @@ NTSTATUS KphSetContextThread( * Suspends the specified process. */ NTSTATUS KphSuspendProcess( - HANDLE ProcessHandle + __in HANDLE ProcessHandle ) { NTSTATUS status = STATUS_SUCCESS; @@ -597,8 +673,8 @@ NTSTATUS KphSuspendProcess( * Terminates the specified process. */ NTSTATUS KphTerminateProcess( - HANDLE ProcessHandle, - NTSTATUS ExitStatus + __in HANDLE ProcessHandle, + __in NTSTATUS ExitStatus ) { NTSTATUS status = STATUS_SUCCESS; @@ -658,8 +734,8 @@ NTSTATUS KphTerminateProcess( * Terminates the specified thread. */ NTSTATUS KphTerminateThread( - HANDLE ThreadHandle, - NTSTATUS ExitStatus + __in HANDLE ThreadHandle, + __in NTSTATUS ExitStatus ) { NTSTATUS status = STATUS_SUCCESS; @@ -700,8 +776,8 @@ NTSTATUS KphTerminateThread( * with STATUS_NOT_SUPPORTED. */ NTSTATUS PsTerminateProcess( - PEPROCESS Process, - NTSTATUS ExitStatus + __in PEPROCESS Process, + __in NTSTATUS ExitStatus ) { PVOID psTerminateProcess = __PsTerminateProcess; @@ -749,8 +825,8 @@ NTSTATUS PsTerminateProcess( * could not be located, the call will fail with STATUS_NOT_SUPPORTED. */ NTSTATUS PspTerminateThreadByPointer( - PETHREAD Thread, - NTSTATUS ExitStatus + __in PETHREAD Thread, + __in NTSTATUS ExitStatus ) { PVOID pspTerminateThreadByPointer = __PspTerminateThreadByPointer; diff --git a/trunk/KProcessHacker/se.c b/trunk/KProcessHacker/se.c index 5cef9e479..ba8b74503 100644 --- a/trunk/KProcessHacker/se.c +++ b/trunk/KProcessHacker/se.c @@ -28,11 +28,11 @@ * Opens the primary token of the specified process. */ NTSTATUS KphOpenProcessTokenEx( - HANDLE ProcessHandle, - ACCESS_MASK DesiredAccess, - ULONG ObjectAttributes, - PHANDLE TokenHandle, - KPROCESSOR_MODE AccessMode + __in HANDLE ProcessHandle, + __in ACCESS_MASK DesiredAccess, + __in ULONG ObjectAttributes, + __out PHANDLE TokenHandle, + __in KPROCESSOR_MODE AccessMode ) { NTSTATUS status = STATUS_SUCCESS; diff --git a/trunk/KProcessHacker/sync.c b/trunk/KProcessHacker/sync.c index 5ba783e26..17297eebd 100644 --- a/trunk/KProcessHacker/sync.c +++ b/trunk/KProcessHacker/sync.c @@ -24,14 +24,14 @@ #include "include/debug.h" ULONG KphpCountBits( - ULONG_PTR Number + __in ULONG_PTR Number ); VOID KphpProcessorLockDpc( - PKDPC Dpc, - PVOID DeferredContext, - PVOID SystemArgument1, - PVOID SystemArgument2 + __in PKDPC Dpc, + __in PVOID DeferredContext, + __in PVOID SystemArgument1, + __in PVOID SystemArgument2 ); /* KphAcquireProcessorLock @@ -65,7 +65,7 @@ VOID KphpProcessorLockDpc( * IRQL: <= APC_LEVEL */ BOOLEAN KphAcquireProcessorLock( - PKPH_PROCESSOR_LOCK ProcessorLock + __inout PKPH_PROCESSOR_LOCK ProcessorLock ) { ULONG i; @@ -148,7 +148,7 @@ BOOLEAN KphAcquireProcessorLock( * IRQL: Any */ VOID KphInitializeProcessorLock( - PKPH_PROCESSOR_LOCK ProcessorLock + __out PKPH_PROCESSOR_LOCK ProcessorLock ) { ExInitializeFastMutex(&ProcessorLock->Mutex); @@ -181,7 +181,7 @@ VOID KphInitializeProcessorLock( * IRQL: DISPATCH_LEVEL */ VOID KphReleaseProcessorLock( - PKPH_PROCESSOR_LOCK ProcessorLock + __inout PKPH_PROCESSOR_LOCK ProcessorLock ) { if (!ProcessorLock->Acquired) @@ -225,7 +225,7 @@ VOID KphReleaseProcessorLock( * Counts the number of bits set in an integer. */ ULONG KphpCountBits( - ULONG_PTR Number + __in ULONG_PTR Number ) { ULONG count = 0; @@ -247,10 +247,10 @@ ULONG KphpCountBits( * IRQL: DISPATCH_LEVEL */ VOID KphpProcessorLockDpc( - PKDPC Dpc, - PVOID DeferredContext, - PVOID SystemArgument1, - PVOID SystemArgument2 + __in PKDPC Dpc, + __in PVOID DeferredContext, + __in PVOID SystemArgument1, + __in PVOID SystemArgument2 ) { PKPH_PROCESSOR_LOCK processorLock = (PKPH_PROCESSOR_LOCK)SystemArgument1; diff --git a/trunk/ProcessHacker.Native/Api/NativeEnums.cs b/trunk/ProcessHacker.Native/Api/NativeEnums.cs index 764a19031..9e0f77bfc 100644 --- a/trunk/ProcessHacker.Native/Api/NativeEnums.cs +++ b/trunk/ProcessHacker.Native/Api/NativeEnums.cs @@ -145,7 +145,8 @@ namespace ProcessHacker.Native.Api public enum HandleFlags : byte { ProtectFromClose = 0x1, - Inherit = 0x2 + Inherit = 0x2, + AuditObjectClose = 0x4 } [Flags] diff --git a/trunk/ProcessHacker.Native/KProcessHacker.cs b/trunk/ProcessHacker.Native/KProcessHacker.cs index 124194c54..b48104a38 100644 --- a/trunk/ProcessHacker.Native/KProcessHacker.cs +++ b/trunk/ProcessHacker.Native/KProcessHacker.cs @@ -81,7 +81,9 @@ namespace ProcessHacker.Native ProtectRemove, ProtectQuery, KphUnsafeReadVirtualMemory, - SetExecuteOptions + SetExecuteOptions, + KphQueryProcessHandles, + KphOpenThreadProcess } [Flags] @@ -437,6 +439,39 @@ namespace ProcessHacker.Native return *(int*)outData; } + public int KphOpenThreadProcess(ThreadHandle threadHandle, ProcessAccess desiredAccess) + { + byte* inData = stackalloc byte[8]; + byte* outData = stackalloc byte[4]; + + *(int*)inData = threadHandle; + *(uint*)(inData + 4) = (uint)desiredAccess; + + _fileHandle.IoControl(CtlCode(Control.KphOpenThreadProcess), inData, 8, outData, 4); + + return *(int*)outData; + } + + public void KphQueryProcessHandles(ProcessHandle processHandle, IntPtr buffer, int bufferLength, out int returnLength) + { + byte* inData = stackalloc byte[0x10]; + int returnLengthLocal; + + *(int*)inData = processHandle; + *(int*)(inData + 0x4) = buffer.ToInt32(); + *(int*)(inData + 0x8) = bufferLength; + *(int*)(inData + 0xc) = (int)&returnLengthLocal; + + try + { + _fileHandle.IoControl(CtlCode(Control.KphQueryProcessHandles), inData, 0x10, null, 0); + } + finally + { + returnLength = returnLengthLocal; + } + } + public void KphReadVirtualMemory(ProcessHandle processHandle, int baseAddress, byte[] buffer, int length, out int bytesRead) { fixed (byte* bufferPointer = buffer) @@ -586,8 +621,14 @@ namespace ProcessHacker.Native *(int*)(inData + 0xc) = length; *(int*)(inData + 0x10) = (int)&returnLength; - _fileHandle.IoControl(CtlCode(Control.KphWriteVirtualMemory), inData, 0x14, null, 0); - bytesWritten = returnLength; + try + { + _fileHandle.IoControl(CtlCode(Control.KphWriteVirtualMemory), inData, 0x14, null, 0); + } + finally + { + bytesWritten = returnLength; + } } public void ProtectAdd(ProcessHandle processHandle, bool allowKernelMode, ProcessAccess ProcessAllowMask, ThreadAccess ThreadAllowMask) @@ -732,4 +773,20 @@ namespace ProcessHacker.Native return status; } } + + public struct ProcessHandleInformation + { + public IntPtr Handle; + public IntPtr Object; + public int GrantedAccess; + public HandleFlags HandleAttributes; // should be an int + private byte Pad1; + private short Pad2; + + private void Dummy() + { + Pad1 = 0; + Pad2 = 0; + } + } } diff --git a/trunk/ProcessHacker.Native/Objects/ProcessHandle.cs b/trunk/ProcessHacker.Native/Objects/ProcessHandle.cs index e5c96c64e..b9dc773c4 100644 --- a/trunk/ProcessHacker.Native/Objects/ProcessHandle.cs +++ b/trunk/ProcessHacker.Native/Objects/ProcessHandle.cs @@ -222,6 +222,19 @@ namespace ProcessHacker.Native.Objects : this(pid, ProcessAccess.All) { } + /// + /// Opens a thread's process. + /// + /// A handle to a thread. + /// The desired access to the process. + public ProcessHandle(ThreadHandle threadHandle, ProcessAccess access) + { + if (KProcessHacker.Instance == null) + throw new NotSupportedException(); + + this.Handle = new IntPtr(KProcessHacker.Instance.KphOpenThreadProcess(threadHandle, access)); + } + /// /// Opens a process. /// @@ -842,6 +855,50 @@ namespace ProcessHacker.Native.Objects return this.GetInformationInt32(ProcessInformationClass.ProcessHandleCount); } + /// + /// Gets the handles owned by the process. + /// + /// An array of handle information structures. + public ProcessHandleInformation[] GetHandles() + { + int returnLength = 0; + int attempts = 0; + + using (var data = new MemoryAlloc(0x1000)) + { + while (true) + { + try + { + KProcessHacker.Instance.KphQueryProcessHandles(this, data, data.Size, out returnLength); + } + catch (WindowsException ex) + { + if (attempts > 3) + throw ex; + + if ( + ex.Status == NtStatus.BufferTooSmall && + returnLength > data.Size + ) + data.Resize(returnLength); + + attempts++; + + continue; + } + + int handleCount = data.ReadInt32(0); + ProcessHandleInformation[] handles = new ProcessHandleInformation[handleCount]; + + for (int i = 0; i < handleCount; i++) + handles[i] = data.ReadStruct(4, i); + + return handles; + } + } + } + /// /// Gets the file name of the process' image. This requires the /// PROCESS_QUERY_LIMITED_INFORMATION permission. @@ -1156,6 +1213,11 @@ namespace ProcessHacker.Native.Objects this.ReadMemory(stringAddr, stringLength)).TrimEnd('\0'); } + /// + /// Gets the command line used to start the process. This + /// function is only valid for POSIX processes. + /// + /// A command line string. public unsafe string GetPosixCommandLine() { byte* buffer = stackalloc byte[IntPtr.Size]; @@ -1814,7 +1876,7 @@ namespace ProcessHacker.Native.Objects /// Idle, /// - /// NT Kernel & System. + /// NT Kernel & System. /// System, /// diff --git a/trunk/ProcessHacker.Native/Objects/ThreadHandle.cs b/trunk/ProcessHacker.Native/Objects/ThreadHandle.cs index 4e1e7a75b..c349e6853 100644 --- a/trunk/ProcessHacker.Native/Objects/ThreadHandle.cs +++ b/trunk/ProcessHacker.Native/Objects/ThreadHandle.cs @@ -417,6 +417,15 @@ namespace ProcessHacker.Native.Objects return (ThreadPriorityLevel)priority; } + /// + /// Opens the thread's process. + /// + /// A process handle. + public ProcessHandle GetProcess(ProcessAccess access) + { + return new ProcessHandle(this, access); + } + /// /// Opens and returns a handle to the thread's token. /// diff --git a/trunk/ProcessHacker.Native/Security/SecurityDescriptor.cs b/trunk/ProcessHacker.Native/Security/SecurityDescriptor.cs index ec25e2e31..9f3342f2f 100644 --- a/trunk/ProcessHacker.Native/Security/SecurityDescriptor.cs +++ b/trunk/ProcessHacker.Native/Security/SecurityDescriptor.cs @@ -10,7 +10,6 @@ namespace ProcessHacker.Native.Security public class SecurityDescriptor : BaseObject { private object _disposeLock = new object(); - private bool _disposed = false; private MemoryAlloc _sd; public static implicit operator IntPtr(SecurityDescriptor securityDescriptor) diff --git a/trunk/ProcessHacker.Native/Windows.cs b/trunk/ProcessHacker.Native/Windows.cs index a5f7b84b8..d7525df27 100644 --- a/trunk/ProcessHacker.Native/Windows.cs +++ b/trunk/ProcessHacker.Native/Windows.cs @@ -383,7 +383,7 @@ namespace ProcessHacker.Native } } - returnProcesses = new Dictionary(); + returnProcesses = new Dictionary(32); // 32 processes on a computer? int i = 0; SystemProcess currentProcess = new SystemProcess(); @@ -494,14 +494,14 @@ namespace ProcessHacker.Native using (MemoryAlloc data = new MemoryAlloc(requiredSize)) { - var dictionary = new Dictionary(); - if (!Win32.EnumServicesStatusEx(manager, IntPtr.Zero, ServiceQueryType.Win32 | ServiceQueryType.Driver, ServiceQueryState.All, data, data.Size, out requiredSize, out servicesReturned, ref resume, null)) Win32.ThrowLastError(); + var dictionary = new Dictionary(servicesReturned); + for (int i = 0; i < servicesReturned; i++) { var service = data.ReadStruct(i); diff --git a/trunk/ProcessHacker/Common/PhUtils.cs b/trunk/ProcessHacker/Common/PhUtils.cs index 6e4df47b9..666db1dd8 100644 --- a/trunk/ProcessHacker/Common/PhUtils.cs +++ b/trunk/ProcessHacker/Common/PhUtils.cs @@ -28,6 +28,7 @@ using ProcessHacker.Native; using ProcessHacker.Native.Api; using ProcessHacker.Native.Objects; using ProcessHacker.UI; +using System.Drawing; namespace ProcessHacker.Common { @@ -96,6 +97,14 @@ namespace ProcessHacker.Common return false; } + public static Color GetForeColor(Color backColor) + { + if (backColor.GetBrightness() > 0.4) + return Color.Black; + else + return Color.White; + } + /// /// Selects all of the specified nodes. /// diff --git a/trunk/ProcessHacker/Components/ProcessTree/ProcessTree.cs b/trunk/ProcessHacker/Components/ProcessTree/ProcessTree.cs index 7eb29a443..32bb015cc 100644 --- a/trunk/ProcessHacker/Components/ProcessTree/ProcessTree.cs +++ b/trunk/ProcessHacker/Components/ProcessTree/ProcessTree.cs @@ -297,14 +297,6 @@ namespace ProcessHacker return SystemColors.Window; } - private Color GetForeColor(Color backColor) - { - if (backColor.GetBrightness() > 0.4) - return Color.Black; - else - return Color.White; - } - private void provider_DictionaryAdded(ProcessItem item) { this.BeginInvoke(new MethodInvoker(delegate @@ -329,7 +321,6 @@ namespace ProcessHacker } node.BackColor = this.GetProcessColor(item); - node.ForeColor = this.GetForeColor(node.BackColor); node.ExpandAll(); } } @@ -347,7 +338,6 @@ namespace ProcessHacker if (node != null) { node.BackColor = this.GetProcessColor(newItem); - node.ForeColor = this.GetForeColor(node.BackColor); } _treeModel.Nodes[newItem.Pid].ProcessItem = newItem; @@ -410,7 +400,6 @@ namespace ProcessHacker ProcessItem item = _provider.Dictionary[pNode.Pid]; node.BackColor = this.GetProcessColor(item); - node.ForeColor = this.GetForeColor(node.BackColor); } } catch (Exception ex) diff --git a/trunk/ProcessHacker/Forms/HiddenProcessesWindow.Designer.cs b/trunk/ProcessHacker/Forms/HiddenProcessesWindow.Designer.cs index 7b7845ef0..1a4b03ced 100644 --- a/trunk/ProcessHacker/Forms/HiddenProcessesWindow.Designer.cs +++ b/trunk/ProcessHacker/Forms/HiddenProcessesWindow.Designer.cs @@ -38,6 +38,7 @@ this.buttonTerminate = new System.Windows.Forms.Button(); this.buttonSave = new System.Windows.Forms.Button(); this.labelCount = new System.Windows.Forms.Label(); + this.comboMethod = new System.Windows.Forms.ComboBox(); this.SuspendLayout(); // // listProcesses @@ -50,10 +51,10 @@ this.columnPID}); this.listProcesses.FullRowSelect = true; this.listProcesses.HideSelection = false; - this.listProcesses.Location = new System.Drawing.Point(12, 55); + this.listProcesses.Location = new System.Drawing.Point(12, 44); this.listProcesses.Name = "listProcesses"; this.listProcesses.ShowItemToolTips = true; - this.listProcesses.Size = new System.Drawing.Size(487, 282); + this.listProcesses.Size = new System.Drawing.Size(487, 296); this.listProcesses.Sorting = System.Windows.Forms.SortOrder.Ascending; this.listProcesses.TabIndex = 0; this.listProcesses.UseCompatibleStateImageBehavior = false; @@ -73,7 +74,7 @@ // this.buttonClose.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.buttonClose.FlatStyle = System.Windows.Forms.FlatStyle.System; - this.buttonClose.Location = new System.Drawing.Point(424, 358); + this.buttonClose.Location = new System.Drawing.Point(424, 361); this.buttonClose.Name = "buttonClose"; this.buttonClose.Size = new System.Drawing.Size(75, 23); this.buttonClose.TabIndex = 1; @@ -85,7 +86,7 @@ // this.buttonScan.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.buttonScan.FlatStyle = System.Windows.Forms.FlatStyle.System; - this.buttonScan.Location = new System.Drawing.Point(343, 358); + this.buttonScan.Location = new System.Drawing.Point(343, 361); this.buttonScan.Name = "buttonScan"; this.buttonScan.Size = new System.Drawing.Size(75, 23); this.buttonScan.TabIndex = 1; @@ -100,16 +101,17 @@ this.label2.AutoEllipsis = true; this.label2.Location = new System.Drawing.Point(12, 9); this.label2.Name = "label2"; - this.label2.Size = new System.Drawing.Size(487, 43); + this.label2.Size = new System.Drawing.Size(487, 32); this.label2.TabIndex = 3; - this.label2.Text = resources.GetString("label2.Text"); + this.label2.Text = "Processes highlighted red are hidden while those highlighted gray have terminated" + + " but are still being referenced by other processes."; // // buttonTerminate // this.buttonTerminate.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.buttonTerminate.Enabled = false; this.buttonTerminate.FlatStyle = System.Windows.Forms.FlatStyle.System; - this.buttonTerminate.Location = new System.Drawing.Point(181, 358); + this.buttonTerminate.Location = new System.Drawing.Point(181, 361); this.buttonTerminate.Name = "buttonTerminate"; this.buttonTerminate.Size = new System.Drawing.Size(75, 23); this.buttonTerminate.TabIndex = 4; @@ -121,7 +123,7 @@ // this.buttonSave.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.buttonSave.FlatStyle = System.Windows.Forms.FlatStyle.System; - this.buttonSave.Location = new System.Drawing.Point(262, 358); + this.buttonSave.Location = new System.Drawing.Point(262, 361); this.buttonSave.Name = "buttonSave"; this.buttonSave.Size = new System.Drawing.Size(75, 23); this.buttonSave.TabIndex = 5; @@ -133,18 +135,33 @@ // this.labelCount.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); - this.labelCount.Location = new System.Drawing.Point(12, 340); + this.labelCount.Location = new System.Drawing.Point(12, 343); this.labelCount.Name = "labelCount"; this.labelCount.Size = new System.Drawing.Size(487, 15); this.labelCount.TabIndex = 6; this.labelCount.Text = "Count"; this.labelCount.TextAlign = System.Drawing.ContentAlignment.TopRight; // + // comboMethod + // + this.comboMethod.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.comboMethod.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.comboMethod.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.comboMethod.FormattingEnabled = true; + this.comboMethod.Items.AddRange(new object[] { + "Brute Force", + "CSR Handles"}); + this.comboMethod.Location = new System.Drawing.Point(12, 363); + this.comboMethod.Name = "comboMethod"; + this.comboMethod.Size = new System.Drawing.Size(121, 21); + this.comboMethod.TabIndex = 7; + // // HiddenProcessesWindow // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(511, 393); + this.ClientSize = new System.Drawing.Size(511, 396); + this.Controls.Add(this.comboMethod); this.Controls.Add(this.labelCount); this.Controls.Add(this.buttonSave); this.Controls.Add(this.buttonTerminate); @@ -174,5 +191,6 @@ private System.Windows.Forms.Button buttonTerminate; private System.Windows.Forms.Button buttonSave; private System.Windows.Forms.Label labelCount; + private System.Windows.Forms.ComboBox comboMethod; } } \ No newline at end of file diff --git a/trunk/ProcessHacker/Forms/HiddenProcessesWindow.cs b/trunk/ProcessHacker/Forms/HiddenProcessesWindow.cs index e13c64bea..672a2cf9c 100644 --- a/trunk/ProcessHacker/Forms/HiddenProcessesWindow.cs +++ b/trunk/ProcessHacker/Forms/HiddenProcessesWindow.cs @@ -21,6 +21,7 @@ */ using System; +using System.Collections.Generic; using System.Drawing; using System.IO; using System.Windows.Forms; @@ -28,6 +29,7 @@ using ProcessHacker.Common; using ProcessHacker.Common.Ui; using ProcessHacker.Native; using ProcessHacker.Native.Objects; +using ProcessHacker.Native.Security; using ProcessHacker.UI; namespace ProcessHacker @@ -44,6 +46,7 @@ namespace ProcessHacker listProcesses.SetDoubleBuffered(true); listProcesses.SetTheme("explorer"); + comboMethod.SelectedItem = "CSR Handles"; labelCount.Text = ""; } @@ -68,7 +71,75 @@ namespace ProcessHacker } } - private void Scan() + private void AddProcessItem( + ProcessHandle phandle, + int pid, + ref int totalCount, ref int hiddenCount, ref int terminatedCount, + Func exists + ) + { + string fileName = phandle.GetNativeImageFileName(); + + if (fileName != null) + fileName = FileUtils.DeviceFileNameToDos(fileName); + + if (pid == 0) + pid = phandle.GetBasicInformation().UniqueProcessId; + + var item = listProcesses.Items.Add(new ListViewItem(new string[] + { + fileName, + pid.ToString() + })); + + // Check if the process has terminated. This is possible because + // a process can be terminated while its object is still being + // referenced. + long exitTime = -1; + + try { exitTime = phandle.GetExitTime(); } + catch { } + + if (exitTime != 0) + { + item.BackColor = Color.DarkGray; + item.ForeColor = Color.White; + terminatedCount++; + } + else + { + totalCount++; + + if (!exists(pid)) + { + item.BackColor = Color.Red; + item.ForeColor = Color.White; + hiddenCount++; + } + } + } + + private void AddErrorItem( + WindowsException ex, + int pid, + ref int totalCount, ref int hiddenCount, ref int terminatedCount + ) + { + if (ex.ErrorCode == 87) // ERROR_INVALID_PARAMETER + return; + + var item = listProcesses.Items.Add(new ListViewItem(new string[] + { + "(" + ex.Message + ")", + pid.ToString() + })); + + item.BackColor = Color.Red; + item.ForeColor = Color.White; + totalCount++; + } + + private void ScanBruteForce() { this.Cursor = Cursors.WaitCursor; listProcesses.BeginUpdate(); @@ -83,60 +154,17 @@ namespace ProcessHacker { try { - var phandle = new ProcessHandle(pid, Program.MinProcessQueryRights); - string fileName = phandle.GetNativeImageFileName(); - - if (fileName != null) - fileName = FileUtils.DeviceFileNameToDos(fileName); - - var item = listProcesses.Items.Add(new ListViewItem(new string[] - { - fileName, - pid.ToString() - })); - - // Check if the process has terminated. This is possible because - // a process can be terminated while its object is still being - // referenced. - long exitTime = -1; - - try { exitTime = phandle.GetExitTime(); } - catch { } - - if (exitTime != 0) - { - item.BackColor = Color.DarkGray; - item.ForeColor = Color.White; - terminatedCount++; - } - else - { - totalCount++; - - if (!processes.ContainsKey(pid)) - { - item.BackColor = Color.Red; - item.ForeColor = Color.White; - hiddenCount++; - } - } - - phandle.Dispose(); + using (var phandle = new ProcessHandle(pid, Program.MinProcessQueryRights)) + AddProcessItem( + phandle, + pid, + ref totalCount, ref hiddenCount, ref terminatedCount, + (pid_) => processes.ContainsKey(pid_) + ); } catch (WindowsException ex) { - if (ex.ErrorCode == 87) // ERROR_INVALID_PARAMETER - continue; - - var item = listProcesses.Items.Add(new ListViewItem(new string[] - { - "(" + ex.Message + ")", - pid.ToString() - })); - - item.BackColor = Color.Red; - item.ForeColor = Color.White; - totalCount++; + AddErrorItem(ex, pid, ref totalCount, ref hiddenCount, ref terminatedCount); } } @@ -152,6 +180,240 @@ namespace ProcessHacker this.Cursor = Cursors.Default; } + private void ScanCsrHandles() + { + this.Cursor = Cursors.WaitCursor; + listProcesses.BeginUpdate(); + listProcesses.Items.Clear(); + + try + { + var processes = Windows.GetProcesses(); + int totalCount = 0; + int hiddenCount = 0; + int terminatedCount = 0; + + processes.Remove(0); + + List foundPids = new List(); + + var csrProcesses = this.GetCsrProcesses(); + + // Duplicate each process handle and check if they exist in the normal list. + foreach (var csrhandle in csrProcesses) + { + try + { + var handles = csrhandle.GetHandles(); + + foreach (var handle in handles) + { + int pid = 0; + bool isThread = false; + + try + { + pid = KProcessHacker.Instance.KphGetProcessId(csrhandle, handle.Handle); + + // HACK: Using exception for program flow! + if (pid == 0) + throw new Exception(); + } + catch + { + // Probably not a process handle. + // Try opening it as a thread. + try + { + int tid = KProcessHacker.Instance.KphGetThreadId(csrhandle, handle.Handle, out pid); + isThread = true; + + if (tid == 0) + throw new Exception(); + } + catch + { + continue; + } + } + + // Avoid duplicate PIDs. + if (foundPids.Contains(pid)) + continue; + + foundPids.Add(pid); + + try + { + ProcessHandle phandle; + + if (!isThread) + { + var dupHandle = + new NativeHandle(csrhandle, + handle.Handle, + Program.MinProcessQueryRights); + phandle = ProcessHandle.FromHandle(dupHandle); + } + else + { + using (var dupHandle = + new NativeHandle(csrhandle, + handle.Handle, + Program.MinThreadQueryRights)) + phandle = ThreadHandle.FromHandle(dupHandle). + GetProcess(Program.MinProcessQueryRights); + } + + AddProcessItem( + phandle, + pid, + ref totalCount, ref hiddenCount, ref terminatedCount, + (pid_) => processes.ContainsKey(pid_) + ); + phandle.Dispose(); + } + catch (WindowsException ex2) + { + AddErrorItem(ex2, pid, ref totalCount, ref hiddenCount, ref terminatedCount); + } + } + } + catch (Exception ex) + { + PhUtils.ShowMessage("Error getting the CSR handle list", ex); + return; + } + + csrhandle.Dispose(); + } + + labelCount.Text = totalCount.ToString() + " running processes (excl. kernel, idle, non-Windows), " + + hiddenCount.ToString() + " hidden, " + terminatedCount.ToString() + " terminated."; + + if (hiddenCount > 0) + labelCount.ForeColor = Color.Red; + else + labelCount.ForeColor = SystemColors.WindowText; + } + finally + { + listProcesses.EndUpdate(); + this.Cursor = Cursors.Default; + } + } + + private List GetCsrProcesses() + { + List csrProcesses = new List(); + + try + { + foreach (var process in Windows.GetProcesses()) + { + if (process.Key <= 4) + continue; + + try + { + var phandle = new ProcessHandle(process.Key, + Program.MinProcessQueryRights | ProcessAccess.DupHandle + ); + + if (phandle.GetKnownProcessType() == KnownProcess.WindowsSubsystem) + csrProcesses.Add(phandle); + else + phandle.Dispose(); + } + catch + { } + } + } + catch (Exception ex) + { + PhUtils.ShowMessage("Error getting the list of CSR processes", ex); + return new List(); + } + + return csrProcesses; + } + + private ProcessHandle OpenProcessCsr(int pid, ProcessAccess access) + { + var csrProcesses = this.GetCsrProcesses(); + + foreach (var csrProcess in csrProcesses) + { + foreach (var handle in csrProcess.GetHandles()) + { + try + { + // Assume that the handle is a process handle. + int handlePid = KProcessHacker.Instance.KphGetProcessId(csrProcess, handle.Handle); + + if (handlePid == pid) + return ProcessHandle.FromHandle( + new NativeHandle(csrProcess, handle.Handle, access) + ); + else if (handlePid == 0) + throw new Exception(); // HACK + } + catch + { + try + { + // Assume that the handle is a thread handle. + int handlePid; + + int tid = KProcessHacker.Instance.KphGetThreadId(csrProcess, handle.Handle, out handlePid); + + if (tid == 0) + throw new Exception(); + + if (handlePid == pid) + { + using (var dupHandle = + new NativeHandle(csrProcess, handle.Handle, Program.MinThreadQueryRights)) + return ThreadHandle.FromHandle(dupHandle).GetProcess(access); + } + } + catch + { } + } + } + + csrProcess.Dispose(); + } + + throw new Exception("Could not find process (hidden from handle table)."); + } + + private ProcessHandle OpenProcess(int pid, ProcessAccess access) + { + switch (comboMethod.SelectedItem.ToString()) + { + case "Brute Force": + return new ProcessHandle(pid, access); + case "CSR Handles": + return this.OpenProcessCsr(pid, access); + } + + return null; + } + + private void Scan() + { + switch (comboMethod.SelectedItem.ToString()) + { + case "Brute Force": + this.ScanBruteForce(); + break; + case "CSR Handles": + this.ScanCsrHandles(); + break; + } + } + private void buttonScan_Click(object sender, EventArgs e) { this.Scan(); @@ -181,8 +443,8 @@ namespace ProcessHacker try { - using (var phandle = - new ProcessHandle(pid, ProcessHacker.Native.Security.ProcessAccess.Terminate)) + using (var phandle = + this.OpenProcess(pid, ProcessAccess.Terminate)) phandle.Terminate(); } catch (Exception ex) @@ -194,6 +456,7 @@ namespace ProcessHacker // Wait a bit to avoid BSODs System.Threading.Thread.Sleep(200); + buttonTerminate.Enabled = false; this.Scan(); } } @@ -226,6 +489,10 @@ namespace ProcessHacker { using (var sw = new StreamWriter(sfd.FileName)) { + sw.WriteLine("Process Hacker Hidden Processes Scan"); + sw.WriteLine("Method: " + comboMethod.SelectedItem.ToString()); + sw.WriteLine(); + foreach (ListViewItem item in listProcesses.Items) { sw.WriteLine( diff --git a/trunk/ProcessHacker/Forms/HiddenProcessesWindow.resx b/trunk/ProcessHacker/Forms/HiddenProcessesWindow.resx index 1f723b438..912b30118 100644 --- a/trunk/ProcessHacker/Forms/HiddenProcessesWindow.resx +++ b/trunk/ProcessHacker/Forms/HiddenProcessesWindow.resx @@ -117,9 +117,6 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - This tool displays the running processes by attempting to open PIDs sequentially from 8 to 65536. Processes highlighted red are hidden while those highlighted gray have terminated but are still being referenced by other processes. - diff --git a/trunk/ProcessHacker/UI/HighlightedListViewItem.cs b/trunk/ProcessHacker/UI/HighlightedListViewItem.cs index 83d090539..95f6a5f6b 100644 --- a/trunk/ProcessHacker/UI/HighlightedListViewItem.cs +++ b/trunk/ProcessHacker/UI/HighlightedListViewItem.cs @@ -24,6 +24,7 @@ using System; using System.Collections.Generic; using System.Drawing; using System.Windows.Forms; +using ProcessHacker.Common; namespace ProcessHacker.UI { @@ -167,11 +168,13 @@ namespace ProcessHacker.UI if (HighlightingContext.StateHighlighting && highlight) { this.BackColor = HighlightingContext.Colors[ListViewItemState.New]; + this.ForeColor = PhUtils.GetForeColor(this.BackColor); _state = ListViewItemState.New; _context.Enqueue(delegate { this.BackColor = _normalColor; + this.ForeColor = PhUtils.GetForeColor(this.BackColor); _state = ListViewItemState.Normal; }); } @@ -188,6 +191,7 @@ namespace ProcessHacker.UI _context.EnqueuePre(delegate { this.BackColor = HighlightingContext.Colors[ListViewItemState.Removed]; + this.ForeColor = PhUtils.GetForeColor(this.BackColor); _context.Enqueue(delegate { @@ -214,7 +218,10 @@ namespace ProcessHacker.UI _normalColor = value; if (_state == ListViewItemState.Normal) + { this.BackColor = value; + this.ForeColor = PhUtils.GetForeColor(this.BackColor); + } } } @@ -223,11 +230,13 @@ namespace ProcessHacker.UI _context.EnqueuePre(delegate { this.BackColor = HighlightingContext.Colors[state]; + this.ForeColor = PhUtils.GetForeColor(this.BackColor); _state = state; _context.Enqueue(delegate { this.BackColor = _normalColor; + this.ForeColor = PhUtils.GetForeColor(this.BackColor); _state = ListViewItemState.Normal; }); }); diff --git a/trunk/TreeViewAdv/Tree/NodeControls/BaseTextControl.cs b/trunk/TreeViewAdv/Tree/NodeControls/BaseTextControl.cs index bd4e57aa5..dda18cf8d 100644 --- a/trunk/TreeViewAdv/Tree/NodeControls/BaseTextControl.cs +++ b/trunk/TreeViewAdv/Tree/NodeControls/BaseTextControl.cs @@ -225,9 +225,7 @@ namespace Aga.Controls.Tree.NodeControls } else if (context.DrawSelection == DrawSelectionMode.Inactive) { - //textColor = SystemColors.ControlText; - // wj32: respect node ForeColor - textColor = node.ForeColor; + textColor = SystemColors.ControlText; backgroundBrush = SystemBrushes.InactiveBorder; } else if (context.DrawSelection == DrawSelectionMode.FullRowSelect) diff --git a/trunk/TreeViewAdv/Tree/TreeNodeAdv.cs b/trunk/TreeViewAdv/Tree/TreeNodeAdv.cs index dba20e931..1c42dbca6 100644 --- a/trunk/TreeViewAdv/Tree/TreeNodeAdv.cs +++ b/trunk/TreeViewAdv/Tree/TreeNodeAdv.cs @@ -112,7 +112,12 @@ namespace Aga.Controls.Tree public NodeState State { get { return _state; } - set { _state = value; } + set + { + _state = value; + if (_automaticForeColor) + _autoForeColor = GetForeColor(this.BackColor); + } } private Color _backColor = SystemColors.Window; @@ -125,16 +130,48 @@ namespace Aga.Controls.Tree else return _backColor; } - set { _backColor = value; } + set + { + _backColor = value; + if (_automaticForeColor) + _autoForeColor = GetForeColor(this.BackColor); + } } + private Color _autoForeColor = Color.Black; private Color _foreColor = SystemColors.ControlText; public Color ForeColor { - get { return _foreColor; } + get + { + if (_automaticForeColor) + return _autoForeColor; + else + return _foreColor; + } set { _foreColor = value; } } + private bool _automaticForeColor = true; + public bool AutomaticForeColor + { + get { return _automaticForeColor; } + set + { + _automaticForeColor = value; + if (_automaticForeColor) + _autoForeColor = GetForeColor(this.BackColor); + } + } + + public static Color GetForeColor(Color color) + { + if (color.GetBrightness() > 0.4) + return Color.Black; + else + return Color.White; + } + private bool _isSelected; public bool IsSelected {