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