diff --git a/trunk/KProcessHacker/hook.c b/trunk/KProcessHacker/hook.c
index 93b440524..660ad2e79 100644
--- a/trunk/KProcessHacker/hook.c
+++ b/trunk/KProcessHacker/hook.c
@@ -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
diff --git a/trunk/KProcessHacker/i386/kprocesshacker.sys b/trunk/KProcessHacker/i386/kprocesshacker.sys
index 26161fbc8..0b8610468 100644
Binary files a/trunk/KProcessHacker/i386/kprocesshacker.sys and b/trunk/KProcessHacker/i386/kprocesshacker.sys differ
diff --git a/trunk/KProcessHacker/include/debug.h b/trunk/KProcessHacker/include/debug.h
index 73572dfce..0a140616b 100644
--- a/trunk/KProcessHacker/include/debug.h
+++ b/trunk/KProcessHacker/include/debug.h
@@ -20,12 +20,16 @@
* along with Process Hacker. If not, see .
*/
+#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
diff --git a/trunk/KProcessHacker/include/hook.h b/trunk/KProcessHacker/include/hook.h
index 072acc3a5..a218beba4 100644
--- a/trunk/KProcessHacker/include/hook.h
+++ b/trunk/KProcessHacker/include/hook.h
@@ -53,6 +53,8 @@ NTSTATUS KphHook(
PKPH_HOOK Hook
);
+NTSTATUS KphHookInit();
+
NTSTATUS KphUnhook(
PKPH_HOOK Hook
);
diff --git a/trunk/KProcessHacker/include/sync.h b/trunk/KProcessHacker/include/sync.h
new file mode 100644
index 000000000..bb5cfebc0
--- /dev/null
+++ b/trunk/KProcessHacker/include/sync.h
@@ -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 .
+ */
+
+#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
diff --git a/trunk/KProcessHacker/kprocesshacker.c b/trunk/KProcessHacker/kprocesshacker.c
index 567f5a4a6..c8a810682 100644
--- a/trunk/KProcessHacker/kprocesshacker.c
+++ b/trunk/KProcessHacker/kprocesshacker.c
@@ -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)
diff --git a/trunk/KProcessHacker/protect.c b/trunk/KProcessHacker/protect.c
index a9d5a394e..f39e8593c 100644
--- a/trunk/KProcessHacker/protect.c
+++ b/trunk/KProcessHacker/protect.c
@@ -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
diff --git a/trunk/KProcessHacker/sources b/trunk/KProcessHacker/sources
index d46de85aa..1be5adcb7 100644
--- a/trunk/KProcessHacker/sources
+++ b/trunk/KProcessHacker/sources
@@ -11,6 +11,7 @@ SOURCES= \
kph.c \
hook.c \
protect.c \
+ sync.c \
mm.c \
ob.c \
ps.c \
diff --git a/trunk/KProcessHacker/sync.c b/trunk/KProcessHacker/sync.c
new file mode 100644
index 000000000..dfabc8190
--- /dev/null
+++ b/trunk/KProcessHacker/sync.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 .
+ */
+
+#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());
+}
diff --git a/trunk/KProcessHacker/version.c b/trunk/KProcessHacker/version.c
index 79d341e75..8e26780fb 100644
--- a/trunk/KProcessHacker/version.c
+++ b/trunk/KProcessHacker/version.c
@@ -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
);
diff --git a/trunk/ProcessHacker.Native/Api/NativeDefinitions.cs b/trunk/ProcessHacker.Native/Api/NativeDefinitions.cs
index 6ff716a71..9b50a8f52 100644
--- a/trunk/ProcessHacker.Native/Api/NativeDefinitions.cs
+++ b/trunk/ProcessHacker.Native/Api/NativeDefinitions.cs
@@ -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");
}
}
diff --git a/trunk/ProcessHacker.Native/Api/NativeStructs.cs b/trunk/ProcessHacker.Native/Api/NativeStructs.cs
index 05e80422c..e39f0e785 100644
--- a/trunk/ProcessHacker.Native/Api/NativeStructs.cs
+++ b/trunk/ProcessHacker.Native/Api/NativeStructs.cs
@@ -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
{
diff --git a/trunk/ProcessHacker.Native/Objects/ProcessHandle.cs b/trunk/ProcessHacker.Native/Objects/ProcessHandle.cs
index b01926d8b..1b8a32305 100644
--- a/trunk/ProcessHacker.Native/Objects/ProcessHandle.cs
+++ b/trunk/ProcessHacker.Native/Objects/ProcessHandle.cs
@@ -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