mirror of
https://github.com/mirror/processhacker
synced 2026-06-08 16:03:24 +00:00
* added KphQueryProcessHandles
* added KphOpenThreadProcess * hidden processes scanner can now detect FUTo * KPH cleanup - added argument attributes * improved auto-ForeColor git-svn-id: svn://svn.code.sf.net/p/processhacker/code@1436 21ef857c-d57f-4fe0-8362-d861dc6d29cd
This commit is contained in:
@@ -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
|
||||
|
||||
+26
-26
@@ -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)
|
||||
|
||||
Binary file not shown.
@@ -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)(
|
||||
|
||||
@@ -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
|
||||
|
||||
+142
-127
@@ -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
|
||||
@@ -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))
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
+12
-12
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
+42
-42
@@ -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;
|
||||
|
||||
+182
-33
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
+116
-40
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
+13
-13
@@ -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;
|
||||
|
||||
@@ -145,7 +145,8 @@ namespace ProcessHacker.Native.Api
|
||||
public enum HandleFlags : byte
|
||||
{
|
||||
ProtectFromClose = 0x1,
|
||||
Inherit = 0x2
|
||||
Inherit = 0x2,
|
||||
AuditObjectClose = 0x4
|
||||
}
|
||||
|
||||
[Flags]
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -222,6 +222,19 @@ namespace ProcessHacker.Native.Objects
|
||||
: this(pid, ProcessAccess.All)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Opens a thread's process.
|
||||
/// </summary>
|
||||
/// <param name="threadHandle">A handle to a thread.</param>
|
||||
/// <param name="access">The desired access to the process.</param>
|
||||
public ProcessHandle(ThreadHandle threadHandle, ProcessAccess access)
|
||||
{
|
||||
if (KProcessHacker.Instance == null)
|
||||
throw new NotSupportedException();
|
||||
|
||||
this.Handle = new IntPtr(KProcessHacker.Instance.KphOpenThreadProcess(threadHandle, access));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens a process.
|
||||
/// </summary>
|
||||
@@ -842,6 +855,50 @@ namespace ProcessHacker.Native.Objects
|
||||
return this.GetInformationInt32(ProcessInformationClass.ProcessHandleCount);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the handles owned by the process.
|
||||
/// </summary>
|
||||
/// <returns>An array of handle information structures.</returns>
|
||||
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<ProcessHandleInformation>(4, i);
|
||||
|
||||
return handles;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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');
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the command line used to start the process. This
|
||||
/// function is only valid for POSIX processes.
|
||||
/// </summary>
|
||||
/// <returns>A command line string.</returns>
|
||||
public unsafe string GetPosixCommandLine()
|
||||
{
|
||||
byte* buffer = stackalloc byte[IntPtr.Size];
|
||||
@@ -1814,7 +1876,7 @@ namespace ProcessHacker.Native.Objects
|
||||
/// </summary>
|
||||
Idle,
|
||||
/// <summary>
|
||||
/// NT Kernel & System.
|
||||
/// NT Kernel & System.
|
||||
/// </summary>
|
||||
System,
|
||||
/// <summary>
|
||||
|
||||
@@ -417,6 +417,15 @@ namespace ProcessHacker.Native.Objects
|
||||
return (ThreadPriorityLevel)priority;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens the thread's process.
|
||||
/// </summary>
|
||||
/// <returns>A process handle.</returns>
|
||||
public ProcessHandle GetProcess(ProcessAccess access)
|
||||
{
|
||||
return new ProcessHandle(this, access);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens and returns a handle to the thread's token.
|
||||
/// </summary>
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -383,7 +383,7 @@ namespace ProcessHacker.Native
|
||||
}
|
||||
}
|
||||
|
||||
returnProcesses = new Dictionary<int, SystemProcess>();
|
||||
returnProcesses = new Dictionary<int, SystemProcess>(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<string, EnumServiceStatusProcess>();
|
||||
|
||||
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<string, EnumServiceStatusProcess>(servicesReturned);
|
||||
|
||||
for (int i = 0; i < servicesReturned; i++)
|
||||
{
|
||||
var service = data.ReadStruct<EnumServiceStatusProcess>(i);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Selects all of the specified nodes.
|
||||
/// </summary>
|
||||
|
||||
@@ -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)
|
||||
|
||||
+28
-10
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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<int, bool> 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<int> foundPids = new List<int>();
|
||||
|
||||
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<ProcessAccess>(csrhandle,
|
||||
handle.Handle,
|
||||
Program.MinProcessQueryRights);
|
||||
phandle = ProcessHandle.FromHandle(dupHandle);
|
||||
}
|
||||
else
|
||||
{
|
||||
using (var dupHandle =
|
||||
new NativeHandle<ThreadAccess>(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<ProcessHandle> GetCsrProcesses()
|
||||
{
|
||||
List<ProcessHandle> csrProcesses = new List<ProcessHandle>();
|
||||
|
||||
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<ProcessHandle>();
|
||||
}
|
||||
|
||||
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<ProcessAccess>(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<ThreadAccess>(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(
|
||||
|
||||
@@ -117,9 +117,6 @@
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="label2.Text" xml:space="preserve">
|
||||
<value>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.</value>
|
||||
</data>
|
||||
<assembly alias="System.Drawing" name="System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
|
||||
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
|
||||
@@ -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;
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user