mirror of
https://github.com/mirror/processhacker
synced 2026-06-08 16:03:24 +00:00
* dynamic PEB offsets
* hooking/unhooking is now completely safe on multi-processor systems git-svn-id: svn://svn.code.sf.net/p/processhacker/code@1303 21ef857c-d57f-4fe0-8362-d861dc6d29cd
This commit is contained in:
+61
-17
@@ -21,6 +21,7 @@
|
||||
*/
|
||||
|
||||
#include "include/hook.h"
|
||||
#include "include/sync.h"
|
||||
|
||||
typedef struct _MAPPED_MDL
|
||||
{
|
||||
@@ -38,10 +39,15 @@ VOID KphpFreeMappedMdl(
|
||||
PMAPPED_MDL MappedMdl
|
||||
);
|
||||
|
||||
static KPH_PROCESSOR_LOCK HookProcessorLock;
|
||||
|
||||
/* KphHook
|
||||
*
|
||||
* Hooks a kernel-mode function.
|
||||
* WARNING: DO NOT HOOK A FUNCTION THAT IS CALLABLE ABOVE PASSIVE_LEVEL.
|
||||
* WARNING: DO NOT HOOK A FUNCTION THAT IS CALLABLE ABOVE APC_LEVEL.
|
||||
*
|
||||
* Thread safety: Full
|
||||
* IRQL: <= APC_LEVEL
|
||||
*/
|
||||
NTSTATUS KphHook(
|
||||
PKPH_HOOK Hook
|
||||
@@ -62,27 +68,49 @@ NTSTATUS KphHook(
|
||||
return status;
|
||||
|
||||
function = (PCHAR)mappedMdl.Address;
|
||||
/* Raise to APC_LEVEL to prevent drivers calling the function while we're patching it. */
|
||||
/* If they do, it's their problem because the function we're patching should only be
|
||||
called at PASSIVE_LEVEL anyway (see hook.h for definition of KPH_HOOK). */
|
||||
KeRaiseIrql(APC_LEVEL, &oldIrql);
|
||||
memcpy(Hook->Bytes, function, 5);
|
||||
Hook->Hooked = TRUE;
|
||||
/* jmp Target */
|
||||
*function = 0xe9;
|
||||
*(PULONG_PTR)(function + 1) = (ULONG_PTR)Hook->Target - (ULONG_PTR)Hook->Function - 5;
|
||||
/* Lower the IRQL back. */
|
||||
KeLowerIrql(oldIrql);
|
||||
|
||||
/* Acquire a lock on all other processors. */
|
||||
if (KphAcquireProcessorLock(&HookProcessorLock))
|
||||
{
|
||||
/* Patch the function. */
|
||||
memcpy(Hook->Bytes, function, 5);
|
||||
Hook->Hooked = TRUE;
|
||||
/* jmp Target */
|
||||
*function = 0xe9;
|
||||
*(PULONG_PTR)(function + 1) = (ULONG_PTR)Hook->Target - (ULONG_PTR)Hook->Function - 5;
|
||||
|
||||
/* Release the processor lock. */
|
||||
KphReleaseProcessorLock(&HookProcessorLock);
|
||||
}
|
||||
else
|
||||
{
|
||||
dprintf("KphHook: Could not acquire processor lock!\n");
|
||||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
KphpFreeMappedMdl(&mappedMdl);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* KphHookInit
|
||||
*
|
||||
* Initializes the hooking module.
|
||||
*/
|
||||
NTSTATUS KphHookInit()
|
||||
{
|
||||
KphInitializeProcessorLock(&HookProcessorLock);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* KphUnhook
|
||||
*
|
||||
* Unhooks a kernel-mode function.
|
||||
* WARNING: DO NOT UNHOOK A FUNCTION THAT IS CALLABLE ABOVE PASSIVE_LEVEL.
|
||||
* WARNING: DO NOT UNHOOK A FUNCTION THAT IS CALLABLE ABOVE APC_LEVEL.
|
||||
*
|
||||
* Thread safety: Full
|
||||
* IRQL: <= APC_LEVEL
|
||||
*/
|
||||
NTSTATUS KphUnhook(
|
||||
PKPH_HOOK Hook
|
||||
@@ -104,10 +132,20 @@ NTSTATUS KphUnhook(
|
||||
if (!NT_SUCCESS(status))
|
||||
return status;
|
||||
|
||||
KeRaiseIrql(APC_LEVEL, &oldIrql);
|
||||
memcpy(mappedMdl.Address, Hook->Bytes, 5);
|
||||
Hook->Hooked = FALSE;
|
||||
KeLowerIrql(oldIrql);
|
||||
/* Acquire a lock on all other processors. */
|
||||
if (KphAcquireProcessorLock(&HookProcessorLock))
|
||||
{
|
||||
/* Unpatch the function. */
|
||||
memcpy(mappedMdl.Address, Hook->Bytes, 5);
|
||||
Hook->Hooked = FALSE;
|
||||
/* Release the processor lock. */
|
||||
KphReleaseProcessorLock(&HookProcessorLock);
|
||||
}
|
||||
else
|
||||
{
|
||||
dprintf("KphUnhook: Could not acquire processor lock!\n");
|
||||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
KphpFreeMappedMdl(&mappedMdl);
|
||||
|
||||
@@ -117,6 +155,9 @@ NTSTATUS KphUnhook(
|
||||
/* KphpCreateMappedMdl
|
||||
*
|
||||
* Creates and maps a MDL.
|
||||
*
|
||||
* Thread safety: Full
|
||||
* IRQL: Any
|
||||
*/
|
||||
NTSTATUS KphpCreateMappedMdl(
|
||||
PVOID Address,
|
||||
@@ -158,6 +199,9 @@ NTSTATUS KphpCreateMappedMdl(
|
||||
/* KphpFreeMappedMdl
|
||||
*
|
||||
* Unmaps and frees a MDL.
|
||||
*
|
||||
* Thread safety: Full
|
||||
* IRQL: Any
|
||||
*/
|
||||
VOID KphpFreeMappedMdl(
|
||||
PMAPPED_MDL MappedMdl
|
||||
|
||||
Binary file not shown.
@@ -20,12 +20,16 @@
|
||||
* along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _DEBUG_H
|
||||
#define _DEBUG_H
|
||||
|
||||
#ifdef DBG
|
||||
#define dprintf(fs, ...) DbgPrint("KProcessHacker: " fs, __VA_ARGS__)
|
||||
#define dfprintf DbgPrint
|
||||
#else
|
||||
#define dprintf
|
||||
#define dfprintf DbgPrint
|
||||
#endif
|
||||
|
||||
#define dfprintf(fs, ...) DbgPrint("KProcessHacker: " fs, __VA_ARGS__)
|
||||
#define dwprintf DbgPrint
|
||||
|
||||
#endif
|
||||
|
||||
@@ -53,6 +53,8 @@ NTSTATUS KphHook(
|
||||
PKPH_HOOK Hook
|
||||
);
|
||||
|
||||
NTSTATUS KphHookInit();
|
||||
|
||||
NTSTATUS KphUnhook(
|
||||
PKPH_HOOK Hook
|
||||
);
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Process Hacker Driver -
|
||||
* synchronization code
|
||||
*
|
||||
* Copyright (C) 2009 wj32
|
||||
*
|
||||
* This file is part of Process Hacker.
|
||||
*
|
||||
* Process Hacker is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Process Hacker is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _SYNC_H
|
||||
#define _SYNC_H
|
||||
|
||||
#include "kprocesshacker.h"
|
||||
|
||||
typedef struct _KPH_PROCESSOR_LOCK
|
||||
{
|
||||
/* Synchronizes access to the processor lock. */
|
||||
FAST_MUTEX Mutex;
|
||||
/* Storage allocated for DPCs. */
|
||||
PKDPC Dpcs;
|
||||
/* The number of currently acquired processors. */
|
||||
LONG AcquiredProcessors;
|
||||
/* The signal for acquired processors to be released. */
|
||||
LONG ReleaseSignal;
|
||||
/* The old IRQL. */
|
||||
KIRQL OldIrql;
|
||||
/* Whether the processor lock has been acquired. */
|
||||
BOOLEAN Acquired;
|
||||
} KPH_PROCESSOR_LOCK, *PKPH_PROCESSOR_LOCK;
|
||||
|
||||
BOOLEAN KphAcquireProcessorLock(
|
||||
PKPH_PROCESSOR_LOCK ProcessorLock
|
||||
);
|
||||
|
||||
VOID KphInitializeProcessorLock(
|
||||
PKPH_PROCESSOR_LOCK ProcessorLock
|
||||
);
|
||||
|
||||
VOID KphReleaseProcessorLock(
|
||||
PKPH_PROCESSOR_LOCK ProcessorLock
|
||||
);
|
||||
|
||||
#endif
|
||||
@@ -34,10 +34,11 @@ typedef struct _KPH_CLIENT_ENTRY
|
||||
HANDLE ProcessId;
|
||||
} KPH_CLIENT_ENTRY, *PKPH_CLIENT_ENTRY;
|
||||
|
||||
LIST_ENTRY ClientListHead;
|
||||
KSPIN_LOCK ClientListLock;
|
||||
NPAGED_LOOKASIDE_LIST ClientLookasideList;
|
||||
static LIST_ENTRY ClientListHead;
|
||||
static KSPIN_LOCK ClientListLock;
|
||||
static NPAGED_LOOKASIDE_LIST ClientLookasideList;
|
||||
static BOOLEAN ProtectionInitialized = FALSE;
|
||||
static FAST_MUTEX ProtectionMutex;
|
||||
|
||||
#pragma alloc_text(PAGE, KphDispatchCreate)
|
||||
#pragma alloc_text(PAGE, KphDispatchClose)
|
||||
@@ -83,6 +84,9 @@ NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
|
||||
0
|
||||
);
|
||||
|
||||
/* Initialize process protection. */
|
||||
ExInitializeFastMutex(&ProtectionMutex);
|
||||
|
||||
RtlInitUnicodeString(&deviceName, KPH_DEVICE_NAME);
|
||||
RtlInitUnicodeString(&dosDeviceName, KPH_DEVICE_DOS_NAME);
|
||||
|
||||
@@ -121,12 +125,16 @@ VOID DriverUnload(PDRIVER_OBJECT DriverObject)
|
||||
/* Destroy client list structures */
|
||||
ExDeleteNPagedLookasideList(&ClientLookasideList);
|
||||
|
||||
ExAcquireFastMutex(&ProtectionMutex);
|
||||
|
||||
if (ProtectionInitialized)
|
||||
{
|
||||
KphProtectDeinit();
|
||||
ProtectionInitialized = FALSE;
|
||||
}
|
||||
|
||||
ExReleaseFastMutex(&ProtectionMutex);
|
||||
|
||||
dprintf("Driver unloaded\n");
|
||||
}
|
||||
|
||||
@@ -161,12 +169,16 @@ NTSTATUS KphDispatchClose(PDEVICE_OBJECT DeviceObject, PIRP Irp)
|
||||
{
|
||||
NTSTATUS status = STATUS_SUCCESS;
|
||||
|
||||
ExAcquireFastMutex(&ProtectionMutex);
|
||||
|
||||
if (ProtectionInitialized)
|
||||
{
|
||||
ULONG count = KphProtectRemoveByTag(PsGetCurrentProcessId());
|
||||
dprintf("Removed %d protection entries\n", count);
|
||||
}
|
||||
|
||||
ExReleaseFastMutex(&ProtectionMutex);
|
||||
|
||||
/* Remove the client entry. */
|
||||
RemoveClientEntry(PsGetCurrentProcessId());
|
||||
|
||||
@@ -177,11 +189,15 @@ NTSTATUS KphDispatchClose(PDEVICE_OBJECT DeviceObject, PIRP Irp)
|
||||
|
||||
VOID InitProtection()
|
||||
{
|
||||
ExAcquireFastMutex(&ProtectionMutex);
|
||||
|
||||
if (!ProtectionInitialized)
|
||||
{
|
||||
KphProtectInit();
|
||||
ProtectionInitialized = TRUE;
|
||||
if (NT_SUCCESS(KphProtectInit()))
|
||||
ProtectionInitialized = TRUE;
|
||||
}
|
||||
|
||||
ExReleaseFastMutex(&ProtectionMutex);
|
||||
}
|
||||
|
||||
BOOLEAN AddClientEntry(HANDLE ProcessId)
|
||||
|
||||
@@ -22,38 +22,38 @@
|
||||
|
||||
#include "include/protect.h"
|
||||
|
||||
/* ProtectedProcessRundownProtect
|
||||
*
|
||||
* Rundown protection making sure this module doesn't deinitialize before all hook targets
|
||||
* have finished executing and no one is accessing the lookaside list.
|
||||
*/
|
||||
EX_RUNDOWN_REF ProtectedProcessRundownProtect;
|
||||
/* ProtectedProcessListHead
|
||||
*
|
||||
* The head of the process protection linked list. Each entry stores protection
|
||||
* information for a process.
|
||||
*/
|
||||
LIST_ENTRY ProtectedProcessListHead;
|
||||
/* ProtectedProcessListLock
|
||||
*
|
||||
* The spinlock which protects all accesses to the protected process list (even
|
||||
* the individual entries)
|
||||
*/
|
||||
KSPIN_LOCK ProtectedProcessListLock;
|
||||
/* ProtectedProcessLookasideList
|
||||
*
|
||||
* The lookaside list for protected process entries.
|
||||
*/
|
||||
NPAGED_LOOKASIDE_LIST ProtectedProcessLookasideList;
|
||||
|
||||
KPH_HOOK ObOpenObjectByPointerHook = { 0 };
|
||||
|
||||
BOOLEAN KphpIsCurrentProcessProtected();
|
||||
|
||||
VOID KphpProtectRemoveEntry(
|
||||
PKPH_PROCESS_ENTRY Entry
|
||||
);
|
||||
|
||||
/* ProtectedProcessRundownProtect
|
||||
*
|
||||
* Rundown protection making sure this module doesn't deinitialize before all hook targets
|
||||
* have finished executing and no one is accessing the lookaside list.
|
||||
*/
|
||||
static EX_RUNDOWN_REF ProtectedProcessRundownProtect;
|
||||
/* ProtectedProcessListHead
|
||||
*
|
||||
* The head of the process protection linked list. Each entry stores protection
|
||||
* information for a process.
|
||||
*/
|
||||
static LIST_ENTRY ProtectedProcessListHead;
|
||||
/* ProtectedProcessListLock
|
||||
*
|
||||
* The spinlock which protects all accesses to the protected process list (even
|
||||
* the individual entries)
|
||||
*/
|
||||
static KSPIN_LOCK ProtectedProcessListLock;
|
||||
/* ProtectedProcessLookasideList
|
||||
*
|
||||
* The lookaside list for protected process entries.
|
||||
*/
|
||||
static NPAGED_LOOKASIDE_LIST ProtectedProcessLookasideList;
|
||||
|
||||
static KPH_HOOK ObOpenObjectByPointerHook = { 0 };
|
||||
|
||||
KPH_DEFINE_HOOK_CALL(
|
||||
NTSTATUS NTAPI KphOldObOpenObjectByPointer,
|
||||
OBOPENOBJECTBYPOINTER_ARGS,
|
||||
@@ -63,6 +63,8 @@ KPH_DEFINE_HOOK_CALL(
|
||||
/* KphProtectInit
|
||||
*
|
||||
* Initializes process protection.
|
||||
*
|
||||
* IRQL: <= APC_LEVEL
|
||||
*/
|
||||
NTSTATUS KphProtectInit()
|
||||
{
|
||||
@@ -83,6 +85,9 @@ NTSTATUS KphProtectInit()
|
||||
0
|
||||
);
|
||||
|
||||
/* Initialize hooking. */
|
||||
KphHookInit();
|
||||
|
||||
/* Hook various functions. */
|
||||
ObOpenObjectByPointerHook.Function = ObOpenObjectByPointer;
|
||||
ObOpenObjectByPointerHook.Target = KphNewObOpenObjectByPointer;
|
||||
@@ -95,14 +100,20 @@ NTSTATUS KphProtectInit()
|
||||
/* KphProtectDeinit
|
||||
*
|
||||
* Removes process protection and frees associated structures.
|
||||
*
|
||||
* IRQL: <= APC_LEVEL
|
||||
*/
|
||||
NTSTATUS KphProtectDeinit()
|
||||
{
|
||||
NTSTATUS status = STATUS_SUCCESS;
|
||||
KIRQL oldIrql;
|
||||
LARGE_INTEGER waitLi;
|
||||
|
||||
/* Unhook. */
|
||||
KphUnhook(&ObOpenObjectByPointerHook);
|
||||
status = KphUnhook(&ObOpenObjectByPointerHook);
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
return status;
|
||||
|
||||
/* Wait for all activity to finish. */
|
||||
ExWaitForRundownProtectionRelease(&ProtectedProcessRundownProtect);
|
||||
@@ -115,12 +126,15 @@ NTSTATUS KphProtectDeinit()
|
||||
/* Free all process protection entries. */
|
||||
ExDeleteNPagedLookasideList(&ProtectedProcessLookasideList);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
return status;
|
||||
}
|
||||
|
||||
/* KphNewObOpenObjectByPointer
|
||||
*
|
||||
* New ObOpenObjectByPointer function.
|
||||
*
|
||||
* Thread safety: Full
|
||||
* IRQL: PASSIVE_LEVEL
|
||||
*/
|
||||
NTSTATUS NTAPI KphNewObOpenObjectByPointer(
|
||||
OBOPENOBJECTBYPOINTER_ARGS
|
||||
@@ -210,6 +224,9 @@ NTSTATUS NTAPI KphNewObOpenObjectByPointer(
|
||||
/* KphProtectAddEntry
|
||||
*
|
||||
* Protects the specified process.
|
||||
*
|
||||
* Thread safety: Full
|
||||
* IRQL: <= DISPATCH_LEVEL
|
||||
*/
|
||||
PKPH_PROCESS_ENTRY KphProtectAddEntry(
|
||||
PEPROCESS Process,
|
||||
@@ -250,6 +267,9 @@ PKPH_PROCESS_ENTRY KphProtectAddEntry(
|
||||
/* KphProtectCopyEntry
|
||||
*
|
||||
* Copies process protection data for the specified process.
|
||||
*
|
||||
* Thread safety: Full
|
||||
* IRQL: <= DISPATCH_LEVEL
|
||||
*/
|
||||
BOOLEAN KphProtectCopyEntry(
|
||||
PEPROCESS Process,
|
||||
@@ -285,6 +305,10 @@ BOOLEAN KphProtectCopyEntry(
|
||||
/* KphProtectFindEntry
|
||||
*
|
||||
* Finds process protection data.
|
||||
*
|
||||
* Thread safety: Limited. The returned pointer is not guaranteed to
|
||||
* point to a valid process entry.
|
||||
* IRQL: <= DISPATCH_LEVEL
|
||||
*/
|
||||
PKPH_PROCESS_ENTRY KphProtectFindEntry(
|
||||
PEPROCESS Process,
|
||||
@@ -322,6 +346,10 @@ PKPH_PROCESS_ENTRY KphProtectFindEntry(
|
||||
/* KphProtectRemoveByProcess
|
||||
*
|
||||
* Removes protection from the specified process.
|
||||
*
|
||||
* Thread safety: Limited. Callers must synchronize remove calls such
|
||||
* as KphProtectRemoveByProcess and KphProtectRemoveByTag.
|
||||
* IRQL: <= DISPATCH_LEVEL
|
||||
*/
|
||||
BOOLEAN KphProtectRemoveByProcess(
|
||||
PEPROCESS Process
|
||||
@@ -340,6 +368,10 @@ BOOLEAN KphProtectRemoveByProcess(
|
||||
/* KphProtectRemoveByTag
|
||||
*
|
||||
* Removes protection from all processes with the specified tag.
|
||||
*
|
||||
* Thread safety: Limited. Callers must synchronize remove calls such
|
||||
* as KphProtectRemoveByProcess and KphProtectRemoveByTag.
|
||||
* IRQL: <= DISPATCH_LEVEL
|
||||
*/
|
||||
ULONG KphProtectRemoveByTag(
|
||||
HANDLE Tag
|
||||
@@ -362,6 +394,9 @@ ULONG KphProtectRemoveByTag(
|
||||
/* KphpIsCurrentProcessProtected
|
||||
*
|
||||
* Determines whether the current process is protected.
|
||||
*
|
||||
* Thread safety: Full
|
||||
* IRQL: <= DISPATCH_LEVEL
|
||||
*/
|
||||
BOOLEAN KphpIsCurrentProcessProtected()
|
||||
{
|
||||
@@ -371,6 +406,9 @@ BOOLEAN KphpIsCurrentProcessProtected()
|
||||
/* KphpProtectRemoveEntry
|
||||
*
|
||||
* Removes and frees process protection data.
|
||||
*
|
||||
* Thread safety: Full
|
||||
* IRQL: <= DISPATCH_LEVEL
|
||||
*/
|
||||
VOID KphpProtectRemoveEntry(
|
||||
PKPH_PROCESS_ENTRY Entry
|
||||
|
||||
@@ -11,6 +11,7 @@ SOURCES= \
|
||||
kph.c \
|
||||
hook.c \
|
||||
protect.c \
|
||||
sync.c \
|
||||
mm.c \
|
||||
ob.c \
|
||||
ps.c \
|
||||
|
||||
@@ -0,0 +1,234 @@
|
||||
/*
|
||||
* Process Hacker Driver -
|
||||
* synchronization code
|
||||
*
|
||||
* Copyright (C) 2009 wj32
|
||||
*
|
||||
* This file is part of Process Hacker.
|
||||
*
|
||||
* Process Hacker is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Process Hacker is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "include/sync.h"
|
||||
#include "include/debug.h"
|
||||
|
||||
ULONG KphpCountBits(
|
||||
ULONG_PTR Number
|
||||
);
|
||||
|
||||
VOID KphpProcessorLockDpc(
|
||||
PKDPC Dpc,
|
||||
PVOID DeferredContext,
|
||||
PVOID SystemArgument1,
|
||||
PVOID SystemArgument2
|
||||
);
|
||||
|
||||
/* KphAcquireProcessorLock
|
||||
*
|
||||
* Raises the IRQL to DISPATCH_LEVEL and prevents threads from
|
||||
* executing on other processors until the processor lock is released.
|
||||
* Blocks if the supplied processor lock is already in use.
|
||||
*
|
||||
* ProcessorLock: A processor lock structure that is present in
|
||||
* non-paged memory.
|
||||
*
|
||||
* Thread safety: Full
|
||||
* IRQL: <= APC_LEVEL
|
||||
*/
|
||||
BOOLEAN KphAcquireProcessorLock(
|
||||
PKPH_PROCESSOR_LOCK ProcessorLock
|
||||
)
|
||||
{
|
||||
ULONG i;
|
||||
ULONG numberProcessors;
|
||||
ULONG currentProcessor;
|
||||
|
||||
/* Acquire the processor lock mutex. */
|
||||
ExAcquireFastMutex(&ProcessorLock->Mutex);
|
||||
|
||||
/* Reset some state. */
|
||||
ASSERT(ProcessorLock->AcquiredProcessors == 0);
|
||||
ProcessorLock->AcquiredProcessors = 0;
|
||||
ProcessorLock->ReleaseSignal = 0;
|
||||
|
||||
/* Get the number of processors. */
|
||||
numberProcessors = KphpCountBits(KeQueryActiveProcessors());
|
||||
|
||||
/* If there's only one processor we can simply raise the IRQL and exit. */
|
||||
if (numberProcessors == 1)
|
||||
{
|
||||
dprintf("KphAcquireProcessorLock: Only one processor, raising IRQL and exiting...\n");
|
||||
KeRaiseIrql(DISPATCH_LEVEL, &ProcessorLock->OldIrql);
|
||||
ProcessorLock->Acquired = TRUE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Allocate storage for the DPCs. */
|
||||
ProcessorLock->Dpcs = ExAllocatePoolWithTag(
|
||||
NonPagedPool,
|
||||
sizeof(KDPC) * numberProcessors,
|
||||
KPH_TAG
|
||||
);
|
||||
|
||||
if (!ProcessorLock->Dpcs)
|
||||
{
|
||||
dprintf("KphAcquireProcessorLock: Could not allocate storage for DPCs!\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Initialize the DPCs. */
|
||||
for (i = 0; i < numberProcessors; i++)
|
||||
{
|
||||
KeInitializeDpc(&ProcessorLock->Dpcs[i], KphpProcessorLockDpc, NULL);
|
||||
KeSetTargetProcessorDpc(&ProcessorLock->Dpcs[i], (CCHAR)i);
|
||||
KeSetImportanceDpc(&ProcessorLock->Dpcs[i], HighImportance);
|
||||
}
|
||||
|
||||
/* Raise the IRQL to DISPATCH_LEVEL to prevent context switching. */
|
||||
KeRaiseIrql(DISPATCH_LEVEL, &ProcessorLock->OldIrql);
|
||||
/* Get the current processor number. */
|
||||
currentProcessor = KeGetCurrentProcessorNumber();
|
||||
|
||||
/* Queue the DPCs (except on the current processor). */
|
||||
for (i = 0; i < numberProcessors; i++)
|
||||
if (i != currentProcessor)
|
||||
KeInsertQueueDpc(&ProcessorLock->Dpcs[i], ProcessorLock, NULL);
|
||||
|
||||
/* Spinwait for all (other) processors to be acquired. */
|
||||
while (InterlockedCompareExchange(
|
||||
&ProcessorLock->AcquiredProcessors,
|
||||
numberProcessors - 1,
|
||||
numberProcessors - 1
|
||||
) != numberProcessors - 1)
|
||||
NOTHING;
|
||||
|
||||
dprintf("KphAcquireProcessorLock: All processors acquired.\n");
|
||||
ProcessorLock->Acquired = TRUE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* KphInitializeProcessorLock
|
||||
*
|
||||
* Initializes a processor lock.
|
||||
*
|
||||
* ProcessorLock: A processor lock structure that is present in
|
||||
* non-paged memory.
|
||||
*
|
||||
* IRQL: Any
|
||||
*/
|
||||
VOID KphInitializeProcessorLock(
|
||||
PKPH_PROCESSOR_LOCK ProcessorLock
|
||||
)
|
||||
{
|
||||
ExInitializeFastMutex(&ProcessorLock->Mutex);
|
||||
ProcessorLock->Dpcs = NULL;
|
||||
ProcessorLock->AcquiredProcessors = 0;
|
||||
ProcessorLock->ReleaseSignal = 0;
|
||||
ProcessorLock->OldIrql = PASSIVE_LEVEL;
|
||||
ProcessorLock->Acquired = FALSE;
|
||||
}
|
||||
|
||||
/* KphReleaseProcessorLock
|
||||
*
|
||||
* Allows threads to execute on other processors and restores the IRQL.
|
||||
*
|
||||
* ProcessorLock: A processor lock structure that is present in
|
||||
* non-paged memory.
|
||||
*
|
||||
* Thread safety: Full
|
||||
* IRQL: <= APC_LEVEL
|
||||
*/
|
||||
VOID KphReleaseProcessorLock(
|
||||
PKPH_PROCESSOR_LOCK ProcessorLock
|
||||
)
|
||||
{
|
||||
if (!ProcessorLock->Acquired)
|
||||
return;
|
||||
|
||||
/* Signal for the acquired processors to be released. */
|
||||
InterlockedExchange(&ProcessorLock->ReleaseSignal, 1);
|
||||
|
||||
/* Spinwait for all acquired processors to be released. */
|
||||
while (InterlockedCompareExchange(
|
||||
&ProcessorLock->AcquiredProcessors,
|
||||
0,
|
||||
0
|
||||
))
|
||||
NOTHING;
|
||||
|
||||
dprintf("KphReleaseProcessorLock: All processors released.\n");
|
||||
|
||||
/* Restore the old IRQL (should always be APC_LEVEL due to the
|
||||
* fast mutex). */
|
||||
KeLowerIrql(ProcessorLock->OldIrql);
|
||||
|
||||
/* Free the DPCs if necessary. */
|
||||
if (ProcessorLock->Dpcs != NULL)
|
||||
{
|
||||
ExFreePoolWithTag(ProcessorLock->Dpcs, KPH_TAG);
|
||||
ProcessorLock->Dpcs = NULL;
|
||||
}
|
||||
|
||||
ProcessorLock->Acquired = FALSE;
|
||||
|
||||
/* Release the processor lock mutex. */
|
||||
ExReleaseFastMutex(&ProcessorLock->Mutex);
|
||||
}
|
||||
|
||||
ULONG KphpCountBits(
|
||||
ULONG_PTR Number
|
||||
)
|
||||
{
|
||||
ULONG count = 0;
|
||||
|
||||
while (Number)
|
||||
{
|
||||
count++;
|
||||
Number &= Number - 1;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
VOID KphpProcessorLockDpc(
|
||||
PKDPC Dpc,
|
||||
PVOID DeferredContext,
|
||||
PVOID SystemArgument1,
|
||||
PVOID SystemArgument2
|
||||
)
|
||||
{
|
||||
PKPH_PROCESSOR_LOCK processorLock = (PKPH_PROCESSOR_LOCK)SystemArgument1;
|
||||
|
||||
ASSERT(processorLock != NULL);
|
||||
|
||||
dprintf("KphpProcessorLockDpc: Acquiring processor %d.\n", KeGetCurrentProcessorNumber());
|
||||
|
||||
/* Increase the number of acquired processors. */
|
||||
InterlockedIncrement(&processorLock->AcquiredProcessors);
|
||||
|
||||
/* Spin until we get the signal to release the processor. */
|
||||
while (!InterlockedCompareExchange(
|
||||
&processorLock->ReleaseSignal,
|
||||
1,
|
||||
1
|
||||
))
|
||||
NOTHING;
|
||||
|
||||
/* Decrease the number of acquired processors. */
|
||||
InterlockedDecrement(&processorLock->AcquiredProcessors);
|
||||
|
||||
dprintf("KphpProcessorLockDpc: Releasing processor %d.\n", KeGetCurrentProcessorNumber());
|
||||
}
|
||||
@@ -87,7 +87,7 @@ NTSTATUS KvInit()
|
||||
minorVersion = RtlWindowsVersion.dwMinorVersion;
|
||||
servicePack = RtlWindowsVersion.wServicePackMajor;
|
||||
buildNumber = RtlWindowsVersion.dwBuildNumber;
|
||||
dprintf("Windows %d.%d, SP%d.%d, build %d\n",
|
||||
dfprintf("Windows %d.%d, SP%d.%d, build %d\n",
|
||||
majorVersion, minorVersion, servicePack,
|
||||
RtlWindowsVersion.wServicePackMinor, buildNumber
|
||||
);
|
||||
|
||||
@@ -31,14 +31,23 @@ namespace ProcessHacker.Native.Api
|
||||
|
||||
public partial class Win32
|
||||
{
|
||||
public const int FlsMaximumAvailable = 128;
|
||||
#if _X64
|
||||
public const int GdiHandleBufferSize = 60;
|
||||
#else
|
||||
public const int GdiHandleBufferSize = 34;
|
||||
#endif
|
||||
public const int MaximumSupportedExtension = 512;
|
||||
public const int SecurityDescriptorMinLength = 20;
|
||||
public const int SecurityDescriptorRevision = 1;
|
||||
public readonly int SecurityMaxSidSize =
|
||||
public static readonly int SecurityMaxSidSize =
|
||||
Marshal.SizeOf(typeof(Sid)) - sizeof(int) + (SidMaxSubAuthorities * sizeof(int));
|
||||
public const int SidMaxSubAuthorities = 15;
|
||||
public const int SidRecommendedSubAuthorities = 1;
|
||||
public const int SidRevision = 1;
|
||||
public const int SizeOf80387Registers = 80;
|
||||
|
||||
public static readonly IntPtr PebLdrOffset = Marshal.OffsetOf(typeof(Peb), "Ldr");
|
||||
public static readonly IntPtr PebProcessParametersOffset = Marshal.OffsetOf(typeof(Peb), "ProcessParameters");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -392,6 +392,98 @@ namespace ProcessHacker.Native.Api
|
||||
public int NonPagedPoolUsage;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct Peb
|
||||
{
|
||||
[MarshalAs(UnmanagedType.I1)]
|
||||
public bool InheritedAddressSpace;
|
||||
[MarshalAs(UnmanagedType.I1)]
|
||||
public bool ReadImageFileExecOptions;
|
||||
[MarshalAs(UnmanagedType.I1)]
|
||||
public bool BeingDebugged;
|
||||
[MarshalAs(UnmanagedType.I1)]
|
||||
public bool BitField;
|
||||
public IntPtr Mutant;
|
||||
|
||||
public IntPtr ImageBaseAddress;
|
||||
public IntPtr Ldr; // ptr to PebLdrData
|
||||
public IntPtr ProcessParameters; // ptr to RtlUserProcessParameters
|
||||
public IntPtr SubSystemData;
|
||||
public IntPtr ProcessHeap;
|
||||
public IntPtr FastPebLock;
|
||||
public IntPtr AtlThunkSListPtr;
|
||||
public IntPtr SparePrt2;
|
||||
public int EnvironmentUpdateCount;
|
||||
public IntPtr KernelCallbackTable;
|
||||
public int SystemReserved;
|
||||
public int SpareUlong;
|
||||
public IntPtr FreeList;
|
||||
public int TlsExpansionCounter;
|
||||
public IntPtr TlsBitmap;
|
||||
public unsafe fixed int TlsBitmapBits[2];
|
||||
public IntPtr ReadOnlySharedMemoryBase;
|
||||
public IntPtr ReadOnlySharedMemoryHeap;
|
||||
public IntPtr ReadOnlyStaticServerData;
|
||||
public IntPtr AnsiCodePageData;
|
||||
public IntPtr OemCodePageData;
|
||||
public IntPtr UnicodeCaseTableData;
|
||||
|
||||
public int NumberOfProcessors;
|
||||
public int NtGlobalFlag;
|
||||
|
||||
public long CriticalSectionTimeout;
|
||||
public IntPtr HeapSegmentReserve;
|
||||
public IntPtr HeapSegmentCommit;
|
||||
public IntPtr HeapDeCommitTotalFreeThreshold;
|
||||
public IntPtr HeapDeCommitFreeBlockThreshold;
|
||||
|
||||
public int NumberOfHeaps;
|
||||
public int MaximumNumberOfHeaps;
|
||||
public IntPtr ProcessHeaps;
|
||||
|
||||
public IntPtr GdiSharedHandleTable;
|
||||
public IntPtr ProcessStarterHelper;
|
||||
public int GdiDCAttributeList;
|
||||
public IntPtr LoaderLock;
|
||||
|
||||
public int OSMajorVersion;
|
||||
public int OSMinorVersion;
|
||||
public short OSBuildNumber;
|
||||
public short OSCSDVersion;
|
||||
public int OSPlatformId;
|
||||
public int ImageSubsystem;
|
||||
public int ImageSubsystemMajorVersion;
|
||||
public int ImageSubsystemMinorVersion;
|
||||
public IntPtr ImageProcessAffinityMask;
|
||||
public unsafe fixed byte GdiHandleBuffer[Win32.GdiHandleBufferSize];
|
||||
public IntPtr PostProcessInitRoutine;
|
||||
|
||||
public IntPtr TlsExpansionBitmap;
|
||||
public unsafe fixed int TlsExpansionBitmapBits[32];
|
||||
|
||||
public int SessionId;
|
||||
|
||||
public long AppCompatFlags;
|
||||
public long AppCompatFlagsUser;
|
||||
public IntPtr pShimData;
|
||||
public IntPtr AppCompatInfo;
|
||||
|
||||
public UnicodeString CSDVersion;
|
||||
|
||||
public IntPtr ActivationContextData;
|
||||
public IntPtr ProcessAssemblyStorageMap;
|
||||
public IntPtr SystemDefaultActivationContextData;
|
||||
public IntPtr SystemAssemblyStorageMap;
|
||||
|
||||
public IntPtr MinimumStackCommit;
|
||||
|
||||
public IntPtr FlsCallback;
|
||||
public ListEntry FlsListHead;
|
||||
public IntPtr FlsBitmap;
|
||||
public unsafe fixed int FlsBitmapBits[Win32.FlsMaximumAvailable / (sizeof(int) * 8)];
|
||||
public int FlsHighIndex;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct PebLdrData
|
||||
{
|
||||
|
||||
@@ -401,11 +401,11 @@ namespace ProcessHacker.Native.Objects
|
||||
|
||||
private unsafe void EnumModulesNative(EnumModulesDelegate enumModulesCallback)
|
||||
{
|
||||
byte* buffer = stackalloc byte[4];
|
||||
byte* buffer = stackalloc byte[IntPtr.Size];
|
||||
|
||||
this.ReadMemory(this.GetBasicInformation().PebBaseAddress.Increment(0xc), buffer, 4);
|
||||
this.ReadMemory(this.GetBasicInformation().PebBaseAddress.Increment(Win32.PebLdrOffset), buffer, IntPtr.Size);
|
||||
|
||||
IntPtr loaderData = new IntPtr(*(int*)buffer);
|
||||
IntPtr loaderData = *(IntPtr*)buffer;
|
||||
|
||||
PebLdrData* data = stackalloc PebLdrData[1];
|
||||
this.ReadMemory(loaderData, data, Marshal.SizeOf(typeof(PebLdrData)));
|
||||
@@ -925,7 +925,7 @@ namespace ProcessHacker.Native.Objects
|
||||
* +0c PVOID LoaderData;
|
||||
* +10 PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
|
||||
*/
|
||||
this.ReadMemory(pebBaseAddress.Increment(0x10), buffer, IntPtr.Size);
|
||||
this.ReadMemory(pebBaseAddress.Increment(Win32.PebProcessParametersOffset), buffer, IntPtr.Size);
|
||||
IntPtr processParameters = *(IntPtr*)buffer;
|
||||
|
||||
// Read length (in bytes) of string. The offset of the UNICODE_STRING structure is
|
||||
@@ -941,7 +941,7 @@ namespace ProcessHacker.Native.Objects
|
||||
byte[] stringData = new byte[stringLength];
|
||||
|
||||
// read address of string
|
||||
this.ReadMemory(processParameters.Increment((int)offset + 0x4), buffer, 4);
|
||||
this.ReadMemory(processParameters.Increment((int)offset + 0x4), buffer, IntPtr.Size);
|
||||
IntPtr stringAddr = *(IntPtr*)buffer;
|
||||
|
||||
// read string and decode it
|
||||
|
||||
Reference in New Issue
Block a user