From 860d7b751d2242ac8a44ef77ced12e5103b52ddd Mon Sep 17 00:00:00 2001 From: wj32 Date: Thu, 21 May 2009 06:13:09 +0000 Subject: [PATCH] * 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 --- trunk/KProcessHacker/hook.c | 78 ++++-- trunk/KProcessHacker/i386/kprocesshacker.sys | Bin 20992 -> 21504 bytes trunk/KProcessHacker/include/debug.h | 8 +- trunk/KProcessHacker/include/hook.h | 2 + trunk/KProcessHacker/include/sync.h | 56 +++++ trunk/KProcessHacker/kprocesshacker.c | 26 +- trunk/KProcessHacker/protect.c | 94 ++++--- trunk/KProcessHacker/sources | 1 + trunk/KProcessHacker/sync.c | 234 ++++++++++++++++++ trunk/KProcessHacker/version.c | 2 +- .../Api/NativeDefinitions.cs | 11 +- .../ProcessHacker.Native/Api/NativeStructs.cs | 92 +++++++ .../Objects/ProcessHandle.cs | 10 +- 13 files changed, 555 insertions(+), 59 deletions(-) create mode 100644 trunk/KProcessHacker/include/sync.h create mode 100644 trunk/KProcessHacker/sync.c 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 26161fbc86f1238d0017a54ae6ee158f1c1794d6..0b86104684c9ee422fd61c75f27a2985641bad06 100644 GIT binary patch delta 9481 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 delta 8279 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 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