diff --git a/2.x/trunk/KProcessHacker/HACKING.txt b/2.x/trunk/KProcessHacker/HACKING.txt
new file mode 100644
index 000000000..00c104cfa
--- /dev/null
+++ b/2.x/trunk/KProcessHacker/HACKING.txt
@@ -0,0 +1,67 @@
+==== KProcessHacker ====
+
+== IMPORTANT ==
+KProcessHacker has been developed from either reverse engineering of
+the Windows kernel or ReactOS code (http://www.reactos.org). The
+following files contain "ported" ReactOS code (with modifications):
+
+ * mm.c
+ * MiDoMappedCopy
+ * MiDoPoolCopy (added smarter buffer management)
+ * MiGetExceptionInfo
+ * ps.c
+ * KphOpenProcess
+ * KphOpenThread
+ * se.c
+ * KphOpenProcessTokenEx
+
+== CODE STRUCTURE ==
+ * handle.c
+ - Contains handle table code.
+ * hook.c
+ - Contains hooking code. Currently you may hook any kernel-mode
+ function and object type open procedures.
+ * io.c
+ - Contains I/O-related code, such as device and driver functions.
+ * kph.c
+ - Contains support routines.
+ * kprocesshacker.c
+ - Contains interfacing code, mainly consisting of the I/O control
+ handler.
+ * mm.c
+ - Contains memory-related code, such as reading and writing.
+ * ob.c
+ - Contains object-related code, such as handle duplication.
+ * protect.c
+ - Contains process protection code. Process protection is
+ achieved by hooking ObOpenObjectByPointer and some object type
+ OpenProcedures.
+ * ps.c
+ - Contains process- and thread-related code, such as opening and
+ terminating.
+ * ref.c
+ - Contains the KPH object manager.
+ * se.c
+ - Contains security-related code. Only function there is
+ KphOpenProcessTokenEx.
+ * sync.c
+ - Various synchronization functions.
+ * sysservice.c
+ - System service logging.
+ * trace.c
+ - Stack trace code.
+ * version.c
+ - Contains Windows-version-specific data.
+
+== POOL TAGS ==
+PhAB: System service logging argument block. sysservice.h
+PhCH: Client handle table. kprocesshacker.h
+PhCt: System service logging argument capture temporary buffer. sysservicep.h
+PhCU: Captured Unicode string. kph.h
+PhEB: System service logging event block. sysservice.h
+PhOb: Object manager object. refp.h
+PhPC: Pool-based virtual memory copying. mm.h
+PhPr: Protection entry. protect.h
+PhSc: System service call entry. sysservicedata.h
+PhSD: Processor lock DPC storage. sync.h
+PhSt: Stack back trace. ps.h
diff --git a/2.x/trunk/KProcessHacker/amd64/kprocesshacker.sys b/2.x/trunk/KProcessHacker/amd64/kprocesshacker.sys
new file mode 100644
index 000000000..9c86f5624
Binary files /dev/null and b/2.x/trunk/KProcessHacker/amd64/kprocesshacker.sys differ
diff --git a/2.x/trunk/KProcessHacker/auto.cmd b/2.x/trunk/KProcessHacker/auto.cmd
new file mode 100644
index 000000000..28cde9736
--- /dev/null
+++ b/2.x/trunk/KProcessHacker/auto.cmd
@@ -0,0 +1,7 @@
+@echo off
+
+build -cZ
+if not %errorlevel%==0 goto end
+copy i386\kprocesshacker.sys ..\ProcessHacker\bin\Release\
+copy i386\kprocesshacker.pdb ..\ProcessHacker\bin\Release\
+:end
\ No newline at end of file
diff --git a/2.x/trunk/KProcessHacker/autoreload.cmd b/2.x/trunk/KProcessHacker/autoreload.cmd
new file mode 100644
index 000000000..b1e09e9c1
--- /dev/null
+++ b/2.x/trunk/KProcessHacker/autoreload.cmd
@@ -0,0 +1,2 @@
+@echo off
+auto & sc stop kprocesshacker & sc start kprocesshacker
\ No newline at end of file
diff --git a/2.x/trunk/KProcessHacker/handle.c b/2.x/trunk/KProcessHacker/handle.c
new file mode 100644
index 000000000..43b94fd9a
--- /dev/null
+++ b/2.x/trunk/KProcessHacker/handle.c
@@ -0,0 +1,355 @@
+/*
+ * Process Hacker Driver -
+ * handle table
+ *
+ * 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/handle.h"
+#include "include/handlep.h"
+
+NTSTATUS KphpAllocateHandleEntry(
+ __in PKPH_HANDLE_TABLE HandleTable,
+ __out PKPH_HANDLE_TABLE_ENTRY *Entry
+ );
+
+NTSTATUS KphpFreeHandleEntry(
+ __in PKPH_HANDLE_TABLE HandleTable,
+ __in PKPH_HANDLE_TABLE_ENTRY Entry
+ );
+
+/* KphCreateHandleTable
+ *
+ * Creates a handle table.
+ *
+ * HandleTable: A variable which receives a pointer to the handle table.
+ * MaximumHandles: The maximum number of handles that can be created.
+ * SizeOfEntry: The size of each handle table entry. This value must be
+ * divisible by 4.
+ * Tag: The tag to use when allocating handle table resources.
+ */
+NTSTATUS KphCreateHandleTable(
+ __out PKPH_HANDLE_TABLE *HandleTable,
+ __in ULONG MaximumHandles,
+ __in ULONG SizeOfEntry,
+ __in ULONG Tag
+ )
+{
+ PKPH_HANDLE_TABLE handleTable;
+
+ /* Each handle entry must be at least the size of our
+ * handle table entry definition.
+ */
+ if (SizeOfEntry < sizeof(KPH_HANDLE_TABLE_ENTRY))
+ return STATUS_INVALID_PARAMETER_3;
+ /* Handle entries must be 4-byte aligned. */
+ if (SizeOfEntry % 4 != 0)
+ return STATUS_INVALID_PARAMETER_3;
+
+ /* Allocate storage for the handle table structure. */
+ handleTable = ExAllocatePoolWithTag(
+ PagedPool,
+ sizeof(KPH_HANDLE_TABLE),
+ Tag
+ );
+
+ if (!handleTable)
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ /* Allocate storage for the handle table itself. */
+ handleTable->Table = ExAllocatePoolWithTag(
+ PagedPool,
+ MaximumHandles * SizeOfEntry,
+ Tag
+ );
+
+ if (!handleTable->Table)
+ {
+ ExFreePoolWithTag(handleTable, Tag);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ /* Initialize the rest of the table descriptor. */
+ handleTable->Tag = Tag;
+ handleTable->SizeOfEntry = SizeOfEntry;
+ handleTable->NextHandle = (HANDLE)0;
+ handleTable->FreeHandle = NULL;
+ ExInitializeFastMutex(&handleTable->Mutex);
+ handleTable->TableSize = MaximumHandles * SizeOfEntry;
+
+ /* Zero the handle table. */
+ memset(handleTable->Table, 0, handleTable->TableSize);
+
+ /* Pass the pointer to the handle table back. */
+ *HandleTable = handleTable;
+
+ return STATUS_SUCCESS;
+}
+
+/* KphFreeHandleTable
+ *
+ * Frees all handle table resources.
+ */
+VOID KphFreeHandleTable(
+ __in PKPH_HANDLE_TABLE HandleTable
+ )
+{
+ ULONG i;
+ ULONG tag;
+
+ /* Free all handle values. */
+ for (i = 0; i < HandleTable->TableSize / HandleTable->SizeOfEntry; i++)
+ {
+ KphCloseHandle(HandleTable, KphHandleFromIndex(i));
+ }
+
+ /* Save the handle table tag first. */
+ tag = HandleTable->Tag;
+ /* Free the table. */
+ ExFreePoolWithTag(HandleTable->Table, tag);
+ /* Free the descriptor. */
+ ExFreePoolWithTag(HandleTable, tag);
+}
+
+/* KphCloseHandle
+ *
+ * Closes a handle, dereferencing the referenced object.
+ */
+NTSTATUS KphCloseHandle(
+ __in PKPH_HANDLE_TABLE HandleTable,
+ __in HANDLE Handle
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ PKPH_HANDLE_TABLE_ENTRY entry;
+ PVOID object;
+
+ if (!KphValidHandle(HandleTable, Handle, &entry))
+ return STATUS_INVALID_HANDLE;
+
+ /* Save a pointer to the object referenced by the handle. */
+ object = entry->Object;
+ /* Free the handle. */
+ status = KphpFreeHandleEntry(HandleTable, entry);
+
+ if (!NT_SUCCESS(status))
+ return status;
+
+ /* Dereference the object. */
+ KphDereferenceObject(object);
+
+ return status;
+}
+
+/* KphCreateHandle
+ *
+ * Creates a handle and references an object.
+ */
+NTSTATUS KphCreateHandle(
+ __in PKPH_HANDLE_TABLE HandleTable,
+ __in PVOID Object,
+ __out PHANDLE Handle
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ PKPH_HANDLE_TABLE_ENTRY entry;
+
+ /* Allocate a handle. */
+ status = KphpAllocateHandleEntry(HandleTable, &entry);
+
+ if (!NT_SUCCESS(status))
+ return status;
+
+ /* Reference and set the object in the entry. */
+ KphReferenceObject(Object);
+ entry->Object = Object;
+
+ /* Pass the handle back. */
+ *Handle = KphGetHandleEntry(entry);
+
+ return status;
+}
+
+/* KphReferenceObjectByHandle
+ *
+ * References an object from a handle.
+ */
+NTSTATUS KphReferenceObjectByHandle(
+ __in PKPH_HANDLE_TABLE HandleTable,
+ __in HANDLE Handle,
+ __in_opt PKPH_OBJECT_TYPE ObjectType,
+ __out PVOID *Object
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ PKPH_HANDLE_TABLE_ENTRY entry;
+
+ if (!KphValidHandle(HandleTable, Handle, &entry))
+ return STATUS_INVALID_HANDLE;
+
+ /* Lock the entry. */
+ if (!KphLockAllocatedHandleEntry(entry))
+ return STATUS_INVALID_HANDLE;
+
+ /* Check the type of object if the caller requested us
+ * to do that.
+ */
+ if (ObjectType)
+ {
+ if (KphGetObjectType(entry->Object) != ObjectType)
+ {
+ /* Bad type. */
+ KphUnlockHandleEntry(entry);
+
+ return STATUS_OBJECT_TYPE_MISMATCH;
+ }
+ }
+
+ /* Reference and pass the object back. */
+ KphReferenceObject(entry->Object);
+ *Object = entry->Object;
+
+ KphUnlockHandleEntry(entry);
+
+ return status;
+}
+
+/* KphValidHandle
+ *
+ * Checks if a handle is valid.
+ */
+BOOLEAN KphValidHandle(
+ __in PKPH_HANDLE_TABLE HandleTable,
+ __in HANDLE Handle,
+ __out_opt PKPH_HANDLE_TABLE_ENTRY *Entry
+ )
+{
+ PKPH_HANDLE_TABLE_ENTRY entry;
+ BOOLEAN valid;
+
+ entry = KphEntryFromHandle(HandleTable, Handle);
+ valid =
+ ((ULONG_PTR)entry >= (ULONG_PTR)HandleTable->Table) &&
+ ((ULONG_PTR)entry + HandleTable->SizeOfEntry <=
+ (ULONG_PTR)HandleTable->Table + HandleTable->TableSize);
+
+ if (valid)
+ *Entry = entry;
+
+ return valid;
+}
+
+/* KphpAllocateHandleEntry
+ *
+ * Allocates a handle table entry.
+ */
+NTSTATUS KphpAllocateHandleEntry(
+ __in PKPH_HANDLE_TABLE HandleTable,
+ __out PKPH_HANDLE_TABLE_ENTRY *Entry
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ PKPH_HANDLE_TABLE_ENTRY entry = NULL;
+
+ /* Prevent others from modifying the handle table. */
+ ExAcquireFastMutex(&HandleTable->Mutex);
+
+ /* Check the free list first. If we have a free entry,
+ * claim it and update the free list. Otherwise, create
+ * a new entry from the NextHandle value.
+ */
+ if (HandleTable->FreeHandle)
+ {
+ /* We have a free entry. Update the free list. */
+ entry = HandleTable->FreeHandle;
+ /* The next free entry goes into FreeHandle. */
+ HandleTable->FreeHandle = KphGetNextFreeEntry(entry);
+ }
+ else
+ {
+ /* No free handles. We have to initialize a new one
+ * based on the NextHandle value.
+ */
+ /* Make sure we don't go past the end of the table. */
+ if (
+ KphIndexFromHandle(HandleTable->NextHandle) *
+ HandleTable->SizeOfEntry <=
+ HandleTable->TableSize
+ )
+ {
+ /* Get a pointer to the entry from the handle. */
+ entry = KphEntryFromHandle(HandleTable, HandleTable->NextHandle);
+ /* Increment the next handle value. */
+ HandleTable->NextHandle = KphIncrementHandle(HandleTable->NextHandle);
+ }
+ else
+ {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ }
+
+ if (NT_SUCCESS(status))
+ {
+ /* Set the entry's handle value. */
+ entry->Handle = KphHandleFromEntry(HandleTable, entry);
+ KphSetAllocatedEntry(entry);
+
+ *Entry = entry;
+ }
+
+ ExReleaseFastMutex(&HandleTable->Mutex);
+
+ return status;
+}
+
+/* KphpFreeHandleEntry
+ *
+ * Frees a handle table entry.
+ */
+NTSTATUS KphpFreeHandleEntry(
+ __in PKPH_HANDLE_TABLE HandleTable,
+ __in PKPH_HANDLE_TABLE_ENTRY Entry
+ )
+{
+ ExAcquireFastMutex(&HandleTable->Mutex);
+
+ /* Lock the entry. */
+ if (!KphLockAllocatedHandleEntry(Entry))
+ {
+ /* Someone else has already freed the entry (or it was never allocated). */
+ ExReleaseFastMutex(&HandleTable->Mutex);
+ return STATUS_INVALID_HANDLE;
+ }
+
+ /* Mark the entry as unallocated. */
+ KphClearAllocatedEntry(Entry);
+
+ /* Add the entry to the free list. */
+ KphSetNextFreeEntry(Entry, HandleTable->FreeHandle);
+ HandleTable->FreeHandle = Entry;
+
+ /* Zero the entry (except for the Value). */
+ memset(&Entry->Object, 0, HandleTable->SizeOfEntry - sizeof(ULONG_PTR));
+
+ /* Unlock the entry. */
+ KphUnlockHandleEntry(Entry);
+
+ ExReleaseFastMutex(&HandleTable->Mutex);
+
+ return STATUS_SUCCESS;
+}
diff --git a/2.x/trunk/KProcessHacker/hook.c b/2.x/trunk/KProcessHacker/hook.c
new file mode 100644
index 000000000..3f775db5d
--- /dev/null
+++ b/2.x/trunk/KProcessHacker/hook.c
@@ -0,0 +1,408 @@
+/*
+ * Process Hacker Driver -
+ * hooks
+ *
+ * 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/hook.h"
+#include "include/sync.h"
+
+static KPH_PROCESSOR_LOCK HookProcessorLock;
+
+/* KphHookInit
+ *
+ * Initializes the hooking module.
+ */
+NTSTATUS KphHookInit()
+{
+ KphInitializeProcessorLock(&HookProcessorLock);
+
+ return STATUS_SUCCESS;
+}
+
+/* KphInitializeHook
+ *
+ * Initializes a hook structure.
+ */
+VOID KphInitializeHook(
+ __out PKPH_HOOK Hook,
+ __in PVOID Function,
+ __in PVOID Target
+ )
+{
+ memset(Hook, 0, sizeof(KPH_HOOK));
+ Hook->Function = Function;
+ Hook->Target = Target;
+}
+
+/* KphHook
+ *
+ * Hooks a kernel-mode function.
+ * WARNING: DO NOT HOOK A FUNCTION THAT IS CALLABLE ABOVE APC_LEVEL.
+ *
+ * Thread safety: Full
+ * IRQL: <= APC_LEVEL
+ */
+NTSTATUS KphHook(
+ __inout PKPH_HOOK Hook
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ MAPPED_MDL mappedMdl;
+ PUCHAR function;
+
+ status = KphpCreateMappedMdl(
+ Hook->Function,
+ 5,
+ &mappedMdl
+ );
+
+ if (!NT_SUCCESS(status))
+ return status;
+
+ function = (PUCHAR)mappedMdl.Address;
+
+ /* Acquire a lock on all other processors. */
+ if (KphAcquireProcessorLock(&HookProcessorLock))
+ {
+ /* Note that this is completely safe even though we are at
+ * DISPATCH_LEVEL because we are using the mapped MDL.
+ */
+ /* Copy the original five bytes (for unhooking). */
+ memcpy(Hook->Bytes, function, 10);
+ /* Hook the function by writing a jump instruction. */
+ 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;
+}
+
+/* KphUnhook
+ *
+ * Unhooks a kernel-mode function.
+ * WARNING: DO NOT UNHOOK A FUNCTION THAT IS CALLABLE ABOVE APC_LEVEL.
+ *
+ * Thread safety: Full
+ * IRQL: <= APC_LEVEL
+ */
+NTSTATUS KphUnhook(
+ __inout PKPH_HOOK Hook
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ MAPPED_MDL mappedMdl;
+
+ if (!Hook->Hooked)
+ return STATUS_UNSUCCESSFUL;
+
+ status = KphpCreateMappedMdl(
+ Hook->Function,
+ 5,
+ &mappedMdl
+ );
+
+ if (!NT_SUCCESS(status))
+ return status;
+
+ /* 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);
+
+ return status;
+}
+
+/* KphObOpenCall
+ *
+ * Calls the original open procedure for an object type.
+ *
+ * AccessMode: If this argument is unavailable, specify KernelMode.
+ */
+NTSTATUS NTAPI KphObOpenCall(
+ __in PKPH_OB_OPEN_HOOK ObOpenHook,
+ __in OB_OPEN_REASON OpenReason,
+ __in KPROCESSOR_MODE AccessMode,
+ __in PEPROCESS Process,
+ __in PVOID Object,
+ __in ACCESS_MASK GrantedAccess,
+ __in ULONG HandleCount
+ )
+{
+ /* If there wasn't any original open procedure, exit. */
+ if (!ObOpenHook->Function)
+ return STATUS_SUCCESS;
+
+ if (WindowsVersion == WINDOWS_XP)
+ {
+ return ((OB_OPEN_METHOD_51)ObOpenHook->Function)(
+ OpenReason,
+ Process,
+ Object,
+ GrantedAccess,
+ HandleCount
+ );
+ }
+ else if (
+ WindowsVersion == WINDOWS_VISTA ||
+ WindowsVersion == WINDOWS_7
+ )
+ {
+ return ((OB_OPEN_METHOD_60)ObOpenHook->Function)(
+ OpenReason,
+ AccessMode,
+ Process,
+ Object,
+ GrantedAccess,
+ HandleCount
+ );
+ }
+ else
+ {
+ return STATUS_NOT_SUPPORTED;
+ }
+}
+
+/* KphInitializeObOpenHook
+ *
+ * Initializes a hook structure.
+ */
+VOID KphInitializeObOpenHook(
+ __inout PKPH_OB_OPEN_HOOK ObOpenHook,
+ __in POBJECT_TYPE ObjectType,
+ __in PVOID Target51,
+ __in PVOID Target60
+ )
+{
+ memset(ObOpenHook, 0, sizeof(KPH_OB_OPEN_HOOK));
+ ObOpenHook->ObjectType = ObjectType;
+ ObOpenHook->Target51 = Target51;
+ ObOpenHook->Target60 = Target60;
+}
+
+/* KphObOpenHook
+ *
+ * Hooks the open procedure for an object type.
+ *
+ * Thread safety: Full
+ * IRQL: <= APC_LEVEL
+ */
+NTSTATUS KphObOpenHook(
+ __inout PKPH_OB_OPEN_HOOK ObOpenHook
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ MAPPED_MDL mappedMdl;
+ PVOID *openProcedure;
+
+ status = KphpCreateMappedMdl(
+ KVOFF(ObOpenHook->ObjectType, OffOtiOpenProcedure),
+ sizeof(PVOID),
+ &mappedMdl
+ );
+
+ if (!NT_SUCCESS(status))
+ return status;
+
+ openProcedure = (PVOID *)mappedMdl.Address;
+
+ /* Acquire a lock on all other processors. */
+ if (KphAcquireProcessorLock(&HookProcessorLock))
+ {
+ /* Save the original open procedure pointer. */
+ ObOpenHook->Function = *openProcedure;
+
+ /* Choose the correct target open procedure and hook. */
+ if (WindowsVersion == WINDOWS_XP)
+ {
+ if (ObOpenHook->Target51)
+ *openProcedure = ObOpenHook->Target51;
+ else
+ status = STATUS_INVALID_PARAMETER;
+ }
+ else if (
+ WindowsVersion == WINDOWS_VISTA ||
+ WindowsVersion == WINDOWS_7
+ )
+ {
+ if (ObOpenHook->Target60)
+ *openProcedure = ObOpenHook->Target60;
+ else
+ status = STATUS_INVALID_PARAMETER;
+ }
+ else
+ {
+ status = STATUS_NOT_SUPPORTED;
+ }
+
+ ObOpenHook->Hooked = TRUE;
+
+ /* Release the processor lock. */
+ KphReleaseProcessorLock(&HookProcessorLock);
+ }
+ else
+ {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ KphpFreeMappedMdl(&mappedMdl);
+
+ return status;
+}
+
+/* KphObOpenUnhook
+ *
+ * Unhooks the open procedure for an object type.
+ *
+ * Thread safety: Full
+ * IRQL: <= APC_LEVEL
+ */
+NTSTATUS KphObOpenUnhook(
+ __inout PKPH_OB_OPEN_HOOK ObOpenHook
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ MAPPED_MDL mappedMdl;
+ PVOID *openProcedure;
+
+ if (!ObOpenHook->Hooked)
+ return STATUS_UNSUCCESSFUL;
+
+ status = KphpCreateMappedMdl(
+ KVOFF(ObOpenHook->ObjectType, OffOtiOpenProcedure),
+ sizeof(PVOID),
+ &mappedMdl
+ );
+
+ if (!NT_SUCCESS(status))
+ return status;
+
+ openProcedure = (PVOID *)mappedMdl.Address;
+
+ /* Acquire a lock on all other processors. */
+ if (KphAcquireProcessorLock(&HookProcessorLock))
+ {
+ /* Restore the original open procedure pointer. */
+ *openProcedure = ObOpenHook->Function;
+ ObOpenHook->Hooked = FALSE;
+
+ /* Release the processor lock. */
+ KphReleaseProcessorLock(&HookProcessorLock);
+ }
+ else
+ {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ KphpFreeMappedMdl(&mappedMdl);
+
+ return status;
+}
+
+/* KphpCreateMappedMdl
+ *
+ * Creates and maps a MDL.
+ *
+ * Thread safety: Full
+ * IRQL: Any
+ */
+NTSTATUS KphpCreateMappedMdl(
+ __in PVOID Address,
+ __in ULONG Length,
+ __out PMAPPED_MDL MappedMdl
+ )
+{
+ PMDL mdl;
+
+ MappedMdl->Mdl = NULL;
+ MappedMdl->Address = NULL;
+
+ mdl = IoAllocateMdl(Address, Length, FALSE, FALSE, NULL);
+
+ if (mdl == NULL)
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ MmBuildMdlForNonPagedPool(mdl);
+ mdl->MdlFlags |= MDL_MAPPED_TO_SYSTEM_VA;
+ MappedMdl->Address = MmMapLockedPagesSpecifyCache(
+ mdl,
+ KernelMode,
+ MmNonCached,
+ NULL,
+ FALSE,
+ HighPagePriority
+ );
+ MappedMdl->Mdl = mdl;
+
+ if (!MappedMdl->Address)
+ {
+ KphpFreeMappedMdl(MappedMdl);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+/* KphpFreeMappedMdl
+ *
+ * Unmaps and frees a MDL.
+ *
+ * Thread safety: Full
+ * IRQL: Any
+ */
+VOID KphpFreeMappedMdl(
+ __in PMAPPED_MDL MappedMdl
+ )
+{
+ if (MappedMdl->Mdl != NULL)
+ {
+ if (MappedMdl->Address != NULL)
+ {
+ MmUnmapLockedPages(MappedMdl->Address, MappedMdl->Mdl);
+ MappedMdl->Address = NULL;
+ }
+
+ IoFreeMdl(MappedMdl->Mdl);
+ MappedMdl->Mdl = NULL;
+ }
+}
diff --git a/2.x/trunk/KProcessHacker/i386/kprocesshacker.sys b/2.x/trunk/KProcessHacker/i386/kprocesshacker.sys
new file mode 100644
index 000000000..247c5f1fa
Binary files /dev/null and b/2.x/trunk/KProcessHacker/i386/kprocesshacker.sys differ
diff --git a/2.x/trunk/KProcessHacker/include/debug.h b/2.x/trunk/KProcessHacker/include/debug.h
new file mode 100644
index 000000000..0a140616b
--- /dev/null
+++ b/2.x/trunk/KProcessHacker/include/debug.h
@@ -0,0 +1,35 @@
+/*
+ * Process Hacker Driver -
+ * debug definitions
+ *
+ * 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 _DEBUG_H
+#define _DEBUG_H
+
+#ifdef DBG
+#define dprintf(fs, ...) DbgPrint("KProcessHacker: " fs, __VA_ARGS__)
+#else
+#define dprintf
+#endif
+
+#define dfprintf(fs, ...) DbgPrint("KProcessHacker: " fs, __VA_ARGS__)
+#define dwprintf DbgPrint
+
+#endif
diff --git a/2.x/trunk/KProcessHacker/include/ex.h b/2.x/trunk/KProcessHacker/include/ex.h
new file mode 100644
index 000000000..bfd06ccbe
--- /dev/null
+++ b/2.x/trunk/KProcessHacker/include/ex.h
@@ -0,0 +1,262 @@
+/*
+ * Process Hacker Driver -
+ * executive
+ *
+ * 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 _EX_H
+#define _EX_H
+
+#include "types.h"
+
+/* HACK - version.c dependency */
+#define WINDOWS_XP 51
+#define WINDOWS_SERVER_2003 52
+#define WINDOWS_VISTA 60
+#define WINDOWS_7 61
+
+extern ULONG WindowsVersion;
+
+/* Handles */
+
+struct _HANDLE_TABLE;
+struct _HANDLE_TABLE_ENTRY;
+
+typedef BOOLEAN (NTAPI *PEX_ENUM_HANDLE_CALLBACK)(
+ struct _HANDLE_TABLE_ENTRY *HandleTableEntry,
+ HANDLE Handle,
+ PVOID Context
+ );
+
+BOOLEAN NTAPI ExEnumHandleTable(
+ __in struct _HANDLE_TABLE *HandleTable,
+ __in PEX_ENUM_HANDLE_CALLBACK EnumHandleProcedure,
+ __inout PVOID Context,
+ __out_opt PHANDLE Handle
+ );
+
+/* Push Locks */
+
+/* Definition for Windows 2003 and above. This means we
+ * MUST use the slow path on Windows XP.
+ */
+typedef struct _EXI_PUSH_LOCK
+{
+ union
+ {
+ struct
+ {
+ ULONG_PTR Locked : 1;
+ ULONG_PTR Waiting : 1;
+ ULONG_PTR Waking : 1;
+ ULONG_PTR MultipleShared : 1;
+ ULONG_PTR Shared : sizeof(ULONG_PTR) * 8 - 4; /* ULONG_PTR bits minus 4 */
+ };
+ ULONG_PTR Value;
+ PVOID Ptr;
+ };
+} EXI_PUSH_LOCK, *PEXI_PUSH_LOCK;
+
+#define EX_PUSH_LOCK_LOCK_SHIFT 0
+#define EX_PUSH_LOCK_LOCK ((ULONG_PTR)0x1)
+/* Indicates chained waiters */
+#define EX_PUSH_LOCK_WAITING ((ULONG_PTR)0x2)
+/* Traversing the list */
+#define EX_PUSH_LOCK_WAKING ((ULONG_PTR)0x4)
+/* Multiple owners + waiters */
+#define EX_PUSH_LOCK_MULTIPLE_SHARED ((ULONG_PTR)0x8)
+
+#define EX_PUSH_LOCK_SHARE_INC ((ULONG_PTR)0x10)
+#define EX_PUSH_LOCK_PTR_BITS ((ULONG_PTR)0xf)
+
+NTKERNELAPI VOID FASTCALL ExfAcquirePushLockExclusive(
+ __inout PEX_PUSH_LOCK PushLock
+ );
+
+NTKERNELAPI VOID FASTCALL ExfAcquirePushLockShared(
+ __inout PEX_PUSH_LOCK PushLock
+ );
+
+NTKERNELAPI VOID FASTCALL ExfReleasePushLock(
+ __inout PEX_PUSH_LOCK PushLock
+ );
+
+/* The below functions are only exported on Vista and higher. */
+
+NTKERNELAPI VOID FASTCALL ExfReleasePushLockShared(
+ __inout PEX_PUSH_LOCK PushLock
+ );
+
+NTKERNELAPI VOID FASTCALL ExfReleasePushLockExclusive(
+ __inout PEX_PUSH_LOCK PushLock
+ );
+
+NTKERNELAPI BOOLEAN FASTCALL ExfTryAcquirePushLockShared(
+ __inout PEX_PUSH_LOCK PushLock
+ );
+
+NTKERNELAPI VOID FASTCALL ExfTryToWakePushLock(
+ __inout PEX_PUSH_LOCK PushLock
+ );
+
+/* Wrapper functions */
+
+/* ExInitializePushLock
+ *
+ * Initializes a push lock.
+ */
+FORCEINLINE VOID ExInitializePushLock(
+ __out PEX_PUSH_LOCK PushLock
+ )
+{
+ *PushLock = 0;
+}
+
+/* ExAcquirePushLockExclusive
+ *
+ * Acquires a push lock in exclusive mode.
+ */
+FORCEINLINE VOID ExAcquirePushLockExclusive(
+ __inout PEX_PUSH_LOCK PushLock
+ )
+{
+ /* Fast path - acquire push lock, no function call. */
+ if (WindowsVersion < WINDOWS_SERVER_2003 || InterlockedBitTestAndSet((PLONG)PushLock, EX_PUSH_LOCK_LOCK_SHIFT))
+ {
+ /* Slow path - call the function. */
+ ExfAcquirePushLockExclusive(PushLock);
+ }
+}
+
+/* ExAcquirePushLockShared
+ *
+ * Acquires a push lock in shared mode.
+ */
+FORCEINLINE VOID ExAcquirePushLockShared(
+ __inout PEX_PUSH_LOCK PushLock
+ )
+{
+ /* Fast path - acquire push lock which is not held at all, no function call. */
+ if (WindowsVersion < WINDOWS_SERVER_2003 || InterlockedCompareExchangePointer(
+ (PVOID)PushLock,
+ (PVOID)(EX_PUSH_LOCK_SHARE_INC | EX_PUSH_LOCK_LOCK),
+ 0
+ ) != 0)
+ {
+ /* Slow path - call the function. */
+ ExfAcquirePushLockShared(PushLock);
+ }
+}
+
+/* ExReleasePushLock
+ *
+ * Releases a push lock (for both types).
+ */
+FORCEINLINE VOID ExReleasePushLock(
+ __inout PEX_PUSH_LOCK PushLock
+ )
+{
+ EXI_PUSH_LOCK oldValue, newValue;
+
+ oldValue.Value = *PushLock;
+
+ /* If we are the last to release in shared mode or we
+ * are releasing in exclusive mode, we simply set
+ * the value to 0.
+ */
+
+ if (oldValue.Shared > 1)
+ {
+ /* One less shared holder. */
+ newValue.Value = oldValue.Value - EX_PUSH_LOCK_SHARE_INC;
+ }
+ else
+ {
+ newValue.Value = 0;
+ }
+
+ /* If we have chained waiters, we can't release the
+ * push lock using the fast path since they need to
+ * be unblocked.
+ */
+ if (
+ WindowsVersion < WINDOWS_SERVER_2003 ||
+ oldValue.Waiting ||
+ InterlockedCompareExchangePointer(
+ (PVOID)PushLock,
+ newValue.Ptr,
+ oldValue.Ptr
+ ) != oldValue.Ptr
+ )
+ {
+ /* Slow path - call the function. */
+ ExfReleasePushLock(PushLock);
+ }
+}
+
+#ifndef NEVER_DEFINED
+/* ExTryAcquirePushLockExclusive
+ *
+ * Attempts to acquire a push lock in exclusive mode.
+ *
+ * Return value: TRUE if the push lock was acquired, FALSE if
+ * the push lock was already acquired in exclusive mode.
+ */
+FORCEINLINE BOOLEAN ExTryAcquirePushLockExclusive(
+ __inout PEX_PUSH_LOCK PushLock
+ )
+{
+ if (!InterlockedBitTestAndSet((PLONG)PushLock, EX_PUSH_LOCK_LOCK_SHIFT))
+ {
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+/* ExTryAcquirePushLockShared
+ *
+ * Attempts to acquire a push lock in shared mode.
+ *
+ * Return value: TRUE if the push lock was acquired, FALSE if
+ * the push lock was already acquired in exclusive mode.
+ */
+FORCEINLINE BOOLEAN ExTryAcquirePushLockShared(
+ __inout PEX_PUSH_LOCK PushLock
+ )
+{
+ /* Fast path with the push lock not held at all. */
+ if (InterlockedCompareExchangePointer(
+ (PVOID)PushLock,
+ (PVOID)(EX_PUSH_LOCK_SHARE_INC | EX_PUSH_LOCK_LOCK),
+ 0
+ ) != 0)
+ {
+ return ExfTryAcquirePushLockShared(PushLock);
+ }
+ else
+ {
+ return TRUE;
+ }
+}
+#endif
+
+#endif
\ No newline at end of file
diff --git a/2.x/trunk/KProcessHacker/include/handle.h b/2.x/trunk/KProcessHacker/include/handle.h
new file mode 100644
index 000000000..710205b3e
--- /dev/null
+++ b/2.x/trunk/KProcessHacker/include/handle.h
@@ -0,0 +1,78 @@
+/*
+ * Process Hacker Driver -
+ * handle table
+ *
+ * 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 _HANDLE_H
+#define _HANDLE_H
+
+#include "kph.h"
+#include "ref.h"
+
+struct _KPH_HANDLE_TABLE;
+typedef struct _KPH_HANDLE_TABLE *PKPH_HANDLE_TABLE;
+
+typedef struct _KPH_HANDLE_TABLE_ENTRY
+{
+ union
+ {
+ HANDLE Handle;
+ ULONG_PTR Value;
+ struct _KPH_HANDLE_TABLE_ENTRY *NextFree;
+ };
+ PVOID Object;
+} KPH_HANDLE_TABLE_ENTRY, *PKPH_HANDLE_TABLE_ENTRY;
+
+NTSTATUS KphCreateHandleTable(
+ __out PKPH_HANDLE_TABLE *HandleTable,
+ __in ULONG MaximumHandles,
+ __in ULONG SizeOfEntry,
+ __in ULONG Tag
+ );
+
+VOID KphFreeHandleTable(
+ __in PKPH_HANDLE_TABLE HandleTable
+ );
+
+NTSTATUS KphCloseHandle(
+ __in PKPH_HANDLE_TABLE HandleTable,
+ __in HANDLE Handle
+ );
+
+NTSTATUS KphCreateHandle(
+ __in PKPH_HANDLE_TABLE HandleTable,
+ __in PVOID Object,
+ __out PHANDLE Handle
+ );
+
+NTSTATUS KphReferenceObjectByHandle(
+ __in PKPH_HANDLE_TABLE HandleTable,
+ __in HANDLE Handle,
+ __in_opt PKPH_OBJECT_TYPE ObjectType,
+ __out PVOID *Object
+ );
+
+BOOLEAN KphValidHandle(
+ __in PKPH_HANDLE_TABLE HandleTable,
+ __in HANDLE Handle,
+ __out_opt PKPH_HANDLE_TABLE_ENTRY *Entry
+ );
+
+#endif
diff --git a/2.x/trunk/KProcessHacker/include/handlep.h b/2.x/trunk/KProcessHacker/include/handlep.h
new file mode 100644
index 000000000..a6cd445ee
--- /dev/null
+++ b/2.x/trunk/KProcessHacker/include/handlep.h
@@ -0,0 +1,144 @@
+/*
+ * Process Hacker Driver -
+ * handle table
+ *
+ * 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 _HANDLEP_H
+#define _HANDLEP_H
+
+#define _HANDLE_PRIVATE
+#include "handle.h"
+#include "sync.h"
+
+#define KPH_HANDLE_INCREMENT 4
+#define KPH_HANDLE_LOCKED 0x1
+#define KPH_HANDLE_LOCKED_SHIFT 0
+#define KPH_HANDLE_ALLOCATED 0x2
+#define KPH_HANDLE_FLAGS 0x3
+
+#define KphGetFlagsEntry(Entry) ((Entry)->Value & KPH_HANDLE_FLAGS)
+#define KphGetHandleEntry(Entry) ((HANDLE)((Entry)->Value & ~KPH_HANDLE_FLAGS))
+#define KphIncrementHandle(Handle) ((HANDLE)((ULONG_PTR)(Handle) + KPH_HANDLE_INCREMENT))
+
+#define KphIsAllocatedEntry(Entry) ((Entry)->Value & KPH_HANDLE_ALLOCATED)
+#define KphClearAllocatedEntry(Entry) ((Entry)->Value &= ~KPH_HANDLE_ALLOCATED)
+#define KphSetAllocatedEntry(Entry) ((Entry)->Value |= KPH_HANDLE_ALLOCATED)
+
+#define KphGetNextFreeEntry(Entry) ((PKPH_HANDLE_TABLE_ENTRY)((Entry)->Value & ~KPH_HANDLE_FLAGS))
+#define KphSetNextFreeEntry(Entry, NextFree) ((Entry)->Value = ((ULONG_PTR)(NextFree) | KphGetFlagsEntry(Entry)))
+
+#define KphHandleFromIndex(Index) ((HANDLE)((ULONG_PTR)(Index) * KPH_HANDLE_INCREMENT))
+#define KphHandleFromIndexEx(Index, Flags) ((HANDLE)(((Index) * KPH_HANDLE_INCREMENT) | (Flags)))
+#define KphIndexFromHandle(Handle) (((ULONG_PTR)(Handle) & ~KPH_HANDLE_FLAGS) / KPH_HANDLE_INCREMENT)
+
+#define KphEntryFromHandle(HandleTable, Handle) KphEntryFromIndex((HandleTable), KphIndexFromHandle(Handle))
+#define KphEntryFromIndex(HandleTable, Index) \
+ ((PKPH_HANDLE_TABLE_ENTRY)((ULONG_PTR)(HandleTable)->Table + (Index) * (HandleTable)->SizeOfEntry))
+#define KphHandleFromEntry(HandleTable, Entry) KphHandleFromIndex(KphIndexFromEntry((HandleTable), (Entry)))
+#define KphHandleFromEntryEx(HandleTable, Entry, Flags) \
+ KphHandleFromIndexEx(KphIndexFromEntry((HandleTable), (Entry)), (Flags))
+#define KphIndexFromEntry(HandleTable, Entry) \
+ (((ULONG_PTR)(Entry) - (ULONG_PTR)(HandleTable)->Table) / (HandleTable)->SizeOfEntry)
+
+typedef struct _KPH_HANDLE_TABLE
+{
+ /* The pool tag used for this descriptor and the table itself. */
+ ULONG Tag;
+ /* The size of each handle table entry. */
+ ULONG SizeOfEntry;
+ /* The next handle value to use. */
+ HANDLE NextHandle;
+ /* The free list of handle table entries. */
+ struct _KPH_HANDLE_TABLE_ENTRY *FreeHandle;
+
+ /* A fast mutex guarding writes to the handle table. */
+ FAST_MUTEX Mutex;
+ /* The size of the table, in bytes. */
+ ULONG TableSize;
+ /* The actual handle table. */
+ PVOID Table;
+} KPH_HANDLE_TABLE, *PKPH_HANDLE_TABLE;
+
+FORCEINLINE BOOLEAN KphLockHandleEntry(
+ __inout PKPH_HANDLE_TABLE_ENTRY Entry
+ );
+
+FORCEINLINE BOOLEAN KphLockAllocatedHandleEntry(
+ __inout PKPH_HANDLE_TABLE_ENTRY Entry
+ );
+
+FORCEINLINE VOID KphUnlockHandleEntry(
+ __inout PKPH_HANDLE_TABLE_ENTRY Entry
+ );
+
+/* KphLockHandle
+ *
+ * Locks a handle table entry for exclusive access. Do not
+ * modify the lowest bit of the entry's value while you
+ * hold the lock.
+ *
+ * Return value: TRUE if the entry is allocated, otherwise FALSE.
+ */
+FORCEINLINE BOOLEAN KphLockHandleEntry(
+ __inout PKPH_HANDLE_TABLE_ENTRY Entry
+ )
+{
+ /* Acquire the spinlock. */
+ KphAcquireBitSpinLock((PLONG)&Entry->Value, KPH_HANDLE_LOCKED_SHIFT);
+
+ /* Return whether the entry is allocated. */
+ return !!(Entry->Value & KPH_HANDLE_ALLOCATED);
+}
+
+/* KphLockAllocatedHandle
+ *
+ * Locks a handle table entry for exclusive access. Do not
+ * modify the lowest bit of the entry's value while you
+ * hold the lock.
+ * The function will not lock the handle if it is unallocated.
+ *
+ * Return value: TRUE if the entry was locked, otherwise FALSE.
+ */
+FORCEINLINE BOOLEAN KphLockAllocatedHandleEntry(
+ __inout PKPH_HANDLE_TABLE_ENTRY Entry
+ )
+{
+ if (!KphLockHandleEntry(Entry))
+ {
+ KphUnlockHandleEntry(Entry);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/* KphUnlockHandle
+ *
+ * Unlocks a handle table entry.
+ */
+FORCEINLINE VOID KphUnlockHandleEntry(
+ __inout PKPH_HANDLE_TABLE_ENTRY Entry
+ )
+{
+ /* Unlock the spinlock. */
+ KphReleaseBitSpinLock((PLONG)&Entry->Value, KPH_HANDLE_LOCKED_SHIFT);
+}
+
+#endif
diff --git a/2.x/trunk/KProcessHacker/include/hook.h b/2.x/trunk/KProcessHacker/include/hook.h
new file mode 100644
index 000000000..12ec3d3f9
--- /dev/null
+++ b/2.x/trunk/KProcessHacker/include/hook.h
@@ -0,0 +1,108 @@
+/*
+ * Process Hacker Driver -
+ * hooks
+ *
+ * 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 _HOOK_H
+#define _HOOK_H
+
+#include "kph.h"
+#include "ob.h"
+
+#define KPH_DEFINE_HOOK_CALL(Name, Arguments, Hook) \
+ __declspec(naked) Name(Arguments) \
+ { \
+ __asm lea eax, Hook \
+ __asm mov eax, [eax+KPH_HOOK.Function] \
+ __asm add eax, 5 \
+ __asm push ebp \
+ __asm mov ebp, esp \
+ __asm jmp eax \
+ } \
+
+typedef struct _KPH_HOOK
+{
+ /* The address of the hooked function.
+ Should NOT be a function that is callable above PASSIVE_LEVEL. */
+ PVOID Function;
+ /* The address of the new function. */
+ PVOID Target;
+ /* Whether the function is hooked. */
+ BOOLEAN Hooked;
+ /* The original first 10 bytes. */
+ CHAR Bytes[10];
+} KPH_HOOK, *PKPH_HOOK;
+
+typedef struct _KPH_OB_OPEN_HOOK
+{
+ /* The object type that is being hooked. */
+ POBJECT_TYPE ObjectType;
+ /* The original open procedure. */
+ PVOID Function;
+ /* The new open procedure for NT 5.1 (XP). */
+ OB_OPEN_METHOD_51 Target51;
+ /* The new open procedure for NT 6.1 and above (Vista, 7 or higher). */
+ OB_OPEN_METHOD_60 Target60;
+ /* Whether the open procedure is hooked. */
+ BOOLEAN Hooked;
+} KPH_OB_OPEN_HOOK, *PKPH_OB_OPEN_HOOK;
+
+NTSTATUS KphHookInit();
+
+VOID KphInitializeHook(
+ __out PKPH_HOOK Hook,
+ __in PVOID Function,
+ __in PVOID Target
+ );
+
+NTSTATUS KphHook(
+ __inout PKPH_HOOK Hook
+ );
+
+NTSTATUS KphUnhook(
+ __inout PKPH_HOOK Hook
+ );
+
+NTSTATUS NTAPI KphObOpenCall(
+ __in PKPH_OB_OPEN_HOOK ObOpenHook,
+ __in OB_OPEN_REASON OpenReason,
+ __in KPROCESSOR_MODE AccessMode,
+ __in PEPROCESS Process,
+ __in PVOID Object,
+ __in ACCESS_MASK GrantedAccess,
+ __in ULONG HandleCount
+ );
+
+VOID KphInitializeObOpenHook(
+ __inout PKPH_OB_OPEN_HOOK ObOpenHook,
+ __in POBJECT_TYPE ObjectType,
+ __in PVOID Target51,
+ __in PVOID Target60
+ );
+
+NTSTATUS KphObOpenHook(
+ __inout PKPH_OB_OPEN_HOOK ObOpenHook
+ );
+
+NTSTATUS KphObOpenUnhook(
+ __inout PKPH_OB_OPEN_HOOK ObOpenHook
+ );
+
+#endif
diff --git a/2.x/trunk/KProcessHacker/include/io.h b/2.x/trunk/KProcessHacker/include/io.h
new file mode 100644
index 000000000..bc98fb151
--- /dev/null
+++ b/2.x/trunk/KProcessHacker/include/io.h
@@ -0,0 +1,34 @@
+/*
+ * Process Hacker Driver -
+ * I/O manager
+ *
+ * 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 _IO_H
+#define _IO_H
+
+#include "types.h"
+
+extern POBJECT_TYPE *IoAdapterObjectType;
+extern POBJECT_TYPE *IoControllerObjectType;
+extern POBJECT_TYPE *IoDeviceHandlerObjectType; /* not used anymore */
+extern POBJECT_TYPE *IoDeviceObjectType;
+extern POBJECT_TYPE *IoDriverObjectType;
+
+#endif
\ No newline at end of file
diff --git a/2.x/trunk/KProcessHacker/include/ke.h b/2.x/trunk/KProcessHacker/include/ke.h
new file mode 100644
index 000000000..741c1b00b
--- /dev/null
+++ b/2.x/trunk/KProcessHacker/include/ke.h
@@ -0,0 +1,95 @@
+/*
+ * Process Hacker Driver -
+ * kernel
+ *
+ * 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 _KE_H
+#define _KE_H
+
+#include "types.h"
+
+/* APCs */
+
+typedef enum _KAPC_ENVIRONMENT
+{
+ OriginalApcEnvironment,
+ AttachedApcEnvironment,
+ CurrentApcEnvironment,
+ InsertApcEnvironment
+} KAPC_ENVIRONMENT, *PKAPC_ENVIRONMENT;
+
+typedef VOID (NTAPI *PKKERNEL_ROUTINE)(
+ PKAPC Apc,
+ PKNORMAL_ROUTINE *NormalRoutine,
+ PVOID *NormalContext,
+ PVOID *SystemArgument1,
+ PVOID *SystemArgument2
+ );
+
+typedef VOID (NTAPI *PKRUNDOWN_ROUTINE)(
+ PKAPC Apc
+ );
+
+typedef VOID (NTAPI *PKNORMAL_ROUTINE)(
+ PVOID NormalContext,
+ PVOID SystemArgument1,
+ PVOID SystemArgument2
+ );
+
+NTKERNELAPI VOID NTAPI KeInitializeApc(
+ PKAPC Apc,
+ PKTHREAD Thread,
+ KAPC_ENVIRONMENT Environment,
+ PKKERNEL_ROUTINE KernelRoutine,
+ PKRUNDOWN_ROUTINE RundownRoutine,
+ PKNORMAL_ROUTINE NormalRoutine,
+ KPROCESSOR_MODE ProcessorMode,
+ PVOID NormalContext
+ );
+
+NTKERNELAPI BOOLEAN NTAPI KeInsertQueueApc(
+ PRKAPC Apc,
+ PVOID SystemArgument1,
+ PVOID SystemArgument2,
+ KPRIORITY Increment
+ );
+
+/* System services */
+
+/* Exported by ntoskrnl as KeServiceDescriptorTable. */
+typedef struct _KSERVICE_TABLE_DESCRIPTOR
+{
+ /* A pointer to an array of ULONG_PTRs - addresses of
+ * system services.
+ */
+ PULONG_PTR Base;
+ /* A pointer to an array of ULONGs which contain counters for
+ * the system services.
+ */
+ PULONG Count;
+ /* The number of system services. */
+ ULONG Limit;
+ /* A pointer to an array of UCHARs which contain
+ * the number of arguments (in bytes) for each system service.
+ */
+ PUCHAR Number;
+} KSERVICE_TABLE_DESCRIPTOR, *PKSERVICE_TABLE_DESCRIPTOR;
+
+#endif
\ No newline at end of file
diff --git a/2.x/trunk/KProcessHacker/include/kph.h b/2.x/trunk/KProcessHacker/include/kph.h
new file mode 100644
index 000000000..99c7a8e8d
--- /dev/null
+++ b/2.x/trunk/KProcessHacker/include/kph.h
@@ -0,0 +1,506 @@
+/*
+ * Process Hacker Driver -
+ * custom APIs
+ *
+ * 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 _KPH_H
+#define _KPH_H
+
+#include "types.h"
+#include "debug.h"
+#include "ref.h"
+#include "version.h"
+
+#include "ke.h"
+#include "mm.h"
+#include "ps.h"
+#include "trace.h"
+#include "zw.h"
+
+#define MAX_UINTEGER(Bits) ((1 << (Bits)) - 1)
+#define BITS_UCHAR 8
+#define MAX_UCHAR MAX_UINTEGER(BITS_UCHAR)
+#define BITS_USHORT 16
+#define MAX_USHORT MAX_UINTEGER(BITS_USHORT)
+#define BITS_ULONG 32
+#define MAX_ULONG MAX_UINTEGER(BITS_ULONG)
+
+#define SYSTEM_PROCESS_ID ((HANDLE)4)
+#define KERNEL_HANDLE_BIT ((ULONG_PTR)1 << (sizeof(HANDLE) * 8 - 1))
+#define IsKernelHandle(Handle) ((LONG_PTR)(Handle) < 0)
+#define MakeKernelHandle(Handle) ((ULONG_PTR)(Handle) |= KERNEL_HANDLE_BIT)
+
+#define PTR_ADD_OFFSET(Pointer, Offset) ((PVOID)((ULONG_PTR)(Pointer) + (ULONG_PTR)(Offset)))
+
+#define GET_BIT(Integer, Bit) (((Integer) >> (Bit)) & 0x1)
+#define SET_BIT(Integer, Bit) ((Integer) |= 1 << (Bit))
+#define CLEAR_BIT(Integer, Bit) ((Integer) &= ~(1 << (Bit)))
+
+#define KPH_TIMEOUT_TO_SEC ((LONGLONG) 1 * 10 * 1000 * 1000)
+#define KPH_REL_TIMEOUT_IN_SEC(Time) (Time * -1 * KPH_TIMEOUT_TO_SEC)
+
+#define TAG_CAPTURED_UNICODE_STRING ('UChP')
+
+#ifdef EXT
+#undef EXT
+#endif
+
+#ifdef _KPH_PRIVATE
+#define EXT
+#define EQNULL = NULL
+#else
+#define EXT extern
+#define EQNULL
+#endif
+
+EXT POBJECT_TYPE *ObDirectoryObjectType EQNULL;
+EXT POBJECT_TYPE *ObTypeObjectType EQNULL;
+
+EXT PKSERVICE_TABLE_DESCRIPTOR __KeServiceDescriptorTable EQNULL;
+EXT PVOID __KiFastCallEntry EQNULL;
+EXT _NtClose __NtClose EQNULL;
+EXT _ObGetObjectType ObGetObjectType EQNULL;
+EXT _PsGetProcessJob PsGetProcessJob EQNULL;
+EXT _PsResumeProcess PsResumeProcess EQNULL;
+EXT _PsSuspendProcess PsSuspendProcess EQNULL;
+EXT _PsTerminateProcess __PsTerminateProcess EQNULL;
+EXT PVOID __PspTerminateThreadByPointer EQNULL;
+EXT _NtClose __ZwClose EQNULL;
+
+/* Driver information */
+
+typedef enum _DRIVER_INFORMATION_CLASS
+{
+ DriverBasicInformation,
+ DriverNameInformation,
+ DriverServiceKeyNameInformation,
+ MaxDriverInfoClass
+} DRIVER_INFORMATION_CLASS;
+
+typedef struct _DRIVER_BASIC_INFORMATION
+{
+ ULONG Flags;
+ PVOID DriverStart;
+ ULONG DriverSize;
+} DRIVER_BASIC_INFORMATION, *PDRIVER_BASIC_INFORMATION;
+
+typedef struct _KPH_ATTACH_STATE
+{
+ BOOLEAN Attached;
+ PEPROCESS Process;
+ KAPC_STATE ApcState;
+} KPH_ATTACH_STATE, *PKPH_ATTACH_STATE;
+
+typedef struct _MAPPED_MDL
+{
+ PMDL Mdl;
+ PVOID Address;
+} MAPPED_MDL, *PMAPPED_MDL;
+
+typedef struct _PROCESS_HANDLE
+{
+ HANDLE Handle;
+ PVOID Object;
+ ACCESS_MASK GrantedAccess;
+ ULONG HandleAttributes;
+} PROCESS_HANDLE, *PPROCESS_HANDLE;
+
+typedef struct _PROCESS_HANDLE_INFORMATION
+{
+ ULONG HandleCount;
+ PROCESS_HANDLE Handles[1];
+} PROCESS_HANDLE_INFORMATION, *PPROCESS_HANDLE_INFORMATION;
+
+/* Support routines */
+
+NTSTATUS KphNtInit();
+
+PVOID GetSystemRoutineAddress(
+ WCHAR *Name
+ );
+
+VOID KphAttachProcess(
+ __in PEPROCESS Process,
+ __out PKPH_ATTACH_STATE AttachState
+ );
+
+NTSTATUS KphAttachProcessHandle(
+ __in HANDLE ProcessHandle,
+ __out PKPH_ATTACH_STATE AttachState
+ );
+
+NTSTATUS KphAttachProcessId(
+ __in HANDLE ProcessId,
+ __out PKPH_ATTACH_STATE AttachState
+ );
+
+NTSTATUS KphCaptureUnicodeString(
+ __in PUNICODE_STRING UnicodeString,
+ __out PUNICODE_STRING CapturedUnicodeString
+ );
+
+VOID KphDetachProcess(
+ __in PKPH_ATTACH_STATE AttachState
+ );
+
+VOID KphFreeCapturedUnicodeString(
+ __in PUNICODE_STRING CapturedUnicodeString
+ );
+
+VOID KphProbeForReadUnicodeString(
+ __in PUNICODE_STRING UnicodeString
+ );
+
+VOID KphProbeSystemAddressRange(
+ __in PVOID BaseAddress,
+ __in ULONG Length
+ );
+
+NTSTATUS OpenProcess(
+ __out PHANDLE ProcessHandle,
+ __in ACCESS_MASK DesiredAccess,
+ __in HANDLE ProcessId
+ );
+
+NTSTATUS SetProcessToken(
+ __in HANDLE sourcePid,
+ __in HANDLE targetPid
+ );
+
+/* KProcessHacker */
+
+BOOLEAN KphAcquireProcessRundownProtection(
+ __in PEPROCESS Process
+ );
+
+NTSTATUS KphAssignImpersonationToken(
+ __in HANDLE ThreadHandle,
+ __in HANDLE TokenHandle
+ );
+
+NTSTATUS KphCaptureStackBackTraceThread(
+ __in HANDLE ThreadHandle,
+ __in ULONG FramesToSkip,
+ __in ULONG FramesToCapture,
+ __out_ecount(FramesToCapture) PVOID *BackTrace,
+ __out_opt PULONG CapturedFrames,
+ __out_opt PULONG BackTraceHash,
+ __in KPROCESSOR_MODE AccessMode
+ );
+
+NTSTATUS KphDangerousTerminateThread(
+ __in HANDLE ThreadHandle,
+ __in NTSTATUS ExitStatus
+ );
+
+NTSTATUS KphDuplicateObject(
+ __in HANDLE SourceProcessHandle,
+ __in HANDLE SourceHandle,
+ __in_opt HANDLE TargetProcessHandle,
+ __out_opt PHANDLE TargetHandle,
+ __in ACCESS_MASK DesiredAccess,
+ __in ULONG HandleAttributes,
+ __in ULONG Options,
+ __in KPROCESSOR_MODE AccessMode
+ );
+
+BOOLEAN KphEnumProcessHandleTable(
+ __in PEPROCESS Process,
+ __in PEX_ENUM_HANDLE_CALLBACK EnumHandleProcedure,
+ __inout PVOID Context,
+ __out_opt PHANDLE Handle
+ );
+
+NTSTATUS KphGetContextThread(
+ __in HANDLE ThreadHandle,
+ __inout PCONTEXT ThreadContext,
+ __in KPROCESSOR_MODE AccessMode
+ );
+
+POBJECT_TYPE KphGetObjectTypeNt(
+ __in PVOID Object
+ );
+
+HANDLE KphGetProcessId(
+ __in HANDLE ProcessHandle
+ );
+
+HANDLE KphGetThreadId(
+ __in HANDLE ThreadHandle,
+ __out_opt PHANDLE ProcessId
+ );
+
+NTSTATUS KphGetThreadWin32Thread(
+ __in HANDLE ThreadHandle,
+ __out PVOID *Win32Thread,
+ __in KPROCESSOR_MODE AccessMode
+ );
+
+NTSTATUS KphOpenDirectoryObject(
+ __out PHANDLE DirectoryObjectHandle,
+ __in ACCESS_MASK DesiredAccess,
+ __in POBJECT_ATTRIBUTES ObjectAttributes,
+ __in KPROCESSOR_MODE AccessMode
+ );
+
+NTSTATUS KphOpenDriver(
+ __out PHANDLE DriverHandle,
+ __in POBJECT_ATTRIBUTES ObjectAttributes,
+ __in KPROCESSOR_MODE AccessMode
+ );
+
+NTSTATUS KphOpenNamedObject(
+ __out PHANDLE ObjectHandle,
+ __in ACCESS_MASK DesiredAccess,
+ __in POBJECT_ATTRIBUTES ObjectAttributes,
+ __in POBJECT_TYPE ObjectType,
+ __in KPROCESSOR_MODE AccessMode
+ );
+
+NTSTATUS KphOpenProcess(
+ __out PHANDLE ProcessHandle,
+ __in ACCESS_MASK DesiredAccess,
+ __in POBJECT_ATTRIBUTES ObjectAttributes,
+ __in_opt PCLIENT_ID ClientId,
+ __in KPROCESSOR_MODE AccessMode
+ );
+
+NTSTATUS KphOpenProcessJob(
+ __in HANDLE ProcessHandle,
+ __in ACCESS_MASK DesiredAccess,
+ __out PHANDLE JobHandle,
+ __in KPROCESSOR_MODE AccessMode
+ );
+
+NTSTATUS KphOpenProcessTokenEx(
+ __in HANDLE ProcessHandle,
+ __in ACCESS_MASK DesiredAccess,
+ __in ULONG ObjectAttributes,
+ __out PHANDLE TokenHandle,
+ __in KPROCESSOR_MODE AccessMode
+ );
+
+NTSTATUS KphOpenThread(
+ __out PHANDLE ThreadHandle,
+ __in ACCESS_MASK DesiredAccess,
+ __in POBJECT_ATTRIBUTES ObjectAttributes,
+ __in_opt PCLIENT_ID ClientId,
+ __in KPROCESSOR_MODE AccessMode
+ );
+
+NTSTATUS KphOpenThreadProcess(
+ __in HANDLE ThreadHandle,
+ __in ACCESS_MASK DesiredAccess,
+ __out PHANDLE ProcessHandle,
+ __in KPROCESSOR_MODE AccessMode
+ );
+
+NTSTATUS KphOpenType(
+ __out PHANDLE TypeHandle,
+ __in POBJECT_ATTRIBUTES ObjectAttributes,
+ __in KPROCESSOR_MODE AccessMode
+ );
+
+NTSTATUS KphQueryInformationDriver(
+ __in HANDLE DriverHandle,
+ __in DRIVER_INFORMATION_CLASS DriverInformationClass,
+ __out_bcount_opt(DriverInformationLength) PVOID DriverInformation,
+ __in ULONG DriverInformationLength,
+ __out_opt PULONG ReturnLength,
+ __in KPROCESSOR_MODE AccessMode
+ );
+
+NTSTATUS KphQueryNameFileObject(
+ __in PFILE_OBJECT FileObject,
+ __inout_bcount(BufferLength) PUNICODE_STRING Buffer,
+ __in ULONG BufferLength,
+ __out PULONG ReturnLength
+ );
+
+NTSTATUS KphQueryNameObject(
+ __in PVOID Object,
+ __inout_bcount(BufferLength) PUNICODE_STRING Buffer,
+ __in ULONG BufferLength,
+ __out PULONG ReturnLength
+ );
+
+NTSTATUS KphQueryProcessHandles(
+ __in HANDLE ProcessHandle,
+ __out_bcount_opt(BufferLength) PPROCESS_HANDLE_INFORMATION Buffer,
+ __in_opt ULONG BufferLength,
+ __out_opt PULONG ReturnLength,
+ __in KPROCESSOR_MODE AccessMode
+ );
+
+NTSTATUS KphReadVirtualMemory(
+ __in HANDLE ProcessHandle,
+ __in PVOID BaseAddress,
+ __out_bcount(BufferLength) PVOID Buffer,
+ __in ULONG BufferLength,
+ __out_opt PULONG ReturnLength,
+ __in KPROCESSOR_MODE AccessMode
+ );
+
+VOID KphReleaseProcessRundownProtection(
+ __in PEPROCESS Process
+ );
+
+NTSTATUS KphResumeProcess(
+ __in HANDLE ProcessHandle
+ );
+
+NTSTATUS KphSetContextThread(
+ __in HANDLE ThreadHandle,
+ __in PCONTEXT ThreadContext,
+ __in KPROCESSOR_MODE AccessMode
+ );
+
+NTSTATUS KphSetHandleGrantedAccess(
+ __in PEPROCESS Process,
+ __in HANDLE Handle,
+ __in ACCESS_MASK GrantedAccess
+ );
+
+NTSTATUS KphSuspendProcess(
+ __in HANDLE ProcessHandle
+ );
+
+NTSTATUS KphTerminateProcess(
+ __in HANDLE ProcessHandle,
+ __in NTSTATUS ExitStatus
+ );
+
+NTSTATUS KphTerminateThread(
+ __in HANDLE ThreadHandle,
+ __in NTSTATUS ExitStatus
+ );
+
+NTSTATUS KphUnsafeReadVirtualMemory(
+ __in HANDLE ProcessHandle,
+ __in PVOID BaseAddress,
+ __out_bcount(BufferLength) PVOID Buffer,
+ __in ULONG BufferLength,
+ __out_opt PULONG ReturnLength,
+ __in KPROCESSOR_MODE AccessMode
+ );
+
+NTSTATUS KphWriteVirtualMemory(
+ __in HANDLE ProcessHandle,
+ __in PVOID BaseAddress,
+ __in_bcount(BufferLength) PVOID Buffer,
+ __in ULONG BufferLength,
+ __out_opt PULONG ReturnLength,
+ __in KPROCESSOR_MODE AccessMode
+ );
+
+/* MM */
+
+NTSTATUS MiDoMappedCopy(
+ __in PEPROCESS FromProcess,
+ __in PVOID FromAddress,
+ __in PEPROCESS ToProcess,
+ __in PVOID ToAddress,
+ __in ULONG BufferLength,
+ __in KPROCESSOR_MODE AccessMode,
+ __out PULONG ReturnLength
+ );
+
+NTSTATUS MiDoPoolCopy(
+ __in PEPROCESS FromProcess,
+ __in PVOID FromAddress,
+ __in PEPROCESS ToProcess,
+ __in PVOID ToAddress,
+ __in ULONG BufferLength,
+ __in KPROCESSOR_MODE AccessMode,
+ __out PULONG ReturnLength
+ );
+
+ULONG MiGetExceptionInfo(
+ __in PEXCEPTION_POINTERS ExceptionInfo,
+ __out PBOOLEAN HaveBadAddress,
+ __out PULONG_PTR BadAddress
+ );
+
+NTSTATUS MmCopyVirtualMemory(
+ __in PEPROCESS FromProcess,
+ __in PVOID FromAddress,
+ __in PEPROCESS ToProcess,
+ __in PVOID ToAddress,
+ __in ULONG BufferLength,
+ __in KPROCESSOR_MODE AccessMode,
+ __out PULONG ReturnLength
+ );
+
+/* KProcessHacker private */
+
+NTSTATUS KphpCaptureStackBackTraceThread(
+ __in PETHREAD Thread,
+ __in ULONG FramesToSkip,
+ __in ULONG FramesToCapture,
+ __out_ecount(FramesToCapture) PVOID *BackTrace,
+ __out_opt PULONG CapturedFrames,
+ __out_opt PULONG BackTraceHash,
+ __in KPROCESSOR_MODE AccessMode
+ );
+
+NTSTATUS KphpCreateMappedMdl(
+ __in PVOID Address,
+ __in ULONG Length,
+ __out PMAPPED_MDL MappedMdl
+ );
+
+VOID KphpFreeMappedMdl(
+ __in PMAPPED_MDL MappedMdl
+ );
+
+/* OB */
+
+NTSTATUS ObDuplicateObject(
+ __in PEPROCESS SourceProcess,
+ __in_opt PEPROCESS TargetProcess,
+ __in HANDLE SourceHandle,
+ __out_opt PHANDLE TargetHandle,
+ __in ACCESS_MASK DesiredAccess,
+ __in ULONG HandleAttributes,
+ __in ULONG Options,
+ __in KPROCESSOR_MODE AccessMode
+ );
+
+PHANDLE_TABLE ObReferenceProcessHandleTable(
+ __in PEPROCESS Process
+ );
+
+VOID ObDereferenceProcessHandleTable(
+ __in PEPROCESS Process
+ );
+
+/* PS */
+
+NTSTATUS PsTerminateProcess(
+ __in PEPROCESS Process,
+ __in NTSTATUS ExitStatus
+ );
+
+NTSTATUS PspTerminateThreadByPointer(
+ __in PETHREAD Thread,
+ __in NTSTATUS ExitStatus
+ );
+
+#endif
\ No newline at end of file
diff --git a/2.x/trunk/KProcessHacker/include/kprocesshacker.h b/2.x/trunk/KProcessHacker/include/kprocesshacker.h
new file mode 100644
index 000000000..0df5a7326
--- /dev/null
+++ b/2.x/trunk/KProcessHacker/include/kprocesshacker.h
@@ -0,0 +1,170 @@
+/*
+ * Process Hacker Driver -
+ * main header file
+ *
+ * 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 KPROCESSHACKER_H
+#define KPROCESSHACKER_H
+
+#include "include/kph.h"
+#include "include/handle.h"
+#include "include/ref.h"
+#include "include/sync.h"
+
+/* KPH Configuration */
+
+//#define KPH_REQUIRE_DEBUG_PRIVILEGE
+
+/* Device */
+
+#define KPH_DEVICE_TYPE (0x9999)
+#define KPH_DEVICE_NAME (L"\\Device\\KProcessHacker")
+#define KPH_DEVICE_DOS_NAME (L"\\DosDevices\\KProcessHacker")
+
+/* Features */
+
+#define KPHF_PSTERMINATEPROCESS 0x1
+#define KPHF_PSPTERMINATETHREADBPYPOINTER 0x2
+
+/* Control Codes */
+
+#define KPH_CTL_CODE(x) CTL_CODE(KPH_DEVICE_TYPE, 0x800 + x, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define KPH_CLOSEHANDLE KPH_CTL_CODE(0)
+#define KPH_SSQUERYCLIENTENTRY KPH_CTL_CODE(1)
+#define KPH_RESERVED1 KPH_CTL_CODE(2)
+#define KPH_OPENPROCESS KPH_CTL_CODE(3)
+#define KPH_OPENTHREAD KPH_CTL_CODE(4)
+#define KPH_OPENPROCESSTOKEN KPH_CTL_CODE(5)
+#define KPH_GETPROCESSPROTECTED KPH_CTL_CODE(6)
+#define KPH_SETPROCESSPROTECTED KPH_CTL_CODE(7)
+#define KPH_TERMINATEPROCESS KPH_CTL_CODE(8)
+#define KPH_SUSPENDPROCESS KPH_CTL_CODE(9)
+#define KPH_RESUMEPROCESS KPH_CTL_CODE(10)
+#define KPH_READVIRTUALMEMORY KPH_CTL_CODE(11)
+#define KPH_WRITEVIRTUALMEMORY KPH_CTL_CODE(12)
+#define KPH_SETPROCESSTOKEN KPH_CTL_CODE(13)
+#define KPH_GETTHREADSTARTADDRESS KPH_CTL_CODE(14)
+#define KPH_SETHANDLEATTRIBUTES KPH_CTL_CODE(15)
+#define KPH_GETHANDLEOBJECTNAME KPH_CTL_CODE(16)
+#define KPH_OPENPROCESSJOB KPH_CTL_CODE(17)
+#define KPH_GETCONTEXTTHREAD KPH_CTL_CODE(18)
+#define KPH_SETCONTEXTTHREAD KPH_CTL_CODE(19)
+#define KPH_GETTHREADWIN32THREAD KPH_CTL_CODE(20)
+#define KPH_DUPLICATEOBJECT KPH_CTL_CODE(21)
+#define KPH_ZWQUERYOBJECT KPH_CTL_CODE(22)
+#define KPH_GETPROCESSID KPH_CTL_CODE(23)
+#define KPH_GETTHREADID KPH_CTL_CODE(24)
+#define KPH_TERMINATETHREAD KPH_CTL_CODE(25)
+#define KPH_GETFEATURES KPH_CTL_CODE(26)
+#define KPH_SETHANDLEGRANTEDACCESS KPH_CTL_CODE(27)
+#define KPH_ASSIGNIMPERSONATIONTOKEN KPH_CTL_CODE(28)
+#define KPH_PROTECTADD KPH_CTL_CODE(29)
+#define KPH_PROTECTREMOVE KPH_CTL_CODE(30)
+#define KPH_PROTECTQUERY KPH_CTL_CODE(31)
+#define KPH_UNSAFEREADVIRTUALMEMORY KPH_CTL_CODE(32)
+#define KPH_SETEXECUTEOPTIONS KPH_CTL_CODE(33)
+#define KPH_QUERYPROCESSHANDLES KPH_CTL_CODE(34)
+#define KPH_OPENTHREADPROCESS KPH_CTL_CODE(35)
+#define KPH_CAPTURESTACKBACKTRACETHREAD KPH_CTL_CODE(36)
+#define KPH_DANGEROUSTERMINATETHREAD KPH_CTL_CODE(37)
+#define KPH_OPENTYPE KPH_CTL_CODE(38)
+#define KPH_OPENDRIVER KPH_CTL_CODE(39)
+#define KPH_QUERYINFORMATIONDRIVER KPH_CTL_CODE(40)
+#define KPH_OPENDIRECTORYOBJECT KPH_CTL_CODE(41)
+#define KPH_SSREF KPH_CTL_CODE(42)
+#define KPH_SSUNREF KPH_CTL_CODE(43)
+#define KPH_SSCREATECLIENTENTRY KPH_CTL_CODE(44)
+#define KPH_SSCREATERULESETENTRY KPH_CTL_CODE(45)
+#define KPH_SSREMOVERULE KPH_CTL_CODE(46)
+#define KPH_SSADDPROCESSIDRULE KPH_CTL_CODE(47)
+#define KPH_SSADDTHREADIDRULE KPH_CTL_CODE(48)
+#define KPH_SSADDPREVIOUSMODERULE KPH_CTL_CODE(49)
+#define KPH_SSADDNUMBERRULE KPH_CTL_CODE(50)
+#define KPH_SSENABLECLIENTENTRY KPH_CTL_CODE(51)
+#define KPH_OPENNAMEDOBJECT KPH_CTL_CODE(52)
+#define KPH_QUERYINFORMATIONPROCESS KPH_CTL_CODE(53)
+#define KPH_QUERYINFORMATIONTHREAD KPH_CTL_CODE(54)
+#define KPH_SETINFORMATIONPROCESS KPH_CTL_CODE(55)
+#define KPH_SETINFORMATIONTHREAD KPH_CTL_CODE(56)
+
+/* Standard Driver Routines */
+
+NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath);
+VOID DriverUnload(PDRIVER_OBJECT DriverObject);
+NTSTATUS KphDispatchCreate(PDEVICE_OBJECT DeviceObject, PIRP Irp);
+NTSTATUS KphDispatchClose(PDEVICE_OBJECT DeviceObject, PIRP Irp);
+NTSTATUS KphDispatchDeviceControl(PDEVICE_OBJECT DeviceObject, PIRP Irp);
+NTSTATUS KphDispatchRead(PDEVICE_OBJECT DeviceObject, PIRP Irp);
+NTSTATUS KphUnsupported(PDEVICE_OBJECT DeviceObject, PIRP Irp);
+
+/* Clients */
+
+#define TAG_CLIENT_HANDLETABLE ('HChP')
+#define KPH_CLIENT_SSMAXCOUNT 1000
+#define KPH_CLIENT_MAXHANDLES 100
+
+typedef struct _KPH_CLIENT_ENTRY
+{
+ LIST_ENTRY ClientListEntry;
+ HANDLE ProcessId;
+ PKPH_HANDLE_TABLE HandleTable;
+
+ KPH_GUARDED_LOCK SsLock;
+ /* The number of times the client has "started" the system service logger. */
+ LONG SsStartCount;
+} KPH_CLIENT_ENTRY, *PKPH_CLIENT_ENTRY;
+
+/* Functions */
+
+VOID SsRef(LONG count);
+VOID SsUnref(LONG count);
+
+VOID NTAPI ClientEntryDeleteProcedure(
+ __in PVOID Object,
+ __in ULONG Flags
+ );
+
+PKPH_CLIENT_ENTRY CreateClientEntry(
+ __in HANDLE ProcessId
+ );
+
+PKPH_CLIENT_ENTRY ReferenceClientEntry(
+ __in_opt HANDLE ProcessId
+ );
+
+NTSTATUS CloseClientHandle(
+ __in_opt HANDLE ProcessId,
+ __in HANDLE Handle
+ );
+
+NTSTATUS CreateClientHandle(
+ __in_opt HANDLE ProcessId,
+ __in PVOID Object,
+ __out PHANDLE Handle
+ );
+
+NTSTATUS ReferenceClientHandle(
+ __in_opt HANDLE ProcessId,
+ __in HANDLE Handle,
+ __in PKPH_OBJECT_TYPE ObjectType,
+ __out PVOID *Object
+ );
+
+#endif
\ No newline at end of file
diff --git a/2.x/trunk/KProcessHacker/include/mm.h b/2.x/trunk/KProcessHacker/include/mm.h
new file mode 100644
index 000000000..07206dc0a
--- /dev/null
+++ b/2.x/trunk/KProcessHacker/include/mm.h
@@ -0,0 +1,37 @@
+/*
+ * Process Hacker Driver -
+ * memory manager
+ *
+ * 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 _MM_H
+#define _MM_H
+
+#define MI_MAX_TRANSFER_SIZE (0x10000)
+#define MI_COPY_STACK_SIZE (0x200)
+#define MI_MAPPED_COPY_PAGES (14)
+#define MM_POOL_COPY_THRESHOLD (0x1ff)
+#define TAG_POOL_COPY ('CPhP')
+
+#define MEM_EXECUTE_OPTION_DISABLE 0x1
+#define MEM_EXECUTE_OPTION_ENABLE 0x2
+#define MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION 0x4
+#define MEM_EXECUTE_OPTION_PERMANENT 0x8
+
+#endif
\ No newline at end of file
diff --git a/2.x/trunk/KProcessHacker/include/ob.h b/2.x/trunk/KProcessHacker/include/ob.h
new file mode 100644
index 000000000..783629c12
--- /dev/null
+++ b/2.x/trunk/KProcessHacker/include/ob.h
@@ -0,0 +1,168 @@
+/*
+ * Process Hacker Driver -
+ * object manager
+ *
+ * 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 _OB_H
+#define _OB_H
+
+#include "types.h"
+#include "ex.h"
+
+#define OBJECT_TO_OBJECT_HEADER(o) \
+ CONTAINING_RECORD((o), OBJECT_HEADER, Body)
+
+#define OBJ_PROTECT_CLOSE 0x00000001L
+#define OBJ_INHERIT 0x00000002L
+#define OBJ_AUDIT_OBJECT_CLOSE 0x00000004L
+#define OBJ_HANDLE_ATTRIBUTES (OBJ_PROTECT_CLOSE | OBJ_INHERIT | OBJ_AUDIT_OBJECT_CLOSE)
+
+#define ObpDecodeGrantedAccess(Access) \
+ ((Access) & ~ObpAccessProtectCloseBit)
+#define ObpDecodeObject(Object) \
+ ((PVOID)((ULONG_PTR)(Object) & ~OBJ_HANDLE_ATTRIBUTES))
+#define ObpGetHandleAttributes(HandleTableEntry) \
+ (((HandleTableEntry)->GrantedAccess & ObpAccessProtectCloseBit) ? \
+ (((HandleTableEntry)->Value & OBJ_HANDLE_ATTRIBUTES) | OBJ_PROTECT_CLOSE) : \
+ ((HandleTableEntry)->Value & (OBJ_INHERIT | OBJ_AUDIT_OBJECT_CLOSE)))
+
+/* FUNCTION DEFS */
+
+struct _OBJECT_HANDLE_FLAG_INFORMATION;
+typedef struct _OBJECT_TYPE_INITIALIZER OBJECT_TYPE_INITIALIZER, *POBJECT_TYPE_INITIALIZER;
+
+NTSTATUS NTAPI ObCreateObjectType(
+ __in PUNICODE_STRING TypeName,
+ __in POBJECT_TYPE_INITIALIZER ObjectTypeInitializer,
+ __in PSECURITY_DESCRIPTOR SecurityDescriptor,
+ __out_opt POBJECT_TYPE *ObjectType
+ );
+
+NTSTATUS NTAPI ObOpenObjectByName(
+ __in POBJECT_ATTRIBUTES ObjectAttributes,
+ __in POBJECT_TYPE ObjectType,
+ __in KPROCESSOR_MODE PreviousMode,
+ __in_opt PACCESS_STATE AccessState,
+ __in_opt ACCESS_MASK DesiredAccess,
+ __in PVOID ParseContext,
+ __out PHANDLE Handle
+ );
+
+NTSTATUS NTAPI ObSetHandleAttributes(
+ __in HANDLE Handle,
+ __in struct _OBJECT_HANDLE_FLAG_INFORMATION *HandleFlags,
+ __in KPROCESSOR_MODE PreviousMode
+ );
+
+/* FUNCTION TYPEDEFS */
+
+/* Seven+ */
+typedef POBJECT_TYPE (NTAPI *_ObGetObjectType)(
+ __in PVOID Object
+ );
+
+enum _OB_OPEN_REASON;
+
+typedef NTSTATUS (NTAPI *OB_OPEN_METHOD_51)(
+ enum _OB_OPEN_REASON OpenReason,
+ PEPROCESS Process,
+ PVOID Object,
+ ACCESS_MASK GrantedAccess,
+ ULONG HandleCount
+ );
+
+typedef NTSTATUS (NTAPI *OB_OPEN_METHOD_60)(
+ enum _OB_OPEN_REASON OpenReason,
+ KPROCESSOR_MODE AccessMode,
+ PEPROCESS Process,
+ PVOID Object,
+ ACCESS_MASK GrantedAccess,
+ ULONG HandleCount
+ );
+
+/* ENUMS */
+typedef enum _OB_OPEN_REASON
+{
+ ObCreateHandle,
+ ObOpenHandle,
+ ObDuplicateHandle,
+ ObInheritHandle,
+ ObMaxOpenReason
+} OB_OPEN_REASON, *POB_OPEN_REASON;
+
+/* STRUCTS */
+
+typedef struct _OBP_QUERY_PROCESS_HANDLES_DATA
+{
+ PVOID Buffer;
+ ULONG BufferLength;
+ ULONG CurrentIndex;
+ NTSTATUS Status;
+} OBP_QUERY_PROCESS_HANDLES_DATA, *POBP_QUERY_PROCESS_HANDLES_DATA;
+
+typedef struct _OBP_SET_HANDLE_GRANTED_ACCESS_DATA
+{
+ HANDLE Handle;
+ ACCESS_MASK GrantedAccess;
+} OBP_SET_HANDLE_GRANTED_ACCESS_DATA, *POBP_SET_HANDLE_GRANTED_ACCESS_DATA;
+
+typedef struct _OBJECT_HANDLE_FLAG_INFORMATION
+{
+ BOOLEAN Inherit;
+ BOOLEAN ProtectFromClose;
+} OBJECT_HANDLE_FLAG_INFORMATION, *POBJECT_HANDLE_FLAG_INFORMATION;
+
+typedef struct _OBJECT_CREATE_INFORMATION OBJECT_CREATE_INFORMATION, *POBJECT_CREATE_INFORMATION;
+
+typedef struct _OBJECT_HEADER
+{
+ LONG PointerCount;
+ union
+ {
+ LONG HandleCount;
+ PVOID NextToFree;
+ };
+ POBJECT_TYPE Type;
+ UCHAR NameInfoOffset;
+ UCHAR HandleInfoOffset;
+ UCHAR QuotaInfoOffset;
+ UCHAR Flags;
+ union
+ {
+ POBJECT_CREATE_INFORMATION ObjectCreateInfo;
+ PVOID QuotaBlockCharged;
+ };
+ PVOID SecurityDescriptor;
+ QUAD Body;
+} OBJECT_HEADER, *POBJECT_HEADER;
+
+typedef struct _HANDLE_TABLE_ENTRY
+{
+ union
+ {
+ PVOID Object;
+ ULONG Value;
+ };
+ ULONG GrantedAccess;
+} HANDLE_TABLE_ENTRY, *PHANDLE_TABLE_ENTRY;
+
+typedef struct _HANDLE_TABLE HANDLE_TABLE, *PHANDLE_TABLE;
+
+#endif
diff --git a/2.x/trunk/KProcessHacker/include/protect.h b/2.x/trunk/KProcessHacker/include/protect.h
new file mode 100644
index 000000000..b714ab1b0
--- /dev/null
+++ b/2.x/trunk/KProcessHacker/include/protect.h
@@ -0,0 +1,95 @@
+/*
+ * Process Hacker Driver -
+ * process protection
+ *
+ * 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 _PROTECT_H
+#define _PROTECT_H
+
+#include "hook.h"
+
+#define TAG_PROTECTION_ENTRY ('rPhP')
+
+#define OBOPENOBJECTBYPOINTER_ARGS \
+ PVOID Object, \
+ ULONG HandleAttributes, \
+ PACCESS_STATE PassedAccessState, \
+ ACCESS_MASK DesiredAccess, \
+ POBJECT_TYPE ObjectType, \
+ KPROCESSOR_MODE AccessMode, \
+ PHANDLE Handle
+
+typedef struct _KPH_PROCESS_ENTRY
+{
+ LIST_ENTRY ListEntry;
+ PEPROCESS Process;
+ PEPROCESS CreatorProcess;
+ HANDLE Tag;
+ LOGICAL AllowKernelMode;
+ ACCESS_MASK ProcessAllowMask;
+ ACCESS_MASK ThreadAllowMask;
+} KPH_PROCESS_ENTRY, *PKPH_PROCESS_ENTRY;
+
+NTSTATUS NTAPI KphNewObOpenObjectByPointer(OBOPENOBJECTBYPOINTER_ARGS);
+NTSTATUS NTAPI KphOldObOpenObjectByPointer(OBOPENOBJECTBYPOINTER_ARGS);
+
+NTSTATUS NTAPI KphNewOpenProcedure51(
+ __in OB_OPEN_REASON OpenReason,
+ __in PEPROCESS Process,
+ __in PVOID Object,
+ __in ACCESS_MASK GrantedAccess,
+ __in ULONG HandleCount
+ );
+
+NTSTATUS NTAPI KphNewOpenProcedure60(
+ __in OB_OPEN_REASON OpenReason,
+ __in KPROCESSOR_MODE AccessMode,
+ __in PEPROCESS Process,
+ __in PVOID Object,
+ __in ACCESS_MASK GrantedAccess,
+ __in ULONG HandleCount
+ );
+
+NTSTATUS KphProtectInit();
+NTSTATUS KphProtectDeinit();
+
+PKPH_PROCESS_ENTRY KphProtectAddEntry(
+ __in PEPROCESS Process,
+ __in HANDLE Tag,
+ __in LOGICAL AllowKernelMode,
+ __in ACCESS_MASK ProcessAllowMask,
+ __in ACCESS_MASK ThreadAllowMask
+ );
+
+PKPH_PROCESS_ENTRY KphProtectFindEntry(
+ __in PEPROCESS Process,
+ __in HANDLE Tag,
+ __out_opt PKPH_PROCESS_ENTRY ProcessEntryCopy
+ );
+
+BOOLEAN KphProtectRemoveByProcess(
+ __in PEPROCESS Process
+ );
+
+ULONG KphProtectRemoveByTag(
+ __in HANDLE Tag
+ );
+
+#endif
diff --git a/2.x/trunk/KProcessHacker/include/ps.h b/2.x/trunk/KProcessHacker/include/ps.h
new file mode 100644
index 000000000..62b7309f2
--- /dev/null
+++ b/2.x/trunk/KProcessHacker/include/ps.h
@@ -0,0 +1,151 @@
+/*
+ * Process Hacker Driver -
+ * processes and threads
+ *
+ * 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 _PS_H
+#define _PS_H
+
+#include "types.h"
+#include "ex.h"
+#include "mm.h"
+#include "ob.h"
+#include "se.h"
+
+#define TAG_CAPTURE_STACK_BACKTRACE ('tShP')
+
+#define PROCESS_TERMINATE (0x0001)
+#define PROCESS_CREATE_THREAD (0x0002)
+#define PROCESS_SET_SESSIONID (0x0004)
+#define PROCESS_VM_OPERATION (0x0008)
+#define PROCESS_VM_READ (0x0010)
+#define PROCESS_VM_WRITE (0x0020)
+#define PROCESS_DUP_HANDLE (0x0040)
+#define PROCESS_CREATE_PROCESS (0x0080)
+#define PROCESS_SET_QUOTA (0x0100)
+#define PROCESS_SET_INFORMATION (0x0200)
+#define PROCESS_QUERY_INFORMATION (0x0400)
+#define PROCESS_SUSPEND_RESUME (0x0800)
+#define PROCESS_QUERY_LIMITED_INFORMATION (0x1000)
+#ifndef PROCESS_ALL_ACCESS
+#define PROCESS_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xffff)
+#endif
+
+#define THREAD_TERMINATE (0x0001)
+#define THREAD_SUSPEND_RESUME (0x0002)
+#define THREAD_ALERT (0x0004)
+#define THREAD_GET_CONTEXT (0x0008)
+#define THREAD_SET_CONTEXT (0x0010)
+#define THREAD_SET_INFORMATION (0x0020)
+#define THREAD_QUERY_INFORMATION (0x0040)
+#define THREAD_SET_THREAD_TOKEN (0x0080)
+#define THREAD_IMPERSONATE (0x0100)
+#define THREAD_DIRECT_IMPERSONATION (0x0200)
+#ifndef THREAD_ALL_ACCESS
+#define THREAD_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x3ff)
+#endif
+
+#define JOB_OBJECT_ASSIGN_PROCESS (0x0001)
+#define JOB_OBJECT_SET_ATTRIBUTES (0x0002)
+#define JOB_OBJECT_QUERY (0x0004)
+#define JOB_OBJECT_TERMINATE (0x0008)
+#define JOB_OBJECT_SET_SECURITY_ATTRIBUTES (0x0010)
+#define JOB_OBJECT_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x1f)
+
+extern POBJECT_TYPE *PsJobType;
+
+typedef struct _CAPTURE_BACKTRACE_THREAD_CONTEXT
+{
+ BOOLEAN Local;
+ KAPC Apc;
+ KEVENT CompletedEvent;
+ ULONG FramesToSkip;
+ ULONG FramesToCapture;
+ PVOID *BackTrace;
+ ULONG CapturedFrames;
+ ULONG BackTraceHash;
+} CAPTURE_BACKTRACE_THREAD_CONTEXT, *PCAPTURE_BACKTRACE_THREAD_CONTEXT;
+
+typedef struct _EXIT_THREAD_CONTEXT
+{
+ KAPC Apc;
+ KEVENT CompletedEvent;
+ NTSTATUS ExitStatus;
+} EXIT_THREAD_CONTEXT, *PEXIT_THREAD_CONTEXT;
+
+/* FUNCTION DEFS */
+
+NTSTATUS NTAPI PsGetContextThread(
+ __in PETHREAD Thread,
+ __inout PCONTEXT ThreadContext,
+ __in KPROCESSOR_MODE PreviousMode
+ );
+
+BOOLEAN NTAPI PsGetProcessExitProcessCalled(
+ __in PEPROCESS Process
+ );
+
+PVOID NTAPI PsGetThreadWin32Thread(
+ __in PETHREAD Thread
+ );
+
+NTSTATUS NTAPI PsLookupProcessThreadByCid(
+ __in PCLIENT_ID ClientId,
+ __out_opt PEPROCESS *Process,
+ __out PETHREAD *Thread
+ );
+
+NTSTATUS NTAPI PsSetContextThread(
+ __in PETHREAD Thread,
+ __in PCONTEXT ThreadContext,
+ __in KPROCESSOR_MODE PreviousMode
+ );
+
+/* FUNCTION TYPEDEFS */
+
+typedef PVOID (NTAPI *_PsGetProcessJob)(
+ PEPROCESS Process
+ );
+
+typedef NTSTATUS (NTAPI *_PsResumeProcess)(
+ PEPROCESS Process
+ );
+
+typedef NTSTATUS (NTAPI *_PsSuspendProcess)(
+ PEPROCESS Process
+ );
+
+typedef NTSTATUS (NTAPI *_PsTerminateProcess)(
+ PEPROCESS Process,
+ NTSTATUS ExitStatus
+ );
+
+typedef NTSTATUS (NTAPI *_PspTerminateThreadByPointer51)(
+ PETHREAD Thread,
+ NTSTATUS ExitStatus
+ );
+
+typedef NTSTATUS (NTAPI *_PspTerminateThreadByPointer52)(
+ PETHREAD Thread,
+ NTSTATUS ExitStatus,
+ BOOLEAN DirectTerminate
+ );
+
+#endif
\ No newline at end of file
diff --git a/2.x/trunk/KProcessHacker/include/ref.h b/2.x/trunk/KProcessHacker/include/ref.h
new file mode 100644
index 000000000..03f9fdb9e
--- /dev/null
+++ b/2.x/trunk/KProcessHacker/include/ref.h
@@ -0,0 +1,113 @@
+/*
+ * Process Hacker Driver -
+ * internal object manager
+ *
+ * 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 _REF_H
+#define _REF_H
+
+#include "kph.h"
+
+/* Object flags */
+#define KPHOBJ_RAISE_ON_FAIL 0x00000001
+#define KPHOBJ_PAGED_POOL 0x00000002
+#define KPHOBJ_NONPAGED_POOL 0x00000004
+#define KPHOBJ_VALID_FLAGS 0x00000007
+
+/* Object type flags */
+#define KPHOBJTYPE_PASSIVE_LEVEL_DELETE 0x00000001
+#define KPHOBJTYPE_VALID_FLAGS 0x00000001
+
+/* Object type callbacks */
+
+/* PKPH_TYPE_DELETE_PROCEDURE
+ *
+ * The delete procedure for an object type, called when
+ * an object of the type is being freed.
+ *
+ * Object: A pointer to the object being freed.
+ * Flags: The flags specified when the object was created.
+ *
+ * IRQL: = PASSIVE_LEVEL if the require passive level flag was
+ * specified for the object type, otherwise <= APC_LEVEL.
+ */
+typedef VOID (NTAPI *PKPH_TYPE_DELETE_PROCEDURE)(
+ __in PVOID Object,
+ __in ULONG Flags
+ );
+
+struct _KPH_OBJECT_TYPE;
+typedef struct _KPH_OBJECT_TYPE *PKPH_OBJECT_TYPE;
+
+#ifndef _REF_PRIVATE
+extern PKPH_OBJECT_TYPE KphObjectTypeObject;
+#endif
+
+NTSTATUS KphRefInit();
+
+NTSTATUS KphRefDeinit();
+
+NTSTATUS KphCreateObject(
+ __out PVOID *Object,
+ __in SIZE_T ObjectSize,
+ __in ULONG Flags,
+ __in_opt PKPH_OBJECT_TYPE ObjectType,
+ __in_opt LONG AdditionalReferences
+ );
+
+NTSTATUS KphCreateObjectType(
+ __out PKPH_OBJECT_TYPE *ObjectType,
+ __in POOL_TYPE DefaultPoolType,
+ __in ULONG Flags,
+ __in PKPH_TYPE_DELETE_PROCEDURE DeleteProcedure
+ );
+
+BOOLEAN KphDereferenceObject(
+ __in PVOID Object
+ );
+
+BOOLEAN KphDereferenceObjectDeferDelete(
+ __in PVOID Object
+ );
+
+LONG KphDereferenceObjectEx(
+ __in PVOID Object,
+ __in LONG RefCount,
+ __in BOOLEAN DeferDelete
+ );
+
+PKPH_OBJECT_TYPE KphGetObjectType(
+ __in PVOID Object
+ );
+
+VOID KphReferenceObject(
+ __in PVOID Object
+ );
+
+LONG KphReferenceObjectEx(
+ __in PVOID Object,
+ __in LONG RefCount
+ );
+
+BOOLEAN KphReferenceObjectSafe(
+ __in PVOID Object
+ );
+
+#endif
diff --git a/2.x/trunk/KProcessHacker/include/refp.h b/2.x/trunk/KProcessHacker/include/refp.h
new file mode 100644
index 000000000..d31fa034e
--- /dev/null
+++ b/2.x/trunk/KProcessHacker/include/refp.h
@@ -0,0 +1,137 @@
+/*
+ * Process Hacker Driver -
+ * internal object manager
+ *
+ * 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 _REFP_H
+#define _REFP_H
+
+#define _REF_PRIVATE
+#include "ref.h"
+#include "sync.h"
+
+#define TAG_KPHOBJ ('bOhP')
+
+#define KphObjectToObjectHeader(Object) ((PKPH_OBJECT_HEADER)CONTAINING_RECORD((PCHAR)(Object), KPH_OBJECT_HEADER, Body))
+#define KphObjectHeaderToObject(ObjectHeader) (&((PKPH_OBJECT_HEADER)(ObjectHeader))->Body)
+#define KphpAddObjectHeaderSize(Size) ((Size) + FIELD_OFFSET(KPH_OBJECT_HEADER, Body))
+
+typedef struct _KPH_OBJECT_HEADER *PKPH_OBJECT_HEADER;
+typedef struct _KPH_OBJECT_TYPE *PKPH_OBJECT_TYPE;
+
+typedef struct _KPH_OBJECT_HEADER
+{
+ /* The reference count of the object. */
+ LONG RefCount;
+ /* The flags that were used to create the object. */
+ ULONG Flags;
+ union
+ {
+ /* The size of the object, excluding the header. */
+ SIZE_T Size;
+ /* A pointer to the object header of the next object to free. */
+ PKPH_OBJECT_HEADER NextToFree;
+ };
+ /* The type of the object. */
+ PKPH_OBJECT_TYPE Type;
+ /* A linked list entry for an optional object manager object list.
+ * For example, this may be used to free all objects when the
+ * driver exits.
+ */
+ LIST_ENTRY GlobalObjectListEntry;
+
+ /* The body of the object. For use by the KphObject(Header)ToObject(Header) macros. */
+ QUAD Body;
+} KPH_OBJECT_HEADER, *PKPH_OBJECT_HEADER;
+
+typedef struct _KPH_OBJECT_TYPE
+{
+ /* The default pool type for objects of this type, used when the
+ * pool type is not specified when an object is created. */
+ POOL_TYPE DefaultPoolType;
+ /* The flags that were used to create the object type. */
+ ULONG Flags;
+ /* An optional procedure called when objects of this type are freed. */
+ PKPH_TYPE_DELETE_PROCEDURE DeleteProcedure;
+
+ /* The total number of objects of this type that are alive. */
+ ULONG NumberOfObjects;
+} KPH_OBJECT_TYPE, *PKPH_OBJECT_TYPE;
+
+/* KphpInterlockedIncrementSafe
+ *
+ * Increments a reference count, but will never increment
+ * from 0 to 1.
+ */
+FORCEINLINE BOOLEAN KphpInterlockedIncrementSafe(
+ __inout PLONG RefCount
+ )
+{
+ LONG refCount;
+
+ /* Here we will attempt to increment the reference count,
+ * making sure that it is not 0.
+ */
+
+ while (TRUE)
+ {
+ refCount = *RefCount;
+
+ /* Check if the reference count is 0. If it is, the
+ * object is being or about to be deleted.
+ */
+ if (refCount == 0)
+ return FALSE;
+
+ /* Try to increment the reference count. */
+ if (InterlockedCompareExchange(
+ RefCount,
+ refCount + 1,
+ refCount
+ ) == refCount)
+ {
+ /* Success. */
+ return TRUE;
+ }
+
+ /* Someone else changed the reference count before we did.
+ * Go back and try again.
+ */
+ }
+}
+
+PKPH_OBJECT_HEADER KphpAllocateObject(
+ __in SIZE_T ObjectSize,
+ __in POOL_TYPE PoolType
+ );
+
+VOID KphpDeferDeleteObject(
+ __in PKPH_OBJECT_HEADER ObjectHeader
+ );
+
+VOID KphpDeferDeleteObjectRoutine(
+ __in PVOID Parameter
+ );
+
+VOID KphpFreeObject(
+ __in PKPH_OBJECT_HEADER ObjectHeader
+ );
+
+#endif
diff --git a/2.x/trunk/KProcessHacker/include/se.h b/2.x/trunk/KProcessHacker/include/se.h
new file mode 100644
index 000000000..947d59f5f
--- /dev/null
+++ b/2.x/trunk/KProcessHacker/include/se.h
@@ -0,0 +1,55 @@
+/*
+ * Process Hacker Driver -
+ * memory manager
+ *
+ * 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 _SE_H
+#define _SE_H
+
+#include "types.h"
+
+extern POBJECT_TYPE *SeTokenObjectType;
+
+/* Was 0x38 on Vista, appears to be 0xc8 on 7. */
+#define AUX_ACCESS_DATA_SIZE (0xc8)
+
+typedef PVOID PAUX_ACCESS_DATA;
+
+/* FUNCTION DEFS */
+
+NTKERNELAPI NTSTATUS NTAPI SeCreateAccessState(
+ PACCESS_STATE AccessState,
+ PAUX_ACCESS_DATA AuxData,
+ ACCESS_MASK DesiredAccess,
+ PGENERIC_MAPPING Mapping
+ );
+
+NTKERNELAPI VOID NTAPI SeDeleteAccessState(
+ PACCESS_STATE AccessState
+ );
+
+/* STRUCTS */
+
+typedef struct _SE_AUDIT_PROCESS_CREATION_INFO
+{
+ POBJECT_NAME_INFORMATION ImageFileName;
+} SE_AUDIT_PROCESS_CREATION_INFO, *PSE_AUDIT_PROCESS_CREATION_INFO;
+
+#endif
diff --git a/2.x/trunk/KProcessHacker/include/sync.h b/2.x/trunk/KProcessHacker/include/sync.h
new file mode 100644
index 000000000..e344ea75e
--- /dev/null
+++ b/2.x/trunk/KProcessHacker/include/sync.h
@@ -0,0 +1,320 @@
+/*
+ * 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 "kph.h"
+#include "ex.h"
+
+/* General synchronization macros */
+
+/* KphEqualSpin
+ *
+ * Spins until the first value is equal to the second
+ * value.
+ */
+FORCEINLINE VOID KphSpinUntilEqual(
+ __inout PLONG Value,
+ __in LONG Value2
+ )
+{
+ while (InterlockedCompareExchange(
+ Value,
+ Value2,
+ Value2
+ ) != Value2)
+ YieldProcessor();
+}
+
+/* KphNotEqualSpin
+ *
+ * Spins until the first value is not equal to the second
+ * value.
+ */
+FORCEINLINE VOID KphSpinUntilNotEqual(
+ __inout PLONG Value,
+ __in LONG Value2
+ )
+{
+ while (InterlockedCompareExchange(
+ Value,
+ Value2,
+ Value2
+ ) == Value2)
+ YieldProcessor();
+}
+
+/* Spin Locks */
+
+/* KphAcquireBitSpinLock
+ *
+ * Uses the specified bit as a spinlock and acquires the
+ * lock in the given value.
+ */
+FORCEINLINE VOID KphAcquireBitSpinLock(
+ __inout PLONG Value,
+ __in LONG Bit
+ )
+{
+ while (InterlockedBitTestAndSet(Value, Bit))
+ YieldProcessor();
+}
+
+/* KphReleaseBitSpinLock
+ *
+ * Uses the specified bit as a spinlock and releases the
+ * lock in the given value.
+ */
+FORCEINLINE VOID KphReleaseBitSpinLock(
+ __inout PLONG Value,
+ __in LONG Bit
+ )
+{
+ InterlockedBitTestAndReset(Value, Bit);
+}
+
+/* Guarded Locks */
+/* Guarded locks are small spinlocks. Code within
+ * synchronized regions run at APC_LEVEL. They also contain
+ * a signal which can used to implement rundown routines.
+ */
+
+#define KPH_GUARDED_LOCK_ACTIVE 0x80000000
+#define KPH_GUARDED_LOCK_ACTIVE_SHIFT 31
+#define KPH_GUARDED_LOCK_SIGNALED 0x40000000
+#define KPH_GUARDED_LOCK_SIGNALED_SHIFT 30
+#define KPH_GUARDED_LOCK_FLAGS 0xc0000000
+
+typedef struct _KPH_GUARDED_LOCK
+{
+ LONG Value;
+} KPH_GUARDED_LOCK, *PKPH_GUARDED_LOCK;
+
+#define KphAcquireGuardedLock KphfAcquireGuardedLock
+VOID FASTCALL KphfAcquireGuardedLock(
+ __inout PKPH_GUARDED_LOCK Lock
+ );
+
+#define KphReleaseGuardedLock KphfReleaseGuardedLock
+VOID FASTCALL KphfReleaseGuardedLock(
+ __inout PKPH_GUARDED_LOCK Lock
+ );
+
+/* KphInitializeGuardedLock
+ *
+ * Initializes a guarded lock.
+ *
+ * IRQL: Any
+ */
+FORCEINLINE VOID KphInitializeGuardedLock(
+ __out PKPH_GUARDED_LOCK Lock,
+ __in BOOLEAN Signaled
+ )
+{
+ Lock->Value = 0;
+
+ if (Signaled)
+ Lock->Value |= KPH_GUARDED_LOCK_SIGNALED;
+}
+
+/* KphClearGuardedLock
+ *
+ * Clears the signal state of a guarded lock, assuming
+ * that the current thread has acquired it.
+ *
+ * IRQL: Any
+ */
+FORCEINLINE VOID KphClearGuardedLock(
+ __in PKPH_GUARDED_LOCK Lock
+ )
+{
+ Lock->Value &= ~KPH_GUARDED_LOCK_SIGNALED;
+}
+
+/* KphSignalGuardedLock
+ *
+ * Signals a guarded lock.
+ *
+ * IRQL: Any
+ */
+FORCEINLINE VOID KphSignalGuardedLock(
+ __in PKPH_GUARDED_LOCK Lock
+ )
+{
+ Lock->Value |= KPH_GUARDED_LOCK_SIGNALED;
+}
+
+/* KphSignaledGuardedLock
+ *
+ * Determines whether a guarded lock is signaled.
+ *
+ * IRQL: Any
+ */
+FORCEINLINE BOOLEAN KphSignaledGuardedLock(
+ __in PKPH_GUARDED_LOCK Lock
+ )
+{
+ return !!(Lock->Value & KPH_GUARDED_LOCK_SIGNALED);
+}
+
+/* KphAcquireAndClearGuardedLock
+ *
+ * Acquires a guarded lock, clear its signal, and raises the IRQL to APC_LEVEL.
+ *
+ * IRQL: <= APC_LEVEL
+ */
+FORCEINLINE VOID KphAcquireAndClearGuardedLock(
+ __inout PKPH_GUARDED_LOCK Lock
+ )
+{
+ KphAcquireGuardedLock(Lock);
+ KphClearGuardedLock(Lock);
+}
+
+/* KphAcquireAndSignalGuardedLock
+ *
+ * Acquires a guarded lock, signals it, and raises the IRQL to APC_LEVEL.
+ *
+ * IRQL: <= APC_LEVEL
+ */
+FORCEINLINE VOID KphAcquireAndSignalGuardedLock(
+ __inout PKPH_GUARDED_LOCK Lock
+ )
+{
+ KphAcquireGuardedLock(Lock);
+ KphSignalGuardedLock(Lock);
+}
+
+/* KphAcquireNonSignaledGuardedLock
+ *
+ * Acquires a guarded lock and raises the IRQL to APC_LEVEL,
+ * making sure the lock is not signaled. If it is, the
+ * lock is not acquired.
+ *
+ * Return value: whether the lock was acquired.
+ * IRQL: <= APC_LEVEL
+ */
+FORCEINLINE BOOLEAN KphAcquireNonSignaledGuardedLock(
+ __inout PKPH_GUARDED_LOCK Lock
+ )
+{
+ KphAcquireGuardedLock(Lock);
+
+ if (Lock->Value & KPH_GUARDED_LOCK_SIGNALED)
+ {
+ KphReleaseGuardedLock(Lock);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/* KphAcquireSignaledGuardedLock
+ *
+ * Acquires a guarded lock and raises the IRQL to APC_LEVEL,
+ * making sure the lock is signaled. If it is not, the
+ * lock is not acquired.
+ *
+ * Return value: whether the lock was acquired.
+ * IRQL: <= APC_LEVEL
+ */
+FORCEINLINE BOOLEAN KphAcquireSignaledGuardedLock(
+ __inout PKPH_GUARDED_LOCK Lock
+ )
+{
+ KphAcquireGuardedLock(Lock);
+
+ if (!(Lock->Value & KPH_GUARDED_LOCK_SIGNALED))
+ {
+ KphReleaseGuardedLock(Lock);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/* KphReleaseAndClearGuardedLock
+ *
+ * Releases a guarded lock, clears its signal, and restores the old IRQL.
+ *
+ * IRQL: >= APC_LEVEL
+ */
+FORCEINLINE VOID KphReleaseAndClearGuardedLock(
+ __inout PKPH_GUARDED_LOCK Lock
+ )
+{
+ KphClearGuardedLock(Lock);
+ KphReleaseGuardedLock(Lock);
+}
+
+/* KphReleaseAndSignalGuardedLock
+ *
+ * Releases a guarded lock, signals it, and restores the old IRQL.
+ *
+ * IRQL: >= APC_LEVEL
+ */
+FORCEINLINE VOID KphReleaseAndSignalGuardedLock(
+ __inout PKPH_GUARDED_LOCK Lock
+ )
+{
+ KphSignalGuardedLock(Lock);
+ KphReleaseGuardedLock(Lock);
+}
+
+/* Processor Locks */
+/* Processor locks prevent code from executing on all other
+ * processors. Code within synchronized regions run at
+ * DISPATCH_LEVEL.
+ */
+
+#define TAG_SYNC_DPC ('DShP')
+
+typedef struct _KPH_PROCESSOR_LOCK
+{
+ /* Synchronizes access to the processor lock. */
+ KPH_GUARDED_LOCK Lock;
+ /* 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(
+ __inout PKPH_PROCESSOR_LOCK ProcessorLock
+ );
+
+VOID KphInitializeProcessorLock(
+ __out PKPH_PROCESSOR_LOCK ProcessorLock
+ );
+
+VOID KphReleaseProcessorLock(
+ __inout PKPH_PROCESSOR_LOCK ProcessorLock
+ );
+
+#endif
diff --git a/2.x/trunk/KProcessHacker/include/sysservice.h b/2.x/trunk/KProcessHacker/include/sysservice.h
new file mode 100644
index 000000000..787847c33
--- /dev/null
+++ b/2.x/trunk/KProcessHacker/include/sysservice.h
@@ -0,0 +1,279 @@
+/*
+ * Process Hacker Driver -
+ * system service logging
+ *
+ * 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 _SYSSERVICE_H
+#define _SYSSERVICE_H
+
+#include "kph.h"
+#include "sysservicedata.h"
+
+/* Define opaque object types */
+
+struct _KPHSS_CLIENT_ENTRY;
+typedef struct _KPHSS_CLIENT_ENTRY *PKPHSS_CLIENT_ENTRY;
+struct _KPHSS_RULESET_ENTRY;
+typedef struct _KPHSS_RULESET_ENTRY *PKPHSS_RULESET_ENTRY;
+struct _KPHSS_RULE_ENTRY;
+typedef struct _KPHSS_RULE_ENTRY *PKPHSS_RULE_ENTRY;
+
+/* Information types */
+
+typedef struct _KPHSS_CLIENT_INFORMATION
+{
+ HANDLE ProcessId;
+ PVOID BufferBase;
+ ULONG BufferSize;
+
+ ULONG NumberOfBlocksWritten;
+ ULONG NumberOfBlocksDropped;
+} KPHSS_CLIENT_INFORMATION, *PKPHSS_CLIENT_INFORMATION;
+
+/* Object types */
+
+#ifndef _SYSSERVICE_PRIVATE
+extern PKPH_OBJECT_TYPE KphSsClientEntryType;
+extern PKPH_OBJECT_TYPE KphSsRuleSetEntryType;
+extern PKPH_OBJECT_TYPE KphSsRuleEntryType;
+#endif
+
+/* Ruleset types */
+
+typedef enum _KPHSS_RULESET_ACTION
+{
+ LogRuleSetAction,
+ MaxRuleSetAction
+} KPHSS_RULESET_ACTION;
+
+/* Rule types */
+
+typedef enum _KPHSS_FILTER_TYPE
+{
+ IncludeFilterType,
+ ExcludeFilterType,
+ MaxFilterType
+} KPHSS_FILTER_TYPE;
+
+typedef enum _KPHSS_RULE_TYPE
+{
+ ProcessIdRuleType = 0,
+ ThreadIdRuleType,
+ PreviousModeRuleType,
+ NumberRuleType,
+ MaxRuleType
+} KPHSS_RULE_TYPE;
+
+/* Block types */
+
+#define KPHSS_BLOCK_SUCCESS(Status) (NT_SUCCESS(Status) && (Status) != STATUS_TIMEOUT)
+
+typedef enum _KPHSS_BLOCK_TYPE
+{
+ ResetBlockType,
+ EventBlockType,
+ ArgumentBlockType,
+ ProcessBlockType,
+ ModuleBlockType
+} KPHSS_BLOCK_TYPE;
+
+typedef struct _KPHSS_BLOCK_HEADER
+{
+ USHORT Size; /* a.k.a. NextEntryOffset */
+ USHORT Type;
+} KPHSS_BLOCK_HEADER, *PKPHSS_BLOCK_HEADER;
+
+typedef struct _KPHSS_RESET_BLOCK
+{
+ KPHSS_BLOCK_HEADER Header;
+} KPHSS_RESET_BLOCK, *PKPHSS_RESET_BLOCK;
+
+#define TAG_EVENT_BLOCK ('BEhP')
+
+#define KPHSS_EVENT_PROBE_ARGUMENTS_FAILED 0x00000001
+#define KPHSS_EVENT_COPY_ARGUMENTS_FAILED 0x00000002
+#define KPHSS_EVENT_KERNEL_MODE 0x00000004
+#define KPHSS_EVENT_USER_MODE 0x00000008
+
+typedef struct _KPHSS_EVENT_BLOCK
+{
+ KPHSS_BLOCK_HEADER Header;
+ USHORT Flags;
+ LARGE_INTEGER Time;
+ CLIENT_ID ClientId;
+
+ /* The system service number. */
+ ULONG Number;
+ /* The number of ULONG arguments to the system service. */
+ USHORT NumberOfArguments;
+ USHORT ArgumentsOffset; /* ULONG[] */
+
+ /* The number of PVOIDs in the trace. */
+ USHORT TraceCount;
+ USHORT TraceOffset; /* PVOID[] */
+} KPHSS_EVENT_BLOCK, *PKPHSS_EVENT_BLOCK;
+
+/* Argument Blocks
+ *
+ * These blocks provide additional information about
+ * arguments.
+ */
+
+#define TAG_ARGUMENT_BLOCK ('BAhP')
+
+#define KPHSS_ARGUMENT_BLOCK_OVERHEAD \
+ FIELD_OFFSET(KPHSS_ARGUMENT_BLOCK, Normal)
+#define KPHSS_ARGUMENT_BLOCK_SIZE(InnerSize) \
+ (KPHSS_ARGUMENT_BLOCK_OVERHEAD + (InnerSize))
+
+typedef struct _KPHSS_ARGUMENT_BLOCK
+{
+ KPHSS_BLOCK_HEADER Header;
+ UCHAR Index;
+ UCHAR Type; /* KPHSS_ARGUMENT_TYPE */
+
+ union
+ {
+ ULONG Normal;
+
+ LARGE_INTEGER Simple;
+ KPHSS_HANDLE Handle;
+ KPHSS_STRING String;
+ KPHSS_WSTRING WString;
+ KPHSS_ANSI_STRING AnsiString;
+ KPHSS_UNICODE_STRING UnicodeString;
+ KPHSS_OBJECT_ATTRIBUTES ObjectAttributes;
+ CLIENT_ID ClientId;
+ CONTEXT Context;
+ KPHSS_INITIAL_TEB InitialTeb;
+ GUID Guid;
+ KPHSS_BYTES Bytes;
+ };
+} KPHSS_ARGUMENT_BLOCK, *PKPHSS_ARGUMENT_BLOCK;
+
+/* Process Blocks
+ *
+ * These blocks notify the client of a new process.
+ */
+
+#define TAG_PROCESS_BLOCK ('BPhP')
+
+typedef struct _KPHSS_PROCESS_BLOCK
+{
+ KPHSS_BLOCK_HEADER Header;
+
+ HANDLE ProcessId;
+ USHORT NameOffset; /* KPHSS_WSTRING */
+ USHORT ImageFileNameOffset; /* KPHSS_WSTRING */
+} KPHSS_PROCESS_BLOCK, *PKPHSS_PROCESS_BLOCK;
+
+/* Module Blocks
+ *
+ * These blocks provide information about modules
+ * loaded by a process.
+ */
+
+#define TAG_MODULE_BLOCK ('BMhP')
+
+typedef struct _KPHSS_MODULE_BLOCK
+{
+ KPHSS_BLOCK_HEADER Header;
+
+ HANDLE ProcessId;
+ PVOID ModuleBase;
+ ULONG ModuleSize;
+ USHORT FileNameOffset; /* KPHSS_WSTRING */
+} KPHSS_MODULE_BLOCK, *PKPHSS_MODULE_BLOCK;
+
+/* Functions */
+
+NTSTATUS KphSsLogInit();
+NTSTATUS KphSsLogDeinit();
+NTSTATUS KphSsLogStart();
+NTSTATUS KphSsLogStop();
+
+NTSTATUS KphSsCreateClientEntry(
+ __out PKPHSS_CLIENT_ENTRY *ClientEntry,
+ __in HANDLE ProcessHandle,
+ __in HANDLE ReadSemaphoreHandle,
+ __in HANDLE WriteSemaphoreHandle,
+ __in PVOID BufferBase,
+ __in ULONG BufferSize,
+ __in KPROCESSOR_MODE AccessMode
+ );
+
+NTSTATUS KphSsEnableClientEntry(
+ __in PKPHSS_CLIENT_ENTRY ClientEntry,
+ __in BOOLEAN Enable
+ );
+
+NTSTATUS KphSsQueryClientEntry(
+ __in PKPHSS_CLIENT_ENTRY ClientEntry,
+ __out_bcount_opt(ClientInformationLength) PKPHSS_CLIENT_INFORMATION ClientInformation,
+ __in ULONG ClientInformationLength,
+ __out_opt PULONG ReturnLength,
+ __in KPROCESSOR_MODE AccessMode
+ );
+
+NTSTATUS KphSsCreateRuleSetEntry(
+ __out PKPHSS_RULESET_ENTRY *RuleSetEntry,
+ __in PKPHSS_CLIENT_ENTRY ClientEntry,
+ __in KPHSS_FILTER_TYPE DefaultFilterType,
+ __in KPHSS_RULESET_ACTION Action
+ );
+
+HANDLE KphSsGetHandleRule(
+ __in PKPHSS_RULE_ENTRY RuleEntry
+ );
+
+NTSTATUS KphSsRemoveRule(
+ __in PKPHSS_RULESET_ENTRY RuleSetEntry,
+ __in HANDLE RuleEntryHandle
+ );
+
+NTSTATUS KphSsAddProcessIdRule(
+ __out PKPHSS_RULE_ENTRY *RuleEntry,
+ __in PKPHSS_RULESET_ENTRY RuleSetEntry,
+ __in KPHSS_FILTER_TYPE FilterType,
+ __in HANDLE ProcessId
+ );
+
+NTSTATUS KphSsAddThreadIdRule(
+ __out PKPHSS_RULE_ENTRY *RuleEntry,
+ __in PKPHSS_RULESET_ENTRY RuleSetEntry,
+ __in KPHSS_FILTER_TYPE FilterType,
+ __in HANDLE ThreadId
+ );
+
+NTSTATUS KphSsAddPreviousModeRule(
+ __out PKPHSS_RULE_ENTRY *RuleEntry,
+ __in PKPHSS_RULESET_ENTRY RuleSetEntry,
+ __in KPHSS_FILTER_TYPE FilterType,
+ __in KPROCESSOR_MODE PreviousMode
+ );
+
+NTSTATUS KphSsAddNumberRule(
+ __out PKPHSS_RULE_ENTRY *RuleEntry,
+ __in PKPHSS_RULESET_ENTRY RuleSetEntry,
+ __in KPHSS_FILTER_TYPE FilterType,
+ __in ULONG Number
+ );
+
+#endif
diff --git a/2.x/trunk/KProcessHacker/include/sysservicedata.h b/2.x/trunk/KProcessHacker/include/sysservicedata.h
new file mode 100644
index 000000000..a2553c33c
--- /dev/null
+++ b/2.x/trunk/KProcessHacker/include/sysservicedata.h
@@ -0,0 +1,174 @@
+/*
+ * Process Hacker Driver -
+ * system service logging (data)
+ *
+ * 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 _SYSSERVICEDATA_H
+#define _SYSSERVICEDATA_H
+
+#include "kph.h"
+
+#define TAG_CALL_ENTRY ('cShP')
+
+typedef enum _KPHSS_ARGUMENT_TYPE
+{
+ /* Having argument info for out variables is very rare
+ * because usually the caller does not fill in anything
+ * in the variable. In some cases, however, the caller
+ * does specify a length (usually Length, or MaximumLength).
+ *
+ * Note that with the exception of a few types such as
+ * HANDLE, all types listed here are POINTER TYPES
+ * (although a handle is the size of a pointer). This
+ * is because non-pointer arguments are already recorded
+ * in the event block.
+ */
+
+ /* Anything passed by value */
+ NormalArgument = 0,
+
+ /* PBOOLEAN */
+ Int8Argument,
+ /* P(U)SHORT */
+ Int16Argument,
+ /* P(U)LONG */
+ Int32Argument,
+ /* P(U)LARGE_INTEGER */
+ Int64Argument,
+ /* HANDLE */
+ /* Only object manager handles, no fake handles. */
+ HandleArgument,
+ /* PSTR */
+ StringArgument,
+ /* PWSTR */
+ WStringArgument,
+ /* PANSI_STRING */
+ AnsiStringArgument,
+ /* PUNICODE_STRING */
+ UnicodeStringArgument,
+ /* POBJECT_ATTRIBUTES */
+ ObjectAttributesArgument,
+ /* PCLIENT_ID */
+ ClientIdArgument,
+ /* PCONTEXT */
+ ContextArgument,
+ /* PINITIAL_TEB */
+ InitialTebArgument,
+ /* PGUID */
+ GuidArgument,
+ /* PVOID */
+ BytesArgument
+} KPHSS_ARGUMENT_TYPE;
+
+typedef struct _KPHSS_HANDLE
+{
+ CLIENT_ID ClientId;
+ USHORT TypeNameOffset; /* KPHSS_WSTRING */
+ USHORT NameOffset; /* KPHSS_WSTRING */
+} KPHSS_HANDLE, *PKPHSS_HANDLE;
+
+typedef struct _KPHSS_STRING
+{
+ USHORT Length;
+ CHAR Buffer[1];
+} KPHSS_STRING, *PKPHSS_STRING;
+
+typedef struct _KPHSS_WSTRING
+{
+ USHORT Length;
+ WCHAR Buffer[1];
+} KPHSS_WSTRING, *PKPHSS_WSTRING;
+
+typedef struct _KPHSS_ANSI_STRING
+{
+ USHORT Length;
+ USHORT MaximumLength;
+ PSTR Pointer;
+ CHAR Buffer[1];
+} KPHSS_ANSI_STRING, *PKPHSS_ANSI_STRING;
+
+typedef struct _KPHSS_UNICODE_STRING
+{
+ USHORT Length;
+ USHORT MaximumLength;
+ PWSTR Pointer;
+ WCHAR Buffer[1];
+} KPHSS_UNICODE_STRING, *PKPHSS_UNICODE_STRING;
+
+typedef struct _KPHSS_OBJECT_ATTRIBUTES
+{
+ union
+ {
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ struct
+ {
+ ULONG Length;
+ HANDLE RootDirectory;
+ PUNICODE_STRING ObjectName;
+ ULONG Attributes;
+ PVOID SecurityDescriptor;
+ PVOID SecurityQualityOfService;
+ };
+ };
+
+ USHORT RootDirectoryOffset; /* KPHSS_HANDLE */
+ USHORT ObjectNameOffset; /* KPHSS_UNICODE_STRING */
+} KPHSS_OBJECT_ATTRIBUTES, *PKPHSS_OBJECT_ATTRIBUTES;
+
+typedef struct _KPHSS_INITIAL_TEB
+{
+ struct
+ {
+ PVOID OldStackBase;
+ PVOID OldStackLimit;
+ } OldInitialTeb;
+ PVOID StackBase;
+ PVOID StackLimit;
+ PVOID StackAllocationBase;
+} KPHSS_INITIAL_TEB, *PKPHSS_INITIAL_TEB;
+
+typedef struct _KPHSS_BYTES
+{
+ USHORT Length;
+ CHAR Buffer[1];
+} KPHSS_BYTES, *PKPHSS_BYTES;
+
+#ifndef _SYSSERVICEDATA_PRIVATE
+extern RTL_GENERIC_TABLE KphSsCallTable;
+#endif
+
+#define KPHSS_MAXIMUM_ARGUMENT_BLOCKS 20
+
+typedef struct _KPHSS_CALL_ENTRY
+{
+ PULONG Number;
+ PSTR Name;
+ ULONG NumberOfArguments;
+ KPHSS_ARGUMENT_TYPE Arguments[KPHSS_MAXIMUM_ARGUMENT_BLOCKS];
+} KPHSS_CALL_ENTRY, *PKPHSS_CALL_ENTRY;
+
+VOID KphSsDataInit();
+VOID KphSsDataDeinit();
+
+PKPHSS_CALL_ENTRY KphSsLookupCallEntry(
+ __in ULONG Number
+ );
+
+#endif
\ No newline at end of file
diff --git a/2.x/trunk/KProcessHacker/include/sysservicep.h b/2.x/trunk/KProcessHacker/include/sysservicep.h
new file mode 100644
index 000000000..5b7e0c133
--- /dev/null
+++ b/2.x/trunk/KProcessHacker/include/sysservicep.h
@@ -0,0 +1,468 @@
+/*
+ * Process Hacker Driver -
+ * system service logging
+ *
+ * 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 _SYSSERVICEP_H
+#define _SYSSERVICEP_H
+
+#define _SYSSERVICE_PRIVATE
+#include "sysservice.h"
+#include "ex.h"
+#include "ref.h"
+
+/* PKPHPSS_KIFASTCALLENTRYPROC
+ *
+ * Represents a function called by KphpSsNewKiFastCallEntry.
+ */
+typedef VOID (NTAPI *PKPHPSS_KIFASTCALLENTRYPROC)(
+ __in ULONG Number,
+ __in ULONG *Arguments,
+ __in ULONG NumberOfArguments,
+ __in PKSERVICE_TABLE_DESCRIPTOR ServiceTable,
+ __in PKTHREAD Thread
+ );
+
+/* Client entries
+ *
+ * Client entries describe a process and a circular buffer which
+ * receives logging events.
+ */
+
+typedef struct _KPHSS_CLIENT_ENTRY
+{
+ PEPROCESS Process;
+ BOOLEAN Enabled;
+
+ /* Buffer */
+ PKSEMAPHORE ReadSemaphore;
+ PKSEMAPHORE WriteSemaphore;
+ FAST_MUTEX BufferMutex;
+ PVOID BufferBase;
+ ULONG BufferSize;
+ ULONG BufferCursor;
+
+ /* Statistics */
+ ULONG NumberOfBlocksWritten; /* excludes reset blocks */
+ ULONG NumberOfBlocksDropped;
+} KPHSS_CLIENT_ENTRY, *PKPHSS_CLIENT_ENTRY;
+
+/* Rulesets
+ *
+ * Rulesets contain a list of rules and an action to take if a
+ * system service matches the set of rules.
+ */
+
+#define KPHSS_RULESET_ENTRY(ListEntry) \
+ CONTAINING_RECORD((ListEntry), KPHSS_RULESET_ENTRY, RuleSetListEntry)
+#define KPHSS_RULESET_ENTRY_LIMIT 10
+#define KPHSS_RULE_HANDLE_INCREMENT 4
+
+typedef struct _KPHSS_RULESET_ENTRY
+{
+ LIST_ENTRY RuleSetListEntry;
+ /* The client is referenced. */
+ PKPHSS_CLIENT_ENTRY Client;
+
+ KPHSS_RULESET_ACTION Action;
+ KPHSS_FILTER_TYPE DefaultFilterType;
+
+ ULONG NextRuleHandle;
+ EX_PUSH_LOCK RuleListPushLock;
+ /* A list of rules. Each rule is referenced when stored. */
+ LIST_ENTRY RuleListHead;
+} KPHSS_RULESET_ENTRY, *PKPHSS_RULESET_ENTRY;
+
+/* Rules */
+
+#define KPHSS_RULE_ENTRY(ListEntry) \
+ CONTAINING_RECORD((ListEntry), KPHSS_RULE_ENTRY, RuleListEntry)
+
+typedef struct _KPHSS_RULE_ENTRY
+{
+ BOOLEAN Initialized;
+ HANDLE Handle;
+ LIST_ENTRY RuleListEntry;
+
+ KPHSS_FILTER_TYPE FilterType;
+ KPHSS_RULE_TYPE RuleType;
+
+ union
+ {
+ struct
+ {
+ HANDLE ProcessId;
+ } ProcessIdRule;
+ struct
+ {
+ HANDLE ThreadId;
+ } ThreadIdRule;
+ struct
+ {
+ KPROCESSOR_MODE PreviousMode;
+ } PreviousModeRule;
+ struct
+ {
+ ULONG Number;
+ } NumberRule;
+ };
+} KPHSS_RULE_ENTRY, *PKPHSS_RULE_ENTRY;
+
+typedef enum _KPHSS_SEQUENCE_MODE
+{
+ NoSequence,
+ StartSequence,
+ InSequence,
+ EndSequence
+} KPHSS_SEQUENCE_MODE;
+
+#define TAG_CAPTURE_TEMP_BUFFER ('tChP')
+#define CAPTURE_HANDLE_BUFFER_SIZE 0x400
+#define CAPTURE_UNICODE_STRING_MAX_SIZE 0x400
+#define CAPTURE_BYTES_MAX_SIZE 0x400
+
+/* Functions */
+
+VOID NTAPI KphpSsClientEntryDeleteProcedure(
+ __in PVOID Object,
+ __in ULONG Flags
+ );
+
+VOID NTAPI KphpSsRuleSetEntryDeleteProcedure(
+ __in PVOID Object,
+ __in ULONG Flags
+ );
+
+NTSTATUS KphpSsAddRule(
+ __out PKPHSS_RULE_ENTRY *RuleEntry,
+ __in PKPHSS_RULESET_ENTRY RuleSetEntry,
+ __in KPHSS_FILTER_TYPE FilterType,
+ __in KPHSS_RULE_TYPE RuleType
+ );
+
+NTSTATUS KphpSsCreateEventBlock(
+ __out PKPHSS_EVENT_BLOCK *EventBlock,
+ __in PKTHREAD Thread,
+ __in ULONG Number,
+ __in ULONG *Arguments,
+ __in ULONG NumberOfArguments
+ );
+
+VOID KphpSsFreeEventBlock(
+ __in PKPHSS_EVENT_BLOCK EventBlock
+ );
+
+NTSTATUS KphpSsCaptureSimpleArgument(
+ __out PKPHSS_ARGUMENT_BLOCK *ArgumentBlock,
+ __in PVOID Argument,
+ __in KPHSS_ARGUMENT_TYPE Type,
+ __in KPROCESSOR_MODE PreviousMode
+ );
+
+NTSTATUS KphpSsCaptureHandleArgument(
+ __out PKPHSS_ARGUMENT_BLOCK *ArgumentBlock,
+ __in HANDLE Argument,
+ __in KPROCESSOR_MODE PreviousMode
+ );
+
+NTSTATUS KphpSsCaptureUnicodeStringArgument(
+ __out PKPHSS_ARGUMENT_BLOCK *ArgumentBlock,
+ __in PUNICODE_STRING Argument,
+ __in KPROCESSOR_MODE PreviousMode
+ );
+
+NTSTATUS KphpSsCaptureObjectAttributesArgument(
+ __out PKPHSS_ARGUMENT_BLOCK *ArgumentBlock,
+ __in POBJECT_ATTRIBUTES Argument,
+ __in KPROCESSOR_MODE PreviousMode
+ );
+
+NTSTATUS KphpSsCaptureClientIdArgument(
+ __out PKPHSS_ARGUMENT_BLOCK *ArgumentBlock,
+ __in PCLIENT_ID Argument,
+ __in KPROCESSOR_MODE PreviousMode
+ );
+
+NTSTATUS KphpSsCaptureBytesArgument(
+ __out PKPHSS_ARGUMENT_BLOCK *ArgumentBlock,
+ __in PVOID Argument,
+ __in ULONG Length,
+ __in KPROCESSOR_MODE PreviousMode
+ );
+
+NTSTATUS KphpSsCreateArgumentBlock(
+ __out PKPHSS_ARGUMENT_BLOCK *ArgumentBlock,
+ __in ULONG Number,
+ __in ULONG Argument,
+ __in ULONG Index,
+ __in_opt KPHSS_ARGUMENT_TYPE Type,
+ __in_opt PVOID Context
+ );
+
+PKPHSS_ARGUMENT_BLOCK KphpSsAllocateArgumentBlock(
+ __in ULONG InnerSize,
+ __in KPHSS_ARGUMENT_TYPE Type
+ );
+
+VOID KphpSsFreeArgumentBlock(
+ __in PKPHSS_ARGUMENT_BLOCK ArgumentBlock
+ );
+
+NTSTATUS KphpSsWriteBlock(
+ __in PKPHSS_CLIENT_ENTRY ClientEntry,
+ __in_opt PKPHSS_BLOCK_HEADER Block,
+ __in KPHSS_SEQUENCE_MODE SequenceMode
+ );
+
+VOID NTAPI KphpSsLogSystemServiceCall(
+ __in ULONG Number,
+ __in ULONG *Arguments,
+ __in ULONG NumberOfArguments,
+ __in PKSERVICE_TABLE_DESCRIPTOR ServiceTable,
+ __in PKTHREAD Thread
+ );
+
+VOID NTAPI KphpSsNewKiFastCallEntry();
+
+/* KphpSsMatchRuleSetEntry
+ *
+ * Determines if a ruleset is relevant to an event.
+ *
+ * Note: This function is inlined for performance reasons.
+ */
+BOOLEAN FORCEINLINE KphpSsMatchRuleSetEntry(
+ __in PKPHSS_RULESET_ENTRY RuleSetEntry,
+ __in ULONG Number,
+ __in ULONG *Arguments,
+ __in ULONG NumberOfArguments,
+ __in PKSERVICE_TABLE_DESCRIPTOR ServiceTable,
+ __in PKTHREAD Thread,
+ __in KPROCESSOR_MODE PreviousMode
+ )
+{
+ PLIST_ENTRY currentListEntry;
+ ULONG i;
+ BOOLEAN ruleTypeUsedArray[MaxRuleType];
+ BOOLEAN ruleTypeIncludeArray[MaxRuleType];
+ BOOLEAN ruleTypeExcludeArray[MaxRuleType];
+ BOOLEAN ruleTypeFailedArray[MaxRuleType];
+ BOOLEAN isRuleSetMatch;
+
+ /* Due to the lack of proper boolean expression support,
+ * we are going to have these rules:
+ *
+ * * Each rule type has four arrays. The standard
+ * filtering rules apply to each rule type,
+ * except that on an include we increment the value
+ * in the include array and on an exclude we
+ * increment the value in the exclude array. On a
+ * failed include we increment the value in the
+ * failed array.
+ * * When we're done matching the rules, we'll look
+ * at the default filter type. If it's Include,
+ * we assume the ruleset matches. If it's Exclude,
+ * we assume the ruleset fails.
+ * * We will go through each rule type and look at
+ * the two arrays. See the code for further
+ * information.
+ */
+
+ /* Initialize the arrays. */
+ for (i = 0; i < MaxRuleType; i++)
+ {
+ ruleTypeUsedArray[i] = FALSE;
+ ruleTypeIncludeArray[i] = FALSE;
+ ruleTypeExcludeArray[i] = FALSE;
+ ruleTypeFailedArray[i] = FALSE;
+ }
+
+ KeEnterCriticalRegion();
+ ExAcquirePushLockShared(&RuleSetEntry->RuleListPushLock);
+
+ currentListEntry = RuleSetEntry->RuleListHead.Flink;
+
+ while (currentListEntry != &RuleSetEntry->RuleListHead)
+ {
+ PKPHSS_RULE_ENTRY ruleEntry = KPHSS_RULE_ENTRY(currentListEntry);
+ BOOLEAN isRuleMatch = FALSE;
+
+ /* Check if the rule is initialized, and if
+ * the rule type has already been failed -
+ * Exclude filter types take precedence.
+ */
+ if (
+ !ruleEntry->Initialized ||
+ ruleTypeExcludeArray[ruleEntry->RuleType]
+ )
+ {
+ currentListEntry = currentListEntry->Flink;
+ continue;
+ }
+
+ /* Attempt to match the rule. All rule types are
+ * considered in this one function.
+ */
+ switch (ruleEntry->RuleType)
+ {
+ case ProcessIdRuleType:
+ if (PsGetProcessId(IoThreadToProcess(Thread)) ==
+ ruleEntry->ProcessIdRule.ProcessId)
+ isRuleMatch = TRUE;
+ break;
+ case ThreadIdRuleType:
+ if (PsGetThreadId(Thread) == ruleEntry->ThreadIdRule.ThreadId)
+ isRuleMatch = TRUE;
+ break;
+ case PreviousModeRuleType:
+ if (PreviousMode == ruleEntry->PreviousModeRule.PreviousMode)
+ isRuleMatch = TRUE;
+ break;
+ case NumberRuleType:
+ if (Number == ruleEntry->NumberRule.Number)
+ isRuleMatch = TRUE;
+ break;
+ }
+
+ /* Now that we have attempted to match the rule, we
+ * must look at the rule filter type to determine
+ * what to do.
+ */
+ if (isRuleMatch)
+ {
+ if (ruleEntry->FilterType == IncludeFilterType)
+ {
+ ruleTypeIncludeArray[ruleEntry->RuleType] = TRUE;
+ }
+ else if (ruleEntry->FilterType == ExcludeFilterType)
+ {
+ ruleTypeExcludeArray[ruleEntry->RuleType] = TRUE;
+ }
+ }
+ else
+ {
+ if (ruleEntry->FilterType == IncludeFilterType)
+ {
+ ruleTypeFailedArray[ruleEntry->RuleType] = TRUE;
+ }
+ }
+
+ /* Declare that we have used the rule type. */
+ ruleTypeUsedArray[ruleEntry->RuleType] = TRUE;
+
+ currentListEntry = currentListEntry->Flink;
+ }
+
+ ExReleasePushLock(&RuleSetEntry->RuleListPushLock);
+ KeLeaveCriticalRegion();
+
+ /* Look at the default filter type. If it's Include,
+ * we assume the ruleset matches. Otherwise, we
+ * assume it fails.
+ */
+ if (RuleSetEntry->DefaultFilterType == IncludeFilterType)
+ {
+ isRuleSetMatch = TRUE;
+ }
+ else if (RuleSetEntry->DefaultFilterType == ExcludeFilterType)
+ {
+ isRuleSetMatch = FALSE;
+ }
+
+ /* Go through the rule type match/failed arrays. */
+
+ for (i = 0; i < MaxRuleType; i++)
+ {
+ /* Make sure this rule type has been used. */
+ if (!ruleTypeUsedArray[i])
+ continue;
+
+ /* The ordering of these if statements are
+ * extremely important. The order of precedence
+ * is: exclude, include, failed include. Failed include
+ * doesn't apply if we're using the Include default
+ * filter type, though.
+ */
+ if (ruleTypeExcludeArray[i])
+ {
+ isRuleSetMatch = FALSE;
+ break;
+ }
+ else if (ruleTypeIncludeArray[i])
+ {
+ isRuleSetMatch = TRUE;
+ }
+ else if (
+ ruleTypeFailedArray[i] &&
+ RuleSetEntry->DefaultFilterType != IncludeFilterType
+ )
+ {
+ isRuleSetMatch = FALSE;
+ break;
+ }
+ }
+
+ return isRuleSetMatch;
+}
+
+/* KphpSsProcessSpecificArguments
+ *
+ * Creates argument blocks for specific system calls.
+ *
+ * Note: This function is inlined for performance reasons.
+ */
+VOID FORCEINLINE KphpSsProcessSpecificArguments(
+ __in PKPHSS_ARGUMENT_BLOCK *ArgumentBlocks,
+ __in ULONG Number,
+ __in ULONG *Arguments,
+ __in ULONG NumberOfArguments,
+ __in KPROCESSOR_MODE PreviousMode
+ )
+{
+ NTSTATUS status;
+
+ /* For safety reasons, system call no. 0 is not supported. */
+ if (Number == 0)
+ return;
+
+ /* Wrap in SEH because we will be accessing the arguments. */
+
+ __try
+ {
+ if (Number == SsNtDeviceIoControlFile)
+ {
+ /* Create an argument block for the input buffer. */
+ if (!NT_SUCCESS(KphpSsCreateArgumentBlock(
+ &ArgumentBlocks[6],
+ Number,
+ Arguments[6],
+ 6,
+ BytesArgument,
+ (PVOID)Arguments[7]
+ )))
+ ArgumentBlocks[6] = NULL;
+ }
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ // Nothing
+ }
+}
+
+#endif
diff --git a/2.x/trunk/KProcessHacker/include/test.h b/2.x/trunk/KProcessHacker/include/test.h
new file mode 100644
index 000000000..49dc96095
--- /dev/null
+++ b/2.x/trunk/KProcessHacker/include/test.h
@@ -0,0 +1,30 @@
+/*
+ * Process Hacker Driver -
+ * testing 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 _TEST_H
+#define _TEST_H
+
+#include "kph.h"
+
+VOID KphTestPushLock();
+
+#endif
diff --git a/2.x/trunk/KProcessHacker/include/trace.h b/2.x/trunk/KProcessHacker/include/trace.h
new file mode 100644
index 000000000..6b707ede5
--- /dev/null
+++ b/2.x/trunk/KProcessHacker/include/trace.h
@@ -0,0 +1,188 @@
+/*
+ * Process Hacker Driver -
+ * stack tracing
+ *
+ * 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 _TRACE_H
+#define _TRACE_H
+
+#include "types.h"
+
+/* Stack Tracing */
+
+/* Sensible limit that may or may not correspond to the actual Windows value. */
+#define MAX_STACK_DEPTH 64
+
+#define RTL_WALK_USER_MODE_STACK 0x00000001
+#define RTL_WALK_VALID_FLAGS 0x00000001
+
+/* RtlWalkFrameChain
+ *
+ * Walks an EBP chain and fills out an array of addresses.
+ *
+ * Return value: the number of frames found.
+ */
+NTSYSAPI ULONG NTAPI RtlWalkFrameChain(
+ __out PVOID *Callers,
+ __in ULONG Count,
+ __in ULONG Flags
+ );
+
+/* Trace Database */
+
+#define RTL_TRACE_IN_USER_MODE 0x00000001
+#define RTL_TRACE_IN_KERNEL_MODE 0x00000002
+#define RTL_TRACE_USE_NONPAGED_POOL 0x00000004
+#define RTL_TRACE_USE_PAGED_POOL 0x00000008
+
+typedef struct _RTL_TRACE_BLOCK
+{
+ ULONG Magic;
+ ULONG Count; /* Reference count */
+ ULONG Size; /* Size, in PVOIDs, of the trace */
+
+ SIZE_T UserCount;
+ SIZE_T UserSize;
+ PVOID UserContext;
+
+ struct _RTL_TRACE_BLOCK *Next;
+ PVOID *Trace;
+} RTL_TRACE_BLOCK, *PRTL_TRACE_BLOCK;
+
+typedef struct _RTL_TRACE_DATABASE *PRTL_TRACE_DATABASE;
+
+/* Enumeration context. */
+typedef struct _RTL_TRACE_ENUMERATE
+{
+ PRTL_TRACE_DATABASE Database;
+ ULONG Index;
+ PRTL_TRACE_BLOCK Block;
+} RTL_TRACE_ENUMERATE, *PRTL_TRACE_ENUMERATE;
+
+typedef ULONG (*RTL_TRACE_HASH_FUNCTION)(
+ ULONG Count,
+ PVOID *Trace
+ );
+
+PRTL_TRACE_DATABASE RtlTraceDatabaseCreate(
+ __in ULONG Buckets,
+ __in_opt SIZE_T MaximumSize,
+ __in ULONG Flags, /* optional in user-mode */
+ __in ULONG Tag, /* optional in user-mode */
+ __in_opt RTL_TRACE_HASH_FUNCTION HashFunction
+ );
+
+BOOLEAN RtlTraceDatabaseDestroy(
+ __in PRTL_TRACE_DATABASE Database
+ );
+
+BOOLEAN RtlTraceDatabaseValidate(
+ __in PRTL_TRACE_DATABASE Database
+ );
+
+BOOLEAN RtlTraceDatabaseAdd(
+ __in PRTL_TRACE_DATABASE Database,
+ __in ULONG Count,
+ __in PVOID *Trace,
+ __out_opt PRTL_TRACE_BLOCK *TraceBlock
+ );
+
+/* RtlTraceDatabaseEnumerate
+ *
+ * Enumerates the trace blocks in the specified trace database.
+ *
+ * Database: The trace database to process.
+ * Enumerate: A context structure for the enumeration. Zero the
+ * structure if you are using it for the first time.
+ * TraceBlock: The trace block that was found by the function.
+ *
+ * Return value: TRUE if a trace block was found, FALSE if there
+ * are no more trace blocks.
+ */
+BOOLEAN RtlTraceDatabaseEnumerate(
+ __in PRTL_TRACE_DATABASE Database,
+ __inout PRTL_TRACE_ENUMERATE Enumerate,
+ __out PRTL_TRACE_BLOCK *TraceBlock
+ );
+
+BOOLEAN RtlTraceDatabaseFind(
+ __in PRTL_TRACE_DATABASE Database,
+ __in ULONG Count,
+ __in PVOID *Trace,
+ __out_opt PRTL_TRACE_BLOCK *TraceBlock
+ );
+
+/* Note: locking/unlocking is only needed when trace blocks are modified.
+ * It is not needed for adding/enumerating/finding. */
+VOID RtlTraceDatabaseLock(
+ __in PRTL_TRACE_DATABASE Database
+ );
+
+VOID RtlTraceDatabaseUnlock(
+ __in PRTL_TRACE_DATABASE Database
+ );
+
+/* KPH trace interface */
+
+typedef enum _KPH_CAPTURE_AND_ADD_STACK_TYPE
+{
+ KphCaptureAndAddKModeStack,
+ KphCaptureAndAddUModeStack,
+ KphCaptureAndAddBothStacks,
+ KphCaptureAndAddMaximum
+} KPH_CAPTURE_AND_ADD_STACK_TYPE, *PKPH_CAPTURE_AND_ADD_STACK_TYPE;
+
+typedef struct _KPH_TRACE_DATABASE
+{
+ PRTL_TRACE_DATABASE Database;
+} KPH_TRACE_DATABASE, *PKPH_TRACE_DATABASE;
+
+typedef struct _KPH_TRACEDB_INFORMATION
+{
+ ULONG NextEntryOffset;
+ ULONG Count;
+ ULONG TraceSize;
+ PVOID Trace[1];
+} KPH_TRACEDB_INFORMATION, *PKPH_TRACEDB_INFORMATION;
+
+NTSTATUS KphTraceDatabaseInitialization();
+
+BOOLEAN KphCaptureAndAddStack(
+ __in PKPH_TRACE_DATABASE Database,
+ __in KPH_CAPTURE_AND_ADD_STACK_TYPE Type,
+ __out_opt PRTL_TRACE_BLOCK *TraceBlock
+ );
+
+ULONG KphCaptureStackBackTrace(
+ __in ULONG FramesToSkip,
+ __in ULONG FramesToCapture,
+ __in_opt ULONG Flags,
+ __out_ecount(FramesToCapture) PVOID *BackTrace,
+ __out_opt PULONG BackTraceHash
+ );
+
+NTSTATUS KphCreateTraceDatabase(
+ __out PKPH_TRACE_DATABASE *Database,
+ __in_opt SIZE_T MaximumSize,
+ __in ULONG Flags,
+ __in ULONG Tag
+ );
+
+#endif
diff --git a/2.x/trunk/KProcessHacker/include/types.h b/2.x/trunk/KProcessHacker/include/types.h
new file mode 100644
index 000000000..e1ca291c1
--- /dev/null
+++ b/2.x/trunk/KProcessHacker/include/types.h
@@ -0,0 +1,7 @@
+#ifndef _TYPES_H
+#define _TYPES_H
+
+#include
+#include "version.h"
+
+#endif
diff --git a/2.x/trunk/KProcessHacker/include/util.h b/2.x/trunk/KProcessHacker/include/util.h
new file mode 100644
index 000000000..b62b0d22e
--- /dev/null
+++ b/2.x/trunk/KProcessHacker/include/util.h
@@ -0,0 +1,133 @@
+/*
+ * Process Hacker Driver -
+ * utility functions
+ *
+ * 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 _UTIL_H
+#define _UTIL_H
+
+#include "kph.h"
+
+/* Streams
+ *
+ * Streams are small buffer management structures. They
+ * automatically raise an exception if the buffer is overrun.
+ */
+
+typedef struct _KPH_STREAM
+{
+ PVOID Buffer;
+ ULONG Length;
+ ULONG Position;
+} KPH_STREAM, *PKPH_STREAM;
+
+typedef enum _KPH_STREAM_ORIGIN
+{
+ StartOrigin,
+ CurrentOrigin,
+ EndOrigin
+} KPH_STREAM_ORIGIN;
+
+VOID KphInitializeStream(
+ __out PKPH_STREAM Stream,
+ __in PVOID Buffer,
+ __in ULONG Length
+ );
+
+ULONG KphWriteDataStream(
+ __inout PKPH_STREAM Stream,
+ __in PVOID Data,
+ __in ULONG Length
+ );
+
+/* KphCheckStreamPosition
+ *
+ * Checks a stream position and raises an exception if
+ * appropriate.
+ */
+FORCEINLINE VOID KphCheckStreamPosition(
+ __in PKPH_STREAM Stream,
+ __in ULONG Position
+ )
+{
+ if (Position > Stream->Length)
+ ExRaiseStatus(STATUS_BUFFER_TOO_SMALL);
+}
+
+/* KphPositionStream
+ *
+ * Gets the current position of the specified stream.
+ */
+FORCEINLINE ULONG KphPositionStream(
+ __in PKPH_STREAM Stream
+ )
+{
+ return Stream->Position;
+}
+
+/* KphWriteInt8Stream
+ *
+ * Writes a 1-byte value to a stream.
+ */
+FORCEINLINE VOID KphWriteInt8Stream(
+ __inout PKPH_STREAM Stream,
+ __in BOOLEAN Value
+ )
+{
+ KphWriteDataStream(Stream, &Value, sizeof(BOOLEAN));
+}
+
+/* KphWriteInt16Stream
+ *
+ * Writes a 2-byte value to a stream.
+ */
+FORCEINLINE VOID KphWriteInt16Stream(
+ __inout PKPH_STREAM Stream,
+ __in SHORT Value
+ )
+{
+ KphWriteDataStream(Stream, &Value, sizeof(SHORT));
+}
+
+/* KphWriteInt32Stream
+ *
+ * Writes a 4-byte value to a stream.
+ */
+FORCEINLINE VOID KphWriteInt32Stream(
+ __inout PKPH_STREAM Stream,
+ __in LONG Value
+ )
+{
+ KphWriteDataStream(Stream, &Value, sizeof(LONG));
+}
+
+/* KphWriteInt64Stream
+ *
+ * Writes a 8-byte value to a stream.
+ */
+FORCEINLINE VOID KphWriteInt64Stream(
+ __inout PKPH_STREAM Stream,
+ __in PLARGE_INTEGER Value
+ )
+{
+ KphWriteDataStream(Stream, Value, sizeof(LARGE_INTEGER));
+}
+
+#endif
diff --git a/2.x/trunk/KProcessHacker/include/version.h b/2.x/trunk/KProcessHacker/include/version.h
new file mode 100644
index 000000000..00d6ba5ab
--- /dev/null
+++ b/2.x/trunk/KProcessHacker/include/version.h
@@ -0,0 +1,241 @@
+/*
+ * Process Hacker Driver -
+ * Windows version-specific data
+ *
+ * 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 _VERSION_H
+#define _VERSION_H
+
+#include "kph.h"
+
+#define WINDOWS_XP 51
+#define WINDOWS_SERVER_2003 52
+#define WINDOWS_VISTA 60
+#define WINDOWS_7 61
+
+#define KVOFF(object, offset) ((PCHAR)(object) + offset)
+#define SCAN_LENGTH 0x100000
+#define INIT_SCAN(scan, bytes, length, address, scanLength, displacement) \
+ ( \
+ ((scan).Initialized = TRUE), \
+ ((scan).Bytes = (bytes)), \
+ ((scan).Length = (length)), \
+ ((scan).StartAddress = (address)), \
+ ((scan).ScanLength = (scanLength)), \
+ ((scan).Displacement = (displacement)), \
+ bytes \
+ )
+
+typedef struct _KV_SCANPROC
+{
+ BOOLEAN Initialized;
+ PUCHAR Bytes;
+ ULONG Length;
+ ULONG_PTR StartAddress;
+ ULONG ScanLength;
+ LONG Displacement;
+} KV_SCANPROC, *PKV_SCANPROC;
+
+NTSTATUS KvInit();
+
+PVOID KvScanProc(
+ PKV_SCANPROC ScanProc
+ );
+
+PVOID KvVerifyPrologue(
+ PVOID Address
+ );
+
+#ifdef EXT
+#undef EXT
+#endif
+
+#ifdef _VERSION_PRIVATE
+#define EXT
+#define SCANNULL = { FALSE, NULL, 0, 0, 0, 0 }
+#else
+#define EXT extern
+#define SCANNULL
+#endif
+
+EXT ULONG WindowsVersion;
+EXT RTL_OSVERSIONINFOEXW RtlWindowsVersion;
+EXT ACCESS_MASK ProcessAllAccess;
+EXT ACCESS_MASK ThreadAllAccess;
+
+/* Offsets */
+/* Structures
+ * Et: ETHREAD
+ * Ep: EPROCESS
+ * Ot: OBJECT_TYPE
+ * Oti: OBJECT_TYPE_INITIALIZER, offset measured from an OBJECT_TYPE
+ */
+EXT ULONG OffEtClientId;
+EXT ULONG OffEtSpareByteForSs;
+EXT ULONG OffEtStartAddress;
+EXT ULONG OffEtWin32StartAddress;
+EXT ULONG OffEpJob;
+EXT ULONG OffEpObjectTable;
+EXT ULONG OffEpProtectedProcessOff;
+EXT ULONG OffEpProtectedProcessBit;
+EXT ULONG OffEpRundownProtect;
+EXT ULONG OffOhBody;
+EXT ULONG OffOtName;
+EXT ULONG OffOtiGenericMapping;
+EXT ULONG OffOtiOpenProcedure;
+
+/* Functions
+ */
+EXT KV_SCANPROC KiFastCallEntryScan SCANNULL;
+EXT KV_SCANPROC PsExitSpecialApcScan SCANNULL;
+EXT KV_SCANPROC PsTerminateProcessScan SCANNULL;
+EXT KV_SCANPROC PspTerminateThreadByPointerScan SCANNULL;
+
+/* System Call Numbers
+ */
+EXT ULONG SsNtAddAtom;
+EXT ULONG SsNtAlertResumeThread;
+EXT ULONG SsNtAlertThread;
+EXT ULONG SsNtAllocateLocallyUniqueId;
+EXT ULONG SsNtAllocateUserPhysicalPages;
+EXT ULONG SsNtAllocateUuids;
+EXT ULONG SsNtAllocateVirtualMemory;
+EXT ULONG SsNtApphelpCacheControl;
+EXT ULONG SsNtAreMappedFilesTheSame;
+EXT ULONG SsNtAssignProcessToJobObject;
+EXT ULONG SsNtCallbackReturn;
+EXT ULONG SsNtCancelDeviceWakeupRequest;
+EXT ULONG SsNtCancelIoFile;
+EXT ULONG SsNtCancelTimer;
+EXT ULONG SsNtClearEvent;
+EXT ULONG SsNtClose;
+EXT ULONG SsNtContinue;
+EXT ULONG SsNtCreateDebugObject;
+EXT ULONG SsNtCreateDirectoryObject;
+EXT ULONG SsNtCreateEvent;
+EXT ULONG SsNtCreateEventPair;
+EXT ULONG SsNtCreateFile;
+EXT ULONG SsNtCreateIoCompletion;
+EXT ULONG SsNtCreateJobObject;
+EXT ULONG SsNtCreateJobSet;
+EXT ULONG SsNtCreateKey;
+EXT ULONG SsNtCreateKeyedEvent;
+EXT ULONG SsNtCreateMailslotFile;
+EXT ULONG SsNtCreateMutant;
+EXT ULONG SsNtCreateNamedPipeFile;
+EXT ULONG SsNtCreatePagingFile;
+EXT ULONG SsNtCreatePort;
+EXT ULONG SsNtCreatePrivateNamespace;
+EXT ULONG SsNtCreateProcess;
+EXT ULONG SsNtCreateProcessEx;
+EXT ULONG SsNtCreateProfile;
+EXT ULONG SsNtCreateSection;
+EXT ULONG SsNtCreateSemaphore;
+EXT ULONG SsNtCreateSymbolicLinkObject;
+EXT ULONG SsNtCreateThread;
+EXT ULONG SsNtCreateTimer;
+EXT ULONG SsNtCreateToken;
+EXT ULONG SsNtCreateUserProcess;
+EXT ULONG SsNtCreateWaitablePort;
+EXT ULONG SsNtDebugActiveProcess;
+EXT ULONG SsNtDebugContinue;
+EXT ULONG SsNtDelayExecution;
+EXT ULONG SsNtDeleteAtom;
+EXT ULONG SsNtDeleteBootEntry;
+EXT ULONG SsNtDeleteDriverEntry;
+EXT ULONG SsNtDeleteFile;
+EXT ULONG SsNtDeleteKey;
+EXT ULONG SsNtDeleteObjectAuditAlarm;
+EXT ULONG SsNtDeletePrivateNamespace;
+EXT ULONG SsNtDeleteValueKey;
+EXT ULONG SsNtDeviceIoControlFile;
+EXT ULONG SsNtDisplayString;
+EXT ULONG SsNtDuplicateObject;
+EXT ULONG SsNtDuplicateToken;
+EXT ULONG SsNtEnumerateBootEntries;
+EXT ULONG SsNtEnumerateDriverEntries;
+EXT ULONG SsNtEnumerateKey;
+EXT ULONG SsNtEnumerateSystemEnvironmentValuesEx;
+EXT ULONG SsNtEnumerateValueKey;
+EXT ULONG SsNtExtendSection;
+EXT ULONG SsNtFilterToken;
+EXT ULONG SsNtFindAtom;
+EXT ULONG SsNtFlushBuffersFile;
+EXT ULONG SsNtFlushInstructionCache;
+EXT ULONG SsNtFlushKey;
+EXT ULONG SsNtFlushProcessWriteBuffers;
+EXT ULONG SsNtFlushVirtualMemory;
+EXT ULONG SsNtFlushWriteBuffer;
+EXT ULONG SsNtFreeUserPhysicalPages;
+EXT ULONG SsNtFreeVirtualMemory;
+EXT ULONG SsNtFsControlFile;
+EXT ULONG SsNtGetContextThread;
+EXT ULONG SsNtGetCurrentProcessorNumber;
+EXT ULONG SsNtGetDevicePowerState;
+EXT ULONG SsNtGetNextProcess;
+EXT ULONG SsNtGetNextThread;
+EXT ULONG SsNtGetPlugPlayEvent;
+EXT ULONG SsNtGetWriteWatch;
+EXT ULONG SsNtImpersonateAnonymousToken;
+EXT ULONG SsNtImpersonateClientOfPort;
+EXT ULONG SsNtImpersonateThread;
+EXT ULONG SsNtInitiatePowerAction;
+EXT ULONG SsNtIsProcessInJob;
+EXT ULONG SsNtIsSystemResumeAutomatic;
+EXT ULONG SsNtListenPort;
+EXT ULONG SsNtLoadDriver;
+EXT ULONG SsNtLoadKey;
+EXT ULONG SsNtLoadKey2;
+EXT ULONG SsNtLockFile;
+EXT ULONG SsNtLockVirtualMemory;
+EXT ULONG SsNtMakePermanentObject;
+EXT ULONG SsNtMakeTemporaryObject;
+EXT ULONG SsNtMapUserPhysicalPages;
+EXT ULONG SsNtMapUserPhysicalPagesScatter;
+EXT ULONG SsNtMapViewOfSection;
+EXT ULONG SsNtModifyBootEntry;
+EXT ULONG SsNtModifyDriverEntry;
+EXT ULONG SsNtNotifyChangeDirectoryFile;
+EXT ULONG SsNtNotifyChangeKey;
+EXT ULONG SsNtNotifyChangeMultipleKeys;
+EXT ULONG SsNtOpenDirectoryObject;
+EXT ULONG SsNtOpenEvent;
+EXT ULONG SsNtOpenEventPair;
+EXT ULONG SsNtOpenFile;
+EXT ULONG SsNtOpenIoCompletion;
+EXT ULONG SsNtOpenJobObject;
+EXT ULONG SsNtOpenKey;
+EXT ULONG SsNtOpenKeyedEvent;
+EXT ULONG SsNtOpenMutant;
+EXT ULONG SsNtOpenObjectAuditAlarm;
+EXT ULONG SsNtOpenProcess;
+EXT ULONG SsNtOpenProcessToken;
+EXT ULONG SsNtOpenProcessTokenEx;
+EXT ULONG SsNtOpenSection;
+EXT ULONG SsNtOpenSemaphore;
+EXT ULONG SsNtOpenSymbolicLinkObject;
+EXT ULONG SsNtOpenThread;
+EXT ULONG SsNtOpenThreadToken;
+EXT ULONG SsNtOpenThreadTokenEx;
+EXT ULONG SsNtOpenTimer;
+EXT ULONG SsNtReadFile;
+EXT ULONG SsNtWriteFile;
+
+#endif
diff --git a/2.x/trunk/KProcessHacker/include/zw.h b/2.x/trunk/KProcessHacker/include/zw.h
new file mode 100644
index 000000000..db943135f
--- /dev/null
+++ b/2.x/trunk/KProcessHacker/include/zw.h
@@ -0,0 +1,68 @@
+/*
+ * Process Hacker Driver -
+ * system calls
+ *
+ * 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 _ZW_H
+#define _ZW_H
+
+#include "types.h"
+
+NTSTATUS NTAPI ZwOpenProcessToken(
+ __in HANDLE ProcessHandle,
+ __in ACCESS_MASK DesiredAccess,
+ __out PHANDLE TokenHandle
+ );
+
+NTSTATUS NTAPI ZwQueryInformationProcess(
+ __in HANDLE ProcessHandle,
+ __in PROCESSINFOCLASS ProcessInformationClass,
+ __out PVOID ProcessInformation,
+ __in ULONG ProcessInformationLength,
+ __out_opt PULONG ReturnLength
+ );
+
+NTSTATUS NTAPI ZwQueryInformationThread(
+ __in HANDLE ThreadHandle,
+ __in PROCESSINFOCLASS ThreadInformationClass,
+ __out PVOID ThreadInformation,
+ __in ULONG ThreadInformationLength,
+ __out_opt PULONG ReturnLength
+ );
+
+NTSTATUS NTAPI ZwSetInformationProcess(
+ __in HANDLE ProcessHandle,
+ __in PROCESSINFOCLASS ProcessInformationClass,
+ __in PVOID ProcessInformation,
+ __in ULONG ProcessInformationLength
+ );
+
+/* NTSTATUS NTAPI ZwSetInformationThread(
+ __in HANDLE ThreadHandle,
+ __in THREADINFOCLASS ThreadInformationClass,
+ __in PVOID ThreadInformation,
+ __in ULONG ThreadInformationLength
+ ); */
+
+typedef NTSTATUS (NTAPI *_NtClose)(
+ __in HANDLE Handle
+ );
+
+#endif
diff --git a/2.x/trunk/KProcessHacker/io.c b/2.x/trunk/KProcessHacker/io.c
new file mode 100644
index 000000000..c8a55d68b
--- /dev/null
+++ b/2.x/trunk/KProcessHacker/io.c
@@ -0,0 +1,265 @@
+/*
+ * Process Hacker Driver -
+ * I/O manager
+ *
+ * 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/io.h"
+
+VOID KphpCopyInfoUnicodeString(
+ __out PVOID Information,
+ __in PUNICODE_STRING UnicodeString
+ );
+
+/* KphOpenDriver
+ *
+ * Opens a driver object.
+ */
+NTSTATUS KphOpenDriver(
+ __out PHANDLE DriverHandle,
+ __in POBJECT_ATTRIBUTES ObjectAttributes,
+ __in KPROCESSOR_MODE AccessMode
+ )
+{
+ return KphOpenNamedObject(
+ DriverHandle,
+ 0,
+ ObjectAttributes,
+ *IoDriverObjectType,
+ AccessMode
+ );
+}
+
+/* KphQueryInformationDriver
+ *
+ * Queries information about a driver object.
+ */
+NTSTATUS KphQueryInformationDriver(
+ __in HANDLE DriverHandle,
+ __in DRIVER_INFORMATION_CLASS DriverInformationClass,
+ __out_bcount_opt(DriverInformationLength) PVOID DriverInformation,
+ __in ULONG DriverInformationLength,
+ __out_opt PULONG ReturnLength,
+ __in KPROCESSOR_MODE AccessMode
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ PDRIVER_OBJECT driverObject;
+
+ if (
+ DriverInformationClass < DriverBasicInformation ||
+ DriverInformationClass >= MaxDriverInfoClass
+ )
+ return STATUS_INVALID_INFO_CLASS;
+
+ /* Probe user input. */
+ if (AccessMode != KernelMode)
+ {
+ __try
+ {
+ if (DriverInformation)
+ ProbeForWrite(DriverInformation, DriverInformationLength, 1);
+ if (ReturnLength)
+ ProbeForWrite(ReturnLength, sizeof(ULONG), 1);
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ return GetExceptionCode();
+ }
+ }
+
+ status = ObReferenceObjectByHandle(
+ DriverHandle,
+ 0,
+ *IoDriverObjectType,
+ KernelMode,
+ &driverObject,
+ NULL
+ );
+
+ if (!NT_SUCCESS(status))
+ return status;
+
+ __try
+ {
+ switch (DriverInformationClass)
+ {
+ /* DriverBasicInformation
+ *
+ * Basic information such as flags, driver base and driver size.
+ */
+ case DriverBasicInformation:
+ {
+ if (DriverInformation)
+ {
+ /* Check buffer length. */
+ if (DriverInformationLength == sizeof(DRIVER_BASIC_INFORMATION))
+ {
+ PDRIVER_BASIC_INFORMATION basicInfo;
+
+ basicInfo = (PDRIVER_BASIC_INFORMATION)DriverInformation;
+ basicInfo->Flags = driverObject->Flags;
+ basicInfo->DriverStart = driverObject->DriverStart;
+ basicInfo->DriverSize = driverObject->DriverSize;
+ }
+ else
+ {
+ status = STATUS_INFO_LENGTH_MISMATCH;
+ }
+ }
+
+ if (ReturnLength)
+ *ReturnLength = sizeof(DRIVER_BASIC_INFORMATION);
+ }
+ break;
+
+ /* DriverNameInformation
+ *
+ * The name of the driver - e.g. \Driver\KProcessHacker.
+ */
+ case DriverNameInformation:
+ {
+ if (DriverInformation)
+ {
+ /* Check buffer length. */
+ if (
+ sizeof(UNICODE_STRING) +
+ driverObject->DriverName.Length <=
+ DriverInformationLength
+ )
+ {
+ KphpCopyInfoUnicodeString(
+ DriverInformation,
+ &driverObject->DriverName
+ );
+ }
+ else
+ {
+ status = STATUS_BUFFER_TOO_SMALL;
+ }
+ }
+
+ /* Pass the ReturnLength. */
+ if (ReturnLength)
+ *ReturnLength = sizeof(UNICODE_STRING) + driverObject->DriverName.Length;
+ }
+ break;
+
+ /* DriverServiceKeyNameInformation
+ *
+ * The name of the driver's service key - e.g. \REGISTRY\...
+ */
+ case DriverServiceKeyNameInformation:
+ {
+ if (driverObject->DriverExtension)
+ {
+ if (DriverInformation)
+ {
+ if (
+ sizeof(UNICODE_STRING) +
+ driverObject->DriverExtension->ServiceKeyName.Length <=
+ DriverInformationLength
+ )
+ {
+ KphpCopyInfoUnicodeString(
+ DriverInformation,
+ &driverObject->DriverExtension->ServiceKeyName
+ );
+ }
+ else
+ {
+ status = STATUS_BUFFER_TOO_SMALL;
+ }
+ }
+
+ if (ReturnLength)
+ *ReturnLength = sizeof(UNICODE_STRING) +
+ driverObject->DriverExtension->ServiceKeyName.Length;
+ }
+ else
+ {
+ if (DriverInformation)
+ {
+ if (sizeof(UNICODE_STRING) <= DriverInformationLength)
+ {
+ /* Zero the information buffer. */
+ KphpCopyInfoUnicodeString(
+ DriverInformation,
+ NULL
+ );
+ }
+ else
+ {
+ status = STATUS_BUFFER_TOO_SMALL;
+ }
+ }
+
+ if (ReturnLength)
+ *ReturnLength = sizeof(UNICODE_STRING);
+ }
+ }
+ break;
+
+ default:
+ {
+ status = STATUS_INVALID_INFO_CLASS;
+ }
+ }
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ status = GetExceptionCode();
+ }
+
+ ObDereferenceObject(driverObject);
+
+ return status;
+}
+
+/* KphpCopyInfoUnicodeString
+ *
+ * Copies a UNICODE_STRING to an information buffer. If
+ * the given string is NULL, the function zeros the
+ * destination UNICODE_STRING.
+ */
+VOID KphpCopyInfoUnicodeString(
+ __out PVOID Information,
+ __in PUNICODE_STRING UnicodeString
+ )
+{
+ PUNICODE_STRING targetUnicodeString = (PUNICODE_STRING)Information;
+
+ if (UnicodeString)
+ {
+ targetUnicodeString->Length = UnicodeString->Length;
+ targetUnicodeString->MaximumLength = targetUnicodeString->Length;
+ targetUnicodeString->Buffer = (PWSTR)((PCHAR)Information + sizeof(UNICODE_STRING));
+ memcpy(
+ targetUnicodeString->Buffer,
+ UnicodeString->Buffer,
+ targetUnicodeString->Length
+ );
+ }
+ else
+ {
+ targetUnicodeString->Length = 0;
+ targetUnicodeString->MaximumLength = 0;
+ targetUnicodeString->Buffer = NULL;
+ }
+}
diff --git a/2.x/trunk/KProcessHacker/kph.c b/2.x/trunk/KProcessHacker/kph.c
new file mode 100644
index 000000000..8bc172a0f
--- /dev/null
+++ b/2.x/trunk/KProcessHacker/kph.c
@@ -0,0 +1,414 @@
+/*
+ * Process Hacker Driver -
+ * custom APIs
+ *
+ * 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 .
+ */
+
+#define _KPH_PRIVATE
+#include "include/kph.h"
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE, GetSystemRoutineAddress)
+#pragma alloc_text(PAGE, KphNtInit)
+#pragma alloc_text(PAGE, OpenProcess)
+#pragma alloc_text(PAGE, SetProcessToken)
+#endif
+
+POBJECT_TYPE ObpDirectoryObjectType;
+POBJECT_TYPE ObpTypeObjectType;
+
+/* GetSystemRoutineAddress
+ *
+ * Gets the address of a function exported by ntoskrnl or hal.
+ */
+PVOID GetSystemRoutineAddress(WCHAR *Name)
+{
+ UNICODE_STRING routineName;
+ PVOID routineAddress = NULL;
+
+ RtlInitUnicodeString(&routineName, Name);
+
+ /* Wrap in SEH because MmGetSystemRoutineAddress is known to cause
+ some BSODs. */
+ try
+ {
+ routineAddress = MmGetSystemRoutineAddress(&routineName);
+ }
+ except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ routineAddress = NULL;
+ }
+
+ return routineAddress;
+}
+
+/* KphNtInit
+ *
+ * Initializes the KProcessHacker NT component.
+ */
+NTSTATUS KphNtInit()
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ /* Confuse those damn AVs... */
+ PWCHAR keService = L"KeService"; // length 9, 18 bytes
+ PWCHAR descriptorTable = L"DescriptorTable"; // 15, 30 bytes
+ WCHAR keServiceDescriptorTable[9 + 15 + 1];
+
+ /* Reconstruct the string. */
+ memcpy(keServiceDescriptorTable, keService, 18);
+ memcpy(keServiceDescriptorTable + 9, descriptorTable, 30);
+ keServiceDescriptorTable[9 + 15] = L'\0';
+
+ /* Dynamically get function pointers. */
+ __KeServiceDescriptorTable = GetSystemRoutineAddress(keServiceDescriptorTable);
+ dfprintf("KeServiceDescriptorTable: %#x\n", __KeServiceDescriptorTable);
+ PsGetProcessJob = GetSystemRoutineAddress(L"PsGetProcessJob");
+ dfprintf("PsGetProcessJob: %#x\n", PsGetProcessJob);
+ PsResumeProcess = GetSystemRoutineAddress(L"PsResumeProcess");
+ dfprintf("PsResumeProcess: %#x\n", PsResumeProcess);
+ PsSuspendProcess = GetSystemRoutineAddress(L"PsSuspendProcess");
+ dfprintf("PsSuspendProcess: %#x\n", PsSuspendProcess);
+
+ if (WindowsVersion >= WINDOWS_7)
+ {
+ ObGetObjectType = GetSystemRoutineAddress(L"ObGetObjectType");
+ dfprintf("ObGetObjectType: %#x\n", ObGetObjectType);
+ }
+
+ /* Scan for functions. */
+ if (KiFastCallEntryScan.Initialized)
+ {
+ __KiFastCallEntry = KvScanProc(&KiFastCallEntryScan);
+ dfprintf("KiFastCallEntry+x: %#x\n", __KiFastCallEntry);
+ }
+ if (PsTerminateProcessScan.Initialized)
+ {
+ __PsTerminateProcess = KvScanProc(&PsTerminateProcessScan);
+ dfprintf("PsTerminateProcess: %#x\n", __PsTerminateProcess);
+ }
+ if (PspTerminateThreadByPointerScan.Initialized)
+ {
+ __PspTerminateThreadByPointer = KvScanProc(&PspTerminateThreadByPointerScan);
+ dfprintf("PspTerminateThreadByPointer: %#x\n", __PspTerminateThreadByPointer);
+ }
+
+ /* Fill in other global variables. */
+
+ /* Directory object type. */
+ {
+ HANDLE rootDirectoryHandle;
+ PVOID rootDirectoryObject;
+ UNICODE_STRING rootDirectoryName;
+ OBJECT_ATTRIBUTES objectAttributes;
+
+ RtlInitUnicodeString(&rootDirectoryName, L"\\");
+ InitializeObjectAttributes(
+ &objectAttributes,
+ &rootDirectoryName,
+ OBJ_KERNEL_HANDLE,
+ NULL,
+ NULL
+ );
+
+ status = ZwOpenDirectoryObject(&rootDirectoryHandle, DIRECTORY_QUERY, &objectAttributes);
+
+ if (!NT_SUCCESS(status))
+ return status;
+
+ status = ObReferenceObjectByHandle(rootDirectoryHandle, 0, NULL, KernelMode, &rootDirectoryObject, NULL);
+ ZwClose(rootDirectoryHandle);
+
+ if (!NT_SUCCESS(status))
+ return status;
+
+ ObpDirectoryObjectType = KphGetObjectTypeNt(rootDirectoryObject);
+ ObDirectoryObjectType = &ObpDirectoryObjectType;
+ ObDereferenceObject(rootDirectoryObject);
+ }
+
+ /* Type object type. */
+ ObpTypeObjectType = KphGetObjectTypeNt(*PsProcessType);
+ ObTypeObjectType = &ObpTypeObjectType;
+
+ return status;
+}
+
+/* KphAttachProcess
+ *
+ * Attaches to a process represented by the specified EPROCESS.
+ */
+VOID KphAttachProcess(
+ __in PEPROCESS Process,
+ __out PKPH_ATTACH_STATE AttachState
+ )
+{
+ AttachState->Attached = FALSE;
+
+ /* Don't attach if we are already attached to the target. */
+ if (Process != PsGetCurrentProcess())
+ {
+ KeStackAttachProcess(Process, &AttachState->ApcState);
+ AttachState->Attached = TRUE;
+ AttachState->Process = Process;
+ }
+}
+
+/* KphAttachProcessHandle
+ *
+ * Attaches to a process represented by the specified handle.
+ */
+NTSTATUS KphAttachProcessHandle(
+ __in HANDLE ProcessHandle,
+ __out PKPH_ATTACH_STATE AttachState
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ PEPROCESS processObject;
+
+ AttachState->Attached = FALSE;
+
+ status = ObReferenceObjectByHandle(
+ ProcessHandle,
+ 0,
+ *PsProcessType,
+ KernelMode,
+ &processObject,
+ NULL
+ );
+
+ if (!NT_SUCCESS(status))
+ return status;
+
+ KphAttachProcess(processObject, AttachState);
+ ObDereferenceObject(processObject);
+
+ return status;
+}
+
+/* KphAttachProcessId
+ *
+ * Attaches to a process represented by the specified process ID.
+ */
+NTSTATUS KphAttachProcessId(
+ __in HANDLE ProcessId,
+ __out PKPH_ATTACH_STATE AttachState
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ PEPROCESS processObject;
+
+ AttachState->Attached = FALSE;
+
+ status = PsLookupProcessByProcessId(ProcessId, &processObject);
+
+ if (!NT_SUCCESS(status))
+ return status;
+
+ KphAttachProcess(processObject, AttachState);
+ ObDereferenceObject(processObject);
+
+ return status;
+}
+
+/* KphCaptureUnicodeString
+ *
+ * Captures a UNICODE_STRING. This function will not throw exceptions.
+ */
+NTSTATUS KphCaptureUnicodeString(
+ __in PUNICODE_STRING UnicodeString,
+ __out PUNICODE_STRING CapturedUnicodeString
+ )
+{
+ __try
+ {
+ CapturedUnicodeString->Length = UnicodeString->Length;
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ return GetExceptionCode();
+ }
+
+ CapturedUnicodeString->MaximumLength = CapturedUnicodeString->Length;
+ CapturedUnicodeString->Buffer = ExAllocatePoolWithTag(
+ PagedPool,
+ CapturedUnicodeString->Length,
+ TAG_CAPTURED_UNICODE_STRING
+ );
+
+ if (!CapturedUnicodeString->Buffer)
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ __try
+ {
+ memcpy(
+ CapturedUnicodeString->Buffer,
+ UnicodeString->Buffer,
+ CapturedUnicodeString->Length
+ );
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ KphFreeCapturedUnicodeString(CapturedUnicodeString);
+ return GetExceptionCode();
+ }
+
+ return STATUS_SUCCESS;
+}
+
+/* KphDetachProcess
+ *
+ * Detaches from the currently attached process.
+ */
+VOID KphDetachProcess(
+ __in PKPH_ATTACH_STATE AttachState
+ )
+{
+ if (AttachState->Attached)
+ KeUnstackDetachProcess(&AttachState->ApcState);
+}
+
+/* KphFreeCapturedUnicodeString
+ *
+ * Frees a UNICODE_STRING captured by KphCaptureUnicodeString.
+ */
+VOID KphFreeCapturedUnicodeString(
+ __in PUNICODE_STRING CapturedUnicodeString
+ )
+{
+ ExFreePoolWithTag(
+ CapturedUnicodeString->Buffer,
+ TAG_CAPTURED_UNICODE_STRING
+ );
+}
+
+/* KphProbeForReadUnicodeString
+ *
+ * Probes a UNICODE_STRING structure for reading.
+ */
+VOID KphProbeForReadUnicodeString(
+ __in PUNICODE_STRING UnicodeString
+ )
+{
+ ProbeForRead(UnicodeString, sizeof(UNICODE_STRING), 1);
+ ProbeForRead(UnicodeString->Buffer, UnicodeString->Length, 1);
+}
+
+/* KphProbeSystemAddressRange
+ *
+ * Probes an address range in kernel-mode memory for reading.
+ */
+VOID KphProbeSystemAddressRange(
+ __in PVOID BaseAddress,
+ __in ULONG Length
+ )
+{
+ ULONG_PTR page, pageEnd;
+
+ /* HACK HACK HACK HACK HACK HACK */
+ /* Check the address range by checking each page. */
+ /* Round down the base address to the page size. Note: please make sure you are
+ * not using a dumbass compiler which optimizes the following line by removing
+ * the divide and multiply.
+ */
+ page = (ULONG_PTR)BaseAddress / PAGE_SIZE * PAGE_SIZE;
+ /* BaseAddress + Length - 1 is the last address we will be reading. */
+ pageEnd = ((ULONG_PTR)BaseAddress + Length - 1) / PAGE_SIZE * PAGE_SIZE;
+
+ for (; page <= pageEnd; page += PAGE_SIZE)
+ {
+ /* Check the page. */
+ if (!MmIsAddressValid((PVOID)page))
+ ExRaiseStatus(STATUS_ACCESS_VIOLATION);
+ }
+}
+
+/* OpenProcess
+ *
+ * Opens the process with the specified PID.
+ */
+NTSTATUS OpenProcess(
+ __out PHANDLE ProcessHandle,
+ __in ACCESS_MASK DesiredAccess,
+ __in HANDLE ProcessId
+ )
+{
+ OBJECT_ATTRIBUTES objAttr = { 0 };
+ CLIENT_ID clientId;
+
+ objAttr.Length = sizeof(objAttr);
+ clientId.UniqueThread = 0;
+ clientId.UniqueProcess = ProcessId;
+
+ return KphOpenProcess(ProcessHandle, DesiredAccess, &objAttr, &clientId, KernelMode);
+}
+
+/* SetProcessToken
+ *
+ * Assigns the primary token of the target process from the
+ * primary token of source process.
+ */
+NTSTATUS SetProcessToken(
+ __in HANDLE sourcePid,
+ __in HANDLE targetPid
+ )
+{
+ NTSTATUS status;
+ HANDLE source;
+
+ if (NT_SUCCESS(status = OpenProcess(&source, PROCESS_QUERY_INFORMATION, sourcePid)))
+ {
+ HANDLE target;
+
+ if (NT_SUCCESS(status = OpenProcess(&target, PROCESS_QUERY_INFORMATION |
+ PROCESS_SET_INFORMATION, targetPid)))
+ {
+ HANDLE sourceToken;
+
+ if (NT_SUCCESS(status = KphOpenProcessTokenEx(source, TOKEN_DUPLICATE, 0,
+ &sourceToken, UserMode)))
+ {
+ HANDLE dupSourceToken;
+ OBJECT_ATTRIBUTES objectAttributes = { 0 };
+
+ objectAttributes.Length = sizeof(objectAttributes);
+
+ if (NT_SUCCESS(status = ZwDuplicateToken(sourceToken, TOKEN_ASSIGN_PRIMARY, &objectAttributes,
+ FALSE, TokenPrimary, &dupSourceToken)))
+ {
+ PROCESS_ACCESS_TOKEN token;
+
+ token.Token = dupSourceToken;
+ token.Thread = 0;
+
+ status = ZwSetInformationProcess(target, ProcessAccessToken, &token, sizeof(token));
+ }
+
+ ZwClose(dupSourceToken);
+ }
+
+ ZwClose(sourceToken);
+ }
+
+ ZwClose(target);
+ }
+
+ ZwClose(source);
+
+ return status;
+}
diff --git a/2.x/trunk/KProcessHacker/kprocesshacker.c b/2.x/trunk/KProcessHacker/kprocesshacker.c
new file mode 100644
index 000000000..5a470578f
--- /dev/null
+++ b/2.x/trunk/KProcessHacker/kprocesshacker.c
@@ -0,0 +1,2609 @@
+/*
+ * Process Hacker Driver -
+ * main driver 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/kprocesshacker.h"
+#include "include/debug.h"
+
+#include "include/kph.h"
+#include "include/protect.h"
+#include "include/ps.h"
+#include "include/sysservice.h"
+#include "include/version.h"
+
+#define CHECK_IN_LENGTH \
+ if (inLength < sizeof(*args)) \
+ { \
+ status = STATUS_BUFFER_TOO_SMALL; \
+ goto IoControlEnd; \
+ }
+#define CHECK_OUT_LENGTH \
+ if (outLength < sizeof(*ret)) \
+ { \
+ status = STATUS_BUFFER_TOO_SMALL; \
+ goto IoControlEnd; \
+ }
+#define CHECK_IN_OUT_LENGTH \
+ if (inLength < sizeof(*args) || outLength < sizeof(*ret)) \
+ { \
+ status = STATUS_BUFFER_TOO_SMALL; \
+ goto IoControlEnd; \
+ }
+
+PDRIVER_OBJECT KphDriverObject;
+
+static PKPH_OBJECT_TYPE ClientEntryType;
+static LIST_ENTRY ClientListHead;
+static EX_PUSH_LOCK ClientListLock;
+
+static BOOLEAN ProtectionInitialized = FALSE;
+static FAST_MUTEX ProtectionMutex;
+
+static ULONG SsStartCount = 0;
+static FAST_MUTEX SsMutex;
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE, DriverEntry)
+#pragma alloc_text(PAGE, DriverUnload)
+#pragma alloc_text(PAGE, KphDispatchCreate)
+#pragma alloc_text(PAGE, KphDispatchClose)
+#pragma alloc_text(PAGE, KphDispatchDeviceControl)
+#pragma alloc_text(PAGE, KphDispatchRead)
+#pragma alloc_text(PAGE, KphUnsupported)
+#endif
+
+NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ int i;
+ PDEVICE_OBJECT deviceObject = NULL;
+ UNICODE_STRING deviceName, dosDeviceName;
+
+ KphDriverObject = DriverObject;
+
+ /* Initialize version information. */
+ status = KvInit();
+
+ if (!NT_SUCCESS(status))
+ {
+ if (status == STATUS_NOT_SUPPORTED)
+ dprintf("Your operating system is not supported by KProcessHacker\n");
+
+ return status;
+ }
+
+ /* Initialize NT KPH. */
+ status = KphNtInit();
+
+ if (!NT_SUCCESS(status))
+ return status;
+
+ /* Initialize hooking. */
+ status = KphHookInit();
+
+ if (!NT_SUCCESS(status))
+ return status;
+
+ /* Initialize the KPH object manager. */
+ status = KphRefInit();
+
+ if (!NT_SUCCESS(status))
+ return status;
+
+ /* Initialize system service logging. */
+ status = KphSsLogInit();
+
+ if (!NT_SUCCESS(status))
+ {
+ KphRefDeinit();
+ return status;
+ }
+
+ /* Initialize trace databases. */
+ status = KphTraceDatabaseInitialization();
+
+ if (!NT_SUCCESS(status))
+ {
+ KphRefDeinit();
+ return status;
+ }
+
+ /* Initialize client list structures. */
+ InitializeListHead(&ClientListHead);
+ ExInitializePushLock(&ClientListLock);
+
+ status = KphCreateObjectType(
+ &ClientEntryType,
+ PagedPool,
+ 0,
+ ClientEntryDeleteProcedure
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ KphRefDeinit();
+ return status;
+ }
+
+ /* Initialize process protection. */
+ ExInitializeFastMutex(&ProtectionMutex);
+ /* Initialize the system service logging mutex. */
+ ExInitializeFastMutex(&SsMutex);
+
+ RtlInitUnicodeString(&deviceName, KPH_DEVICE_NAME);
+ RtlInitUnicodeString(&dosDeviceName, KPH_DEVICE_DOS_NAME);
+
+ /* Create the KProcessHacker device. */
+ status = IoCreateDevice(DriverObject, 0, &deviceName,
+ FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &deviceObject);
+
+ /* Set up the major functions. */
+ for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)
+ DriverObject->MajorFunction[i] = NULL;
+
+ DriverObject->MajorFunction[IRP_MJ_CLOSE] = KphDispatchClose;
+ DriverObject->MajorFunction[IRP_MJ_CREATE] = KphDispatchCreate;
+ DriverObject->MajorFunction[IRP_MJ_READ] = KphDispatchRead;
+ DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = KphDispatchDeviceControl;
+ DriverObject->DriverUnload = DriverUnload;
+
+ deviceObject->Flags |= DO_BUFFERED_IO;
+ deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
+
+ IoCreateSymbolicLink(&dosDeviceName, &deviceName);
+
+ dprintf("Driver loaded\n");
+
+ return STATUS_SUCCESS;
+}
+
+VOID DriverUnload(PDRIVER_OBJECT DriverObject)
+{
+ UNICODE_STRING dosDeviceName;
+
+ RtlInitUnicodeString(&dosDeviceName, KPH_DEVICE_DOS_NAME);
+ IoDeleteSymbolicLink(&dosDeviceName);
+ IoDeleteDevice(DriverObject->DeviceObject);
+
+ ExAcquireFastMutex(&ProtectionMutex);
+
+ if (ProtectionInitialized)
+ {
+ KphProtectDeinit();
+ ProtectionInitialized = FALSE;
+ }
+
+ ExReleaseFastMutex(&ProtectionMutex);
+
+ /* Make sure system service logging is disabled. */
+ if (SsStartCount > 0)
+ SsUnref(SsStartCount);
+
+ /* Free system service logging structures. */
+ KphSsLogDeinit();
+
+ /* Free all objects in the object manager. */
+ KphRefDeinit();
+
+ dprintf("Driver unloaded\n");
+}
+
+NTSTATUS KphDispatchCreate(PDEVICE_OBJECT DeviceObject, PIRP Irp)
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+#ifdef KPH_REQUIRE_DEBUG_PRIVILEGE
+ if (!SeSinglePrivilegeCheck(SeExports->SeDebugPrivilege, UserMode))
+ {
+ dprintf("Client (PID %d) was refused\n", PsGetCurrentProcessId());
+ Irp->IoStatus.Status = STATUS_PRIVILEGE_NOT_HELD;
+
+ return STATUS_PRIVILEGE_NOT_HELD;
+ }
+#endif
+
+ /* Add a client entry. Note that we don't dereference it because
+ * we keep one reference for it being on the client list.
+ */
+ if (!CreateClientEntry(NULL))
+ {
+ Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ dprintf("Client (PID %d) connected\n", PsGetCurrentProcessId());
+ dprintf("Base IOCTL is 0x%08x\n", KPH_CTL_CODE(0));
+
+ return status;
+}
+
+NTSTATUS KphDispatchClose(PDEVICE_OBJECT DeviceObject, PIRP Irp)
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ PKPH_CLIENT_ENTRY clientEntry;
+
+ ExAcquireFastMutex(&ProtectionMutex);
+
+ if (ProtectionInitialized)
+ {
+ ULONG count = KphProtectRemoveByTag(PsGetCurrentProcessId());
+ dprintf("Removed %d protection entries\n", count);
+ }
+
+ ExReleaseFastMutex(&ProtectionMutex);
+
+ /* Get the current client entry and dereference it twice to remove it. */
+ clientEntry = ReferenceClientEntry(NULL);
+
+ if (clientEntry)
+ KphDereferenceObjectEx(clientEntry, 2, FALSE);
+
+ dprintf("Client (PID %d) disconnected\n", PsGetCurrentProcessId());
+
+ return status;
+}
+
+VOID InitProtection()
+{
+ ExAcquireFastMutex(&ProtectionMutex);
+
+ if (!ProtectionInitialized)
+ {
+ if (NT_SUCCESS(KphProtectInit()))
+ ProtectionInitialized = TRUE;
+ }
+
+ ExReleaseFastMutex(&ProtectionMutex);
+}
+
+VOID SsRef(LONG count)
+{
+ LONG oldRefCount;
+
+ ASSERT(count >= 0);
+
+ if (count == 0)
+ return;
+
+ ExAcquireFastMutex(&SsMutex);
+
+ /* Add references. */
+ oldRefCount = InterlockedExchangeAdd(&SsStartCount, count);
+ ASSERT(oldRefCount >= 0);
+
+ /* Start system service logging if this was the first bunch of references. */
+ if (oldRefCount == 0)
+ KphSsLogStart();
+
+ ExReleaseFastMutex(&SsMutex);
+}
+
+VOID SsUnref(LONG count)
+{
+ LONG oldRefCount;
+
+ ASSERT(count >= 0);
+
+ if (count == 0)
+ return;
+
+ ExAcquireFastMutex(&SsMutex);
+
+ oldRefCount = InterlockedExchangeAdd(&SsStartCount, -count);
+ ASSERT(oldRefCount > 0);
+
+ if (oldRefCount - count == 0)
+ KphSsLogStop();
+
+ ExReleaseFastMutex(&SsMutex);
+}
+
+VOID NTAPI ClientEntryDeleteProcedure(
+ __in PVOID Object,
+ __in ULONG Flags
+ )
+{
+ PKPH_CLIENT_ENTRY entry = (PKPH_CLIENT_ENTRY)Object;
+
+ /* Lower the SS start count. */
+ SsUnref(entry->SsStartCount);
+
+ /* Free the handle table. */
+ KphFreeHandleTable(entry->HandleTable);
+
+ /* Remove the entry from the client list. */
+ KeEnterCriticalRegion();
+ ExAcquirePushLockExclusive(&ClientListLock);
+ RemoveEntryList(&entry->ClientListEntry);
+ ExReleasePushLock(&ClientListLock);
+ KeLeaveCriticalRegion();
+}
+
+PKPH_CLIENT_ENTRY CreateClientEntry(
+ __in_opt HANDLE ProcessId
+ )
+{
+ PKPH_CLIENT_ENTRY entry;
+ PKPH_HANDLE_TABLE handleTable;
+
+ /* If the PID wasn't specified, use the current one. */
+ if (!ProcessId)
+ ProcessId = PsGetCurrentProcessId();
+
+ if (!NT_SUCCESS(KphCreateHandleTable(
+ &handleTable,
+ KPH_CLIENT_MAXHANDLES,
+ sizeof(KPH_HANDLE_TABLE_ENTRY),
+ TAG_CLIENT_HANDLETABLE
+ )))
+ return NULL;
+
+ if (!NT_SUCCESS(KphCreateObject(
+ &entry,
+ sizeof(KPH_CLIENT_ENTRY),
+ 0,
+ ClientEntryType,
+ 0
+ )))
+ {
+ KphFreeHandleTable(handleTable);
+ return NULL;
+ }
+
+ /* Initialize the entry. */
+ entry->ProcessId = ProcessId;
+ entry->HandleTable = handleTable;
+ KphInitializeGuardedLock(&entry->SsLock, FALSE);
+ entry->SsStartCount = 0;
+
+ /* Insert the entry into the client list. */
+ KeEnterCriticalRegion();
+ ExAcquirePushLockExclusive(&ClientListLock);
+ InsertHeadList(&ClientListHead, &entry->ClientListEntry);
+ ExReleasePushLock(&ClientListLock);
+ KeLeaveCriticalRegion();
+
+ return entry;
+}
+
+PKPH_CLIENT_ENTRY ReferenceClientEntry(
+ __in_opt HANDLE ProcessId
+ )
+{
+ PLIST_ENTRY entry = ClientListHead.Flink;
+
+ /* If the PID wasn't specified, use the current one. */
+ if (!ProcessId)
+ ProcessId = PsGetCurrentProcessId();
+
+ KeEnterCriticalRegion();
+ ExAcquirePushLockShared(&ClientListLock);
+
+ /* Find the client entry. */
+ while (entry != &ClientListHead)
+ {
+ PKPH_CLIENT_ENTRY clientEntry =
+ CONTAINING_RECORD(entry, KPH_CLIENT_ENTRY, ClientListEntry);
+
+ if (clientEntry->ProcessId == ProcessId)
+ {
+ PKPH_CLIENT_ENTRY returnEntry = NULL;
+
+ /* Reference and return the entry. */
+ if (KphReferenceObjectSafe(clientEntry))
+ {
+ returnEntry = clientEntry;
+ }
+
+ ExReleasePushLock(&ClientListLock);
+ KeLeaveCriticalRegion();
+
+ return returnEntry;
+ }
+
+ entry = entry->Flink;
+ }
+
+ ExReleasePushLock(&ClientListLock);
+ KeLeaveCriticalRegion();
+
+ return NULL;
+}
+
+NTSTATUS CloseClientHandle(
+ __in_opt HANDLE ProcessId,
+ __in HANDLE Handle
+ )
+{
+ NTSTATUS status;
+ PKPH_CLIENT_ENTRY clientEntry;
+
+ clientEntry = ReferenceClientEntry(ProcessId);
+
+ if (!clientEntry)
+ return STATUS_UNSUCCESSFUL;
+
+ status = KphCloseHandle(clientEntry->HandleTable, Handle);
+ KphDereferenceObject(clientEntry);
+
+ return status;
+}
+
+NTSTATUS CreateClientHandle(
+ __in_opt HANDLE ProcessId,
+ __in PVOID Object,
+ __out PHANDLE Handle
+ )
+{
+ NTSTATUS status;
+ PKPH_CLIENT_ENTRY clientEntry;
+
+ clientEntry = ReferenceClientEntry(ProcessId);
+
+ if (!clientEntry)
+ return STATUS_UNSUCCESSFUL;
+
+ status = KphCreateHandle(clientEntry->HandleTable, Object, Handle);
+ KphDereferenceObject(clientEntry);
+
+ return status;
+}
+
+NTSTATUS ReferenceClientHandle(
+ __in_opt HANDLE ProcessId,
+ __in HANDLE Handle,
+ __in PKPH_OBJECT_TYPE ObjectType,
+ __out PVOID *Object
+ )
+{
+ NTSTATUS status;
+ PKPH_CLIENT_ENTRY clientEntry;
+
+ clientEntry = ReferenceClientEntry(ProcessId);
+
+ if (!clientEntry)
+ return STATUS_UNSUCCESSFUL;
+
+ status = KphReferenceObjectByHandle(
+ clientEntry->HandleTable,
+ Handle,
+ ObjectType,
+ Object
+ );
+ KphDereferenceObject(clientEntry);
+
+ return status;
+}
+
+PCHAR GetIoControlName(ULONG ControlCode)
+{
+ switch (ControlCode)
+ {
+ case KPH_CLOSEHANDLE:
+ return "Client Close Handle";
+ case KPH_SSQUERYCLIENTENTRY:
+ return "SsQueryClientEntry";
+ case KPH_OPENPROCESS:
+ return "KphOpenProcess";
+ case KPH_OPENTHREAD:
+ return "KphOpenThread";
+ case KPH_OPENPROCESSTOKEN:
+ return "KphOpenProcessTokenEx";
+ case KPH_GETPROCESSPROTECTED:
+ return "Get Process Protected";
+ case KPH_SETPROCESSPROTECTED:
+ return "Set Process Protected";
+ case KPH_TERMINATEPROCESS:
+ return "KphTerminateProcess";
+ case KPH_SUSPENDPROCESS:
+ return "KphSuspendProcess";
+ case KPH_RESUMEPROCESS:
+ return "KphResumeProcess";
+ case KPH_READVIRTUALMEMORY:
+ return "KphReadVirtualMemory";
+ case KPH_WRITEVIRTUALMEMORY:
+ return "KphWriteVirtualMemory";
+ case KPH_SETPROCESSTOKEN:
+ return "Set Process Token";
+ case KPH_GETTHREADSTARTADDRESS:
+ return "Get Thread Start Address";
+ case KPH_SETHANDLEATTRIBUTES:
+ return "Set Handle Attributes";
+ case KPH_GETHANDLEOBJECTNAME:
+ return "Get Handle Object Name";
+ case KPH_OPENPROCESSJOB:
+ return "KphOpenProcessJob";
+ case KPH_GETCONTEXTTHREAD:
+ return "KphGetContextThread";
+ case KPH_SETCONTEXTTHREAD:
+ return "KphSetContextThread";
+ case KPH_GETTHREADWIN32THREAD:
+ return "KphGetThreadWin32Thread";
+ case KPH_DUPLICATEOBJECT:
+ return "KphDuplicateObject";
+ case KPH_ZWQUERYOBJECT:
+ return "ZwQueryObject";
+ case KPH_GETPROCESSID:
+ return "KphGetProcessId";
+ case KPH_GETTHREADID:
+ return "KphGetThreadId";
+ case KPH_TERMINATETHREAD:
+ return "KphTerminateThread";
+ case KPH_GETFEATURES:
+ return "Get Features";
+ case KPH_SETHANDLEGRANTEDACCESS:
+ return "KphSetHandleGrantedAccess";
+ case KPH_ASSIGNIMPERSONATIONTOKEN:
+ return "KphAssignImpersonationToken";
+ case KPH_PROTECTADD:
+ return "Add Process Protection";
+ case KPH_PROTECTREMOVE:
+ return "Remove Process Protection";
+ case KPH_PROTECTQUERY:
+ return "Query Process Protection";
+ case KPH_UNSAFEREADVIRTUALMEMORY:
+ return "KphUnsafeReadVirtualMemory";
+ case KPH_SETEXECUTEOPTIONS:
+ return "Set Execute Options";
+ case KPH_QUERYPROCESSHANDLES:
+ return "KphQueryProcessHandles";
+ case KPH_OPENTHREADPROCESS:
+ return "KphOpenThreadProcess";
+ case KPH_CAPTURESTACKBACKTRACETHREAD:
+ return "KphCaptureStackBackTraceThread";
+ case KPH_DANGEROUSTERMINATETHREAD:
+ return "KphDangerousTerminateThread";
+ case KPH_OPENTYPE:
+ return "KphOpenType";
+ case KPH_OPENDRIVER:
+ return "KphOpenDriver";
+ case KPH_QUERYINFORMATIONDRIVER:
+ return "KphQueryInformationDriver";
+ case KPH_OPENDIRECTORYOBJECT:
+ return "KphOpenDirectoryObject";
+ case KPH_SSREF:
+ return "SsRef";
+ case KPH_SSUNREF:
+ return "SsUnref";
+ case KPH_SSCREATECLIENTENTRY:
+ return "SsCreateClientEntry";
+ case KPH_SSCREATERULESETENTRY:
+ return "SsCreateRuleSetEntry";
+ case KPH_SSREMOVERULE:
+ return "SsRemoveRule";
+ case KPH_SSADDPROCESSIDRULE:
+ return "SsAddProcessIdRule";
+ case KPH_SSADDTHREADIDRULE:
+ return "SsAddThreadIdRule";
+ case KPH_SSADDPREVIOUSMODERULE:
+ return "SsAddPreviousModeRule";
+ case KPH_SSADDNUMBERRULE:
+ return "SsAddNumberRule";
+ case KPH_SSENABLECLIENTENTRY:
+ return "SsEnableClientEntry";
+ case KPH_OPENNAMEDOBJECT:
+ return "KphOpenNamedObject";
+ case KPH_QUERYINFORMATIONPROCESS:
+ return "KphQueryInformationProcess";
+ case KPH_QUERYINFORMATIONTHREAD:
+ return "KphQueryInformationThread";
+ case KPH_SETINFORMATIONPROCESS:
+ return "KphSetInformationProcess";
+ case KPH_SETINFORMATIONTHREAD:
+ return "KphSetInformationThread";
+ default:
+ return "Unknown";
+ }
+}
+
+NTSTATUS KphDispatchDeviceControl(PDEVICE_OBJECT DeviceObject, PIRP Irp)
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ PIO_STACK_LOCATION ioStackIrp = NULL;
+ PVOID dataBuffer;
+ ULONG controlCode;
+ ULONG inLength = 0;
+ ULONG outLength = 0;
+ ULONG retLength = 0;
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ Irp->IoStatus.Information = 0;
+
+ ioStackIrp = IoGetCurrentIrpStackLocation(Irp);
+
+ if (ioStackIrp == NULL)
+ {
+ status = STATUS_INTERNAL_ERROR;
+ goto IoControlEnd;
+ }
+
+ dataBuffer = Irp->AssociatedIrp.SystemBuffer;
+
+ if (dataBuffer == NULL && (inLength != 0 || outLength != 0))
+ {
+ status = STATUS_BUFFER_TOO_SMALL;
+ goto IoControlEnd;
+ }
+
+ inLength = ioStackIrp->Parameters.DeviceIoControl.InputBufferLength;
+ outLength = ioStackIrp->Parameters.DeviceIoControl.OutputBufferLength;
+ controlCode = ioStackIrp->Parameters.DeviceIoControl.IoControlCode;
+
+ dprintf("IoControl 0x%08x (%s)\n", controlCode, GetIoControlName(controlCode));
+
+ /* 1-byte packing for KPH input/output structures. */
+ #include
+
+ switch (controlCode)
+ {
+ /* Client Close Handle
+ *
+ * Closes a handle opened by the client.
+ */
+ case KPH_CLOSEHANDLE:
+ {
+ struct
+ {
+ HANDLE Handle;
+ } *args = dataBuffer;
+ PKPH_CLIENT_ENTRY clientEntry;
+
+ CHECK_IN_LENGTH;
+
+ status = CloseClientHandle(NULL, args->Handle);
+ }
+ break;
+
+ /* SsQueryClientEntry
+ *
+ * Queries information about a client entry.
+ */
+ case KPH_SSQUERYCLIENTENTRY:
+ {
+ struct
+ {
+ HANDLE ClientEntryHandle;
+ PKPHSS_CLIENT_INFORMATION ClientInformation;
+ ULONG ClientInformationLength;
+ PULONG ReturnLength;
+ } *args = dataBuffer;
+ PKPHSS_CLIENT_ENTRY clientEntry;
+
+ CHECK_IN_LENGTH;
+
+ /* Reference the client entry. */
+ status = ReferenceClientHandle(
+ NULL,
+ args->ClientEntryHandle,
+ KphSsClientEntryType,
+ &clientEntry
+ );
+
+ if (!NT_SUCCESS(status))
+ goto IoControlEnd;
+
+ /* Query the client entry. */
+ status = KphSsQueryClientEntry(
+ clientEntry,
+ args->ClientInformation,
+ args->ClientInformationLength,
+ args->ReturnLength,
+ UserMode
+ );
+ KphDereferenceObject(clientEntry);
+ }
+ break;
+
+ /* KphOpenProcess
+ *
+ * Opens the specified process. This call will never fail unless:
+ * 1. PsLookupProcessByProcessId, ObOpenObjectByPointer or some lower-level
+ * function is hooked, or
+ * 2. The process is protected.
+ */
+ case KPH_OPENPROCESS:
+ {
+ struct
+ {
+ HANDLE ProcessId;
+ ACCESS_MASK DesiredAccess;
+ } *args = dataBuffer;
+ struct
+ {
+ HANDLE ProcessHandle;
+ } *ret = dataBuffer;
+ OBJECT_ATTRIBUTES objectAttributes = { 0 };
+ CLIENT_ID clientId;
+
+ CHECK_IN_OUT_LENGTH;
+
+ clientId.UniqueThread = 0;
+ clientId.UniqueProcess = args->ProcessId;
+ status = KphOpenProcess(
+ &ret->ProcessHandle,
+ args->DesiredAccess,
+ &objectAttributes,
+ &clientId,
+ KernelMode
+ );
+
+ if (!NT_SUCCESS(status))
+ goto IoControlEnd;
+
+ retLength = sizeof(*ret);
+ }
+ break;
+
+ /* KphOpenThread
+ *
+ * Opens the specified thread. This call will never fail unless:
+ * 1. PsLookupProcessThreadByCid, ObOpenObjectByPointer or some lower-level
+ * function is hooked, or
+ * 2. The thread's process is protected.
+ */
+ case KPH_OPENTHREAD:
+ {
+ struct
+ {
+ HANDLE ThreadId;
+ ACCESS_MASK DesiredAccess;
+ } *args = dataBuffer;
+ struct
+ {
+ HANDLE ThreadHandle;
+ } *ret = dataBuffer;
+ OBJECT_ATTRIBUTES objectAttributes = { 0 };
+ CLIENT_ID clientId;
+
+ CHECK_IN_OUT_LENGTH;
+
+ clientId.UniqueThread = args->ThreadId;
+ clientId.UniqueProcess = 0;
+ status = KphOpenThread(
+ &ret->ThreadHandle,
+ args->DesiredAccess,
+ &objectAttributes,
+ &clientId,
+ KernelMode
+ );
+
+ if (!NT_SUCCESS(status))
+ goto IoControlEnd;
+
+ retLength = sizeof(*ret);
+ }
+ break;
+
+ /* KphOpenProcessToken
+ *
+ * Opens the specified process' token. This call will never fail unless
+ * a low-level function is hooked.
+ */
+ case KPH_OPENPROCESSTOKEN:
+ {
+ struct
+ {
+ HANDLE ProcessHandle;
+ ACCESS_MASK DesiredAccess;
+ } *args = dataBuffer;
+ struct
+ {
+ HANDLE TokenHandle;
+ } *ret = dataBuffer;
+
+ CHECK_IN_OUT_LENGTH;
+
+ status = KphOpenProcessTokenEx(
+ args->ProcessHandle,
+ args->DesiredAccess,
+ 0,
+ &ret->TokenHandle,
+ KernelMode
+ );
+
+ if (!NT_SUCCESS(status))
+ goto IoControlEnd;
+
+ retLength = sizeof(*ret);
+ }
+ break;
+
+ /* Get Process Protected
+ *
+ * Gets whether the process is protected.
+ */
+ case KPH_GETPROCESSPROTECTED:
+ {
+ struct
+ {
+ HANDLE ProcessId;
+ } *args = dataBuffer;
+ struct
+ {
+ BOOLEAN IsProtected;
+ } *ret = dataBuffer;
+ PEPROCESS processObject;
+
+ CHECK_IN_OUT_LENGTH;
+
+ status = PsLookupProcessByProcessId(args->ProcessId, &processObject);
+
+ if (!NT_SUCCESS(status))
+ goto IoControlEnd;
+
+ ret->IsProtected =
+ (CHAR)GET_BIT(
+ *(PULONG)KVOFF(processObject, OffEpProtectedProcessOff),
+ OffEpProtectedProcessBit
+ );
+ ObDereferenceObject(processObject);
+ retLength = sizeof(*ret);
+ }
+ break;
+
+ /* Set Process Protected
+ *
+ * Sets whether the process is protected.
+ */
+ case KPH_SETPROCESSPROTECTED:
+ {
+ struct
+ {
+ HANDLE ProcessId;
+ BOOLEAN IsProtected;
+ } *args = dataBuffer;
+ PEPROCESS processObject;
+
+ CHECK_IN_LENGTH;
+
+ status = PsLookupProcessByProcessId(args->ProcessId, &processObject);
+
+ if (!NT_SUCCESS(status))
+ goto IoControlEnd;
+
+ if (args->IsProtected)
+ {
+ SET_BIT(
+ *(PULONG)KVOFF(processObject, OffEpProtectedProcessOff),
+ OffEpProtectedProcessBit
+ );
+ }
+ else
+ {
+ CLEAR_BIT(
+ *(PULONG)KVOFF(processObject, OffEpProtectedProcessOff),
+ OffEpProtectedProcessBit
+ );
+ }
+
+ ObDereferenceObject(processObject);
+ }
+ break;
+
+ /* KphTerminateProcess
+ *
+ * Terminates the specified process. This call will never fail unless
+ * PsTerminateProcess could not be located and Zw/NtTerminateProcess
+ * is hooked, or an attempt was made to terminate the current process.
+ * In that case, the call will fail with STATUS_CANT_TERMINATE_SELF.
+ */
+ case KPH_TERMINATEPROCESS:
+ {
+ struct
+ {
+ HANDLE ProcessHandle;
+ NTSTATUS ExitStatus;
+ } *args = dataBuffer;
+
+ CHECK_IN_LENGTH;
+
+ status = KphTerminateProcess(args->ProcessHandle, args->ExitStatus);
+ }
+ break;
+
+ /* KphSuspendProcess
+ *
+ * Suspends the specified process. This call will fail on Windows XP
+ * and below.
+ */
+ case KPH_SUSPENDPROCESS:
+ {
+ struct
+ {
+ HANDLE ProcessHandle;
+ } *args = dataBuffer;
+
+ CHECK_IN_LENGTH;
+
+ status = KphSuspendProcess(args->ProcessHandle);
+ }
+ break;
+
+ /* KphResumeProcess
+ *
+ * Resumes the specified process. This call will fail on Windows XP
+ * and below.
+ */
+ case KPH_RESUMEPROCESS:
+ {
+ struct
+ {
+ HANDLE ProcessHandle;
+ } *args = dataBuffer;
+
+ CHECK_IN_LENGTH;
+
+ status = KphResumeProcess(args->ProcessHandle);
+ }
+ break;
+
+ /* KphReadVirtualMemory
+ *
+ * Reads process memory.
+ */
+ case KPH_READVIRTUALMEMORY:
+ {
+ struct
+ {
+ HANDLE ProcessHandle;
+ PVOID BaseAddress;
+ PVOID Buffer;
+ ULONG BufferLength;
+ PULONG ReturnLength;
+ } *args = dataBuffer;
+
+ CHECK_IN_LENGTH;
+
+ status = KphReadVirtualMemory(
+ args->ProcessHandle,
+ args->BaseAddress,
+ args->Buffer,
+ args->BufferLength,
+ args->ReturnLength,
+ UserMode
+ );
+ }
+ break;
+
+ /* KphWriteVirtualMemory
+ *
+ * Writes to process memory.
+ */
+ case KPH_WRITEVIRTUALMEMORY:
+ {
+ struct
+ {
+ HANDLE ProcessHandle;
+ PVOID BaseAddress;
+ PVOID Buffer;
+ ULONG BufferLength;
+ PULONG ReturnLength;
+ } *args = dataBuffer;
+
+ CHECK_IN_LENGTH;
+
+ status = KphWriteVirtualMemory(
+ args->ProcessHandle,
+ args->BaseAddress,
+ args->Buffer,
+ args->BufferLength,
+ args->ReturnLength,
+ UserMode
+ );
+ }
+ break;
+
+ /* Set Process Token
+ *
+ * Assigns the primary token of a source process to a target process.
+ */
+ case KPH_SETPROCESSTOKEN:
+ {
+ struct
+ {
+ HANDLE SourceProcessId;
+ HANDLE TargetProcessId;
+ } *args = dataBuffer;
+
+ CHECK_IN_LENGTH;
+
+ status = SetProcessToken(args->SourceProcessId, args->TargetProcessId);
+ }
+ break;
+
+ /* Get Thread Start Address
+ *
+ * Gets the specified thread's start address.
+ */
+ case KPH_GETTHREADSTARTADDRESS:
+ {
+ struct
+ {
+ HANDLE ThreadHandle;
+ } *args = dataBuffer;
+ struct
+ {
+ PVOID StartAddress;
+ } *ret = dataBuffer;
+ PETHREAD threadObject;
+
+ CHECK_IN_OUT_LENGTH;
+
+ status = ObReferenceObjectByHandle(args->ThreadHandle, 0, *PsThreadType, KernelMode, &threadObject, NULL);
+
+ if (!NT_SUCCESS(status))
+ goto IoControlEnd;
+
+ /* Get the Win32StartAddress */
+ if (!(ret->StartAddress = *(PVOID *)KVOFF(threadObject, OffEtWin32StartAddress)))
+ {
+ /* If that failed, get the StartAddress */
+ ret->StartAddress = *(PVOID *)KVOFF(threadObject, OffEtStartAddress);
+ }
+
+ ObDereferenceObject(threadObject);
+ retLength = sizeof(*ret);
+ }
+ break;
+
+ /* Set Handle Attributes
+ *
+ * Sets handle flags in the specified process.
+ */
+ case KPH_SETHANDLEATTRIBUTES:
+ {
+ struct
+ {
+ HANDLE ProcessHandle;
+ HANDLE Handle;
+ ULONG Flags;
+ } *args = dataBuffer;
+ KPH_ATTACH_STATE attachState;
+ OBJECT_HANDLE_FLAG_INFORMATION handleFlags = { 0 };
+
+ CHECK_IN_LENGTH;
+
+ status = KphAttachProcessHandle(args->ProcessHandle, &attachState);
+
+ if (!NT_SUCCESS(status))
+ goto IoControlEnd;
+
+ if (args->Flags & OBJ_PROTECT_CLOSE)
+ handleFlags.ProtectFromClose = TRUE;
+ if (args->Flags & OBJ_INHERIT)
+ handleFlags.Inherit = TRUE;
+
+ status = ObSetHandleAttributes(args->Handle, &handleFlags, UserMode);
+ KphDetachProcess(&attachState);
+ }
+ break;
+
+ /* Get Handle Object Name
+ *
+ * Gets the name of the specified handle. The handle can be remote; in
+ * that case a valid process handle must be passed. Otherwise, set the
+ * process handle to -1 (NtCurrentProcess()).
+ */
+ case KPH_GETHANDLEOBJECTNAME:
+ {
+ struct
+ {
+ HANDLE ProcessHandle;
+ HANDLE Handle;
+ } *args = dataBuffer;
+ KPH_ATTACH_STATE attachState;
+ PVOID object;
+
+ CHECK_IN_LENGTH;
+
+ status = KphAttachProcessHandle(args->ProcessHandle, &attachState);
+
+ if (!NT_SUCCESS(status))
+ goto IoControlEnd;
+
+ /* See the block for KPH_ZWQUERYOBJECT for information. */
+ if (attachState.Process == PsInitialSystemProcess)
+ MakeKernelHandle(args->Handle);
+
+ status = ObReferenceObjectByHandle(args->Handle, 0, NULL, KernelMode, &object, NULL);
+ KphDetachProcess(&attachState);
+
+ if (!NT_SUCCESS(status))
+ goto IoControlEnd;
+
+ status = KphQueryNameObject(object, (PUNICODE_STRING)dataBuffer, outLength, &retLength);
+ ObDereferenceObject(object);
+
+ /* Check if the return length is greater than the length of the user buffer.
+ * If so, it means the user needs to provide a larger buffer. In that case,
+ * store the length in the Unicode string structure.
+ */
+ if (retLength > outLength)
+ {
+ if (outLength >= sizeof(UNICODE_STRING))
+ {
+ ((PUNICODE_STRING)dataBuffer)->Length = (USHORT)retLength;
+ retLength = sizeof(UNICODE_STRING);
+ }
+ }
+ }
+ break;
+
+ /* KphOpenProcessJob
+ *
+ * Opens the job object that the process is assigned to. If the process is
+ * not assigned to any job object, the call will fail with STATUS_PROCESS_NOT_IN_JOB.
+ */
+ case KPH_OPENPROCESSJOB:
+ {
+ struct
+ {
+ HANDLE ProcessHandle;
+ ACCESS_MASK DesiredAccess;
+ } *args = dataBuffer;
+ struct
+ {
+ HANDLE JobHandle;
+ } *ret = dataBuffer;
+
+ CHECK_IN_OUT_LENGTH;
+
+ status = KphOpenProcessJob(args->ProcessHandle, args->DesiredAccess, &ret->JobHandle, KernelMode);
+
+ if (!NT_SUCCESS(status))
+ goto IoControlEnd;
+
+ retLength = sizeof(*ret);
+ }
+ break;
+
+ /* KphGetContextThread
+ *
+ * Gets the context of the specified thread.
+ */
+ case KPH_GETCONTEXTTHREAD:
+ {
+ struct
+ {
+ HANDLE ThreadHandle;
+ PCONTEXT ThreadContext;
+ } *args = dataBuffer;
+
+ CHECK_IN_LENGTH;
+
+ status = KphGetContextThread(args->ThreadHandle, args->ThreadContext, UserMode);
+ }
+ break;
+
+ /* KphSetContextThread
+ *
+ * Sets the context of the specified thread.
+ */
+ case KPH_SETCONTEXTTHREAD:
+ {
+ struct
+ {
+ HANDLE ThreadHandle;
+ PCONTEXT ThreadContext;
+ } *args = dataBuffer;
+
+ CHECK_IN_LENGTH;
+
+ status = KphSetContextThread(args->ThreadHandle, args->ThreadContext, UserMode);
+ }
+ break;
+
+ /* KphGetThreadWin32Thread
+ *
+ * Gets a pointer to the specified thread's Win32Thread structure.
+ */
+ case KPH_GETTHREADWIN32THREAD:
+ {
+ struct
+ {
+ HANDLE ThreadHandle;
+ } *args = dataBuffer;
+ struct
+ {
+ PVOID Win32Thread;
+ } *ret = dataBuffer;
+
+ CHECK_IN_OUT_LENGTH;
+
+ status = KphGetThreadWin32Thread(args->ThreadHandle, &ret->Win32Thread, KernelMode);
+
+ if (!NT_SUCCESS(status))
+ goto IoControlEnd;
+
+ retLength = sizeof(*ret);
+ }
+ break;
+
+ /* KphDuplicateObject
+ *
+ * Duplicates the specified handle from the source process to the target process.
+ * Do not use this call to duplicate file handles; it may freeze indefinitely if
+ * the file is a named pipe.
+ */
+ case KPH_DUPLICATEOBJECT:
+ {
+ struct
+ {
+ HANDLE SourceProcessHandle;
+ HANDLE SourceHandle;
+ HANDLE TargetProcessHandle;
+ PHANDLE TargetHandle;
+ ACCESS_MASK DesiredAccess;
+ ULONG HandleAttributes;
+ ULONG Options;
+ } *args = dataBuffer;
+
+ CHECK_IN_LENGTH;
+
+ status = KphDuplicateObject(
+ args->SourceProcessHandle,
+ args->SourceHandle,
+ args->TargetProcessHandle,
+ args->TargetHandle,
+ args->DesiredAccess,
+ args->HandleAttributes,
+ args->Options,
+ UserMode
+ );
+ }
+ break;
+
+ /* ZwQueryObject
+ *
+ * Performs ZwQueryObject in the context of another process.
+ */
+ case KPH_ZWQUERYOBJECT:
+ {
+ struct
+ {
+ HANDLE ProcessHandle;
+ HANDLE Handle;
+ OBJECT_INFORMATION_CLASS ObjectInformationClass;
+ } *args = dataBuffer;
+ struct
+ {
+ NTSTATUS Status;
+ ULONG ReturnLength;
+ PVOID BufferBase;
+ CHAR Buffer[1];
+ } *ret = dataBuffer;
+ NTSTATUS status2 = STATUS_SUCCESS;
+ KPH_ATTACH_STATE attachState;
+ BOOLEAN attached;
+
+ if (inLength < sizeof(*args) || outLength < sizeof(*ret) - sizeof(CHAR))
+ {
+ status = STATUS_BUFFER_TOO_SMALL;
+ goto IoControlEnd;
+ }
+
+ status = KphAttachProcessHandle(args->ProcessHandle, &attachState);
+
+ if (!NT_SUCCESS(status))
+ goto IoControlEnd;
+
+ /* Are we attached to the system process? If we are,
+ * we must set the high bit in the handle to indicate
+ * that it is a kernel handle - a new check for this
+ * was added in Windows 7.
+ */
+ if (attachState.Process == PsInitialSystemProcess)
+ MakeKernelHandle(args->Handle);
+
+ status2 = ZwQueryObject(
+ args->Handle,
+ args->ObjectInformationClass,
+ ret->Buffer,
+ outLength - (sizeof(*ret) - sizeof(CHAR)),
+ &retLength
+ );
+ KphDetachProcess(&attachState);
+
+ ret->ReturnLength = retLength;
+ ret->BufferBase = ret->Buffer;
+
+ if (NT_SUCCESS(status2))
+ retLength += sizeof(*ret) - sizeof(CHAR);
+ else
+ retLength = sizeof(*ret) - sizeof(CHAR);
+
+ ret->Status = status2;
+ }
+ break;
+
+ /* KphGetProcessId
+ *
+ * Gets the process ID of a process handle in the context of another process.
+ */
+ case KPH_GETPROCESSID:
+ {
+ struct
+ {
+ HANDLE ProcessHandle;
+ HANDLE Handle;
+ } *args = dataBuffer;
+ struct
+ {
+ HANDLE ProcessId;
+ } *ret = dataBuffer;
+ KPH_ATTACH_STATE attachState;
+
+ CHECK_IN_OUT_LENGTH;
+
+ status = KphAttachProcessHandle(args->ProcessHandle, &attachState);
+
+ if (!NT_SUCCESS(status))
+ goto IoControlEnd;
+
+ if (attachState.Process == PsInitialSystemProcess)
+ MakeKernelHandle(args->Handle);
+
+ ret->ProcessId = KphGetProcessId(args->Handle);
+ KphDetachProcess(&attachState);
+ retLength = sizeof(*ret);
+ }
+ break;
+
+ /* KphGetThreadId
+ *
+ * Gets the thread ID of a thread handle in the context of another process.
+ */
+ case KPH_GETTHREADID:
+ {
+ struct
+ {
+ HANDLE ProcessHandle;
+ HANDLE Handle;
+ } *args = dataBuffer;
+ struct
+ {
+ HANDLE ThreadId;
+ HANDLE ProcessId;
+ } *ret = dataBuffer;
+ KPH_ATTACH_STATE attachState;
+
+ CHECK_IN_OUT_LENGTH;
+
+ status = KphAttachProcessHandle(args->ProcessHandle, &attachState);
+
+ if (!NT_SUCCESS(status))
+ goto IoControlEnd;
+
+ if (attachState.Process == PsInitialSystemProcess)
+ MakeKernelHandle(args->Handle);
+
+ ret->ThreadId = KphGetThreadId(args->Handle, &ret->ProcessId);
+ KphDetachProcess(&attachState);
+ retLength = sizeof(*ret);
+ }
+ break;
+
+ /* KphTerminateThread
+ *
+ * Terminates the specified thread. This call will fail if
+ * PspTerminateThreadByPointer could not be located or if an attempt
+ * was made to terminate the current thread. In that case, the call
+ * will return STATUS_CANT_TERMINATE_SELF.
+ */
+ case KPH_TERMINATETHREAD:
+ {
+ struct
+ {
+ HANDLE ThreadHandle;
+ NTSTATUS ExitStatus;
+ } *args = dataBuffer;
+
+ CHECK_IN_LENGTH;
+
+ status = KphTerminateThread(args->ThreadHandle, args->ExitStatus);
+ }
+ break;
+
+ /* Get Features
+ *
+ * Gets the features supported by the driver.
+ */
+ case KPH_GETFEATURES:
+ {
+ struct
+ {
+ ULONG Features;
+ } *ret = dataBuffer;
+ ULONG features = 0;
+
+ CHECK_OUT_LENGTH;
+
+ if (__PsTerminateProcess)
+ features |= KPHF_PSTERMINATEPROCESS;
+ if (__PspTerminateThreadByPointer)
+ features |= KPHF_PSPTERMINATETHREADBPYPOINTER;
+
+ ret->Features = features;
+ retLength = sizeof(*ret);
+ }
+ break;
+
+ /* KphSetHandleGrantedAccess
+ *
+ * Sets the granted access for a handle.
+ */
+ case KPH_SETHANDLEGRANTEDACCESS:
+ {
+ struct
+ {
+ HANDLE Handle;
+ ACCESS_MASK GrantedAccess;
+ } *args = dataBuffer;
+
+ CHECK_IN_LENGTH;
+
+ status = KphSetHandleGrantedAccess(
+ PsGetCurrentProcess(),
+ args->Handle,
+ args->GrantedAccess
+ );
+ }
+ break;
+
+ /* KphAssignImpersonationToken
+ *
+ * Assigns an impersonation token to a thread.
+ */
+ case KPH_ASSIGNIMPERSONATIONTOKEN:
+ {
+ struct
+ {
+ HANDLE ThreadHandle;
+ HANDLE TokenHandle;
+ } *args = dataBuffer;
+
+ CHECK_IN_LENGTH;
+
+ status = KphAssignImpersonationToken(args->ThreadHandle, args->TokenHandle);
+ }
+ break;
+
+ /* Add Process Protection */
+ case KPH_PROTECTADD:
+ {
+ struct
+ {
+ HANDLE ProcessHandle;
+ LOGICAL AllowKernelMode;
+ ACCESS_MASK ProcessAllowMask;
+ ACCESS_MASK ThreadAllowMask;
+ } *args = dataBuffer;
+ PEPROCESS processObject;
+
+ CHECK_IN_LENGTH;
+
+ /* We'll reference the process and then dereference it. That way
+ * we can get the address of the object - that's all we need.
+ */
+
+ status = ObReferenceObjectByHandle(
+ args->ProcessHandle,
+ 0,
+ *PsProcessType,
+ KernelMode,
+ &processObject,
+ NULL
+ );
+
+ if (!NT_SUCCESS(status))
+ goto IoControlEnd;
+
+ ObDereferenceObject(processObject);
+
+ InitProtection();
+
+ /* Don't protect the same process twice. */
+ if (KphProtectFindEntry(processObject, NULL, NULL))
+ {
+ status = STATUS_NOT_SUPPORTED;
+ goto IoControlEnd;
+ }
+
+ if (!KphProtectAddEntry(
+ processObject,
+ PsGetCurrentProcessId(),
+ args->AllowKernelMode,
+ args->ProcessAllowMask,
+ args->ThreadAllowMask
+ ))
+ {
+ status = STATUS_UNSUCCESSFUL;
+ goto IoControlEnd;
+ }
+ }
+ break;
+
+ /* Remove Process Protection */
+ case KPH_PROTECTREMOVE:
+ {
+ struct
+ {
+ HANDLE ProcessHandle;
+ } *args = dataBuffer;
+ PEPROCESS processObject;
+
+ /* Can't remove anything if process protection hasn't been initialized -
+ there isn't anything to remove. */
+ if (!ProtectionInitialized)
+ {
+ status = STATUS_INVALID_PARAMETER;
+ goto IoControlEnd;
+ }
+
+ CHECK_IN_LENGTH;
+
+ status = ObReferenceObjectByHandle(
+ args->ProcessHandle,
+ 0,
+ *PsProcessType,
+ KernelMode,
+ &processObject,
+ NULL
+ );
+
+ if (!NT_SUCCESS(status))
+ goto IoControlEnd;
+
+ ObDereferenceObject(processObject);
+
+ if (!KphProtectRemoveByProcess(processObject))
+ {
+ status = STATUS_UNSUCCESSFUL;
+ goto IoControlEnd;
+ }
+ }
+ break;
+
+ /* Query Process Protection */
+ case KPH_PROTECTQUERY:
+ {
+ struct
+ {
+ HANDLE ProcessHandle;
+ PLOGICAL AllowKernelMode;
+ PACCESS_MASK ProcessAllowMask;
+ PACCESS_MASK ThreadAllowMask;
+ } *args = dataBuffer;
+ PEPROCESS processObject;
+ KPH_PROCESS_ENTRY processEntry;
+
+ /* Can't query anything if process protection hasn't been initialized -
+ there isn't anything to query. */
+ if (!ProtectionInitialized)
+ {
+ status = STATUS_INVALID_PARAMETER;
+ goto IoControlEnd;
+ }
+
+ CHECK_IN_LENGTH;
+
+ __try
+ {
+ ProbeForWrite(args->AllowKernelMode, sizeof(LOGICAL), 1);
+ ProbeForWrite(args->ProcessAllowMask, sizeof(ACCESS_MASK), 1);
+ ProbeForWrite(args->ThreadAllowMask, sizeof(ACCESS_MASK), 1);
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ status = GetExceptionCode();
+ goto IoControlEnd;
+ }
+
+ status = ObReferenceObjectByHandle(
+ args->ProcessHandle,
+ 0,
+ *PsProcessType,
+ KernelMode,
+ &processObject,
+ NULL
+ );
+
+ if (!NT_SUCCESS(status))
+ goto IoControlEnd;
+
+ ObDereferenceObject(processObject);
+
+ if (!KphProtectFindEntry(processObject, NULL, &processEntry))
+ {
+ status = STATUS_UNSUCCESSFUL;
+ goto IoControlEnd;
+ }
+
+ __try
+ {
+ *(args->AllowKernelMode) = processEntry.AllowKernelMode;
+ *(args->ProcessAllowMask) = processEntry.ProcessAllowMask;
+ *(args->ThreadAllowMask) = processEntry.ThreadAllowMask;
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ status = GetExceptionCode();
+ }
+ }
+ break;
+
+ /* KphUnsafeReadVirtualMemory
+ *
+ * Reads process memory or kernel memory.
+ */
+ case KPH_UNSAFEREADVIRTUALMEMORY:
+ {
+ struct
+ {
+ HANDLE ProcessHandle;
+ PVOID BaseAddress;
+ PVOID Buffer;
+ ULONG BufferLength;
+ PULONG ReturnLength;
+ } *args = dataBuffer;
+
+ CHECK_IN_LENGTH;
+
+ status = KphUnsafeReadVirtualMemory(
+ args->ProcessHandle,
+ args->BaseAddress,
+ args->Buffer,
+ args->BufferLength,
+ args->ReturnLength,
+ UserMode
+ );
+ }
+ break;
+
+ /* Set Execute Options
+ *
+ * Sets NX status for a process.
+ */
+ case KPH_SETEXECUTEOPTIONS:
+ {
+ struct
+ {
+ HANDLE ProcessHandle;
+ ULONG ExecuteOptions;
+ } *args = dataBuffer;
+ KPH_ATTACH_STATE attachState;
+
+ CHECK_IN_LENGTH;
+
+ status = KphAttachProcessHandle(args->ProcessHandle, &attachState);
+
+ if (!NT_SUCCESS(status))
+ goto IoControlEnd;
+
+ status = ZwSetInformationProcess(
+ NtCurrentProcess(),
+ ProcessExecuteFlags,
+ &args->ExecuteOptions,
+ sizeof(ULONG)
+ );
+ KphDetachProcess(&attachState);
+ }
+ break;
+
+ /* KphQueryProcessHandles
+ *
+ * Gets the handles in a process handle table.
+ */
+ case KPH_QUERYPROCESSHANDLES:
+ {
+ struct
+ {
+ HANDLE ProcessHandle;
+ PVOID Buffer;
+ ULONG BufferLength;
+ PULONG ReturnLength;
+ } *args = dataBuffer;
+
+ CHECK_IN_LENGTH;
+
+ status = KphQueryProcessHandles(
+ args->ProcessHandle,
+ (PPROCESS_HANDLE_INFORMATION)args->Buffer,
+ args->BufferLength,
+ args->ReturnLength,
+ UserMode
+ );
+ }
+ break;
+
+ /* KphOpenThreadProcess
+ *
+ * Opens the process associated with the specified thread.
+ */
+ case KPH_OPENTHREADPROCESS:
+ {
+ struct
+ {
+ HANDLE ThreadHandle;
+ ACCESS_MASK DesiredAccess;
+ } *args = dataBuffer;
+ struct
+ {
+ HANDLE ProcessHandle;
+ } *ret = dataBuffer;
+
+ CHECK_IN_OUT_LENGTH;
+
+ status = KphOpenThreadProcess(
+ args->ThreadHandle,
+ args->DesiredAccess,
+ &ret->ProcessHandle,
+ KernelMode
+ );
+
+ if (!NT_SUCCESS(status))
+ goto IoControlEnd;
+
+ retLength = sizeof(*ret);
+ }
+ break;
+
+ /* KphCaptureStackBackTraceThread
+ *
+ * Captures a kernel stack trace for the specified thread.
+ */
+ case KPH_CAPTURESTACKBACKTRACETHREAD:
+ {
+ struct
+ {
+ HANDLE ThreadHandle;
+ ULONG FramesToSkip;
+ ULONG FramesToCapture;
+ PVOID *BackTrace;
+ PULONG CapturedFrames;
+ PULONG BackTraceHash;
+ } *args = dataBuffer;
+
+ CHECK_IN_LENGTH;
+
+ status = KphCaptureStackBackTraceThread(
+ args->ThreadHandle,
+ args->FramesToSkip,
+ args->FramesToCapture,
+ args->BackTrace,
+ args->CapturedFrames,
+ args->BackTraceHash,
+ UserMode
+ );
+ }
+ break;
+
+ /* KphDangerousTerminateThread
+ *
+ * Terminates the specified thread. This operation may cause a bugcheck.
+ */
+ case KPH_DANGEROUSTERMINATETHREAD:
+ {
+ struct
+ {
+ HANDLE ThreadHandle;
+ NTSTATUS ExitStatus;
+ } *args = dataBuffer;
+
+ CHECK_IN_LENGTH;
+
+ status = KphDangerousTerminateThread(args->ThreadHandle, args->ExitStatus);
+ }
+ break;
+
+ /* KphOpenType
+ *
+ * Opens a type object.
+ */
+ case KPH_OPENTYPE:
+ {
+ struct
+ {
+ PHANDLE TypeHandle;
+ POBJECT_ATTRIBUTES ObjectAttributes;
+ } *args = dataBuffer;
+
+ CHECK_IN_LENGTH;
+
+ status = KphOpenType(args->TypeHandle, args->ObjectAttributes, UserMode);
+ }
+ break;
+
+ /* KphOpenDriver
+ *
+ * Opens a driver object.
+ */
+ case KPH_OPENDRIVER:
+ {
+ struct
+ {
+ PHANDLE DriverHandle;
+ POBJECT_ATTRIBUTES ObjectAttributes;
+ } *args = dataBuffer;
+
+ CHECK_IN_LENGTH;
+
+ status = KphOpenDriver(args->DriverHandle, args->ObjectAttributes, UserMode);
+ }
+ break;
+
+ /* KphQueryInformationDriver
+ *
+ * Queries information about a driver object.
+ */
+ case KPH_QUERYINFORMATIONDRIVER:
+ {
+ struct
+ {
+ HANDLE DriverHandle;
+ DRIVER_INFORMATION_CLASS DriverInformationClass;
+ PVOID DriverInformation;
+ ULONG DriverInformationLength;
+ PULONG ReturnLength;
+ } *args = dataBuffer;
+
+ CHECK_IN_LENGTH;
+
+ status = KphQueryInformationDriver(
+ args->DriverHandle,
+ args->DriverInformationClass,
+ args->DriverInformation,
+ args->DriverInformationLength,
+ args->ReturnLength,
+ UserMode
+ );
+ }
+ break;
+
+ /* KphOpenDirectoryObject
+ *
+ * Opens a directory object.
+ */
+ case KPH_OPENDIRECTORYOBJECT:
+ {
+ struct
+ {
+ PHANDLE DirectoryObjectHandle;
+ ACCESS_MASK DesiredAccess;
+ POBJECT_ATTRIBUTES ObjectAttributes;
+ } *args = dataBuffer;
+
+ CHECK_IN_LENGTH;
+
+ status = KphOpenDirectoryObject(
+ args->DirectoryObjectHandle,
+ args->DesiredAccess,
+ args->ObjectAttributes,
+ UserMode
+ );
+ }
+ break;
+
+ /* SsRef
+ *
+ * Adds a system service logging reference.
+ */
+ case KPH_SSREF:
+ {
+ PKPH_CLIENT_ENTRY clientEntry = ReferenceClientEntry(NULL);
+
+ if (!clientEntry)
+ {
+ status = STATUS_INTERNAL_ERROR;
+ goto IoControlEnd;
+ }
+
+ KphAcquireGuardedLock(&clientEntry->SsLock);
+
+ if (clientEntry->SsStartCount < KPH_CLIENT_SSMAXCOUNT)
+ {
+ clientEntry->SsStartCount++;
+ SsRef(1);
+ }
+ else
+ {
+ status = STATUS_UNSUCCESSFUL;
+ }
+
+ KphReleaseGuardedLock(&clientEntry->SsLock);
+
+ KphDereferenceObject(clientEntry);
+ }
+ break;
+
+ /* SsUnref
+ *
+ * Removes a system service logging reference.
+ */
+ case KPH_SSUNREF:
+ {
+ PKPH_CLIENT_ENTRY clientEntry = ReferenceClientEntry(NULL);
+
+ if (!clientEntry)
+ {
+ status = STATUS_INTERNAL_ERROR;
+ goto IoControlEnd;
+ }
+
+ KphAcquireGuardedLock(&clientEntry->SsLock);
+
+ if (clientEntry->SsStartCount > 0)
+ {
+ clientEntry->SsStartCount--;
+ SsUnref(1);
+ }
+ else
+ {
+ status = STATUS_UNSUCCESSFUL;
+ }
+
+ KphReleaseGuardedLock(&clientEntry->SsLock);
+
+ KphDereferenceObject(clientEntry);
+ }
+ break;
+
+ /* SsCreateClientEntry
+ *
+ * Creates a system service logging client entry.
+ */
+ case KPH_SSCREATECLIENTENTRY:
+ {
+ struct
+ {
+ HANDLE ProcessHandle;
+ HANDLE EventHandle;
+ HANDLE SemaphoreHandle;
+ PVOID BufferBase;
+ ULONG BufferSize;
+ } *args = dataBuffer;
+ struct
+ {
+ HANDLE ClientEntryHandle;
+ } *ret = dataBuffer;
+ PKPHSS_CLIENT_ENTRY clientEntry;
+
+ CHECK_IN_OUT_LENGTH;
+
+ status = KphSsCreateClientEntry(
+ &clientEntry,
+ args->ProcessHandle,
+ args->EventHandle,
+ args->SemaphoreHandle,
+ args->BufferBase,
+ args->BufferSize,
+ UserMode
+ );
+
+ if (!NT_SUCCESS(status))
+ goto IoControlEnd;
+
+ status = CreateClientHandle(NULL, clientEntry, &ret->ClientEntryHandle);
+ KphDereferenceObject(clientEntry);
+ retLength = sizeof(*ret);
+ }
+ break;
+
+ /* SsCreateRuleSetEntry
+ *
+ * Creates a system service logging ruleset entry.
+ */
+ case KPH_SSCREATERULESETENTRY:
+ {
+ struct
+ {
+ HANDLE ClientEntryHandle;
+ KPHSS_FILTER_TYPE DefaultFilterType;
+ KPHSS_RULESET_ACTION Action;
+ } *args = dataBuffer;
+ struct
+ {
+ HANDLE RuleSetEntryHandle;
+ } *ret = dataBuffer;
+ PKPHSS_CLIENT_ENTRY clientEntry;
+ PKPHSS_RULESET_ENTRY ruleSetEntry;
+
+ CHECK_IN_OUT_LENGTH;
+
+ /* Reference the client entry. */
+ status = ReferenceClientHandle(
+ NULL,
+ args->ClientEntryHandle,
+ KphSsClientEntryType,
+ &clientEntry
+ );
+
+ if (!NT_SUCCESS(status))
+ goto IoControlEnd;
+
+ /* Create the ruleset entry. */
+ status = KphSsCreateRuleSetEntry(
+ &ruleSetEntry,
+ clientEntry,
+ args->DefaultFilterType,
+ args->Action
+ );
+ KphDereferenceObject(clientEntry);
+
+ if (!NT_SUCCESS(status))
+ goto IoControlEnd;
+
+ /* Create and return a handle to the ruleset entry. */
+ status = CreateClientHandle(NULL, ruleSetEntry, &ret->RuleSetEntryHandle);
+ KphDereferenceObject(ruleSetEntry);
+ retLength = sizeof(*ret);
+ }
+ break;
+
+ /* SsRemoveRule
+ *
+ * Removes a rule from a ruleset.
+ */
+ case KPH_SSREMOVERULE:
+ {
+ struct
+ {
+ HANDLE RuleSetEntryHandle;
+ HANDLE RuleEntryHandle;
+ } *args = dataBuffer;
+ PKPHSS_RULESET_ENTRY ruleSetEntry;
+
+ CHECK_IN_LENGTH;
+
+ /* Reference the ruleset entry. */
+ status = ReferenceClientHandle(
+ NULL,
+ args->RuleSetEntryHandle,
+ KphSsRuleSetEntryType,
+ &ruleSetEntry
+ );
+
+ if (!NT_SUCCESS(status))
+ goto IoControlEnd;
+
+ /* Remove the rule. */
+ status = KphSsRemoveRule(ruleSetEntry, args->RuleEntryHandle);
+ KphDereferenceObject(ruleSetEntry);
+ }
+ break;
+
+ /* SsAddProcessIdRule
+ *
+ * Adds a process ID rule to a ruleset.
+ */
+ case KPH_SSADDPROCESSIDRULE:
+ {
+ struct
+ {
+ HANDLE RuleSetEntryHandle;
+ KPHSS_FILTER_TYPE FilterType;
+ HANDLE ProcessId;
+ } *args = dataBuffer;
+ struct
+ {
+ HANDLE RuleEntryHandle;
+ } *ret = dataBuffer;
+ PKPHSS_RULESET_ENTRY ruleSetEntry;
+ PKPHSS_RULE_ENTRY ruleEntry;
+
+ CHECK_IN_OUT_LENGTH;
+
+ /* Reference the client entry. */
+ status = ReferenceClientHandle(
+ NULL,
+ args->RuleSetEntryHandle,
+ KphSsRuleSetEntryType,
+ &ruleSetEntry
+ );
+
+ if (!NT_SUCCESS(status))
+ goto IoControlEnd;
+
+ /* Add a process ID rule. */
+ status = KphSsAddProcessIdRule(
+ &ruleEntry,
+ ruleSetEntry,
+ args->FilterType,
+ args->ProcessId
+ );
+ KphDereferenceObject(ruleSetEntry);
+
+ if (!NT_SUCCESS(status))
+ goto IoControlEnd;
+
+ /* Return the rule handle. */
+ ret->RuleEntryHandle = KphSsGetHandleRule(ruleEntry);
+ KphDereferenceObject(ruleEntry);
+ retLength = sizeof(*ret);
+ }
+ break;
+
+ /* SsAddThreadIdRule
+ *
+ * Adds a thread ID rule to a ruleset.
+ */
+ case KPH_SSADDTHREADIDRULE:
+ {
+ struct
+ {
+ HANDLE RuleSetEntryHandle;
+ KPHSS_FILTER_TYPE FilterType;
+ HANDLE ThreadId;
+ } *args = dataBuffer;
+ struct
+ {
+ HANDLE RuleEntryHandle;
+ } *ret = dataBuffer;
+ PKPHSS_RULESET_ENTRY ruleSetEntry;
+ PKPHSS_RULE_ENTRY ruleEntry;
+
+ CHECK_IN_OUT_LENGTH;
+
+ /* Reference the client entry. */
+ status = ReferenceClientHandle(
+ NULL,
+ args->RuleSetEntryHandle,
+ KphSsRuleSetEntryType,
+ &ruleSetEntry
+ );
+
+ if (!NT_SUCCESS(status))
+ goto IoControlEnd;
+
+ /* Add a thread ID rule. */
+ status = KphSsAddThreadIdRule(
+ &ruleEntry,
+ ruleSetEntry,
+ args->FilterType,
+ args->ThreadId
+ );
+ KphDereferenceObject(ruleSetEntry);
+
+ if (!NT_SUCCESS(status))
+ goto IoControlEnd;
+
+ /* Return the rule handle. */
+ ret->RuleEntryHandle = KphSsGetHandleRule(ruleEntry);
+ KphDereferenceObject(ruleEntry);
+ retLength = sizeof(*ret);
+ }
+ break;
+
+ /* SsAddPreviousModeRule
+ *
+ * Adds a previous mode rule to a ruleset.
+ */
+ case KPH_SSADDPREVIOUSMODERULE:
+ {
+ struct
+ {
+ HANDLE RuleSetEntryHandle;
+ KPHSS_FILTER_TYPE FilterType;
+ KPROCESSOR_MODE PreviousMode;
+ } *args = dataBuffer;
+ struct
+ {
+ HANDLE RuleEntryHandle;
+ } *ret = dataBuffer;
+ PKPHSS_RULESET_ENTRY ruleSetEntry;
+ PKPHSS_RULE_ENTRY ruleEntry;
+
+ CHECK_IN_OUT_LENGTH;
+
+ /* Reference the client entry. */
+ status = ReferenceClientHandle(
+ NULL,
+ args->RuleSetEntryHandle,
+ KphSsRuleSetEntryType,
+ &ruleSetEntry
+ );
+
+ if (!NT_SUCCESS(status))
+ goto IoControlEnd;
+
+ /* Add a previous mode rule. */
+ status = KphSsAddPreviousModeRule(
+ &ruleEntry,
+ ruleSetEntry,
+ args->FilterType,
+ args->PreviousMode
+ );
+ KphDereferenceObject(ruleSetEntry);
+
+ if (!NT_SUCCESS(status))
+ goto IoControlEnd;
+
+ /* Return the rule handle. */
+ ret->RuleEntryHandle = KphSsGetHandleRule(ruleEntry);
+ KphDereferenceObject(ruleEntry);
+ retLength = sizeof(*ret);
+ }
+ break;
+
+ /* SsAddNumberRule
+ *
+ * Adds a system service number rule to a ruleset.
+ */
+ case KPH_SSADDNUMBERRULE:
+ {
+ struct
+ {
+ HANDLE RuleSetEntryHandle;
+ KPHSS_FILTER_TYPE FilterType;
+ ULONG Number;
+ } *args = dataBuffer;
+ struct
+ {
+ HANDLE RuleEntryHandle;
+ } *ret = dataBuffer;
+ PKPHSS_RULESET_ENTRY ruleSetEntry;
+ PKPHSS_RULE_ENTRY ruleEntry;
+
+ CHECK_IN_OUT_LENGTH;
+
+ /* Reference the client entry. */
+ status = ReferenceClientHandle(
+ NULL,
+ args->RuleSetEntryHandle,
+ KphSsRuleSetEntryType,
+ &ruleSetEntry
+ );
+
+ if (!NT_SUCCESS(status))
+ goto IoControlEnd;
+
+ /* Add a number rule. */
+ status = KphSsAddNumberRule(
+ &ruleEntry,
+ ruleSetEntry,
+ args->FilterType,
+ args->Number
+ );
+ KphDereferenceObject(ruleSetEntry);
+
+ if (!NT_SUCCESS(status))
+ goto IoControlEnd;
+
+ /* Return the rule handle. */
+ ret->RuleEntryHandle = KphSsGetHandleRule(ruleEntry);
+ KphDereferenceObject(ruleEntry);
+ retLength = sizeof(*ret);
+ }
+ break;
+
+ /* SsEnableClientEntry
+ *
+ * Enables or disables a client entry.
+ */
+ case KPH_SSENABLECLIENTENTRY:
+ {
+ struct
+ {
+ HANDLE ClientEntryHandle;
+ BOOLEAN Enable;
+ } *args = dataBuffer;
+ PKPHSS_CLIENT_ENTRY clientEntry;
+
+ CHECK_IN_LENGTH;
+
+ /* Reference the client entry. */
+ status = ReferenceClientHandle(
+ NULL,
+ args->ClientEntryHandle,
+ KphSsClientEntryType,
+ &clientEntry
+ );
+
+ if (!NT_SUCCESS(status))
+ goto IoControlEnd;
+
+ /* Enable/disable the client entry. */
+ status = KphSsEnableClientEntry(clientEntry, args->Enable);
+ KphDereferenceObject(clientEntry);
+ }
+ break;
+
+ /* KphOpenNamedObject
+ *
+ * Opens a named object of any type.
+ */
+ case KPH_OPENNAMEDOBJECT:
+ {
+ struct
+ {
+ PHANDLE Handle;
+ ACCESS_MASK DesiredAccess;
+ POBJECT_ATTRIBUTES ObjectAttributes;
+ } *args = dataBuffer;
+
+ CHECK_IN_LENGTH;
+
+ status = KphOpenNamedObject(
+ args->Handle,
+ args->DesiredAccess,
+ args->ObjectAttributes,
+ NULL,
+ UserMode
+ );
+ }
+ break;
+
+ case KPH_QUERYINFORMATIONPROCESS:
+ {
+ struct
+ {
+ HANDLE ProcessHandle;
+ PROCESSINFOCLASS ProcessInformationClass;
+ PVOID ProcessInformation;
+ ULONG ProcessInformationLength;
+ PULONG ReturnLength;
+ } *args = dataBuffer;
+
+ CHECK_IN_LENGTH;
+
+ if (
+ args->ProcessInformationClass != ProcessIoPriority
+ )
+ {
+ status = STATUS_INVALID_PARAMETER;
+ goto IoControlEnd;
+ }
+
+ __try
+ {
+ ProbeForWrite(args->ProcessInformation, args->ProcessInformationLength, 1);
+
+ if (args->ReturnLength)
+ ProbeForWrite(args->ReturnLength, sizeof(ULONG), 1);
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ status = GetExceptionCode();
+ goto IoControlEnd;
+ }
+
+ __try
+ {
+ status = ZwQueryInformationProcess(
+ args->ProcessHandle,
+ args->ProcessInformationClass,
+ args->ProcessInformation,
+ args->ProcessInformationLength,
+ args->ReturnLength
+ );
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ status = GetExceptionCode();
+ }
+ }
+ break;
+
+ case KPH_QUERYINFORMATIONTHREAD:
+ {
+ struct
+ {
+ HANDLE ThreadHandle;
+ THREADINFOCLASS ThreadInformationClass;
+ PVOID ThreadInformation;
+ ULONG ThreadInformationLength;
+ PULONG ReturnLength;
+ } *args = dataBuffer;
+
+ CHECK_IN_LENGTH;
+
+ if (
+ args->ThreadInformationClass != ThreadIoPriority
+ )
+ {
+ status = STATUS_INVALID_PARAMETER;
+ goto IoControlEnd;
+ }
+
+ __try
+ {
+ ProbeForWrite(args->ThreadInformation, args->ThreadInformationLength, 1);
+
+ if (args->ReturnLength)
+ ProbeForWrite(args->ReturnLength, sizeof(ULONG), 1);
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ status = GetExceptionCode();
+ goto IoControlEnd;
+ }
+
+ __try
+ {
+ status = ZwQueryInformationThread(
+ args->ThreadHandle,
+ args->ThreadInformationClass,
+ args->ThreadInformation,
+ args->ThreadInformationLength,
+ args->ReturnLength
+ );
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ status = GetExceptionCode();
+ }
+ }
+ break;
+
+ case KPH_SETINFORMATIONPROCESS:
+ {
+ struct
+ {
+ HANDLE ProcessHandle;
+ PROCESSINFOCLASS ProcessInformationClass;
+ PVOID ProcessInformation;
+ ULONG ProcessInformationLength;
+ } *args = dataBuffer;
+
+ CHECK_IN_LENGTH;
+
+ if (
+ args->ProcessInformationClass != ProcessIoPriority
+ )
+ {
+ status = STATUS_INVALID_PARAMETER;
+ goto IoControlEnd;
+ }
+
+ __try
+ {
+ ProbeForRead(args->ProcessInformation, args->ProcessInformationLength, 1);
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ status = GetExceptionCode();
+ goto IoControlEnd;
+ }
+
+ __try
+ {
+ status = ZwSetInformationProcess(
+ args->ProcessHandle,
+ args->ProcessInformationClass,
+ args->ProcessInformation,
+ args->ProcessInformationLength
+ );
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ status = GetExceptionCode();
+ }
+ }
+ break;
+
+ case KPH_SETINFORMATIONTHREAD:
+ {
+ struct
+ {
+ HANDLE ThreadHandle;
+ THREADINFOCLASS ThreadInformationClass;
+ PVOID ThreadInformation;
+ ULONG ThreadInformationLength;
+ } *args = dataBuffer;
+
+ CHECK_IN_LENGTH;
+
+ if (
+ args->ThreadInformationClass != ThreadIoPriority
+ )
+ {
+ status = STATUS_INVALID_PARAMETER;
+ goto IoControlEnd;
+ }
+
+ __try
+ {
+ ProbeForRead(args->ThreadInformation, args->ThreadInformationLength, 1);
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ status = GetExceptionCode();
+ goto IoControlEnd;
+ }
+
+ __try
+ {
+ status = ZwSetInformationThread(
+ args->ThreadHandle,
+ args->ThreadInformationClass,
+ args->ThreadInformation,
+ args->ThreadInformationLength
+ );
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ status = GetExceptionCode();
+ }
+ }
+ break;
+
+ default:
+ {
+ dprintf("Unrecognized IOCTL code 0x%08x\n", controlCode);
+ status = STATUS_INVALID_DEVICE_REQUEST;
+ }
+ break;
+ }
+
+ /* Restore the old packing. */
+ #include
+
+IoControlEnd:
+ Irp->IoStatus.Information = retLength;
+ Irp->IoStatus.Status = status;
+ dprintf("IOCTL 0x%08x result was 0x%08x\n", controlCode, status);
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+NTSTATUS KphDispatchRead(PDEVICE_OBJECT DeviceObject, PIRP Irp)
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ PIO_STACK_LOCATION ioStackIrp = NULL;
+ ULONG retLength = 0;
+
+ ioStackIrp = IoGetCurrentIrpStackLocation(Irp);
+
+ if (ioStackIrp != NULL)
+ {
+ PCHAR readDataBuffer = (PCHAR)Irp->AssociatedIrp.SystemBuffer;
+ ULONG readLength = ioStackIrp->Parameters.Read.Length;
+
+ if (readDataBuffer != NULL)
+ {
+ dprintf("Client read %d bytes!\n", readLength);
+
+ if (readLength == 4)
+ {
+ *(ULONG *)readDataBuffer = KPH_CTL_CODE(0);
+ retLength = 4;
+ }
+ else
+ {
+ status = STATUS_INFO_LENGTH_MISMATCH;
+ }
+ }
+ }
+
+ Irp->IoStatus.Information = retLength;
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+NTSTATUS KphUnsupported(PDEVICE_OBJECT DeviceObject, PIRP Irp)
+{
+ dfprintf("Unsupported function called.\n");
+
+ return STATUS_NOT_SUPPORTED;
+}
diff --git a/2.x/trunk/KProcessHacker/makefile b/2.x/trunk/KProcessHacker/makefile
new file mode 100644
index 000000000..05a507be4
--- /dev/null
+++ b/2.x/trunk/KProcessHacker/makefile
@@ -0,0 +1 @@
+!INCLUDE $(NTMAKEENV)\makefile.def
\ No newline at end of file
diff --git a/2.x/trunk/KProcessHacker/mm.c b/2.x/trunk/KProcessHacker/mm.c
new file mode 100644
index 000000000..84492ab34
--- /dev/null
+++ b/2.x/trunk/KProcessHacker/mm.c
@@ -0,0 +1,703 @@
+/*
+ * Process Hacker Driver -
+ * memory manager
+ *
+ * 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/kph.h"
+#include "include/mm.h"
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE, KphReadVirtualMemory)
+#pragma alloc_text(PAGE, KphUnsafeReadVirtualMemory)
+#pragma alloc_text(PAGE, KphWriteVirtualMemory)
+#pragma alloc_text(PAGE, MiDoMappedCopy)
+#pragma alloc_text(PAGE, MiDoPoolCopy)
+#pragma alloc_text(PAGE, MiGetExceptionInfo)
+#pragma alloc_text(PAGE, MmCopyVirtualMemory)
+#endif
+
+/* KphReadVirtualMemory
+ *
+ * Reads virtual memory from the specified process.
+ */
+NTSTATUS KphReadVirtualMemory(
+ __in HANDLE ProcessHandle,
+ __in PVOID BaseAddress,
+ __out_bcount(BufferLength) PVOID Buffer,
+ __in ULONG BufferLength,
+ __out_opt PULONG ReturnLength,
+ __in KPROCESSOR_MODE AccessMode
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ PEPROCESS processObject;
+ ULONG returnLength = 0;
+
+ /* Probe user input if we're not from kernel-mode. */
+ if (AccessMode != KernelMode)
+ {
+ if ((((ULONG_PTR)BaseAddress + BufferLength) < (ULONG_PTR)BaseAddress) ||
+ (((ULONG_PTR)Buffer + BufferLength) < (ULONG_PTR)Buffer) ||
+ (((ULONG_PTR)BaseAddress + BufferLength) > (ULONG_PTR)MmHighestUserAddress) ||
+ (((ULONG_PTR)Buffer + BufferLength) > (ULONG_PTR)MmHighestUserAddress))
+ {
+ return STATUS_ACCESS_VIOLATION;
+ }
+
+ __try
+ {
+ if (ReturnLength)
+ ProbeForWrite(ReturnLength, sizeof(ULONG), 1);
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ return STATUS_ACCESS_VIOLATION;
+ }
+ }
+
+ /* If we actually have work to do, reference the process object and
+ call the internal function. */
+ if (BufferLength)
+ {
+ status = ObReferenceObjectByHandle(
+ ProcessHandle,
+ PROCESS_VM_READ,
+ *PsProcessType,
+ KernelMode,
+ &processObject,
+ NULL
+ );
+
+ if (!NT_SUCCESS(status))
+ return status;
+
+ status = MmCopyVirtualMemory(
+ processObject,
+ BaseAddress,
+ PsGetCurrentProcess(),
+ Buffer,
+ BufferLength,
+ AccessMode,
+ &returnLength
+ );
+ ObDereferenceObject(processObject);
+ }
+
+ if (ReturnLength)
+ {
+ __try
+ {
+ *ReturnLength = returnLength;
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ status = GetExceptionCode();
+ }
+ }
+
+ return status;
+}
+
+NTSTATUS KphUnsafeReadVirtualMemory(
+ __in HANDLE ProcessHandle,
+ __in PVOID BaseAddress,
+ __out_bcount(BufferLength) PVOID Buffer,
+ __in ULONG BufferLength,
+ __out_opt PULONG ReturnLength,
+ __in KPROCESSOR_MODE AccessMode
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ ULONG returnLength = 0;
+
+ /* Initial probing. */
+ if (AccessMode != KernelMode)
+ {
+ if ((((ULONG_PTR)BaseAddress + BufferLength) < (ULONG_PTR)BaseAddress) ||
+ (((ULONG_PTR)Buffer + BufferLength) < (ULONG_PTR)Buffer) ||
+ (((ULONG_PTR)Buffer + BufferLength) > (ULONG_PTR)MmHighestUserAddress))
+ {
+ return STATUS_ACCESS_VIOLATION;
+ }
+
+ __try
+ {
+ ProbeForWrite(Buffer, BufferLength, 1);
+
+ if (ReturnLength)
+ ProbeForWrite(ReturnLength, sizeof(ULONG), 1);
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ return GetExceptionCode();
+ }
+ }
+
+ /* Make sure we have something to copy. */
+ if (BufferLength == 0)
+ {
+ __try
+ {
+ *ReturnLength = 0;
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ return GetExceptionCode();
+ }
+
+ return STATUS_SUCCESS;
+ }
+
+ /* Select the appropriate copy method. */
+ if (((ULONG_PTR)BaseAddress + BufferLength) > (ULONG_PTR)MmHighestUserAddress)
+ {
+ /* Kernel memory unsafe copy. */
+
+ __try
+ {
+ /* Probe the address range. */
+ KphProbeSystemAddressRange(BaseAddress, BufferLength);
+
+ /* Copy the data. */
+ memcpy(Buffer, BaseAddress, BufferLength);
+ returnLength = BufferLength;
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ status = GetExceptionCode();
+ }
+
+ if (ReturnLength)
+ {
+ __try
+ {
+ *ReturnLength = returnLength;
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ status = GetExceptionCode();
+ }
+ }
+ }
+ else
+ {
+ /* User memory safe copy. */
+ status = KphReadVirtualMemory(
+ ProcessHandle,
+ BaseAddress,
+ Buffer,
+ BufferLength,
+ ReturnLength,
+ AccessMode
+ );
+ }
+
+ return status;
+}
+
+/* KphWriteVirtualMemory
+ *
+ * Writes virtual memory to the specified process.
+ */
+NTSTATUS KphWriteVirtualMemory(
+ __in HANDLE ProcessHandle,
+ __in PVOID BaseAddress,
+ __in_bcount(BufferLength) PVOID Buffer,
+ __in ULONG BufferLength,
+ __out_opt PULONG ReturnLength,
+ __in KPROCESSOR_MODE AccessMode
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ PEPROCESS processObject;
+ ULONG returnLength = 0;
+
+ /* Probe user input if we're not from kernel-mode. */
+ if (AccessMode != KernelMode)
+ {
+ if ((((ULONG_PTR)BaseAddress + BufferLength) < (ULONG_PTR)BaseAddress) ||
+ (((ULONG_PTR)Buffer + BufferLength) < (ULONG_PTR)Buffer) ||
+ (((ULONG_PTR)BaseAddress + BufferLength) > (ULONG_PTR)MmHighestUserAddress) ||
+ (((ULONG_PTR)Buffer + BufferLength) > (ULONG_PTR)MmHighestUserAddress))
+ {
+ return STATUS_ACCESS_VIOLATION;
+ }
+
+ __try
+ {
+ if (ReturnLength)
+ ProbeForWrite(ReturnLength, sizeof(ULONG), 1);
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ return STATUS_ACCESS_VIOLATION;
+ }
+ }
+
+ /* If we actually have work to do, reference the process object and
+ call the internal function. */
+ if (BufferLength)
+ {
+ status = ObReferenceObjectByHandle(
+ ProcessHandle,
+ PROCESS_VM_WRITE,
+ *PsProcessType,
+ KernelMode,
+ &processObject,
+ NULL
+ );
+
+ if (!NT_SUCCESS(status))
+ return status;
+
+ status = MmCopyVirtualMemory(
+ PsGetCurrentProcess(),
+ Buffer,
+ processObject,
+ BaseAddress,
+ BufferLength,
+ AccessMode,
+ &returnLength
+ );
+ ObDereferenceObject(processObject);
+ }
+
+ if (ReturnLength)
+ {
+ __try
+ {
+ *ReturnLength = returnLength;
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ status = GetExceptionCode();
+ }
+ }
+
+ return status;
+}
+
+/* MiDoMappedCopy
+ *
+ * Copies virtual memory from the source process to the target process
+ * using a memory mapping.
+ */
+NTSTATUS MiDoMappedCopy(
+ __in PEPROCESS FromProcess,
+ __in PVOID FromAddress,
+ __in PEPROCESS ToProcess,
+ __in PVOID ToAddress,
+ __in ULONG BufferLength,
+ __in KPROCESSOR_MODE AccessMode,
+ __out PULONG ReturnLength
+ )
+{
+ PFN_NUMBER mdlBuffer[(sizeof(MDL) / sizeof(PFN_NUMBER)) + MI_MAPPED_COPY_PAGES + 1];
+ PMDL mdl = (PMDL)mdlBuffer;
+ /* The mapped address. */
+ PVOID mappedAddress;
+ /* The total size allocated (mapped pages). */
+ ULONG totalSize;
+ /* The block size. */
+ ULONG blockSize;
+ /* The amount still left to copy. */
+ ULONG stillToCopy;
+ /* Attach state. */
+ KPH_ATTACH_STATE attachState;
+ /* The current source address. */
+ PVOID sourceAddress;
+ /* The current target address. */
+ PVOID targetAddress;
+ /* Whether the pages have been locked. */
+ BOOLEAN pagesLocked;
+ /* Whether we are currently copying. */
+ BOOLEAN copying = FALSE;
+ /* Whether we are currently probing. */
+ BOOLEAN probing = FALSE;
+ /* Whether we are currently mapping. */
+ BOOLEAN mapping = FALSE;
+ /* Whether we have the bad address. */
+ BOOLEAN haveBadAddress;
+ /* The bad address of the exception. */
+ ULONG_PTR badAddress;
+
+ sourceAddress = FromAddress;
+ targetAddress = ToAddress;
+
+ totalSize = (MI_MAPPED_COPY_PAGES - 2) * PAGE_SIZE;
+
+ if (BufferLength <= totalSize)
+ totalSize = BufferLength;
+
+ stillToCopy = BufferLength;
+ blockSize = totalSize;
+
+ while (stillToCopy)
+ {
+ /* If we're at the last copy block, copy the remaining bytes instead
+ of the whole block size. */
+ if (stillToCopy < blockSize)
+ blockSize = stillToCopy;
+
+ /* Reset state. */
+ mappedAddress = NULL;
+ pagesLocked = FALSE;
+ copying = FALSE;
+
+ KphAttachProcess(FromProcess, &attachState);
+
+ __try
+ {
+ /* Probe only if this is the first time. */
+ if ((sourceAddress == FromAddress) && (AccessMode != KernelMode))
+ {
+ probing = TRUE;
+ ProbeForRead(sourceAddress, BufferLength, 1);
+ probing = FALSE;
+ }
+
+ /* Initialize the MDL. */
+ MmInitializeMdl(mdl, sourceAddress, blockSize);
+ MmProbeAndLockPages(mdl, AccessMode, IoReadAccess);
+ pagesLocked = TRUE;
+
+ /* Map the pages. */
+ mappedAddress = MmMapLockedPagesSpecifyCache(
+ mdl,
+ KernelMode,
+ MmCached,
+ NULL,
+ FALSE,
+ HighPagePriority
+ );
+
+ if (!mappedAddress)
+ {
+ /* Insufficient resources; exit. */
+ mapping = TRUE;
+ ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ KphDetachProcess(&attachState);
+
+ /* Attach to the target process and copy the mapped contents. */
+ KphAttachProcess(ToProcess, &attachState);
+
+ /* Probe only if this is the first time. */
+ if ((targetAddress == ToAddress) && (AccessMode != KernelMode))
+ {
+ probing = TRUE;
+ ProbeForWrite(targetAddress, BufferLength, 1);
+ probing = FALSE;
+ }
+
+ /* Copy the data. */
+ copying = TRUE;
+ memcpy(targetAddress, mappedAddress, blockSize);
+ }
+ __except (MiGetExceptionInfo(
+ GetExceptionInformation(),
+ &haveBadAddress,
+ &badAddress
+ ))
+ {
+ KphDetachProcess(&attachState);
+
+ /* If we mapped the pages, unmap them. */
+ if (mappedAddress)
+ MmUnmapLockedPages(mappedAddress, mdl);
+
+ /* If we locked the pages, unlock them. */
+ if (pagesLocked)
+ MmUnlockPages(mdl);
+
+ /* If we failed when probing or mapping, return the error code. */
+ if (probing || mapping)
+ return GetExceptionCode();
+
+ /* Otherwise, give the caller the number of bytes we copied. */
+ *ReturnLength = BufferLength - stillToCopy;
+
+ /* If we were copying, we can probably get the exact
+ number of bytes copied. */
+ if (copying && haveBadAddress)
+ *ReturnLength = (ULONG)(badAddress - (ULONG_PTR)sourceAddress);
+
+ return STATUS_PARTIAL_COPY;
+ }
+
+ KphDetachProcess(&attachState);
+ MmUnmapLockedPages(mappedAddress, mdl);
+ MmUnlockPages(mdl);
+
+ stillToCopy -= blockSize;
+ sourceAddress = (PVOID)((ULONG_PTR)sourceAddress + blockSize);
+ targetAddress = (PVOID)((ULONG_PTR)targetAddress + blockSize);
+ }
+
+ *ReturnLength = BufferLength;
+
+ return STATUS_SUCCESS;
+}
+
+/* MiDoPoolCopy
+ *
+ * Copies virtual memory from the source process to the target process
+ * using either a pool allocation or a stack buffer.
+ */
+NTSTATUS MiDoPoolCopy(
+ __in PEPROCESS FromProcess,
+ __in PVOID FromAddress,
+ __in PEPROCESS ToProcess,
+ __in PVOID ToAddress,
+ __in ULONG BufferLength,
+ __in KPROCESSOR_MODE AccessMode,
+ __out PULONG ReturnLength
+ )
+{
+ /* The size of the pool-allocated buffer. */
+ ULONG allocSize = MI_MAX_TRANSFER_SIZE;
+ /* The stack-based buffer. */
+ CHAR stackBuffer[MI_COPY_STACK_SIZE];
+ /* The buffer - could be from the pool or could be the stack buffer. */
+ PVOID buffer = NULL;
+ /* The block size - should be the same as the allocated size. */
+ ULONG blockSize;
+ /* The amount still left to copy. */
+ ULONG stillToCopy;
+ /* Attach state. */
+ KPH_ATTACH_STATE attachState;
+ /* The current source address. */
+ PVOID sourceAddress;
+ /* The current target address. */
+ PVOID targetAddress;
+ /* Whether we are currently copying. */
+ BOOLEAN copying = FALSE;
+ /* Whether we are currently probing. */
+ BOOLEAN probing = FALSE;
+ /* Whether we have the bad address. */
+ BOOLEAN haveBadAddress;
+ /* The bad address of the exception. */
+ ULONG_PTR badAddress;
+
+ sourceAddress = FromAddress;
+ targetAddress = ToAddress;
+
+ /* Don't allocate a buffer larger than the amount we're about to copy. */
+ if (allocSize > BufferLength)
+ allocSize = BufferLength;
+
+ /* If we're copying MI_COPY_STACK_SIZE bytes or less, use the stack buffer. */
+ if (BufferLength <= MI_COPY_STACK_SIZE)
+ {
+ buffer = stackBuffer;
+ }
+ else
+ {
+ /* Keep on trying to allocate a buffer, halving the size each time
+ we fail. */
+ while (TRUE)
+ {
+ buffer = ExAllocatePoolWithTag(NonPagedPool, allocSize, TAG_POOL_COPY);
+
+ /* Stop trying if we got a buffer. */
+ if (buffer)
+ break;
+
+ /* Otherwise, halve the size and try again. */
+ allocSize /= 2;
+ /* Could we use the stack buffer? */
+ if (allocSize <= MI_COPY_STACK_SIZE)
+ {
+ buffer = stackBuffer;
+ break;
+ }
+ }
+ }
+
+ stillToCopy = BufferLength;
+ blockSize = allocSize;
+
+ /* Perform the copy in blocks of blockSize. */
+ while (stillToCopy)
+ {
+ /* If we're at the last copy block, copy the remaining bytes instead
+ of the whole block size. */
+ if (stillToCopy < blockSize)
+ blockSize = stillToCopy;
+
+ copying = FALSE;
+ KphAttachProcess(FromProcess, &attachState);
+
+ __try
+ {
+ /* Probe before reading the source contents. */
+ /* Probe only if this is the first time. */
+ if ((sourceAddress == FromAddress) && (AccessMode != KernelMode))
+ {
+ probing = TRUE;
+ ProbeForRead(sourceAddress, BufferLength, 1);
+ probing = FALSE;
+ }
+
+ /* Copy the source contents to the buffer. */
+ memcpy(buffer, sourceAddress, blockSize);
+ KphDetachProcess(&attachState);
+
+ /* Probe before writing. */
+ KphAttachProcess(ToProcess, &attachState);
+
+ /* Probe only if this is the first time. */
+ if ((targetAddress == ToAddress) && (AccessMode != KernelMode))
+ {
+ probing = TRUE;
+ ProbeForWrite(targetAddress, BufferLength, 1);
+ probing = FALSE;
+ }
+
+ /* Copy the buffer contents to the destination. */
+ copying = TRUE;
+ memcpy(targetAddress, buffer, blockSize);
+ }
+ __except (MiGetExceptionInfo(
+ GetExceptionInformation(),
+ &haveBadAddress,
+ &badAddress
+ ))
+ {
+ KphDetachProcess(&attachState);
+
+ /* Free the allocated buffer if needed. */
+ if (buffer != stackBuffer)
+ ExFreePoolWithTag(buffer, TAG_POOL_COPY);
+
+ /* If we were probing an address, return the error code. */
+ if (probing)
+ return GetExceptionCode();
+
+ /* Otherwise, give the caller the number of bytes we copied. */
+ *ReturnLength = BufferLength - stillToCopy;
+
+ /* If we were copying, we can probably get the exact
+ number of bytes copied. */
+ if (copying && haveBadAddress)
+ *ReturnLength = (ULONG)(badAddress - (ULONG_PTR)sourceAddress);
+
+ return STATUS_PARTIAL_COPY;
+ }
+
+ KphDetachProcess(&attachState);
+
+ stillToCopy -= blockSize;
+ sourceAddress = (PVOID)((ULONG_PTR)sourceAddress + blockSize);
+ targetAddress = (PVOID)((ULONG_PTR)targetAddress + blockSize);
+ }
+
+ /* Free the buffer if it wasn't stack-allocated. */
+ if (buffer != stackBuffer)
+ ExFreePoolWithTag(buffer, TAG_POOL_COPY);
+
+ *ReturnLength = BufferLength;
+
+ return STATUS_SUCCESS;
+}
+
+ULONG MiGetExceptionInfo(
+ __in PEXCEPTION_POINTERS ExceptionInfo,
+ __out PBOOLEAN HaveBadAddress,
+ __out PULONG_PTR BadAddress
+ )
+{
+ PEXCEPTION_RECORD exceptionRecord;
+
+ *HaveBadAddress = FALSE;
+ exceptionRecord = ExceptionInfo->ExceptionRecord;
+
+ if ((exceptionRecord->ExceptionCode == STATUS_ACCESS_VIOLATION) ||
+ (exceptionRecord->ExceptionCode == STATUS_GUARD_PAGE_VIOLATION) ||
+ (exceptionRecord->ExceptionCode == STATUS_IN_PAGE_ERROR))
+ {
+ if (exceptionRecord->NumberParameters > 1)
+ {
+ /* We have the address. */
+ *HaveBadAddress = TRUE;
+ *BadAddress = exceptionRecord->ExceptionInformation[1];
+ }
+ }
+
+ return EXCEPTION_EXECUTE_HANDLER;
+}
+
+NTSTATUS MmCopyVirtualMemory(
+ __in PEPROCESS FromProcess,
+ __in PVOID FromAddress,
+ __in PEPROCESS ToProcess,
+ __in PVOID ToAddress,
+ __in ULONG BufferLength,
+ __in KPROCESSOR_MODE AccessMode,
+ __out PULONG ReturnLength
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ PEPROCESS processToLock = FromProcess;
+
+ if (!BufferLength)
+ return STATUS_SUCCESS;
+
+ /* If we're copying from the current process, lock the target. */
+ if (processToLock == PsGetCurrentProcess())
+ processToLock = ToProcess;
+
+ /* Prevent the process from terminating. */
+ if (!KphAcquireProcessRundownProtection(processToLock))
+ return STATUS_PROCESS_IS_TERMINATING;
+
+ /* If the amount we're trying to copy is over the threshold
+ for MiDoPoolCopy, use MiDoMappedCopy. */
+ if (BufferLength > MM_POOL_COPY_THRESHOLD)
+ {
+ status = MiDoMappedCopy(
+ FromProcess,
+ FromAddress,
+ ToProcess,
+ ToAddress,
+ BufferLength,
+ AccessMode,
+ ReturnLength
+ );
+ }
+ else
+ {
+ status = MiDoPoolCopy(
+ FromProcess,
+ FromAddress,
+ ToProcess,
+ ToAddress,
+ BufferLength,
+ AccessMode,
+ ReturnLength
+ );
+ }
+
+ /* Allow the process to terminate. */
+ KphReleaseProcessRundownProtection(processToLock);
+
+ return status;
+}
diff --git a/2.x/trunk/KProcessHacker/ob.c b/2.x/trunk/KProcessHacker/ob.c
new file mode 100644
index 000000000..e5325b95e
--- /dev/null
+++ b/2.x/trunk/KProcessHacker/ob.c
@@ -0,0 +1,872 @@
+/*
+ * Process Hacker Driver -
+ * object manager
+ *
+ * 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/kph.h"
+#include "include/ob.h"
+
+BOOLEAN KphpQueryProcessHandlesEnumCallback(
+ __inout PHANDLE_TABLE_ENTRY HandleTableEntry,
+ __in HANDLE Handle,
+ __in POBP_QUERY_PROCESS_HANDLES_DATA Context
+ );
+
+BOOLEAN KphpSetHandleGrantedAccessEnumCallback(
+ __inout PHANDLE_TABLE_ENTRY HandleTableEntry,
+ __in HANDLE Handle,
+ __in POBP_SET_HANDLE_GRANTED_ACCESS_DATA Context
+ );
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE, KphDuplicateObject)
+#pragma alloc_text(PAGE, ObDuplicateObject)
+#endif
+
+/* This attribute is now stored in the GrantedAccess field. */
+ULONG ObpAccessProtectCloseBit = 0x80000000;
+
+/* KphDuplicateObject
+ *
+ * Duplicates a handle from the source process to the target process.
+ */
+NTSTATUS KphDuplicateObject(
+ __in HANDLE SourceProcessHandle,
+ __in HANDLE SourceHandle,
+ __in_opt HANDLE TargetProcessHandle,
+ __out_opt PHANDLE TargetHandle,
+ __in ACCESS_MASK DesiredAccess,
+ __in ULONG HandleAttributes,
+ __in ULONG Options,
+ __in KPROCESSOR_MODE AccessMode
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ PEPROCESS sourceProcess = NULL;
+ PEPROCESS targetProcess = NULL;
+ HANDLE targetHandle;
+
+ if (TargetHandle && AccessMode != KernelMode)
+ {
+ __try
+ {
+ ProbeForWrite(TargetHandle, sizeof(HANDLE), 1);
+ *TargetHandle = NULL;
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ return STATUS_ACCESS_VIOLATION;
+ }
+ }
+
+ status = ObReferenceObjectByHandle(
+ SourceProcessHandle,
+ PROCESS_DUP_HANDLE,
+ *PsProcessType,
+ KernelMode,
+ &sourceProcess,
+ NULL
+ );
+
+ if (!NT_SUCCESS(status))
+ return status;
+
+ /* Target handle is optional. */
+ if (TargetProcessHandle)
+ {
+ status = ObReferenceObjectByHandle(
+ TargetProcessHandle,
+ PROCESS_DUP_HANDLE,
+ *PsProcessType,
+ KernelMode,
+ &targetProcess,
+ NULL
+ );
+
+ if (!NT_SUCCESS(status))
+ return status;
+ }
+
+ /* Fix the source handle if the source process is
+ * the system process.
+ */
+ if (sourceProcess == PsInitialSystemProcess)
+ MakeKernelHandle(SourceHandle);
+
+ /* Call the internal function. */
+ status = ObDuplicateObject(
+ sourceProcess,
+ targetProcess,
+ SourceHandle,
+ &targetHandle,
+ DesiredAccess,
+ HandleAttributes,
+ Options,
+ AccessMode
+ );
+
+ if (TargetHandle)
+ {
+ __try
+ {
+ *TargetHandle = targetHandle;
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ status = STATUS_ACCESS_VIOLATION;
+ }
+ }
+
+ ObDereferenceObject(sourceProcess);
+ if (targetProcess)
+ ObDereferenceObject(targetProcess);
+
+ return status;
+}
+
+/* KphEnumProcessHandleTable
+ *
+ * Enumerates the handles in the specified process' handle table.
+ */
+BOOLEAN KphEnumProcessHandleTable(
+ __in PEPROCESS Process,
+ __in PEX_ENUM_HANDLE_CALLBACK EnumHandleProcedure,
+ __inout PVOID Context,
+ __out_opt PHANDLE Handle
+ )
+{
+ BOOLEAN result = FALSE;
+ PHANDLE_TABLE handleTable = NULL;
+
+ handleTable = ObReferenceProcessHandleTable(Process);
+
+ if (!handleTable)
+ return FALSE;
+
+ result = ExEnumHandleTable(
+ handleTable,
+ EnumHandleProcedure,
+ Context,
+ Handle
+ );
+ ObDereferenceProcessHandleTable(Process);
+
+ return result;
+}
+
+/* KphGetObjectTypeNt
+ *
+ * Gets the type of an object.
+ */
+POBJECT_TYPE KphGetObjectTypeNt(
+ __in PVOID Object
+ )
+{
+ /* XP to Vista: A pointer to the object type is
+ * stored in the object header.
+ */
+ if (
+ WindowsVersion >= WINDOWS_XP &&
+ WindowsVersion <= WINDOWS_VISTA
+ )
+ {
+ return OBJECT_TO_OBJECT_HEADER(Object)->Type;
+ }
+ /* Seven and above: An index to an internal object type
+ * table is stored in the object header. Luckily we have
+ * a new exported function, ObGetObjectType, to get
+ * the object type.
+ */
+ else if (WindowsVersion >= WINDOWS_7)
+ {
+ return ObGetObjectType(Object);
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+/* KphOpenDirectoryObject
+ *
+ * Opens a directory object.
+ */
+NTSTATUS KphOpenDirectoryObject(
+ __out PHANDLE DirectoryObjectHandle,
+ __in ACCESS_MASK DesiredAccess,
+ __in POBJECT_ATTRIBUTES ObjectAttributes,
+ __in KPROCESSOR_MODE AccessMode
+ )
+{
+ return KphOpenNamedObject(
+ DirectoryObjectHandle,
+ DesiredAccess,
+ ObjectAttributes,
+ *ObDirectoryObjectType,
+ AccessMode
+ );
+}
+
+/* KphOpenNamedObject
+ *
+ * Opens a named object.
+ */
+NTSTATUS KphOpenNamedObject(
+ __out PHANDLE ObjectHandle,
+ __in ACCESS_MASK DesiredAccess,
+ __in POBJECT_ATTRIBUTES ObjectAttributes,
+ __in POBJECT_TYPE ObjectType,
+ __in KPROCESSOR_MODE AccessMode
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ HANDLE objectHandle;
+ UNICODE_STRING capturedObjectName;
+ OBJECT_ATTRIBUTES objectAttributes = { 0 };
+
+ if (!ObjectAttributes)
+ return STATUS_INVALID_PARAMETER;
+
+ /* Probe user input. */
+ if (AccessMode != KernelMode)
+ {
+ __try
+ {
+ ProbeForWrite(ObjectHandle, sizeof(HANDLE), 1);
+ ProbeForRead(ObjectAttributes, sizeof(OBJECT_ATTRIBUTES), 1);
+
+ if (ObjectAttributes->ObjectName)
+ KphProbeForReadUnicodeString(ObjectAttributes->ObjectName);
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ return GetExceptionCode();
+ }
+ }
+
+ __try
+ {
+ /* Copy the object attributes structure. */
+ memcpy(&objectAttributes, ObjectAttributes, sizeof(OBJECT_ATTRIBUTES));
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ return GetExceptionCode();
+ }
+
+ /* Verify parameters. */
+ if (!objectAttributes.ObjectName)
+ return STATUS_INVALID_PARAMETER;
+
+ /* Make sure the root directory handle isn't a kernel handle if
+ * we're from user-mode.
+ */
+ if (AccessMode != KernelMode && IsKernelHandle(objectAttributes.RootDirectory))
+ return STATUS_INVALID_PARAMETER;
+
+ /* Capture the ObjectName string. */
+ status = KphCaptureUnicodeString(
+ objectAttributes.ObjectName,
+ &capturedObjectName
+ );
+
+ if (!NT_SUCCESS(status))
+ return status;
+
+ /* Set the new string in the object attributes. */
+ objectAttributes.ObjectName = &capturedObjectName;
+ /* Make sure the SecurityDescriptor and SecurityQualityOfService fields are NULL
+ * since we haven't probed them.
+ */
+ objectAttributes.SecurityDescriptor = NULL;
+ objectAttributes.SecurityQualityOfService = NULL;
+
+ /* Open the object. */
+ status = ObOpenObjectByName(
+ &objectAttributes,
+ ObjectType,
+ KernelMode,
+ NULL,
+ DesiredAccess,
+ NULL,
+ &objectHandle
+ );
+
+ /* Free the captured ObjectName. */
+ KphFreeCapturedUnicodeString(&capturedObjectName);
+
+ /* Pass the handle back. */
+ __try
+ {
+ *ObjectHandle = objectHandle;
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ status = GetExceptionCode();
+ }
+
+ return status;
+}
+
+/* KphOpenType
+ *
+ * Opens a type object.
+ */
+NTSTATUS KphOpenType(
+ __out PHANDLE TypeHandle,
+ __in POBJECT_ATTRIBUTES ObjectAttributes,
+ __in KPROCESSOR_MODE AccessMode
+ )
+{
+ return KphOpenNamedObject(
+ TypeHandle,
+ 0,
+ ObjectAttributes,
+ *ObTypeObjectType,
+ AccessMode
+ );
+}
+
+/* KphQueryFileObjectName
+ *
+ * Queries the name of a file object.
+ *
+ * Technique from YAPM.
+ */
+NTSTATUS KphQueryNameFileObject(
+ __in PFILE_OBJECT FileObject,
+ __inout_bcount(BufferLength) PUNICODE_STRING Buffer,
+ __in ULONG BufferLength,
+ __out PULONG ReturnLength
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ ULONG returnLength;
+ PCHAR objectName;
+ ULONG usedLength;
+ ULONG subNameLength;
+ PFILE_OBJECT relatedFileObject;
+
+ /* We need at least the size of UNICODE_STRING to
+ * continue.
+ */
+ if (BufferLength < sizeof(UNICODE_STRING))
+ {
+ *ReturnLength = sizeof(UNICODE_STRING);
+
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ /* Assume failure. */
+ Buffer->Length = 0;
+ /* We will place the object name directly after the
+ * UNICODE_STRING structure in the buffer.
+ */
+ Buffer->Buffer = (PWSTR)PTR_ADD_OFFSET(Buffer, sizeof(UNICODE_STRING));
+ /* Retain a local pointer to the object name so we
+ * can manipulate the pointer.
+ */
+ objectName = (PCHAR)Buffer->Buffer;
+ /* A variable that keeps track of how much space we
+ * have used.
+ */
+ usedLength = sizeof(UNICODE_STRING);
+
+ /* Check if the file object has an associated device
+ * (e.g. "\Device\NamedPipe", "\Device\Mup"). We can
+ * use the user-supplied buffer for this since if the
+ * buffer isn't big enough, we can't proceed anyway
+ * (we are going to use the name).
+ */
+ if (FileObject->DeviceObject)
+ {
+ status = ObQueryNameString(
+ FileObject->DeviceObject,
+ (POBJECT_NAME_INFORMATION)Buffer,
+ BufferLength,
+ &returnLength
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ *ReturnLength = returnLength;
+
+ return status;
+ }
+
+ /* The UNICODE_STRING in the buffer is now filled in.
+ * We will append to the object name later, so
+ * we need to fix the object name pointer by adding
+ * the length, in bytes, of the device name string we
+ * just got.
+ */
+ objectName += Buffer->Length;
+ usedLength += Buffer->Length;
+ }
+
+ /* Check if the file object has a file name component. If not,
+ * we can't do anything else, so we just return the name we
+ * have already.
+ */
+ if (!FileObject->FileName.Buffer)
+ {
+ *ReturnLength = usedLength;
+
+ return STATUS_SUCCESS;
+ }
+
+ /* The file object has a name. We need to walk up the file
+ * object tree and append the names of the related file
+ * objects in reverse order. This means we need to calculate
+ * the total length first.
+ */
+
+ relatedFileObject = FileObject;
+ subNameLength = 0;
+
+ do
+ {
+ subNameLength += relatedFileObject->FileName.Length;
+
+ /* Avoid infinite loops. */
+ if (relatedFileObject == relatedFileObject->RelatedFileObject)
+ break;
+
+ relatedFileObject = relatedFileObject->RelatedFileObject;
+ }
+ while (relatedFileObject);
+
+ usedLength += subNameLength;
+
+ /* Check if we have enough space to write the whole thing. */
+ if (usedLength > BufferLength)
+ {
+ *ReturnLength = usedLength;
+
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ /* We're ready to begin copying the names. */
+
+ /* Add the name length because we're copying in reverse order. */
+ objectName += subNameLength;
+
+ relatedFileObject = FileObject;
+
+ do
+ {
+ objectName -= relatedFileObject->FileName.Length;
+ memcpy(objectName, relatedFileObject->FileName.Buffer, relatedFileObject->FileName.Length);
+
+ /* Avoid infinite loops. */
+ if (relatedFileObject == relatedFileObject->RelatedFileObject)
+ break;
+
+ relatedFileObject = relatedFileObject->RelatedFileObject;
+ }
+ while (relatedFileObject);
+
+ /* Update the length. */
+ Buffer->Length += (USHORT)subNameLength;
+
+ /* Pass the return length back. */
+ *ReturnLength = usedLength;
+
+ return STATUS_SUCCESS;
+}
+
+/* KphQueryObjectName
+ *
+ * Queries the name of an object.
+ */
+NTSTATUS KphQueryNameObject(
+ __in PVOID Object,
+ __inout_bcount(BufferLength) PUNICODE_STRING Buffer,
+ __in ULONG BufferLength,
+ __out PULONG ReturnLength
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ POBJECT_TYPE objectType;
+
+ objectType = KphGetObjectTypeNt(Object);
+
+ /* Check if we are going to hang when querying the object, and use
+ * the special file object query function if needed.
+ */
+ if (
+ (objectType == *IoFileObjectType) &&
+ (((PFILE_OBJECT)Object)->Busy || ((PFILE_OBJECT)Object)->Waiters)
+ )
+ {
+ status = KphQueryNameFileObject((PFILE_OBJECT)Object, Buffer, BufferLength, ReturnLength);
+ }
+ else
+ {
+ status = ObQueryNameString(Object, (POBJECT_NAME_INFORMATION)Buffer, BufferLength, ReturnLength);
+ }
+
+ return status;
+}
+
+/* KphQueryProcessHandles
+ *
+ * Queries a process handle table.
+ */
+NTSTATUS KphQueryProcessHandles(
+ __in HANDLE ProcessHandle,
+ __out_bcount_opt(BufferLength) PPROCESS_HANDLE_INFORMATION Buffer,
+ __in_opt ULONG BufferLength,
+ __out_opt PULONG ReturnLength,
+ __in KPROCESSOR_MODE AccessMode
+ )
+{
+ NTSTATUS status;
+ BOOLEAN result;
+ PEPROCESS processObject;
+ OBP_QUERY_PROCESS_HANDLES_DATA context;
+
+ /* Probe buffer contents. */
+ if (AccessMode != KernelMode)
+ {
+ __try
+ {
+ if (Buffer)
+ ProbeForWrite(Buffer, BufferLength, 1);
+ if (ReturnLength)
+ ProbeForWrite(ReturnLength, sizeof(ULONG), 1);
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ return GetExceptionCode();
+ }
+ }
+
+ /* Reference the process object. */
+ status = ObReferenceObjectByHandle(
+ ProcessHandle,
+ PROCESS_QUERY_INFORMATION,
+ *PsProcessType,
+ KernelMode,
+ &processObject,
+ NULL
+ );
+
+ if (!NT_SUCCESS(status))
+ return status;
+
+ /* Initialize the enumeration context. */
+ context.Buffer = Buffer;
+ context.BufferLength = BufferLength;
+ context.CurrentIndex = 0;
+ context.Status = STATUS_SUCCESS;
+
+ /* Enumerate the handles. */
+ result = KphEnumProcessHandleTable(
+ processObject,
+ KphpQueryProcessHandlesEnumCallback,
+ &context,
+ NULL
+ );
+ ObDereferenceObject(processObject);
+
+ /* Write the number of handles (if we have a buffer). */
+ if (
+ Buffer &&
+ BufferLength >= sizeof(ULONG)
+ )
+ {
+ __try
+ {
+ Buffer->HandleCount = context.CurrentIndex;
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ return GetExceptionCode();
+ }
+ }
+
+ /* Supply the return length if the caller wanted it. */
+ if (ReturnLength)
+ {
+ __try
+ {
+ /* CurrentIndex should contain the number of handles, so we simply multiply it
+ by the size of PROCESS_HANDLE. */
+ *ReturnLength = sizeof(ULONG) + context.CurrentIndex * sizeof(PROCESS_HANDLE);
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ return GetExceptionCode();
+ }
+ }
+
+ return context.Status;
+}
+
+/* KphpQueryProcessHandlesEnumCallback
+ *
+ * The callback for KphEnumProcessHandleTable, used by
+ * KphQueryProcessHandles.
+ */
+BOOLEAN KphpQueryProcessHandlesEnumCallback(
+ __inout PHANDLE_TABLE_ENTRY HandleTableEntry,
+ __in HANDLE Handle,
+ __in POBP_QUERY_PROCESS_HANDLES_DATA Context
+ )
+{
+ PROCESS_HANDLE handleInfo;
+ PPROCESS_HANDLE_INFORMATION buffer = Context->Buffer;
+ ULONG i;
+
+ handleInfo.Handle = Handle;
+ handleInfo.Object = ObpDecodeObject(HandleTableEntry->Object);
+ handleInfo.GrantedAccess = ObpDecodeGrantedAccess(HandleTableEntry->GrantedAccess);
+ handleInfo.HandleAttributes = ObpGetHandleAttributes(HandleTableEntry);
+
+ /* Increment the index regardless of whether the information will be written;
+ this will allow KphQueryProcessHandles to report the correct return length. */
+ i = Context->CurrentIndex++;
+
+ /* Only write if we have a buffer and have not exceeded the buffer length. */
+ if (
+ buffer &&
+ (sizeof(ULONG) + Context->CurrentIndex * sizeof(PROCESS_HANDLE)) <= Context->BufferLength
+ )
+ {
+ __try
+ {
+ buffer->Handles[i] = handleInfo;
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* Report an error. */
+ if (Context->Status == STATUS_SUCCESS)
+ Context->Status = GetExceptionCode();
+ }
+ }
+ else
+ {
+ /* Report that the buffer is too small. */
+ if (Context->Status == STATUS_SUCCESS)
+ Context->Status = STATUS_BUFFER_TOO_SMALL;
+ }
+
+ return FALSE;
+}
+
+/* KphSetHandleGrantedAccess
+ *
+ * Sets the granted access of a handle.
+ */
+NTSTATUS KphSetHandleGrantedAccess(
+ __in PEPROCESS Process,
+ __in HANDLE Handle,
+ __in ACCESS_MASK GrantedAccess
+ )
+{
+ BOOLEAN result;
+ OBP_SET_HANDLE_GRANTED_ACCESS_DATA context;
+
+ context.Handle = Handle;
+ context.GrantedAccess = GrantedAccess;
+
+ result = KphEnumProcessHandleTable(
+ Process,
+ KphpSetHandleGrantedAccessEnumCallback,
+ &context,
+ NULL
+ );
+
+ return result ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
+}
+
+/* KphpSetHandleGrantedAccessEnumCallback
+ *
+ * The callback for KphEnumProcessHandleTable, used by
+ * KphSetHandleGrantedAccess.
+ */
+BOOLEAN KphpSetHandleGrantedAccessEnumCallback(
+ __inout PHANDLE_TABLE_ENTRY HandleTableEntry,
+ __in HANDLE Handle,
+ __in POBP_SET_HANDLE_GRANTED_ACCESS_DATA Context
+ )
+{
+ if (Handle != Context->Handle)
+ return FALSE;
+
+ HandleTableEntry->GrantedAccess = Context->GrantedAccess;
+
+ return TRUE;
+}
+
+/* ObDereferenceProcessHandleTable
+ *
+ * Allows the process to terminate.
+ */
+VOID ObDereferenceProcessHandleTable(
+ __in PEPROCESS Process
+ )
+{
+ KphReleaseProcessRundownProtection(Process);
+}
+
+/* ObDuplicateObject
+ *
+ * Duplicates a handle from the source process to the target process.
+ * WARNING: This does not actually duplicate a handle. It simply
+ * re-opens an object in another process.
+ */
+NTSTATUS ObDuplicateObject(
+ __in PEPROCESS SourceProcess,
+ __in_opt PEPROCESS TargetProcess,
+ __in HANDLE SourceHandle,
+ __out_opt PHANDLE TargetHandle,
+ __in ACCESS_MASK DesiredAccess,
+ __in ULONG HandleAttributes,
+ __in ULONG Options,
+ __in KPROCESSOR_MODE AccessMode
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ BOOLEAN sourceAttached = FALSE;
+ BOOLEAN targetAttached = FALSE;
+ KAPC_STATE apcState;
+ PVOID object;
+ HANDLE objectHandle;
+
+ /* Validate the parameters */
+ if (!TargetProcess || !TargetHandle)
+ {
+ if (!(Options & DUPLICATE_CLOSE_SOURCE))
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ /* Check if we need to attach to the source process */
+ if (SourceProcess != PsGetCurrentProcess())
+ {
+ KeStackAttachProcess(SourceProcess, &apcState);
+ sourceAttached = TRUE;
+ }
+
+ /* If the caller wants us to close the source handle, do it now */
+ if (Options & DUPLICATE_CLOSE_SOURCE)
+ {
+ status = NtClose(SourceHandle);
+ if (sourceAttached)
+ KeUnstackDetachProcess(&apcState);
+
+ return status;
+ }
+
+ /* Reference the object and detach from the source process */
+ status = ObReferenceObjectByHandle(
+ SourceHandle,
+ 0,
+ NULL,
+ KernelMode,
+ &object,
+ NULL
+ );
+ if (sourceAttached)
+ KeUnstackDetachProcess(&apcState);
+
+ if (!NT_SUCCESS(status))
+ return status;
+
+ /* Check if we need to attach to the target process */
+ if (TargetProcess != PsGetCurrentProcess())
+ {
+ KeStackAttachProcess(TargetProcess, &apcState);
+ targetAttached = TRUE;
+ }
+
+ /* Open the object and detach from the target process */
+ {
+ POBJECT_TYPE objectType = KphGetObjectTypeNt(object);
+ ACCESS_STATE accessState;
+ CHAR auxData[AUX_ACCESS_DATA_SIZE];
+
+ if (!objectType && AccessMode != KernelMode)
+ {
+ status = STATUS_INVALID_HANDLE;
+ goto OpenObjectEnd;
+ }
+
+ status = SeCreateAccessState(
+ &accessState,
+ (PAUX_ACCESS_DATA)auxData,
+ DesiredAccess,
+ (PGENERIC_MAPPING)KVOFF(objectType, OffOtiGenericMapping)
+ );
+
+ if (!NT_SUCCESS(status))
+ goto OpenObjectEnd;
+
+ accessState.PreviouslyGrantedAccess |= 0xffffffff; /* HACK, doesn't work properly */
+ accessState.RemainingDesiredAccess = 0;
+
+ status = ObOpenObjectByPointer(
+ object,
+ HandleAttributes,
+ &accessState,
+ DesiredAccess,
+ objectType,
+ KernelMode,
+ &objectHandle
+ );
+ SeDeleteAccessState(&accessState);
+ }
+
+OpenObjectEnd:
+ ObDereferenceObject(object);
+
+ if (targetAttached)
+ KeUnstackDetachProcess(&apcState);
+
+ if (NT_SUCCESS(status))
+ *TargetHandle = objectHandle;
+ else
+ *TargetHandle = NULL;
+
+ return status;
+}
+
+/* ObReferenceProcessHandleTable
+ *
+ * Prevents the process from terminating and returns a pointer
+ * to its handle table.
+ */
+PHANDLE_TABLE ObReferenceProcessHandleTable(
+ __in PEPROCESS Process
+ )
+{
+ PHANDLE_TABLE handleTable = NULL;
+
+ if (KphAcquireProcessRundownProtection(Process))
+ {
+ handleTable = *(PHANDLE_TABLE *)KVOFF(Process, OffEpObjectTable);
+
+ if (!handleTable)
+ KphReleaseProcessRundownProtection(Process);
+ }
+
+ return handleTable;
+}
diff --git a/2.x/trunk/KProcessHacker/protect.c b/2.x/trunk/KProcessHacker/protect.c
new file mode 100644
index 000000000..406c32019
--- /dev/null
+++ b/2.x/trunk/KProcessHacker/protect.c
@@ -0,0 +1,457 @@
+/*
+ * Process Hacker Driver -
+ * process protection
+ *
+ * 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/protect.h"
+
+BOOLEAN KphpIsAccessAllowed(
+ __in PVOID Object,
+ __in KPROCESSOR_MODE AccessMode,
+ __in ACCESS_MASK DesiredAccess
+ );
+
+BOOLEAN KphpIsCurrentProcessProtected();
+
+VOID KphpProtectRemoveEntry(
+ __in 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_OB_OPEN_HOOK ProcessOpenHook = { 0 };
+static KPH_OB_OPEN_HOOK ThreadOpenHook = { 0 };
+
+/* KphProtectInit
+ *
+ * Initializes process protection.
+ *
+ * IRQL: <= APC_LEVEL
+ */
+NTSTATUS KphProtectInit()
+{
+ NTSTATUS status;
+
+ /* Initialize rundown protection. */
+ ExInitializeRundownProtection(&ProtectedProcessRundownProtect);
+ /* Initialize list structures. */
+ InitializeListHead(&ProtectedProcessListHead);
+ KeInitializeSpinLock(&ProtectedProcessListLock);
+ ExInitializeNPagedLookasideList(
+ &ProtectedProcessLookasideList,
+ NULL,
+ NULL,
+ 0,
+ sizeof(KPH_PROCESS_ENTRY),
+ TAG_PROTECTION_ENTRY,
+ 0
+ );
+
+ /* Hook various functions. */
+ /* Hooking the open procedure calls for processes and threads allows
+ * us to intercept handle creation/duplication/inheritance. */
+ KphInitializeObOpenHook(&ProcessOpenHook, *PsProcessType, KphNewOpenProcedure51, KphNewOpenProcedure60);
+ if (!NT_SUCCESS(status = KphObOpenHook(&ProcessOpenHook)))
+ return status;
+ KphInitializeObOpenHook(&ThreadOpenHook, *PsThreadType, KphNewOpenProcedure51, KphNewOpenProcedure60);
+ if (!NT_SUCCESS(status = KphObOpenHook(&ThreadOpenHook)))
+ return status;
+
+ return STATUS_SUCCESS;
+}
+
+/* KphProtectDeinit
+ *
+ * Removes process protection and frees associated structures.
+ *
+ * IRQL: <= APC_LEVEL
+ */
+NTSTATUS KphProtectDeinit()
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ KIRQL oldIrql;
+ LARGE_INTEGER waitLi;
+
+ /* Unhook. */
+ status = KphObOpenUnhook(&ProcessOpenHook);
+ status = KphObOpenUnhook(&ThreadOpenHook);
+
+ /* Wait for all activity to finish. */
+ ExWaitForRundownProtectionRelease(&ProtectedProcessRundownProtect);
+ /* Wait for a bit (some regions of hook target functions
+ are NOT guarded by rundown protection, e.g.
+ prologues and epilogues). */
+ waitLi.QuadPart = KPH_REL_TIMEOUT_IN_SEC(1);
+ KeDelayExecutionThread(KernelMode, FALSE, &waitLi);
+
+ /* Free all process protection entries. */
+ ExDeleteNPagedLookasideList(&ProtectedProcessLookasideList);
+
+ return status;
+}
+
+/* KphNewOpenProcedure51
+ *
+ * New process/thread open procedure for NT 5.1.
+ */
+NTSTATUS NTAPI KphNewOpenProcedure51(
+ __in OB_OPEN_REASON OpenReason,
+ __in PEPROCESS Process,
+ __in PVOID Object,
+ __in ACCESS_MASK GrantedAccess,
+ __in ULONG HandleCount
+ )
+{
+ /* Simply call the 6.0 open procedure. */
+ /* NOTE: GrantedAccess is always 0 on XP... */
+ return KphNewOpenProcedure60(
+ OpenReason,
+ /* Assume worst case. */
+ UserMode,
+ Process,
+ Object,
+ GrantedAccess,
+ HandleCount
+ );
+}
+
+/* KphNewOpenProcedure60
+ *
+ * New process/thread open procedure for NT 6.0 and 6.1.
+ */
+NTSTATUS NTAPI KphNewOpenProcedure60(
+ __in OB_OPEN_REASON OpenReason,
+ __in KPROCESSOR_MODE AccessMode,
+ __in PEPROCESS Process,
+ __in PVOID Object,
+ __in ACCESS_MASK GrantedAccess,
+ __in ULONG HandleCount
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ BOOLEAN accessAllowed = TRUE;
+
+ /* Prevent the driver from unloading while this routine is executing. */
+ if (!ExAcquireRundownProtection(&ProtectedProcessRundownProtect))
+ {
+ /* Should never happen. */
+ return STATUS_INTERNAL_ERROR;
+ }
+
+ accessAllowed = KphpIsAccessAllowed(
+ Object,
+ AccessMode,
+ /* Assume worst case if granted access not available. */
+ !GrantedAccess ? (ACCESS_MASK)-1 : GrantedAccess
+ );
+
+ if (accessAllowed)
+ {
+ POBJECT_TYPE objectType = KphGetObjectTypeNt(Object);
+
+ /* Call the original open procedure. There shouldn't be any for Windows XP,
+ * while on Windows Vista and 7 it is used for implementing protected
+ * processes (Big Content's DRM protection, not KProcessHacker's protection).
+ */
+ status = KphObOpenCall(
+ objectType == *PsProcessType ? &ProcessOpenHook : &ThreadOpenHook,
+ OpenReason,
+ AccessMode,
+ Process,
+ Object,
+ GrantedAccess,
+ HandleCount
+ );
+ }
+ else
+ {
+ dprintf("KphNewOpenProcedure60: Access denied.\n");
+ status = STATUS_ACCESS_DENIED;
+ }
+
+ ExReleaseRundownProtection(&ProtectedProcessRundownProtect);
+
+ return status;
+}
+
+/* KphProtectAddEntry
+ *
+ * Protects the specified process.
+ *
+ * Thread safety: Full
+ * IRQL: <= DISPATCH_LEVEL
+ */
+PKPH_PROCESS_ENTRY KphProtectAddEntry(
+ __in PEPROCESS Process,
+ __in HANDLE Tag,
+ __in LOGICAL AllowKernelMode,
+ __in ACCESS_MASK ProcessAllowMask,
+ __in ACCESS_MASK ThreadAllowMask
+ )
+{
+ KIRQL oldIrql;
+ PKPH_PROCESS_ENTRY entry;
+
+ /* Prevent the lookaside list from being freed. */
+ if (!ExAcquireRundownProtection(&ProtectedProcessRundownProtect))
+ return NULL;
+
+ entry = ExAllocateFromNPagedLookasideList(&ProtectedProcessLookasideList);
+ /* Lookaside list no longer needed. */
+ ExReleaseRundownProtection(&ProtectedProcessRundownProtect);
+
+ if (!entry)
+ return NULL;
+
+ entry->Process = Process;
+ entry->CreatorProcess = PsGetCurrentProcess();
+ entry->Tag = Tag;
+ entry->AllowKernelMode = AllowKernelMode;
+ entry->ProcessAllowMask = ProcessAllowMask;
+ entry->ThreadAllowMask = ThreadAllowMask;
+
+ KeAcquireSpinLock(&ProtectedProcessListLock, &oldIrql);
+ InsertHeadList(&ProtectedProcessListHead, &entry->ListEntry);
+ KeReleaseSpinLock(&ProtectedProcessListLock, oldIrql);
+
+ return entry;
+}
+
+/* KphProtectFindEntry
+ *
+ * Finds process protection data.
+ *
+ * Thread safety: Full/Limited. The returned pointer is not guaranteed to
+ * point to a valid process entry. However, the copied entry is safe to
+ * read.
+ * IRQL: <= DISPATCH_LEVEL
+ */
+PKPH_PROCESS_ENTRY KphProtectFindEntry(
+ __in PEPROCESS Process,
+ __in HANDLE Tag,
+ __out_opt PKPH_PROCESS_ENTRY ProcessEntryCopy
+ )
+{
+ KIRQL oldIrql;
+ PLIST_ENTRY entry = ProtectedProcessListHead.Flink;
+
+ KeAcquireSpinLock(&ProtectedProcessListLock, &oldIrql);
+
+ while (entry != &ProtectedProcessListHead)
+ {
+ PKPH_PROCESS_ENTRY processEntry =
+ CONTAINING_RECORD(entry, KPH_PROCESS_ENTRY, ListEntry);
+
+ if (
+ (Process != NULL && processEntry->Process == Process) ||
+ (Tag != NULL && processEntry->Tag == Tag)
+ )
+ {
+ /* Copy the entry if requested. */
+ if (ProcessEntryCopy)
+ memcpy(ProcessEntryCopy, processEntry, sizeof(KPH_PROCESS_ENTRY));
+
+ KeReleaseSpinLock(&ProtectedProcessListLock, oldIrql);
+
+ return processEntry;
+ }
+
+ entry = entry->Flink;
+ }
+
+ KeReleaseSpinLock(&ProtectedProcessListLock, oldIrql);
+
+ return NULL;
+}
+
+/* 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(
+ __in PEPROCESS Process
+ )
+{
+ PKPH_PROCESS_ENTRY entry = KphProtectFindEntry(Process, NULL, NULL);
+
+ if (!entry)
+ return FALSE;
+
+ KphpProtectRemoveEntry(entry);
+
+ return TRUE;
+}
+
+/* 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(
+ __in HANDLE Tag
+ )
+{
+ KIRQL oldIrql;
+ ULONG count = 0;
+ PKPH_PROCESS_ENTRY entry;
+
+ /* Keep removing entries until we can't find any more. */
+ while (entry = KphProtectFindEntry(NULL, Tag, NULL))
+ {
+ KphpProtectRemoveEntry(entry);
+ count++;
+ }
+
+ return count;
+}
+
+/* KphpIsAccessAllowed
+ *
+ * Checks if the specified access is allowed, according to process
+ * protection rules.
+ *
+ * Thread safety: Full
+ * IRQL: <= DISPATCH_LEVEL
+ */
+BOOLEAN KphpIsAccessAllowed(
+ __in PVOID Object,
+ __in KPROCESSOR_MODE AccessMode,
+ __in ACCESS_MASK DesiredAccess
+ )
+{
+ POBJECT_TYPE objectType;
+ PEPROCESS processObject;
+ BOOLEAN isThread = FALSE;
+
+ objectType = KphGetObjectTypeNt(Object);
+ /* It doesn't matter if it isn't actually a process because we won't be
+ dereferencing it. */
+ processObject = (PEPROCESS)Object;
+ isThread = objectType == *PsThreadType;
+
+ /* If this is a thread, get its parent process. */
+ if (isThread)
+ processObject = IoThreadToProcess((PETHREAD)Object);
+
+ if (
+ processObject != PsGetCurrentProcess() && /* let the caller open its own processes/threads */
+ (objectType == *PsProcessType || objectType == *PsThreadType) /* only protect processes and threads */
+ )
+ {
+ KPH_PROCESS_ENTRY processEntry;
+
+ /* Search for and copy the corresponding process protection entry. */
+ if (KphProtectFindEntry(processObject, NULL, &processEntry))
+ {
+ ACCESS_MASK mask =
+ isThread ? processEntry.ThreadAllowMask : processEntry.ProcessAllowMask;
+
+ /* The process/thread is protected. Check if the requested access is allowed. */
+ if (
+ /* check if kernel-mode is exempt from protection */
+ !(processEntry.AllowKernelMode && AccessMode == KernelMode) &&
+ /* allow the creator of the rule to bypass protection */
+ processEntry.CreatorProcess != PsGetCurrentProcess() &&
+ (DesiredAccess & mask) != DesiredAccess
+ )
+ {
+ /* Access denied. */
+ dprintf(
+ "%d: Access denied: 0x%08x (%s)\n",
+ PsGetCurrentProcessId(),
+ DesiredAccess,
+ isThread ? "Thread" : "Process"
+ );
+
+ return FALSE;
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+/* KphpIsCurrentProcessProtected
+ *
+ * Determines whether the current process is protected.
+ *
+ * Thread safety: Full
+ * IRQL: <= DISPATCH_LEVEL
+ */
+BOOLEAN KphpIsCurrentProcessProtected()
+{
+ return KphProtectFindEntry(PsGetCurrentProcess(), NULL, NULL) != NULL;
+}
+
+/* KphpProtectRemoveEntry
+ *
+ * Removes and frees process protection data.
+ *
+ * Thread safety: Full
+ * IRQL: <= DISPATCH_LEVEL
+ */
+VOID KphpProtectRemoveEntry(
+ __in PKPH_PROCESS_ENTRY Entry
+ )
+{
+ KIRQL oldIrql;
+
+ KeAcquireSpinLock(&ProtectedProcessListLock, &oldIrql);
+ RemoveEntryList(&Entry->ListEntry);
+
+ /* Prevent the lookaside list from being destroyed. */
+ ExAcquireRundownProtection(&ProtectedProcessRundownProtect);
+ ExFreeToNPagedLookasideList(
+ &ProtectedProcessLookasideList,
+ Entry
+ );
+ ExReleaseRundownProtection(&ProtectedProcessRundownProtect);
+
+ KeReleaseSpinLock(&ProtectedProcessListLock, oldIrql);
+}
diff --git a/2.x/trunk/KProcessHacker/ps.c b/2.x/trunk/KProcessHacker/ps.c
new file mode 100644
index 000000000..c5662d7e3
--- /dev/null
+++ b/2.x/trunk/KProcessHacker/ps.c
@@ -0,0 +1,1221 @@
+/*
+ * Process Hacker Driver -
+ * processes and threads
+ *
+ * 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/kph.h"
+#include "include/ke.h"
+#include "include/ps.h"
+
+VOID NTAPI KphpCaptureStackBackTraceThreadSpecialApc(
+ PKAPC Apc,
+ PKNORMAL_ROUTINE *NormalRoutine,
+ PVOID *NormalContext,
+ PVOID *SystemArgument1,
+ PVOID *SystemArgument2
+ );
+
+VOID NTAPI KphpExitSpecialApc(
+ PKAPC Apc,
+ PKNORMAL_ROUTINE *NormalRoutine,
+ PVOID *NormalContext,
+ PVOID *SystemArgument1,
+ PVOID *SystemArgument2
+ );
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE, KphAssignImpersonationToken)
+#pragma alloc_text(PAGE, KphCaptureStackBackTraceThread)
+#pragma alloc_text(PAGE, KphpCaptureStackBackTraceThread)
+#pragma alloc_text(PAGE, KphpCaptureStackBackTraceThreadSpecialApc)
+#pragma alloc_text(PAGE, KphDangerousTerminateThread)
+#pragma alloc_text(PAGE, KphpExitSpecialApc)
+#pragma alloc_text(PAGE, KphGetContextThread)
+#pragma alloc_text(PAGE, KphGetProcessId)
+#pragma alloc_text(PAGE, KphGetThreadId)
+#pragma alloc_text(PAGE, KphGetThreadWin32Thread)
+#pragma alloc_text(PAGE, KphOpenProcess)
+#pragma alloc_text(PAGE, KphOpenProcessJob)
+#pragma alloc_text(PAGE, KphOpenThread)
+#pragma alloc_text(PAGE, KphOpenThreadProcess)
+#pragma alloc_text(PAGE, KphResumeProcess)
+#pragma alloc_text(PAGE, KphSetContextThread)
+#pragma alloc_text(PAGE, KphSuspendProcess)
+#pragma alloc_text(PAGE, KphResumeProcess)
+#pragma alloc_text(PAGE, KphTerminateProcess)
+#pragma alloc_text(PAGE, KphTerminateThread)
+#pragma alloc_text(PAGE, PsTerminateProcess)
+#pragma alloc_text(PAGE, PspTerminateThreadByPointer)
+#endif
+
+/* KphAcquireProcessRundownProtection
+ *
+ * Prevents the process from terminating.
+ */
+BOOLEAN KphAcquireProcessRundownProtection(
+ __in PEPROCESS Process
+ )
+{
+ return ExAcquireRundownProtection((PEX_RUNDOWN_REF)KVOFF(Process, OffEpRundownProtect));
+}
+
+/* KphAssignImpersonationToken
+ *
+ * Assigns an impersonation token to the specified thread.
+ */
+NTSTATUS KphAssignImpersonationToken(
+ __in HANDLE ThreadHandle,
+ __in HANDLE TokenHandle
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ PETHREAD threadObject;
+
+ status = ObReferenceObjectByHandle(
+ ThreadHandle,
+ 0,
+ *PsThreadType,
+ KernelMode,
+ &threadObject,
+ NULL
+ );
+
+ if (!NT_SUCCESS(status))
+ return status;
+
+ status = PsAssignImpersonationToken(threadObject, TokenHandle);
+ ObDereferenceObject(threadObject);
+
+ return status;
+}
+
+/* KphCaptureStackBackTraceThread
+ *
+ * Captures a kernel-mode stack backtrace for the specified thread.
+ */
+NTSTATUS KphCaptureStackBackTraceThread(
+ __in HANDLE ThreadHandle,
+ __in ULONG FramesToSkip,
+ __in ULONG FramesToCapture,
+ __out_ecount(FramesToCapture) PVOID *BackTrace,
+ __out_opt PULONG CapturedFrames,
+ __out_opt PULONG BackTraceHash,
+ __in KPROCESSOR_MODE AccessMode
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ PETHREAD threadObject;
+
+ /* Reference the thread. */
+ status = ObReferenceObjectByHandle(
+ ThreadHandle,
+ THREAD_QUERY_INFORMATION,
+ *PsThreadType,
+ KernelMode,
+ &threadObject,
+ NULL
+ );
+
+ if (!NT_SUCCESS(status))
+ return status;
+
+ /* Get the stack trace. */
+ status = KphpCaptureStackBackTraceThread(
+ threadObject,
+ FramesToSkip,
+ FramesToCapture,
+ BackTrace,
+ CapturedFrames,
+ BackTraceHash,
+ AccessMode
+ );
+ /* Dereference the thread. */
+ ObDereferenceObject(threadObject);
+
+ return status;
+}
+
+/* KphpCaptureStackBackTraceThread
+ *
+ * Captures a kernel-mode stack backtrace for the specified thread.
+ *
+ * IRQL: <= APC_LEVEL
+ */
+NTSTATUS KphpCaptureStackBackTraceThread(
+ __in PETHREAD Thread,
+ __in ULONG FramesToSkip,
+ __in ULONG FramesToCapture,
+ __out_ecount(FramesToCapture) PVOID *BackTrace,
+ __out_opt PULONG CapturedFrames,
+ __out_opt PULONG BackTraceHash,
+ __in KPROCESSOR_MODE AccessMode
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ CAPTURE_BACKTRACE_THREAD_CONTEXT context;
+ ULONG backTraceSize;
+ PVOID *backTrace;
+
+ backTraceSize = FramesToCapture * sizeof(PVOID);
+
+ /* Probe user input. */
+ if (AccessMode != KernelMode)
+ {
+ __try
+ {
+ ProbeForWrite(BackTrace, backTraceSize, 1);
+
+ if (CapturedFrames)
+ ProbeForWrite(CapturedFrames, sizeof(ULONG), 1);
+ if (BackTraceHash)
+ ProbeForWrite(BackTraceHash, sizeof(ULONG), 1);
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ return GetExceptionCode();
+ }
+ }
+
+ /* Allocate storage for the stack trace. */
+ backTrace = (PVOID *)ExAllocatePoolWithTag(NonPagedPool, backTraceSize, TAG_CAPTURE_STACK_BACKTRACE);
+
+ if (!backTrace)
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ /* Initialize the context structure. */
+ context.FramesToSkip = FramesToSkip;
+ context.FramesToCapture = FramesToCapture;
+ context.BackTrace = backTrace;
+
+ /* Check if we're trying to get a stack trace of the current thread. */
+ if (Thread == PsGetCurrentThread())
+ {
+ PCAPTURE_BACKTRACE_THREAD_CONTEXT contextPtr = &context;
+ PVOID dummy = NULL;
+ KIRQL oldIrql;
+
+ context.Local = TRUE;
+ /* Raise the IRQL to APC_LEVEL to simulate an APC environment. */
+ KeRaiseIrql(APC_LEVEL, &oldIrql);
+ /* Call the APC routine directly. */
+ KphpCaptureStackBackTraceThreadSpecialApc(
+ &context.Apc,
+ NULL,
+ NULL,
+ &contextPtr,
+ &dummy
+ );
+ /* Lower the IRQL back. */
+ KeLowerIrql(oldIrql);
+ }
+ else
+ {
+ context.Local = FALSE;
+ /* Initialize the stack trace completed event. */
+ KeInitializeEvent(&context.CompletedEvent, NotificationEvent, FALSE);
+ /* Initialize the APC. */
+ KeInitializeApc(
+ &context.Apc,
+ (PKTHREAD)Thread,
+ OriginalApcEnvironment,
+ KphpCaptureStackBackTraceThreadSpecialApc,
+ NULL,
+ NULL,
+ KernelMode,
+ NULL
+ );
+ /* Queue the APC. */
+ if (KeInsertQueueApc(&context.Apc, &context, NULL, 2))
+ {
+ /* Wait for the APC to complete. */
+ status = KeWaitForSingleObject(
+ &context.CompletedEvent,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL
+ );
+ }
+ else
+ {
+ status = STATUS_UNSUCCESSFUL;
+ }
+ }
+
+ if (NT_SUCCESS(status))
+ {
+ ASSERT(context.CapturedFrames <= FramesToCapture);
+
+ /* Write the information. */
+ __try
+ {
+ memcpy(BackTrace, backTrace, context.CapturedFrames * sizeof(PVOID));
+
+ if (CapturedFrames)
+ *CapturedFrames = context.CapturedFrames;
+ if (BackTraceHash)
+ *BackTraceHash = context.BackTraceHash;
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ status = GetExceptionCode();
+ }
+ }
+
+ /* Free the allocated stack trace storage. */
+ ExFreePoolWithTag(backTrace, TAG_CAPTURE_STACK_BACKTRACE);
+
+ return status;
+}
+
+/* KphpCaptureStackBackTraceThreadSpecialApc
+ *
+ * The special APC routine which captures a thread stack trace.
+ */
+VOID NTAPI KphpCaptureStackBackTraceThreadSpecialApc(
+ PKAPC Apc,
+ PKNORMAL_ROUTINE *NormalRoutine,
+ PVOID *NormalContext,
+ PVOID *SystemArgument1,
+ PVOID *SystemArgument2
+ )
+{
+ PCAPTURE_BACKTRACE_THREAD_CONTEXT context =
+ (PCAPTURE_BACKTRACE_THREAD_CONTEXT)*SystemArgument1;
+
+ /* Capture a stack trace. */
+ context->CapturedFrames = KphCaptureStackBackTrace(
+ context->FramesToSkip,
+ context->FramesToCapture,
+ 0,
+ context->BackTrace,
+ &context->BackTraceHash
+ );
+
+ if (!context->Local)
+ {
+ /* Signal the completed event. */
+ KeSetEvent(&context->CompletedEvent, 0, FALSE);
+ }
+}
+
+/* KphDangerousTerminateThread
+ *
+ * Terminates the specified thread by queueing an APC.
+ */
+NTSTATUS KphDangerousTerminateThread(
+ __in HANDLE ThreadHandle,
+ __in NTSTATUS ExitStatus
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ PETHREAD threadObject;
+
+ if (!__PspTerminateThreadByPointer)
+ return STATUS_NOT_SUPPORTED;
+
+ status = ObReferenceObjectByHandle(
+ ThreadHandle,
+ THREAD_TERMINATE,
+ *PsThreadType,
+ KernelMode,
+ &threadObject,
+ NULL
+ );
+
+ if (!NT_SUCCESS(status))
+ return status;
+
+ if (threadObject != PsGetCurrentThread())
+ {
+ EXIT_THREAD_CONTEXT context;
+
+ /* Initialize the context structure. */
+ context.ExitStatus = ExitStatus;
+ /* Initialize the completion event. */
+ KeInitializeEvent(&context.CompletedEvent, NotificationEvent, FALSE);
+ /* Initialize the APC. */
+ KeInitializeApc(
+ &context.Apc,
+ (PKTHREAD)threadObject,
+ OriginalApcEnvironment,
+ KphpExitSpecialApc,
+ NULL,
+ NULL,
+ KernelMode,
+ NULL
+ );
+
+ /* Queue the APC. */
+ if (KeInsertQueueApc(&context.Apc, &context, NULL, 2))
+ {
+ /* Wait for the APC to initialize. */
+ status = KeWaitForSingleObject(
+ &context.CompletedEvent,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL
+ );
+ }
+ else
+ {
+ status = STATUS_UNSUCCESSFUL;
+ }
+
+ ObDereferenceObject(threadObject);
+ }
+ else
+ {
+ /* Can't terminate self. */
+ ObDereferenceObject(threadObject);
+ return STATUS_CANT_TERMINATE_SELF;
+ }
+
+ return status;
+}
+
+VOID NTAPI KphpExitSpecialApc(
+ PKAPC Apc,
+ PKNORMAL_ROUTINE *NormalRoutine,
+ PVOID *NormalContext,
+ PVOID *SystemArgument1,
+ PVOID *SystemArgument2
+ )
+{
+ PEXIT_THREAD_CONTEXT context =
+ (PEXIT_THREAD_CONTEXT)*SystemArgument1;
+ NTSTATUS exitStatus;
+
+ /* Get the exit status. */
+ exitStatus = context->ExitStatus;
+ /* That's the best we can do. Once we exit the current thread we can't
+ * signal the event, so just signal it now. */
+ KeSetEvent(&context->CompletedEvent, 0, FALSE);
+ /* Exit the thread by calling PspTerminateThreadByPointer. */
+ PspTerminateThreadByPointer(PsGetCurrentThread(), exitStatus);
+ /* Should never happen. */
+ dfprintf(
+ "WARNING: Thread was not terminated by PspTerminateThreadByPointer: %d, %#x\n",
+ PsGetCurrentThreadId(),
+ PsGetCurrentThread()
+ );
+}
+
+/* KphGetContextThread
+ *
+ * Gets the context of the specified thread.
+ */
+NTSTATUS KphGetContextThread(
+ __in HANDLE ThreadHandle,
+ __inout PCONTEXT ThreadContext,
+ __in KPROCESSOR_MODE AccessMode
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ PETHREAD threadObject;
+
+ status = ObReferenceObjectByHandle(
+ ThreadHandle,
+ THREAD_GET_CONTEXT,
+ *PsThreadType,
+ KernelMode,
+ &threadObject,
+ NULL
+ );
+
+ if (!NT_SUCCESS(status))
+ return status;
+
+ status = PsGetContextThread(threadObject, ThreadContext, AccessMode);
+ ObDereferenceObject(threadObject);
+
+ return status;
+}
+
+/* KphGetProcessId
+ *
+ * Gets the ID of the process referenced by the specified handle.
+ */
+HANDLE KphGetProcessId(
+ __in HANDLE ProcessHandle
+ )
+{
+ PEPROCESS processObject;
+ HANDLE processId;
+
+ if (!NT_SUCCESS(ObReferenceObjectByHandle(ProcessHandle, 0,
+ *PsProcessType, KernelMode, &processObject, NULL)))
+ return 0;
+
+ processId = PsGetProcessId(processObject);
+ ObDereferenceObject(processObject);
+
+ return processId;
+}
+
+/* KphGetThreadId
+ *
+ * Gets the ID of the thread referenced by the specified handle,
+ * and optionally the ID of the thread's process.
+ */
+HANDLE KphGetThreadId(
+ __in HANDLE ThreadHandle,
+ __out_opt PHANDLE ProcessId
+ )
+{
+ PETHREAD threadObject;
+ CLIENT_ID clientId;
+
+ if (!NT_SUCCESS(ObReferenceObjectByHandle(ThreadHandle, 0,
+ *PsThreadType, KernelMode, &threadObject, NULL)))
+ return 0;
+
+ clientId = *(PCLIENT_ID)KVOFF(threadObject, OffEtClientId);
+
+ ObDereferenceObject(threadObject);
+
+ if (ProcessId)
+ {
+ *ProcessId = clientId.UniqueProcess;
+ }
+
+ return clientId.UniqueThread;
+}
+
+/* KphGetThreadWin32Thread
+ *
+ * Gets a pointer to the WIN32THREAD structure of the specified thread.
+ */
+NTSTATUS KphGetThreadWin32Thread(
+ __in HANDLE ThreadHandle,
+ __out PVOID *Win32Thread,
+ __in KPROCESSOR_MODE AccessMode
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ PETHREAD threadObject;
+ PVOID win32Thread;
+
+ if (AccessMode != KernelMode)
+ {
+ __try
+ {
+ ProbeForWrite(Win32Thread, sizeof(PVOID), 1);
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ return GetExceptionCode();
+ }
+ }
+
+ status = ObReferenceObjectByHandle(
+ ThreadHandle,
+ 0,
+ *PsThreadType,
+ KernelMode,
+ &threadObject,
+ NULL
+ );
+
+ if (!NT_SUCCESS(status))
+ return status;
+
+ win32Thread = PsGetThreadWin32Thread(threadObject);
+ ObDereferenceObject(threadObject);
+
+ __try
+ {
+ *Win32Thread = win32Thread;
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ return GetExceptionCode();
+ }
+
+ return status;
+}
+
+/* KphOpenProcess
+ *
+ * Opens a process.
+ */
+NTSTATUS KphOpenProcess(
+ __out PHANDLE ProcessHandle,
+ __in ACCESS_MASK DesiredAccess,
+ __in POBJECT_ATTRIBUTES ObjectAttributes,
+ __in_opt PCLIENT_ID ClientId,
+ __in KPROCESSOR_MODE AccessMode
+ )
+{
+ BOOLEAN hasObjectName = ObjectAttributes->ObjectName != NULL;
+ ULONG attributes = ObjectAttributes->Attributes;
+ NTSTATUS status = STATUS_SUCCESS;
+ ACCESS_STATE accessState;
+ CHAR auxData[AUX_ACCESS_DATA_SIZE];
+ PEPROCESS processObject = NULL;
+ PETHREAD threadObject = NULL;
+ HANDLE processHandle = NULL;
+
+ if (hasObjectName && ClientId)
+ return STATUS_INVALID_PARAMETER_MIX;
+
+ /* ReactOS code cleared this bit up for me :) */
+ status = SeCreateAccessState(
+ &accessState,
+ (PAUX_ACCESS_DATA)auxData,
+ DesiredAccess,
+ (PGENERIC_MAPPING)KVOFF(*PsProcessType, OffOtiGenericMapping)
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ return status;
+ }
+
+ /* Let's hope our client isn't a virus... */
+ if (accessState.RemainingDesiredAccess & MAXIMUM_ALLOWED)
+ accessState.PreviouslyGrantedAccess |= ProcessAllAccess;
+ else
+ accessState.PreviouslyGrantedAccess |= accessState.RemainingDesiredAccess;
+
+ accessState.RemainingDesiredAccess = 0;
+
+ if (hasObjectName)
+ {
+ status = ObOpenObjectByName(
+ ObjectAttributes,
+ *PsProcessType,
+ AccessMode,
+ &accessState,
+ 0,
+ NULL,
+ &processHandle
+ );
+ SeDeleteAccessState(&accessState);
+ }
+ else if (ClientId)
+ {
+ if (ClientId->UniqueThread)
+ {
+ status = PsLookupProcessThreadByCid(ClientId, &processObject, &threadObject);
+ }
+ else
+ {
+ status = PsLookupProcessByProcessId(ClientId->UniqueProcess, &processObject);
+ }
+
+ if (!NT_SUCCESS(status))
+ {
+ SeDeleteAccessState(&accessState);
+ return status;
+ }
+
+ status = ObOpenObjectByPointer(
+ processObject,
+ attributes,
+ &accessState,
+ 0,
+ *PsProcessType,
+ AccessMode,
+ &processHandle
+ );
+
+ SeDeleteAccessState(&accessState);
+ ObDereferenceObject(processObject);
+
+ if (threadObject)
+ ObDereferenceObject(threadObject);
+ }
+ else
+ {
+ SeDeleteAccessState(&accessState);
+ return STATUS_INVALID_PARAMETER_MIX;
+ }
+
+ if (NT_SUCCESS(status))
+ {
+ *ProcessHandle = processHandle;
+ }
+
+ return status;
+}
+
+/* KphOpenProcessJob
+ *
+ * Opens the specified process' job object. If the process has
+ * not been assigned to a job object, the function returns
+ * STATUS_PROCESS_NOT_IN_JOB.
+ */
+NTSTATUS KphOpenProcessJob(
+ __in HANDLE ProcessHandle,
+ __in ACCESS_MASK DesiredAccess,
+ __out PHANDLE JobHandle,
+ __in KPROCESSOR_MODE AccessMode
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ PEPROCESS processObject;
+ PVOID jobObject;
+ HANDLE jobHandle;
+ ACCESS_STATE accessState;
+ CHAR auxData[AUX_ACCESS_DATA_SIZE];
+
+ status = SeCreateAccessState(
+ &accessState,
+ (PAUX_ACCESS_DATA)auxData,
+ DesiredAccess,
+ (PGENERIC_MAPPING)KVOFF(*PsJobType, OffOtiGenericMapping)
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ return status;
+ }
+
+ if (accessState.RemainingDesiredAccess & MAXIMUM_ALLOWED)
+ accessState.PreviouslyGrantedAccess |= JOB_OBJECT_ALL_ACCESS;
+ else
+ accessState.PreviouslyGrantedAccess |= accessState.RemainingDesiredAccess;
+
+ accessState.RemainingDesiredAccess = 0;
+
+ status = ObReferenceObjectByHandle(ProcessHandle, 0, *PsProcessType, KernelMode, &processObject, 0);
+
+ if (!NT_SUCCESS(status))
+ {
+ SeDeleteAccessState(&accessState);
+ return status;
+ }
+
+ /* If we have PsGetProcessJob, use it. Otherwise, read the EPROCESS structure. */
+ if (PsGetProcessJob)
+ {
+ jobObject = PsGetProcessJob(processObject);
+ }
+ else
+ {
+ jobObject = *(PVOID *)((PCHAR)processObject + OffEpJob);
+ }
+
+ ObDereferenceObject(processObject);
+
+ if (jobObject == NULL)
+ {
+ /* No such job. Output a NULL handle and exit. */
+ SeDeleteAccessState(&accessState);
+ *JobHandle = NULL;
+ return STATUS_PROCESS_NOT_IN_JOB;
+ }
+
+ ObReferenceObject(jobObject);
+ status = ObOpenObjectByPointer(
+ jobObject,
+ 0,
+ &accessState,
+ 0,
+ *PsJobType,
+ AccessMode,
+ &jobHandle
+ );
+ SeDeleteAccessState(&accessState);
+ ObDereferenceObject(jobObject);
+
+ if (NT_SUCCESS(status))
+ *JobHandle = jobHandle;
+
+ return status;
+}
+
+/* KphOpenThread
+ *
+ * Opens a thread.
+ */
+NTSTATUS KphOpenThread(
+ __out PHANDLE ThreadHandle,
+ __in ACCESS_MASK DesiredAccess,
+ __in POBJECT_ATTRIBUTES ObjectAttributes,
+ __in_opt PCLIENT_ID ClientId,
+ __in KPROCESSOR_MODE AccessMode
+ )
+{
+ BOOLEAN hasObjectName = ObjectAttributes->ObjectName != NULL;
+ ULONG attributes = ObjectAttributes->Attributes;
+ NTSTATUS status = STATUS_SUCCESS;
+ ACCESS_STATE accessState;
+ CHAR auxData[AUX_ACCESS_DATA_SIZE];
+ PETHREAD threadObject = NULL;
+ HANDLE threadHandle = NULL;
+
+ if (hasObjectName && ClientId)
+ return STATUS_INVALID_PARAMETER_MIX;
+
+ status = SeCreateAccessState(
+ &accessState,
+ (PAUX_ACCESS_DATA)auxData,
+ DesiredAccess,
+ (PGENERIC_MAPPING)KVOFF(*PsThreadType, OffOtiGenericMapping)
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ return status;
+ }
+
+ if (accessState.RemainingDesiredAccess & MAXIMUM_ALLOWED)
+ accessState.PreviouslyGrantedAccess |= ThreadAllAccess;
+ else
+ accessState.PreviouslyGrantedAccess |= accessState.RemainingDesiredAccess;
+
+ accessState.RemainingDesiredAccess = 0;
+
+ if (hasObjectName)
+ {
+ status = ObOpenObjectByName(
+ ObjectAttributes,
+ *PsThreadType,
+ AccessMode,
+ &accessState,
+ 0,
+ NULL,
+ &threadHandle
+ );
+ SeDeleteAccessState(&accessState);
+ }
+ else if (ClientId)
+ {
+ if (ClientId->UniqueProcess)
+ {
+ status = PsLookupProcessThreadByCid(ClientId, NULL, &threadObject);
+ }
+ else
+ {
+ status = PsLookupThreadByThreadId(ClientId->UniqueThread, &threadObject);
+ }
+
+ if (!NT_SUCCESS(status))
+ {
+ SeDeleteAccessState(&accessState);
+ return status;
+ }
+
+ status = ObOpenObjectByPointer(
+ threadObject,
+ attributes,
+ &accessState,
+ 0,
+ *PsThreadType,
+ AccessMode,
+ &threadHandle
+ );
+
+ SeDeleteAccessState(&accessState);
+ ObDereferenceObject(threadObject);
+ }
+ else
+ {
+ SeDeleteAccessState(&accessState);
+ return STATUS_INVALID_PARAMETER_MIX;
+ }
+
+ if (NT_SUCCESS(status))
+ {
+ *ThreadHandle = threadHandle;
+ }
+
+ return status;
+}
+
+/* KphOpenThreadProcess
+ *
+ * Opens a thread's process.
+ */
+NTSTATUS KphOpenThreadProcess(
+ __in HANDLE ThreadHandle,
+ __in ACCESS_MASK DesiredAccess,
+ __out PHANDLE ProcessHandle,
+ __in KPROCESSOR_MODE AccessMode
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ PETHREAD threadObject;
+ PEPROCESS processObject;
+ HANDLE processHandle;
+ ACCESS_STATE accessState;
+ CHAR auxData[AUX_ACCESS_DATA_SIZE];
+
+ status = SeCreateAccessState(
+ &accessState,
+ (PAUX_ACCESS_DATA)auxData,
+ DesiredAccess,
+ (PGENERIC_MAPPING)KVOFF(*PsProcessType, OffOtiGenericMapping)
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ return status;
+ }
+
+ if (accessState.RemainingDesiredAccess & MAXIMUM_ALLOWED)
+ accessState.PreviouslyGrantedAccess |= ProcessAllAccess;
+ else
+ accessState.PreviouslyGrantedAccess |= accessState.RemainingDesiredAccess;
+
+ accessState.RemainingDesiredAccess = 0;
+
+ status = ObReferenceObjectByHandle(ThreadHandle, 0, *PsThreadType, KernelMode, &threadObject, 0);
+
+ if (!NT_SUCCESS(status))
+ {
+ SeDeleteAccessState(&accessState);
+ return status;
+ }
+
+ /* Get the process object. */
+ processObject = IoThreadToProcess(threadObject);
+ ObDereferenceObject(threadObject);
+
+ if (processObject == NULL)
+ {
+ /* Thread does not have a process (?). */
+ SeDeleteAccessState(&accessState);
+ *ProcessHandle = NULL;
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ ObReferenceObject(processObject);
+ status = ObOpenObjectByPointer(
+ processObject,
+ 0,
+ &accessState,
+ 0,
+ *PsProcessType,
+ AccessMode,
+ &processHandle
+ );
+ SeDeleteAccessState(&accessState);
+ ObDereferenceObject(processObject);
+
+ if (NT_SUCCESS(status))
+ *ProcessHandle = processHandle;
+
+ return status;
+}
+
+/* KphReleaseProcessRundownProtection
+ *
+ * Allows the process to terminate.
+ */
+VOID KphReleaseProcessRundownProtection(
+ __in PEPROCESS Process
+ )
+{
+ ExReleaseRundownProtection((PEX_RUNDOWN_REF)KVOFF(Process, OffEpRundownProtect));
+}
+
+/* KphResumeProcess
+ *
+ * Resumes the specified process.
+ */
+NTSTATUS KphResumeProcess(
+ __in HANDLE ProcessHandle
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ PEPROCESS processObject;
+
+ if (!PsResumeProcess)
+ return STATUS_NOT_SUPPORTED;
+
+ status = ObReferenceObjectByHandle(
+ ProcessHandle,
+ PROCESS_SUSPEND_RESUME,
+ *PsProcessType,
+ KernelMode,
+ &processObject,
+ NULL);
+
+ if (!NT_SUCCESS(status))
+ return status;
+
+ status = PsResumeProcess(processObject);
+ ObDereferenceObject(processObject);
+
+ return status;
+}
+
+/* KphSetContextThread
+ *
+ * Sets the context of the specified thread.
+ */
+NTSTATUS KphSetContextThread(
+ __in HANDLE ThreadHandle,
+ __in PCONTEXT ThreadContext,
+ __in KPROCESSOR_MODE AccessMode
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ PETHREAD threadObject;
+
+ status = ObReferenceObjectByHandle(
+ ThreadHandle,
+ THREAD_SET_CONTEXT,
+ *PsThreadType,
+ KernelMode,
+ &threadObject,
+ NULL);
+
+ if (!NT_SUCCESS(status))
+ return status;
+
+ status = PsSetContextThread(threadObject, ThreadContext, AccessMode);
+ ObDereferenceObject(threadObject);
+
+ return status;
+}
+
+/* KphSuspendProcess
+ *
+ * Suspends the specified process.
+ */
+NTSTATUS KphSuspendProcess(
+ __in HANDLE ProcessHandle
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ PEPROCESS processObject;
+
+ if (!PsSuspendProcess)
+ return STATUS_NOT_SUPPORTED;
+
+ status = ObReferenceObjectByHandle(
+ ProcessHandle,
+ PROCESS_SUSPEND_RESUME,
+ *PsProcessType,
+ KernelMode,
+ &processObject,
+ NULL);
+
+ if (!NT_SUCCESS(status))
+ return status;
+
+ status = PsSuspendProcess(processObject);
+ ObDereferenceObject(processObject);
+
+ return status;
+}
+
+/* KphTerminateProcess
+ *
+ * Terminates the specified process.
+ */
+NTSTATUS KphTerminateProcess(
+ __in HANDLE ProcessHandle,
+ __in NTSTATUS ExitStatus
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ PEPROCESS processObject;
+
+ status = ObReferenceObjectByHandle(
+ ProcessHandle,
+ PROCESS_TERMINATE,
+ *PsProcessType,
+ KernelMode,
+ &processObject,
+ NULL);
+
+ if (!NT_SUCCESS(status))
+ return status;
+
+ /* Can't terminate ourself. Get user-mode to do it. */
+ if (processObject == PsGetCurrentProcess())
+ {
+ ObDereferenceObject(processObject);
+ return STATUS_CANT_TERMINATE_SELF;
+ }
+
+ /* If we have located PsTerminateProcess/PspTerminateProcess,
+ call it. */
+ if (__PsTerminateProcess)
+ {
+ status = PsTerminateProcess(processObject, ExitStatus);
+ ObDereferenceObject(processObject);
+ }
+ else
+ {
+ /* Otherwise, we'll have to call ZwTerminateProcess - most hooks on this function
+ allow kernel-mode callers through. */
+ OBJECT_ATTRIBUTES objectAttributes = { 0 };
+ CLIENT_ID clientId;
+ HANDLE newProcessHandle;
+
+ /* We have to open it again because ZwTerminateProcess only accepts kernel handles. */
+ clientId.UniqueThread = 0;
+ clientId.UniqueProcess = PsGetProcessId(processObject);
+ status = KphOpenProcess(&newProcessHandle, 0x1, &objectAttributes, &clientId, KernelMode);
+ ObDereferenceObject(processObject);
+
+ if (NT_SUCCESS(status))
+ {
+ status = ZwTerminateProcess(newProcessHandle, ExitStatus);
+ ZwClose(newProcessHandle);
+ }
+ }
+
+ return status;
+}
+
+/* KphTerminateThread
+ *
+ * Terminates the specified thread.
+ */
+NTSTATUS KphTerminateThread(
+ __in HANDLE ThreadHandle,
+ __in NTSTATUS ExitStatus
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ PETHREAD threadObject;
+
+ status = ObReferenceObjectByHandle(
+ ThreadHandle,
+ THREAD_TERMINATE,
+ *PsThreadType,
+ KernelMode,
+ &threadObject,
+ NULL);
+
+ if (!NT_SUCCESS(status))
+ return status;
+
+ if (threadObject != PsGetCurrentThread())
+ {
+ status = PspTerminateThreadByPointer(threadObject, ExitStatus);
+ ObDereferenceObject(threadObject);
+ }
+ else
+ {/*
+ ObDereferenceObject(threadObject);
+ status = PspTerminateThreadByPointer(PsGetCurrentThread(), ExitStatus); */
+ /* Leads to bugs, so don't terminate self. */
+ ObDereferenceObject(threadObject);
+ return STATUS_CANT_TERMINATE_SELF;
+ }
+
+ return status;
+}
+
+/* PsTerminateProcess
+ *
+ * Terminates the specified process. If PsTerminateProcess or
+ * PspTerminateProcess could not be located, the call will fail
+ * with STATUS_NOT_SUPPORTED.
+ */
+NTSTATUS PsTerminateProcess(
+ __in PEPROCESS Process,
+ __in NTSTATUS ExitStatus
+ )
+{
+ PVOID psTerminateProcess = __PsTerminateProcess;
+ NTSTATUS status;
+
+ if (!psTerminateProcess)
+ return STATUS_NOT_SUPPORTED;
+
+#ifdef _X86_
+ if (
+ WindowsVersion == WINDOWS_XP ||
+ WindowsVersion == WINDOWS_SERVER_2003
+ )
+ {
+ /* PspTerminateProcess on XP and Server 2003 is stdcall. */
+ __asm
+ {
+ push [ExitStatus]
+ push [Process]
+ call [psTerminateProcess]
+ mov [status], eax
+ }
+ }
+ else if (
+ WindowsVersion == WINDOWS_VISTA ||
+ WindowsVersion == WINDOWS_7
+ )
+ {
+ /* PsTerminateProcess on Vista and above is thiscall. */
+ __asm
+ {
+ push [ExitStatus]
+ mov ecx, [Process]
+ call [psTerminateProcess]
+ mov [status], eax
+ }
+ }
+ else
+ {
+ return STATUS_NOT_SUPPORTED;
+ }
+#else
+ status = __PsTerminateProcess(Process, ExitStatus);
+#endif
+
+ return status;
+}
+
+/* PspTerminateThreadByPointer
+ *
+ * Terminates the specified thread. If PspTerminateThreadByPointer
+ * could not be located, the call will fail with STATUS_NOT_SUPPORTED.
+ */
+NTSTATUS PspTerminateThreadByPointer(
+ __in PETHREAD Thread,
+ __in NTSTATUS ExitStatus
+ )
+{
+ PVOID pspTerminateThreadByPointer = __PspTerminateThreadByPointer;
+
+ if (!pspTerminateThreadByPointer)
+ return STATUS_NOT_SUPPORTED;
+
+ if (WindowsVersion == WINDOWS_XP)
+ {
+ return ((_PspTerminateThreadByPointer51)pspTerminateThreadByPointer)(
+ Thread,
+ ExitStatus
+ );
+ }
+ else if (
+ WindowsVersion == WINDOWS_SERVER_2003 ||
+ WindowsVersion == WINDOWS_VISTA ||
+ WindowsVersion == WINDOWS_7
+ )
+ {
+ return ((_PspTerminateThreadByPointer52)pspTerminateThreadByPointer)(
+ Thread,
+ ExitStatus,
+ Thread == PsGetCurrentThread()
+ );
+ }
+ else
+ {
+ return STATUS_NOT_SUPPORTED;
+ }
+}
diff --git a/2.x/trunk/KProcessHacker/ref.c b/2.x/trunk/KProcessHacker/ref.c
new file mode 100644
index 000000000..eeb0f917a
--- /dev/null
+++ b/2.x/trunk/KProcessHacker/ref.c
@@ -0,0 +1,574 @@
+/*
+ * Process Hacker Driver -
+ * internal object manager
+ *
+ * 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/refp.h"
+
+/* A list of all objects created by the object manager. */
+LIST_ENTRY KphObjectListHead;
+/* A mutex protecting global data structures. */
+FAST_MUTEX KphObjectListMutex;
+/* The object type type. */
+PKPH_OBJECT_TYPE KphObjectTypeObject = NULL;
+
+/* Whether the object manager is destroying all objects. */
+BOOLEAN KphObjectDeinitializing = FALSE;
+/* The work item for deferred object deletes. */
+WORK_QUEUE_ITEM KphObjectDeferDeleteWorkItem;
+/* The next object to delete. */
+PKPH_OBJECT_HEADER KphObjectNextToFree = NULL;
+
+/* KphRefInit
+ *
+ * Initializes the KPH object manager.
+ *
+ * IRQL: <= APC_LEVEL
+ */
+NTSTATUS KphRefInit()
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ /* Initialize the object list. */
+ InitializeListHead(&KphObjectListHead);
+ /* Initialize the object list mutex. */
+ ExInitializeFastMutex(&KphObjectListMutex);
+
+ /* Initialize the deferred delete work item. */
+ ExInitializeWorkItem(
+ &KphObjectDeferDeleteWorkItem,
+ KphpDeferDeleteObjectRoutine,
+ NULL
+ );
+
+ /* Create the fundamental object type. */
+ status = KphCreateObjectType(
+ &KphObjectTypeObject,
+ NonPagedPool,
+ 0,
+ NULL
+ );
+
+ if (!NT_SUCCESS(status))
+ return status;
+
+ /* Now that the fundamental object type exists, fix it up. */
+ KphObjectToObjectHeader(KphObjectTypeObject)->Type = KphObjectTypeObject;
+ KphObjectTypeObject->NumberOfObjects = 1;
+
+ return status;
+}
+
+/* KphRefDeinit
+ *
+ * Frees all objects created by the KPH object manager.
+ *
+ * IRQL: = PASSIVE_LEVEL
+ */
+NTSTATUS KphRefDeinit()
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ PLIST_ENTRY currentEntry;
+
+ KphObjectDeinitializing = TRUE;
+
+ /* Acquire the object list mutex to make sure no one else
+ * modifies the list. */
+ ExAcquireFastMutex(&KphObjectListMutex);
+
+ /* Remove and free all objects in the list. */
+ while ((currentEntry = RemoveHeadList(&KphObjectListHead)) != &KphObjectListHead)
+ {
+ PKPH_OBJECT_HEADER objectHeader =
+ CONTAINING_RECORD(currentEntry, KPH_OBJECT_HEADER, GlobalObjectListEntry);
+
+ /* Free the object, ignoring its reference count. */
+ KphpFreeObject(objectHeader);
+ }
+
+ /* Release the object list mutex and restore the IRQL. */
+ ExReleaseFastMutex(&KphObjectListMutex);
+
+ return STATUS_SUCCESS;
+}
+
+/* KphCreateObject
+ *
+ * Allocates a object.
+ *
+ * Object: A variable which receives a pointer to the newly allocated object.
+ * ObjectSize: The size of the object.
+ * Flags: A combination of flags specifying how the object is to be allocated.
+ * * KPHOBJ_RAISE_ON_FAIL: An exception will be raised if the object could
+ * not be allocated.
+ * * KPHOBJ_PAGED_POOL: The object will be allocated in the paged pool. If
+ * this flag is specified, KPHOBJ_NONPAGED_POOL cannot be specified.
+ * * KPHOBJ_NONPAGED_POOL: The object will be allocated in the non-paged pool.
+ * If this flag is specified, KPHOBJ_PAGED_POOL cannot be specified.
+ * ObjectType: The type of the object.
+ * AdditionalReferences: The number of references to add to the object. The
+ * object will have a reference count of 1 + AdditionalReferences.
+ *
+ * IRQL: <= APC_LEVEL
+ */
+NTSTATUS KphCreateObject(
+ __out PVOID *Object,
+ __in SIZE_T ObjectSize,
+ __in ULONG Flags,
+ __in_opt PKPH_OBJECT_TYPE ObjectType,
+ __in_opt LONG AdditionalReferences
+ )
+{
+ PKPH_OBJECT_HEADER objectHeader;
+ POOL_TYPE poolType;
+
+ /* Check the flags. */
+ if ((Flags & KPHOBJ_VALID_FLAGS) != Flags) /* Valid flag mask */
+ return STATUS_INVALID_PARAMETER_3;
+ if ((Flags & KPHOBJ_PAGED_POOL) && (Flags & KPHOBJ_NONPAGED_POOL)) /* Can't be both pools */
+ return STATUS_INVALID_PARAMETER_3;
+ /* The object type is only optional if the fundamental object type
+ * hasn't been created. */
+ if (!ObjectType && KphObjectTypeObject)
+ return STATUS_INVALID_PARAMETER_4;
+ /* Make sure the additional reference count isn't negative. */
+ if (AdditionalReferences < 0)
+ return STATUS_INVALID_PARAMETER_5;
+
+ /* Figure out the pool type. If it wasn't specified in Flags,
+ * get the pool type from the object type. */
+ if (Flags & KPHOBJ_PAGED_POOL)
+ poolType = PagedPool;
+ else if (Flags & KPHOBJ_NONPAGED_POOL)
+ poolType = NonPagedPool;
+ else if (ObjectType) /* May be null if we're creating the fundamental type */
+ poolType = ObjectType->DefaultPoolType;
+ else
+ poolType = NonPagedPool;
+
+ /* Allocate storage for the object. Note that this includes
+ * the object header followed by the object body. */
+ objectHeader = KphpAllocateObject(ObjectSize, poolType);
+
+ if (!objectHeader)
+ {
+ if (Flags & KPHOBJ_RAISE_ON_FAIL)
+ ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
+ else
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ /* Object type statistics. */
+ if (ObjectType)
+ {
+ InterlockedIncrement(&ObjectType->NumberOfObjects);
+ }
+
+ /* Initialize the object header. */
+ objectHeader->RefCount = 1 + AdditionalReferences;
+ objectHeader->Flags = Flags;
+ objectHeader->Size = ObjectSize;
+ objectHeader->Type = ObjectType;
+
+ /* Insert the object into the global object list. */
+ ExAcquireFastMutex(&KphObjectListMutex);
+ InsertHeadList(&KphObjectListHead, &objectHeader->GlobalObjectListEntry);
+ ExReleaseFastMutex(&KphObjectListMutex);
+
+ /* Pass a pointer to the object body back to the caller. */
+ *Object = KphObjectHeaderToObject(objectHeader);
+
+ return STATUS_SUCCESS;
+}
+
+/* KphCreateObjectType
+ *
+ * Creates an object type.
+ *
+ * IRQL: <= APC_LEVEL
+ */
+NTSTATUS KphCreateObjectType(
+ __out PKPH_OBJECT_TYPE *ObjectType,
+ __in POOL_TYPE DefaultPoolType,
+ __in ULONG Flags,
+ __in PKPH_TYPE_DELETE_PROCEDURE DeleteProcedure
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ PKPH_OBJECT_TYPE objectType;
+
+ /* Check the flags. */
+ if ((Flags & KPHOBJTYPE_VALID_FLAGS) != Flags) /* Valid flag mask */
+ return STATUS_INVALID_PARAMETER_3;
+
+ /* Create the type object. */
+ status = KphCreateObject(
+ &objectType,
+ sizeof(KPH_OBJECT_TYPE),
+ 0,
+ KphObjectTypeObject,
+ 0
+ );
+
+ if (!NT_SUCCESS(status))
+ return status;
+
+ /* Initialize the type object. */
+ objectType->DefaultPoolType = DefaultPoolType;
+ objectType->Flags = Flags;
+ objectType->DeleteProcedure = DeleteProcedure;
+ objectType->NumberOfObjects = 0;
+
+ *ObjectType = objectType;
+
+ return status;
+}
+
+/* KphDereferenceObject
+ *
+ * Dereferences the specified object. The object will be freed if
+ * its reference count reaches 0.
+ *
+ * Object: A pointer to the object to dereference.
+ *
+ * Return value: TRUE if the object was freed, otherwise FALSE.
+ *
+ * IRQL: <= APC_LEVEL
+ */
+BOOLEAN KphDereferenceObject(
+ __in PVOID Object
+ )
+{
+ return KphDereferenceObjectEx(Object, 1, FALSE) == 0;
+}
+
+/* KphDereferenceObjectDeferDelete
+ *
+ * Dereferences the specified object. The object will be freed in
+ * a worker thread if its reference count reaches 0.
+ *
+ * Object: A pointer to the object to dereference.
+ *
+ * Return value: TRUE if the object was freed, otherwise FALSE.
+ *
+ * IRQL: <= DISPATCH_LEVEL if the object was allocated using the
+ * non-paged pool, otherwise <= APC_LEVEL.
+ */
+BOOLEAN KphDereferenceObjectDeferDelete(
+ __in PVOID Object
+ )
+{
+ return KphDereferenceObjectEx(Object, 1, TRUE) == 0;
+}
+
+/* KphDereferenceObjectEx
+ *
+ * Dereferences the specified object. The object will be freed if
+ * its reference count reaches 0.
+ *
+ * Object: A pointer to the object to dereference.
+ * RefCount: The number of references to remove.
+ *
+ * Return value: The new reference count of the object.
+ *
+ * IRQL: <= DISPATCH_LEVEL if the object was allocated using the
+ * non-paged pool and deletion is being deferred, otherwise <= APC_LEVEL.
+ */
+LONG KphDereferenceObjectEx(
+ __in PVOID Object,
+ __in LONG RefCount,
+ __in BOOLEAN DeferDelete
+ )
+{
+ PKPH_OBJECT_HEADER objectHeader;
+ LONG oldRefCount;
+
+ /* Make sure we're not subtracting a negative reference count. */
+ if (RefCount < 0)
+ ExRaiseStatus(STATUS_INVALID_PARAMETER_2);
+
+ objectHeader = KphObjectToObjectHeader(Object);
+
+ /* Decrease the reference count. */
+ oldRefCount = InterlockedExchangeAdd(&objectHeader->RefCount, -RefCount);
+
+ /* Free the object if it has 0 references. */
+ if (oldRefCount - RefCount == 0)
+ {
+ /* If we are at DISPATCH_LEVEL or higher, the type requests
+ * us to do so, or the caller requests us to do so, defer
+ * the deletion.
+ */
+ if (
+ DeferDelete ||
+ (objectHeader->Type->Flags & KPHOBJTYPE_PASSIVE_LEVEL_DELETE) ||
+ (KeGetCurrentIrql() > APC_LEVEL)
+ )
+ {
+ KphpDeferDeleteObject(objectHeader);
+ }
+ else
+ {
+ /* Free the object. */
+ KphpFreeObject(objectHeader);
+ }
+ }
+
+ return oldRefCount - RefCount;
+}
+
+/* KphGetObjectType
+ *
+ * Gets an object's type.
+ *
+ * IRQL: <= DISPATCH_LEVEL if the object was allocated using the
+ * non-paged pool, otherwise <= APC_LEVEL.
+ */
+PKPH_OBJECT_TYPE KphGetObjectType(
+ __in PVOID Object
+ )
+{
+ return KphObjectToObjectHeader(Object)->Type;
+}
+
+/* KphReferenceObject
+ *
+ * References the specified object.
+ *
+ * Object: A pointer to the object to reference.
+ *
+ * IRQL: <= DISPATCH_LEVEL if the object was allocated using the
+ * non-paged pool, otherwise <= APC_LEVEL.
+ */
+VOID KphReferenceObject(
+ __in PVOID Object
+ )
+{
+ PKPH_OBJECT_HEADER objectHeader;
+
+ objectHeader = KphObjectToObjectHeader(Object);
+ /* Increment the reference count. */
+ InterlockedIncrement(&objectHeader->RefCount);
+}
+
+/* KphReferenceObjectEx
+ *
+ * References the specified object.
+ *
+ * Object: A pointer to the object to reference.
+ * RefCount: The number of references to add.
+ *
+ * Return value: The new reference count of the object.
+ *
+ * IRQL: <= DISPATCH_LEVEL if the object was allocated using the
+ * non-paged pool, otherwise <= APC_LEVEL.
+ */
+LONG KphReferenceObjectEx(
+ __in PVOID Object,
+ __in LONG RefCount
+ )
+{
+ PKPH_OBJECT_HEADER objectHeader;
+ LONG oldRefCount;
+
+ /* Make sure we're not adding a negative reference count. */
+ if (RefCount < 0)
+ ExRaiseStatus(STATUS_INVALID_PARAMETER_2);
+
+ objectHeader = KphObjectToObjectHeader(Object);
+ /* Increase the reference count. */
+ oldRefCount = InterlockedExchangeAdd(&objectHeader->RefCount, RefCount);
+
+ return oldRefCount + RefCount;
+}
+
+/* KphReferenceObjectSafe
+ *
+ * Attempts to reference an object and fails if it is being
+ * destroyed.
+ *
+ * Object: The object to reference if it is not being deleted.
+ *
+ * Return value: TRUE if the object was referenced, FALSE if
+ * it was being deleted and was not referenced.
+ *
+ * Remarks:
+ * This function is useful if a reference to an object is
+ * held, protected by a mutex, and the delete procedure of
+ * the object's type attempts to acquire the mutex. If this
+ * function is called while the mutex is owned, you can
+ * avoid referencing an object that is being destroyed.
+ *
+ * IRQL: <= DISPATCH_LEVEL if the object was allocated using the
+ * non-paged pool, otherwise <= APC_LEVEL.
+ */
+BOOLEAN KphReferenceObjectSafe(
+ __in PVOID Object
+ )
+{
+ PKPH_OBJECT_HEADER objectHeader;
+ BOOLEAN result;
+
+ objectHeader = KphObjectToObjectHeader(Object);
+ /* Increase the reference count only if it isn't 0 (atomically). */
+ result = KphpInterlockedIncrementSafe(&objectHeader->RefCount);
+
+ return result;
+}
+
+/* KphpAllocateObject
+ *
+ * Allocates storage for an object.
+ *
+ * ObjectSize: The size of the object, excluding the header.
+ * PoolType: The pool in which to allocate the object.
+ */
+PKPH_OBJECT_HEADER KphpAllocateObject(
+ __in SIZE_T ObjectSize,
+ __in POOL_TYPE PoolType
+ )
+{
+ return ExAllocatePoolWithTag(
+ PoolType,
+ KphpAddObjectHeaderSize(ObjectSize),
+ TAG_KPHOBJ
+ );
+}
+
+/* KphpDeferDeleteObject
+ *
+ * Queues an object for deletion.
+ *
+ * IRQL: <= DISPATCH_LEVEL if the object was allocated using the
+ * non-paged pool, otherwise <= APC_LEVEL.
+ */
+VOID KphpDeferDeleteObject(
+ __in PKPH_OBJECT_HEADER ObjectHeader
+ )
+{
+ PKPH_OBJECT_HEADER nextToFree;
+
+ /* Add the object to the list while saving the old value, atomically.
+ * Note that it is first-in, last-out.
+ */
+ while (TRUE)
+ {
+ nextToFree = KphObjectNextToFree;
+ ObjectHeader->NextToFree = nextToFree;
+
+ /* Attempt to set the global next-to-free variable. */
+ if (InterlockedCompareExchangePointer(
+ &KphObjectNextToFree,
+ ObjectHeader,
+ nextToFree
+ ) == nextToFree)
+ {
+ /* Success. */
+ break;
+ }
+
+ /* Someone else changed the next-to-free variable.
+ * Go back and try again.
+ */
+ }
+
+ /* Was the to-free list empty before? If so, we need to queue
+ * the work item.
+ */
+ if (!nextToFree)
+ {
+ ExQueueWorkItem(&KphObjectDeferDeleteWorkItem, CriticalWorkQueue);
+ }
+}
+
+/* KphpDeferDeleteObjectRoutine
+ *
+ * Removes and frees objects from the to-free list.
+ *
+ * IRQL: PASSIVE_LEVEL
+ */
+VOID KphpDeferDeleteObjectRoutine(
+ __in PVOID Parameter
+ )
+{
+ PKPH_OBJECT_HEADER objectHeader = NULL;
+
+ while (TRUE)
+ {
+ /* Get the next object to free while replacing the global variable with
+ * what we needed to free next.
+ */
+ objectHeader = InterlockedExchangePointer(&KphObjectNextToFree, objectHeader);
+
+ /* If we have an object to free, free it and move on to the
+ * next object. Otherwise, stop.
+ */
+ if (objectHeader)
+ {
+ KphpFreeObject(objectHeader);
+ objectHeader = objectHeader->NextToFree;
+ }
+ else
+ {
+ break;
+ }
+ }
+}
+
+/* KphpFreeObject
+ *
+ * Calls the delete procedure for an object and frees its
+ * allocated storage.
+ *
+ * ObjectHeader: A pointer to the object header of an allocated object.
+ */
+VOID KphpFreeObject(
+ __in PKPH_OBJECT_HEADER ObjectHeader
+ )
+{
+ /* Object type statistics. */
+ InterlockedDecrement(&ObjectHeader->Type->NumberOfObjects);
+
+ /* Remove the object from the global object list.
+ * If the object manager is being destroyed, don't do this -
+ * we will deadlock because the deinitialization function
+ * holds the mutex.
+ */
+ if (!KphObjectDeinitializing)
+ {
+ ExAcquireFastMutex(&KphObjectListMutex);
+ RemoveEntryList(&ObjectHeader->GlobalObjectListEntry);
+ ExReleaseFastMutex(&KphObjectListMutex);
+ }
+
+ /* Call the delete procedure if we have one. */
+ if (ObjectHeader->Type->DeleteProcedure)
+ {
+ ObjectHeader->Type->DeleteProcedure(
+ KphObjectHeaderToObject(ObjectHeader),
+ ObjectHeader->Flags
+ );
+ }
+
+ ExFreePoolWithTag(
+ ObjectHeader,
+ TAG_KPHOBJ
+ );
+}
diff --git a/2.x/trunk/KProcessHacker/resource.rc b/2.x/trunk/KProcessHacker/resource.rc
new file mode 100644
index 000000000..d38b333d6
--- /dev/null
+++ b/2.x/trunk/KProcessHacker/resource.rc
@@ -0,0 +1,53 @@
+#include
+
+#define VER_COMMA 1,10,0,0
+#define VER_STR "1.10\0"
+
+#define VER_FILEVERSION VER_COMMA
+#define VER_FILEVERSION_STR VER_STR
+#define VER_PRODUCTVERSION VER_COMMA
+#define VER_PRODUCTVERSION_STR VER_STR
+
+#ifndef DEBUG
+#define VER_DEBUG 0
+#else
+#define VER_DEBUG VS_FF_DEBUG
+#endif
+
+#define VER_PRIVATEBUILD 0
+#define VER_PRERELEASE 0
+
+#define VER_COMPANYNAME_STR "wj32\0"
+#define VER_FILEDESCRIPTION_STR "KProcessHacker\0"
+#define VER_LEGALCOPYRIGHT_STR "Copyright (c) 2009 wj32. Licensed under the GNU GPL, v3.\0"
+#define VER_ORIGINALFILENAME_STR "kprocesshacker.sys\0"
+#define VER_PRODUCTNAME_STR "KProcessHacker\0"
+
+VS_VERSION_INFO VERSIONINFO
+FILEVERSION VER_FILEVERSION
+PRODUCTVERSION VER_PRODUCTVERSION
+FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+FILEFLAGS (VER_PRIVATEBUILD | VER_PRERELEASE | VER_DEBUG)
+FILEOS VOS__WINDOWS32
+FILETYPE VFT_DRV
+FILESUBTYPE VFT2_DRV_SYSTEM
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904E4"
+ BEGIN
+ VALUE "CompanyName", VER_COMPANYNAME_STR
+ VALUE "FileDescription", VER_FILEDESCRIPTION_STR
+ VALUE "FileVersion", VER_FILEVERSION_STR
+ VALUE "LegalCopyright", VER_LEGALCOPYRIGHT_STR
+ VALUE "OriginalFilename", VER_ORIGINALFILENAME_STR
+ VALUE "ProductName", VER_PRODUCTNAME_STR
+ VALUE "ProductVersion", VER_PRODUCTVERSION_STR
+ END
+ END
+
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1252
+ END
+END
diff --git a/2.x/trunk/KProcessHacker/se.c b/2.x/trunk/KProcessHacker/se.c
new file mode 100644
index 000000000..ce09c6607
--- /dev/null
+++ b/2.x/trunk/KProcessHacker/se.c
@@ -0,0 +1,102 @@
+/*
+ * Process Hacker Driver -
+ * security
+ *
+ * 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/kph.h"
+#include "include/se.h"
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE, KphOpenProcessTokenEx)
+#endif
+
+/* KphOpenProcessTokenEx
+ *
+ * Opens the primary token of the specified process.
+ */
+NTSTATUS KphOpenProcessTokenEx(
+ __in HANDLE ProcessHandle,
+ __in ACCESS_MASK DesiredAccess,
+ __in ULONG ObjectAttributes,
+ __out PHANDLE TokenHandle,
+ __in KPROCESSOR_MODE AccessMode
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ PEPROCESS processObject;
+ PACCESS_TOKEN tokenObject;
+ HANDLE tokenHandle;
+ ACCESS_STATE accessState;
+ CHAR auxData[AUX_ACCESS_DATA_SIZE];
+
+ status = SeCreateAccessState(
+ &accessState,
+ (PAUX_ACCESS_DATA)auxData,
+ DesiredAccess,
+ (PGENERIC_MAPPING)KVOFF(*SeTokenObjectType, OffOtiGenericMapping)
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ return status;
+ }
+
+ if (accessState.RemainingDesiredAccess & MAXIMUM_ALLOWED)
+ accessState.PreviouslyGrantedAccess |= TOKEN_ALL_ACCESS;
+ else
+ accessState.PreviouslyGrantedAccess |= accessState.RemainingDesiredAccess;
+
+ accessState.RemainingDesiredAccess = 0;
+
+ status = ObReferenceObjectByHandle(
+ ProcessHandle,
+ 0,
+ *PsProcessType,
+ KernelMode,
+ &processObject,
+ NULL
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ SeDeleteAccessState(&accessState);
+ return status;
+ }
+
+ tokenObject = PsReferencePrimaryToken(processObject);
+ ObDereferenceObject(processObject);
+
+ status = ObOpenObjectByPointer(
+ tokenObject,
+ ObjectAttributes,
+ &accessState,
+ 0,
+ *SeTokenObjectType,
+ AccessMode,
+ &tokenHandle
+ );
+ SeDeleteAccessState(&accessState);
+ ObDereferenceObject(tokenObject);
+
+ if (NT_SUCCESS(status))
+ *TokenHandle = tokenHandle;
+
+ return status;
+}
diff --git a/2.x/trunk/KProcessHacker/sources b/2.x/trunk/KProcessHacker/sources
new file mode 100644
index 000000000..ff6e07b5e
--- /dev/null
+++ b/2.x/trunk/KProcessHacker/sources
@@ -0,0 +1,29 @@
+TARGETNAME=kprocesshacker
+TARGETTYPE=DRIVER
+TARGETPATH=.\
+
+INCLUDES=$(DDK_INC_PATH)
+LIBS=%BUILD%\lib
+
+SOURCES= \
+ kprocesshacker.c \
+ version.c \
+ \
+ kph.c \
+ handle.c \
+ hook.c \
+ protect.c \
+ ref.c \
+ sync.c \
+ sysservice.c \
+ sysservicedata.c \
+ test.c \
+ trace.c \
+ util.c \
+ \
+ io.c \
+ mm.c \
+ ob.c \
+ ps.c \
+ se.c \
+ resource.rc
diff --git a/2.x/trunk/KProcessHacker/sync.c b/2.x/trunk/KProcessHacker/sync.c
new file mode 100644
index 000000000..99bd46bf8
--- /dev/null
+++ b/2.x/trunk/KProcessHacker/sync.c
@@ -0,0 +1,312 @@
+/*
+ * 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(
+ __in ULONG_PTR Number
+ );
+
+VOID KphpProcessorLockDpc(
+ __in PKDPC Dpc,
+ __in PVOID DeferredContext,
+ __in PVOID SystemArgument1,
+ __in PVOID SystemArgument2
+ );
+
+/* KphfAcquireGuardedLock
+ *
+ * Acquires a guarded lock and raises the IRQL to APC_LEVEL.
+ *
+ * IRQL: <= APC_LEVEL
+ */
+VOID FASTCALL KphfAcquireGuardedLock(
+ __inout PKPH_GUARDED_LOCK Lock
+ )
+{
+ KIRQL oldIrql;
+
+ ASSERT(KeGetCurrentIrql() <= APC_LEVEL);
+
+ /* Raise to APC_LEVEL. */
+ oldIrql = KeRaiseIrql(APC_LEVEL, &oldIrql);
+
+ /* Acquire the spinlock. */
+ KphAcquireBitSpinLock(&Lock->Value, KPH_GUARDED_LOCK_ACTIVE_SHIFT);
+
+ /* Now that we have the lock, we must save the old IRQL. */
+ /* Clear the old IRQL. */
+ Lock->Value &= KPH_GUARDED_LOCK_FLAGS;
+ /* Set the new IRQL. */
+ Lock->Value |= oldIrql;
+}
+
+/* KphfReleaseGuardedLock
+ *
+ * Releases a guarded lock and restores the old IRQL.
+ *
+ * IRQL: >= APC_LEVEL
+ */
+VOID FASTCALL KphfReleaseGuardedLock(
+ __inout PKPH_GUARDED_LOCK Lock
+ )
+{
+ KIRQL oldIrql;
+
+ ASSERT(KeGetCurrentIrql() >= APC_LEVEL);
+
+ /* Get the old IRQL. */
+ oldIrql = (KIRQL)(Lock->Value & ~KPH_GUARDED_LOCK_FLAGS);
+ /* Unlock the spinlock. */
+ KphReleaseBitSpinLock(&Lock->Value, KPH_GUARDED_LOCK_ACTIVE_SHIFT);
+ /* Restore the old IRQL. */
+ KeLowerIrql(oldIrql);
+}
+
+/* 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.
+ *
+ * Comments:
+ * Here is how the processor lock works:
+ * 1. Tries to acquire the mutex in the processor lock, and
+ * blocks until it can be obtained.
+ * 2. Initializes a DPC for each processor on the computer.
+ * 3. Raises the IRQL to DISPATCH_LEVEL to make sure the
+ * code is not interrupted by a context switch.
+ * 4. Queues each of the previously-initialized DPCs, except if
+ * it is targeted at the current processor.
+ * 5. Since DPCs run at DISPATCH_LEVEL, they have exclusive
+ * control of the processor. As each runs, they increment
+ * a counter in the processor lock. They then enter a loop.
+ * 6. The routine waits for the counter to become n - 1,
+ * signaling that all (other) processors have been acquired
+ * (where n is the number of processors).
+ * 7. It returns. Any code from here will be running in
+ * DISPATCH_LEVEL and will be the only code running on the
+ * machine.
+ * Thread safety: Full
+ * IRQL: <= APC_LEVEL
+ */
+BOOLEAN KphAcquireProcessorLock(
+ __inout PKPH_PROCESSOR_LOCK ProcessorLock
+ )
+{
+ ULONG i;
+ ULONG numberProcessors;
+ ULONG currentProcessor;
+
+ /* Acquire the processor lock guarded lock. */
+ KphAcquireGuardedLock(&ProcessorLock->Lock);
+
+ /* Reset some state. */
+ ASSERT(ProcessorLock->AcquiredProcessors == 0);
+ ProcessorLock->AcquiredProcessors = 0;
+ ProcessorLock->ReleaseSignal = 0; /* IMPORTANT */
+
+ /* 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,
+ TAG_SYNC_DPC
+ );
+
+ if (!ProcessorLock->Dpcs)
+ {
+ dprintf("KphAcquireProcessorLock: Could not allocate storage for DPCs!\n");
+ KphReleaseGuardedLock(&ProcessorLock->Lock);
+ 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. */
+ KphSpinUntilEqual(&ProcessorLock->AcquiredProcessors, numberProcessors - 1);
+
+ 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(
+ __out PKPH_PROCESSOR_LOCK ProcessorLock
+ )
+{
+ KphInitializeGuardedLock(&ProcessorLock->Lock, FALSE);
+ 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.
+ *
+ * Comments:
+ * Here is how the processor lock is released:
+ * 1. Sets the signal to release the processors. The DPCs that are
+ * currently waiting for the signal will return and decrement
+ * the acquired processors counter.
+ * 2. Waits for the acquired processors counter to become zero.
+ * 3. Restores the old IRQL. This will always be APC_LEVEL due to
+ * the mutex.
+ * 4. Frees the storage allocated for the DPCs.
+ * 5. Releases the processor lock mutex. This will restore the IRQL
+ * back to normal.
+ * Thread safety: Full
+ * IRQL: DISPATCH_LEVEL
+ */
+VOID KphReleaseProcessorLock(
+ __inout 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. */
+ KphSpinUntilEqual(&ProcessorLock->AcquiredProcessors, 0);
+
+ 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, TAG_SYNC_DPC);
+ ProcessorLock->Dpcs = NULL;
+ }
+
+ ProcessorLock->Acquired = FALSE;
+
+ /* Release the processor lock guarded lock. This will restore the
+ * IRQL back to what it was before the processor lock was
+ * acquired.
+ */
+ KphReleaseGuardedLock(&ProcessorLock->Lock);
+}
+
+/* KphpCountBits
+ *
+ * Counts the number of bits set in an integer.
+ */
+ULONG KphpCountBits(
+ __in ULONG_PTR Number
+ )
+{
+ ULONG count = 0;
+
+ while (Number)
+ {
+ count++;
+ Number &= Number - 1;
+ }
+
+ return count;
+}
+
+/* KphpProcessorLockDpc
+ *
+ * The DPC routine which "locks" processors.
+ *
+ * Thread safety: Full
+ * IRQL: DISPATCH_LEVEL
+ */
+VOID KphpProcessorLockDpc(
+ __in PKDPC Dpc,
+ __in PVOID DeferredContext,
+ __in PVOID SystemArgument1,
+ __in 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. */
+ KphSpinUntilNotEqual(&processorLock->ReleaseSignal, 0);
+
+ /* Decrease the number of acquired processors. */
+ InterlockedDecrement(&processorLock->AcquiredProcessors);
+
+ dprintf("KphpProcessorLockDpc: Releasing processor %d.\n", KeGetCurrentProcessorNumber());
+}
diff --git a/2.x/trunk/KProcessHacker/sysservice.c b/2.x/trunk/KProcessHacker/sysservice.c
new file mode 100644
index 000000000..784706b4b
--- /dev/null
+++ b/2.x/trunk/KProcessHacker/sysservice.c
@@ -0,0 +1,2140 @@
+/*
+ * Process Hacker Driver -
+ * system service logging
+ *
+ * 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 .
+ */
+
+/* ================ IMPORTANT ================
+ * Please read the comments in KphpSsNewKiFastCallEntry to find out how
+ * KiFastCallEntry can be hooked.
+ *
+ * Note that the ONLY SUPPORTED METHOD of hooking is KiFastCallEntry,
+ * which means you MUST be using a CPU which supports sysenter.
+ * ===========================================
+ */
+
+#include "include/sysservicep.h"
+#include "include/hook.h"
+#include "include/sync.h"
+#include "include/trace.h"
+
+extern PDRIVER_OBJECT KphDriverObject;
+
+/* A fast mutex guarding starting/stopping system service logging. */
+FAST_MUTEX KphSsMutex;
+/* Whether system service logging has been initialized. */
+BOOLEAN KphSsInitialized = FALSE;
+/* The KiFastCallEntry hook. */
+KPH_HOOK KphSsKiFastCallEntryHook;
+/* The number of active loggers. */
+ULONG KphSsNumberOfActiveLoggers = 0;
+
+/* The object type for client entries. */
+PKPH_OBJECT_TYPE KphSsClientEntryType;
+/* The object type for ruleset entries. */
+PKPH_OBJECT_TYPE KphSsRuleSetEntryType;
+/* The object type for rule entries. */
+PKPH_OBJECT_TYPE KphSsRuleEntryType;
+
+/* The list of ruleset entries. */
+LIST_ENTRY KphSsRuleSetListHead;
+/* A push lock guarding accesses to the ruleset list. */
+EX_PUSH_LOCK KphSsRuleSetListPushLock;
+
+/* KphSsLogInit
+ *
+ * Initializes system service logging.
+ */
+NTSTATUS KphSsLogInit()
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ /* Initialize the system service call data. */
+ KphSsDataInit();
+
+ /* Initialize the ruleset list. */
+ InitializeListHead(&KphSsRuleSetListHead);
+ ExInitializeFastMutex(&KphSsMutex);
+ ExInitializePushLock(&KphSsRuleSetListPushLock);
+
+ /* Initialize the object types. */
+ status = KphCreateObjectType(
+ &KphSsClientEntryType,
+ NonPagedPool,
+ 0,
+ KphpSsClientEntryDeleteProcedure
+ );
+
+ if (!NT_SUCCESS(status))
+ return status;
+
+ status = KphCreateObjectType(
+ &KphSsRuleSetEntryType,
+ NonPagedPool,
+ 0,
+ KphpSsRuleSetEntryDeleteProcedure
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ KphDereferenceObject(KphSsClientEntryType);
+ return status;
+ }
+
+ status = KphCreateObjectType(
+ &KphSsRuleEntryType,
+ NonPagedPool,
+ 0,
+ NULL
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ KphDereferenceObject(KphSsClientEntryType);
+ KphDereferenceObject(KphSsRuleSetEntryType);
+ return status;
+ }
+
+ return status;
+}
+
+/* KphSsLogDeinit
+ *
+ * Frees system service logging data.
+ */
+NTSTATUS KphSsLogDeinit()
+{
+ KphSsDataDeinit();
+
+ return STATUS_SUCCESS;
+}
+
+/* KphSsLogStart
+ *
+ * Starts system service logging.
+ */
+NTSTATUS KphSsLogStart()
+{
+#ifdef _X86_
+ NTSTATUS status = STATUS_SUCCESS;
+
+ /* Make sure we have the KiFastCallEntry+x address. */
+ if (!__KiFastCallEntry)
+ return STATUS_NOT_SUPPORTED;
+
+ ExAcquireFastMutex(&KphSsMutex);
+
+ if (KphSsInitialized)
+ {
+ ExReleaseFastMutex(&KphSsMutex);
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ /* Hook KiFastCallEntry. Logging will start from now. */
+ KphInitializeHook(
+ &KphSsKiFastCallEntryHook,
+ __KiFastCallEntry,
+ KphpSsNewKiFastCallEntry
+ );
+ status = KphHook(&KphSsKiFastCallEntryHook);
+
+ if (!NT_SUCCESS(status))
+ {
+ ExReleaseFastMutex(&KphSsMutex);
+ return status;
+ }
+
+ KphSsInitialized = TRUE;
+
+ ExReleaseFastMutex(&KphSsMutex);
+
+ return status;
+#else
+ return STATUS_NOT_SUPPORTED;
+#endif
+}
+
+/* KphSsLogStop
+ *
+ * Stops system service logging.
+ */
+NTSTATUS KphSsLogStop()
+{
+#ifdef _X86_
+ NTSTATUS status = STATUS_SUCCESS;
+
+ ExAcquireFastMutex(&KphSsMutex);
+
+ if (!KphSsInitialized)
+ {
+ ExReleaseFastMutex(&KphSsMutex);
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ status = KphUnhook(&KphSsKiFastCallEntryHook);
+
+ if (!NT_SUCCESS(status))
+ {
+ ExReleaseFastMutex(&KphSsMutex);
+ return status;
+ }
+
+ /* Spin until the logger count reaches 0. */
+ KphSpinUntilEqual(&KphSsNumberOfActiveLoggers, 0);
+
+ KphSsInitialized = FALSE;
+
+ ExReleaseFastMutex(&KphSsMutex);
+
+ return status;
+#else
+ return STATUS_NOT_SUPPORTED;
+#endif
+}
+
+/* KphSsCreateClientEntry
+ *
+ * Creates a client entry which describes a client of the
+ * system service logger. Clients receive system service log events.
+ * Note that a client may have several ruleset entries associated
+ * with it.
+ *
+ * ClientEntry: A variable which receives a pointer to the client entry.
+ * ProcessHandle: A handle to the client process, with PROCESS_VM_WRITE
+ * access.
+ * ReadSemaphoreHandle: A handle to a semaphore which is released when an
+ * event is written to the client buffer. The client must wait for the
+ * semaphore when it is about to read a block.
+ * WriteSemaphoreHandle: A handle to a semaphore which is acquired when an
+ * event is about to be written to the client buffer. If the semaphore
+ * cannot be acquired immediately, the event is dropped. The client must
+ * continually read the buffer and release the semaphore.
+ * BufferBase: A pointer to a buffer in the client process.
+ * BufferSize: The size of the buffer, in bytes.
+ * AccessMode: The mode to use when probing arguments.
+ */
+NTSTATUS KphSsCreateClientEntry(
+ __out PKPHSS_CLIENT_ENTRY *ClientEntry,
+ __in HANDLE ProcessHandle,
+ __in HANDLE ReadSemaphoreHandle,
+ __in HANDLE WriteSemaphoreHandle,
+ __in PVOID BufferBase,
+ __in ULONG BufferSize,
+ __in KPROCESSOR_MODE AccessMode
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ PKPHSS_CLIENT_ENTRY clientEntry;
+ PEPROCESS processObject;
+ PKSEMAPHORE readSemaphore;
+ PKSEMAPHORE writeSemaphore;
+
+ /* Probe. */
+ if (AccessMode != KernelMode)
+ {
+ __try
+ {
+ ProbeForWrite(BufferBase, BufferSize, 1);
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ return GetExceptionCode();
+ }
+ }
+
+ /* Reference the client process. */
+ status = ObReferenceObjectByHandle(
+ ProcessHandle,
+ PROCESS_VM_WRITE,
+ *PsProcessType,
+ AccessMode,
+ &processObject,
+ NULL
+ );
+
+ if (!NT_SUCCESS(status))
+ return status;
+
+ /* Reference the read semaphore. */
+ status = ObReferenceObjectByHandle(
+ ReadSemaphoreHandle,
+ SEMAPHORE_MODIFY_STATE,
+ *ExSemaphoreObjectType,
+ AccessMode,
+ &readSemaphore,
+ NULL
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ ObDereferenceObject(processObject);
+ return status;
+ }
+
+ /* Reference the write semaphore. */
+ status = ObReferenceObjectByHandle(
+ WriteSemaphoreHandle,
+ SEMAPHORE_MODIFY_STATE,
+ *ExSemaphoreObjectType,
+ AccessMode,
+ &writeSemaphore,
+ NULL
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ ObDereferenceObject(processObject);
+ ObDereferenceObject(readSemaphore);
+ return status;
+ }
+
+ /* Create the client entry object. */
+ status = KphCreateObject(
+ &clientEntry,
+ sizeof(KPHSS_CLIENT_ENTRY),
+ 0,
+ KphSsClientEntryType,
+ 0
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ ObDereferenceObject(processObject);
+ ObDereferenceObject(readSemaphore);
+ ObDereferenceObject(writeSemaphore);
+
+ return status;
+ }
+
+ clientEntry->Process = processObject;
+ clientEntry->Enabled = TRUE;
+ clientEntry->ReadSemaphore = readSemaphore;
+ clientEntry->WriteSemaphore = writeSemaphore;
+ ExInitializeFastMutex(&clientEntry->BufferMutex);
+ clientEntry->BufferBase = BufferBase;
+ clientEntry->BufferSize = BufferSize;
+ clientEntry->BufferCursor = 0;
+ clientEntry->NumberOfBlocksWritten = 0;
+ clientEntry->NumberOfBlocksDropped = 0;
+
+ *ClientEntry = clientEntry;
+
+ return status;
+}
+
+/* KphSsEnableClientEntry
+ *
+ * Enables or disables a client entry.
+ */
+NTSTATUS KphSsEnableClientEntry(
+ __in PKPHSS_CLIENT_ENTRY ClientEntry,
+ __in BOOLEAN Enable
+ )
+{
+ if (Enable)
+ ClientEntry->Enabled = TRUE;
+ else
+ ClientEntry->Enabled = FALSE;
+
+ return STATUS_SUCCESS;
+}
+
+/* KphSsQueryClientEntry
+ *
+ * Queries information about a client entry.
+ */
+NTSTATUS KphSsQueryClientEntry(
+ __in PKPHSS_CLIENT_ENTRY ClientEntry,
+ __out_bcount_opt(ClientInformationLength) PKPHSS_CLIENT_INFORMATION ClientInformation,
+ __in ULONG ClientInformationLength,
+ __out_opt PULONG ReturnLength,
+ __in KPROCESSOR_MODE AccessMode
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ /* Probe the return length if necessary. */
+ if (AccessMode != KernelMode)
+ {
+ __try
+ {
+ ProbeForWrite(ReturnLength, sizeof(ULONG), 1);
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ return GetExceptionCode();
+ }
+ }
+
+ /* Check the length. */
+ if (ClientInformationLength >= sizeof(KPHSS_CLIENT_INFORMATION))
+ {
+ if (ClientInformation)
+ {
+ __try
+ {
+ /* Probe the buffer if we're not from kernel-mode. */
+ if (AccessMode != KernelMode)
+ ProbeForWrite(ClientInformation, sizeof(KPHSS_CLIENT_INFORMATION), 1);
+
+ ClientInformation->ProcessId = PsGetProcessId(ClientEntry->Process);
+ ClientInformation->BufferBase = ClientEntry->BufferBase;
+ ClientInformation->BufferSize = ClientEntry->BufferSize;
+ ClientInformation->NumberOfBlocksWritten = ClientEntry->NumberOfBlocksWritten;
+ ClientInformation->NumberOfBlocksDropped = ClientEntry->NumberOfBlocksDropped;
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ status = GetExceptionCode();
+ }
+ }
+ }
+ else
+ {
+ status = STATUS_BUFFER_TOO_SMALL;
+ }
+
+ /* Pass the return length back if requested. */
+ if (ReturnLength)
+ {
+ __try
+ {
+ *ReturnLength = sizeof(KPHSS_CLIENT_INFORMATION);
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ status = GetExceptionCode();
+ }
+ }
+
+ return status;
+}
+
+/* KphpSsClientEntryDeleteProcedure
+ *
+ * Performs cleanup for a client entry.
+ */
+VOID NTAPI KphpSsClientEntryDeleteProcedure(
+ __in PVOID Object,
+ __in ULONG Flags
+ )
+{
+ PKPHSS_CLIENT_ENTRY clientEntry = (PKPHSS_CLIENT_ENTRY)Object;
+
+ ObDereferenceObject(clientEntry->Process);
+ ObDereferenceObject(clientEntry->ReadSemaphore);
+ ObDereferenceObject(clientEntry->WriteSemaphore);
+}
+
+/* KphSsCreateRuleSetEntry
+ *
+ * Creates a ruleset entry which contains a list of rules
+ * and an action to perform.
+ */
+NTSTATUS KphSsCreateRuleSetEntry(
+ __out PKPHSS_RULESET_ENTRY *RuleSetEntry,
+ __in PKPHSS_CLIENT_ENTRY ClientEntry,
+ __in KPHSS_FILTER_TYPE DefaultFilterType,
+ __in KPHSS_RULESET_ACTION Action
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ PKPHSS_RULESET_ENTRY ruleSetEntry;
+
+ /* Make sure the action is valid. */
+ if (Action < LogRuleSetAction || Action >= MaxRuleSetAction)
+ return STATUS_INVALID_PARAMETER_3;
+
+ /* Create the ruleset object. */
+ status = KphCreateObject(
+ &ruleSetEntry,
+ sizeof(KPHSS_RULESET_ENTRY),
+ 0,
+ KphSsRuleSetEntryType,
+ 0
+ );
+
+ if (!NT_SUCCESS(status))
+ return status;
+
+ /* Initialize the ruleset object. */
+ KphReferenceObject(ClientEntry);
+ ruleSetEntry->Client = ClientEntry;
+ ruleSetEntry->DefaultFilterType = DefaultFilterType;
+ ruleSetEntry->Action = Action;
+ ruleSetEntry->NextRuleHandle = 4;
+ ExInitializePushLock(&ruleSetEntry->RuleListPushLock);
+ InitializeListHead(&ruleSetEntry->RuleListHead);
+
+ /* Add the ruleset to the list. */
+ KeEnterCriticalRegion();
+ ExAcquirePushLockExclusive(&KphSsRuleSetListPushLock);
+ InsertHeadList(&KphSsRuleSetListHead, &ruleSetEntry->RuleSetListEntry);
+ ExReleasePushLock(&KphSsRuleSetListPushLock);
+ KeLeaveCriticalRegion();
+
+ *RuleSetEntry = ruleSetEntry;
+
+ return status;
+}
+
+/* KphpSsRuleSetEntryDeleteProcedure
+ *
+ * Performs cleanup for a ruleset entry.
+ */
+VOID NTAPI KphpSsRuleSetEntryDeleteProcedure(
+ __in PVOID Object,
+ __in ULONG Flags
+ )
+{
+ PKPHSS_RULESET_ENTRY ruleSetEntry = (PKPHSS_RULESET_ENTRY)Object;
+ PLIST_ENTRY currentRuleListEntry;
+
+ /* Dereference the client entry. */
+ KphDereferenceObject(ruleSetEntry->Client);
+
+ KeEnterCriticalRegion();
+
+ /* Dereference all rules in the ruleset. */
+ ExAcquirePushLockExclusive(&ruleSetEntry->RuleListPushLock);
+
+ currentRuleListEntry = ruleSetEntry->RuleListHead.Flink;
+
+ while (currentRuleListEntry != &ruleSetEntry->RuleListHead)
+ {
+ PLIST_ENTRY nextEntry;
+
+ /* Save the next entry pointer since currentRuleListEntry may
+ * be deallocated due to the dereference.
+ */
+ nextEntry = currentRuleListEntry->Flink;
+ KphDereferenceObject(KPHSS_RULE_ENTRY(currentRuleListEntry));
+ currentRuleListEntry = nextEntry;
+ }
+
+ ExReleasePushLock(&ruleSetEntry->RuleListPushLock);
+
+ /* Remove the ruleset from the list. */
+ ExAcquirePushLockExclusive(&KphSsRuleSetListPushLock);
+ RemoveEntryList(&ruleSetEntry->RuleSetListEntry);
+ ExReleasePushLock(&KphSsRuleSetListPushLock);
+
+ KeLeaveCriticalRegion();
+}
+
+/* KphSsAddProcessIdRule
+ *
+ * Adds a process ID rule entry to a ruleset entry.
+ */
+NTSTATUS KphSsAddProcessIdRule(
+ __out PKPHSS_RULE_ENTRY *RuleEntry,
+ __in PKPHSS_RULESET_ENTRY RuleSetEntry,
+ __in KPHSS_FILTER_TYPE FilterType,
+ __in HANDLE ProcessId
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ PKPHSS_RULE_ENTRY ruleEntry;
+
+ /* Add the rule. */
+ status = KphpSsAddRule(&ruleEntry, RuleSetEntry, FilterType, ProcessIdRuleType);
+
+ if (!NT_SUCCESS(status))
+ return status;
+
+ ruleEntry->ProcessIdRule.ProcessId = ProcessId;
+ ruleEntry->Initialized = TRUE;
+
+ *RuleEntry = ruleEntry;
+
+ return status;
+}
+
+/* KphSsAddThreadIdRule
+ *
+ * Adds a thread ID rule entry to a ruleset entry.
+ */
+NTSTATUS KphSsAddThreadIdRule(
+ __out PKPHSS_RULE_ENTRY *RuleEntry,
+ __in PKPHSS_RULESET_ENTRY RuleSetEntry,
+ __in KPHSS_FILTER_TYPE FilterType,
+ __in HANDLE ThreadId
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ PKPHSS_RULE_ENTRY ruleEntry;
+
+ /* Add the rule. */
+ status = KphpSsAddRule(&ruleEntry, RuleSetEntry, FilterType, ThreadIdRuleType);
+
+ if (!NT_SUCCESS(status))
+ return status;
+
+ ruleEntry->ThreadIdRule.ThreadId = ThreadId;
+ ruleEntry->Initialized = TRUE;
+
+ *RuleEntry = ruleEntry;
+
+ return status;
+}
+
+/* KphSsAddPreviousModeRule
+ *
+ * Adds a previous mode rule entry to a ruleset entry.
+ */
+NTSTATUS KphSsAddPreviousModeRule(
+ __out PKPHSS_RULE_ENTRY *RuleEntry,
+ __in PKPHSS_RULESET_ENTRY RuleSetEntry,
+ __in KPHSS_FILTER_TYPE FilterType,
+ __in KPROCESSOR_MODE PreviousMode
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ PKPHSS_RULE_ENTRY ruleEntry;
+
+ /* Add the rule. */
+ status = KphpSsAddRule(&ruleEntry, RuleSetEntry, FilterType, PreviousModeRuleType);
+
+ if (!NT_SUCCESS(status))
+ return status;
+
+ ruleEntry->PreviousModeRule.PreviousMode = PreviousMode;
+ ruleEntry->Initialized = TRUE;
+
+ *RuleEntry = ruleEntry;
+
+ return status;
+}
+
+/* KphSsAddNumberRule
+ *
+ * Adds a system service number rule entry to a ruleset entry.
+ */
+NTSTATUS KphSsAddNumberRule(
+ __out PKPHSS_RULE_ENTRY *RuleEntry,
+ __in PKPHSS_RULESET_ENTRY RuleSetEntry,
+ __in KPHSS_FILTER_TYPE FilterType,
+ __in ULONG Number
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ PKPHSS_RULE_ENTRY ruleEntry;
+
+ /* Add the rule. */
+ status = KphpSsAddRule(&ruleEntry, RuleSetEntry, FilterType, NumberRuleType);
+
+ if (!NT_SUCCESS(status))
+ return status;
+
+ ruleEntry->NumberRule.Number = Number;
+ ruleEntry->Initialized = TRUE;
+
+ *RuleEntry = ruleEntry;
+
+ return status;
+}
+
+/* KphSsGetHandleRule
+ *
+ * Gets the handle of a rule.
+ */
+HANDLE KphSsGetHandleRule(
+ __in PKPHSS_RULE_ENTRY RuleEntry
+ )
+{
+ return RuleEntry->Handle;
+}
+
+/* KphSsRemoveRule
+ *
+ * Removes a rule entry from a ruleset entry.
+ */
+NTSTATUS KphSsRemoveRule(
+ __in PKPHSS_RULESET_ENTRY RuleSetEntry,
+ __in HANDLE RuleEntryHandle
+ )
+{
+ PLIST_ENTRY currentListEntry;
+
+ KeEnterCriticalRegion();
+ ExAcquirePushLockExclusive(&RuleSetEntry->RuleListPushLock);
+
+ /* Find the rule in the ruleset. */
+
+ currentListEntry = RuleSetEntry->RuleListHead.Flink;
+
+ while (currentListEntry != &RuleSetEntry->RuleListHead)
+ {
+ PKPHSS_RULE_ENTRY ruleEntry = KPHSS_RULE_ENTRY(currentListEntry);
+
+ if (ruleEntry->Handle == RuleEntryHandle)
+ {
+ /* Remove the rule from the list. */
+ RemoveEntryList(&ruleEntry->RuleListEntry);
+ /* Dereference the rule (it was referenced when it
+ * got added to the list).
+ */
+ KphDereferenceObject(ruleEntry);
+
+ ExReleasePushLock(&RuleSetEntry->RuleListPushLock);
+ KeLeaveCriticalRegion();
+
+ return STATUS_SUCCESS;
+ }
+
+ currentListEntry = currentListEntry->Flink;
+ }
+
+ ExReleasePushLock(&RuleSetEntry->RuleListPushLock);
+ KeLeaveCriticalRegion();
+
+ return STATUS_INVALID_PARAMETER_2;
+}
+
+/* KphpSsAddRule
+ *
+ * Adds a rule entry to a ruleset entry.
+ */
+NTSTATUS KphpSsAddRule(
+ __out PKPHSS_RULE_ENTRY *RuleEntry,
+ __in PKPHSS_RULESET_ENTRY RuleSetEntry,
+ __in KPHSS_FILTER_TYPE FilterType,
+ __in KPHSS_RULE_TYPE RuleType
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ PKPHSS_RULE_ENTRY ruleEntry;
+
+ /* Make sure the filter/rule type is valid. */
+ if (FilterType < IncludeFilterType || FilterType >= MaxFilterType)
+ return STATUS_INVALID_PARAMETER_3;
+ if (RuleType < ProcessIdRuleType || RuleType >= MaxRuleType)
+ return STATUS_INVALID_PARAMETER_4;
+
+ /* Create the rule entry object. */
+ status = KphCreateObject(
+ &ruleEntry,
+ sizeof(KPHSS_RULE_ENTRY),
+ 0,
+ KphSsRuleEntryType,
+ 0
+ );
+
+ if (!NT_SUCCESS(status))
+ return status;
+
+ /* Initialize the object. */
+ ruleEntry->Initialized = FALSE;
+ ruleEntry->FilterType = FilterType;
+ ruleEntry->RuleType = RuleType;
+
+ /* Get a handle for the rule. */
+ ruleEntry->Handle = (HANDLE)(ULONG_PTR)InterlockedExchangeAdd(
+ &RuleSetEntry->NextRuleHandle,
+ KPHSS_RULE_HANDLE_INCREMENT
+ );
+
+ /* Add the rule to the ruleset. */
+ KeEnterCriticalRegion();
+ ExAcquirePushLockExclusive(&RuleSetEntry->RuleListPushLock);
+ InsertTailList(&RuleSetEntry->RuleListHead, &ruleEntry->RuleListEntry);
+ ExReleasePushLock(&RuleSetEntry->RuleListPushLock);
+ KeLeaveCriticalRegion();
+ /* Add a reference for the rule being on the list. */
+ KphReferenceObject(ruleEntry);
+
+ *RuleEntry = ruleEntry;
+
+ return status;
+}
+
+/* KphpSsCreateEventBlock
+ *
+ * Allocates and initializes an event block.
+ *
+ * EventBlock: A variable which receives a pointer to the event block.
+ * Thread: The thread for which the event is being generated.
+ * Number: The system service number.
+ * Arguments: A pointer to the caller-supplied arguments.
+ * NumberOfArguments: The number of arguments, in ULONGs.
+ */
+NTSTATUS KphpSsCreateEventBlock(
+ __out PKPHSS_EVENT_BLOCK *EventBlock,
+ __in PKTHREAD Thread,
+ __in ULONG Number,
+ __in ULONG *Arguments,
+ __in ULONG NumberOfArguments
+ )
+{
+ PKPHSS_EVENT_BLOCK eventBlock;
+ KPROCESSOR_MODE previousMode;
+ ULONG eventBlockSize;
+ ULONG argumentsSize;
+ ULONG traceSize;
+ PVOID stackTrace[MAX_STACK_DEPTH * 2];
+ ULONG capturedFrames;
+
+ /* Make sure the argument count isn't too large. */
+ if (NumberOfArguments > MAX_USHORT)
+ return STATUS_INVALID_PARAMETER;
+
+ previousMode = ExGetPreviousMode();
+
+ /* Capture kernel-mode and user-mode stack traces.
+ * We do this before we allocate the event block so
+ * we can calculate how large the block should be.
+ */
+
+ /* Get a kernel-mode stack trace. */
+ capturedFrames = KphCaptureStackBackTrace(
+ 0,
+ MAX_STACK_DEPTH - 1,
+ 0,
+ stackTrace,
+ NULL
+ );
+
+ if (PsGetCurrentProcess() != PsInitialSystemProcess)
+ {
+ /* Get a user-mode stack trace. */
+ capturedFrames += KphCaptureStackBackTrace(
+ 0,
+ MAX_STACK_DEPTH - 1,
+ RTL_WALK_USER_MODE_STACK,
+ &stackTrace[capturedFrames],
+ NULL
+ );
+ }
+
+ /* Calculate the size of the event block. */
+ argumentsSize = NumberOfArguments * sizeof(ULONG);
+ traceSize = capturedFrames * sizeof(PVOID);
+ eventBlockSize = sizeof(KPHSS_EVENT_BLOCK) + argumentsSize + traceSize;
+
+ /* Make sure the block size isn't too large. */
+ if (eventBlockSize > MAX_USHORT)
+ return STATUS_INVALID_PARAMETER;
+
+ /* Allocate the event block. */
+ eventBlock = ExAllocatePoolWithTag(PagedPool, eventBlockSize, TAG_EVENT_BLOCK);
+
+ if (!eventBlock)
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ /* Initialize the event block. */
+ eventBlock->Header.Size = (USHORT)eventBlockSize;
+ eventBlock->Header.Type = EventBlockType;
+ eventBlock->Flags = 0;
+ KeQuerySystemTime(&eventBlock->Time);
+ eventBlock->ClientId.UniqueThread = PsGetThreadId(Thread);
+ eventBlock->ClientId.UniqueProcess = PsGetProcessId(IoThreadToProcess(Thread));
+ eventBlock->Number = Number;
+ eventBlock->NumberOfArguments = (USHORT)NumberOfArguments;
+ eventBlock->ArgumentsOffset = sizeof(KPHSS_EVENT_BLOCK);
+ eventBlock->TraceCount = (USHORT)capturedFrames;
+ eventBlock->TraceOffset = (USHORT)(sizeof(KPHSS_EVENT_BLOCK) + argumentsSize);
+
+ /* Set the flags according to the previous mode. */
+ if (previousMode == UserMode)
+ eventBlock->Flags |= KPHSS_EVENT_USER_MODE;
+ else if (previousMode == KernelMode)
+ eventBlock->Flags |= KPHSS_EVENT_KERNEL_MODE;
+
+ /* Probe and copy the arguments. */
+ if (previousMode != KernelMode)
+ {
+ __try
+ {
+ ProbeForRead(Arguments, argumentsSize, 4);
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ eventBlock->Flags |= KPHSS_EVENT_PROBE_ARGUMENTS_FAILED;
+ }
+ }
+
+ __try
+ {
+ /* Copy the arguments to the space immediately after the event block. */
+ memcpy((PCHAR)eventBlock + eventBlock->ArgumentsOffset, Arguments, argumentsSize);
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ eventBlock->Flags |= KPHSS_EVENT_COPY_ARGUMENTS_FAILED;
+ }
+
+ /* Copy the stack trace. */
+ memcpy((PCHAR)eventBlock + eventBlock->TraceOffset, stackTrace, traceSize);
+
+ /* Pass the pointer to the event block back. */
+ *EventBlock = eventBlock;
+
+ return STATUS_SUCCESS;
+}
+
+/* KphpSsFreeEventBlock
+ *
+ * Frees an event block created by KphpSsCreateEventBlock.
+ */
+VOID KphpSsFreeEventBlock(
+ __in PKPHSS_EVENT_BLOCK EventBlock
+ )
+{
+ ExFreePoolWithTag(EventBlock, TAG_EVENT_BLOCK);
+}
+
+/* KphpSsCaptureSimpleArgument
+ *
+ * Captures a simple (1-, 2-, 4- or 8-byte) argument.
+ */
+NTSTATUS KphpSsCaptureSimpleArgument(
+ __out PKPHSS_ARGUMENT_BLOCK *ArgumentBlock,
+ __in PVOID Argument,
+ __in KPHSS_ARGUMENT_TYPE Type,
+ __in KPROCESSOR_MODE PreviousMode
+ )
+{
+ PKPHSS_ARGUMENT_BLOCK argumentBlock;
+ ULONG size;
+ LARGE_INTEGER value;
+
+ /* Return if we have a NULL pointer. */
+ if (!Argument)
+ return STATUS_INVALID_PARAMETER_2;
+
+ /* Get the proper argument size based on the argument type. */
+ switch (Type)
+ {
+ case Int8Argument:
+ size = sizeof(BOOLEAN);
+ break;
+ case Int16Argument:
+ size = sizeof(SHORT);
+ break;
+ case Int32Argument:
+ size = sizeof(LONG);
+ break;
+ case Int64Argument:
+ size = sizeof(LARGE_INTEGER);
+ break;
+ default:
+ return STATUS_INVALID_PARAMETER_3;
+ }
+
+ /* Probe and read the value. */
+ __try
+ {
+ if (PreviousMode != KernelMode)
+ ProbeForRead(Argument, size, 1);
+
+ memcpy(&value, Argument, size);
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ return GetExceptionCode();
+ }
+
+ /* Allocate an argument block. */
+ argumentBlock = KphpSsAllocateArgumentBlock(size, Type);
+
+ if (!argumentBlock)
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ /* Copy the value into the argument block. */
+ memcpy(&argumentBlock->Simple, &value, size);
+ *ArgumentBlock = argumentBlock;
+
+ return STATUS_SUCCESS;
+}
+
+/* KphpSsCaptureHandleArgument
+ *
+ * Captures a handle argument.
+ */
+NTSTATUS KphpSsCaptureHandleArgument(
+ __out PKPHSS_ARGUMENT_BLOCK *ArgumentBlock,
+ __in HANDLE Argument,
+ __in KPROCESSOR_MODE PreviousMode
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ PKPHSS_ARGUMENT_BLOCK argumentBlock;
+ ULONG bufferLength;
+ PVOID object;
+ POBJECT_TYPE objectType;
+ PUNICODE_STRING objectTypeName;
+ PUNICODE_STRING objectNameInfo;
+ ULONG returnLength;
+ PKPHSS_HANDLE handleInfo;
+ PKPHSS_WSTRING wString;
+
+ /* Return if we have a NULL handle. */
+ if (!Argument)
+ return STATUS_INVALID_PARAMETER_2;
+
+ /* Make sure the handle isn't a kernel handle if we're
+ * from user-mode. We need exceptions for the process
+ * and thread pseudo-handles.
+ */
+ if (PreviousMode != KernelMode)
+ {
+ if (
+ IsKernelHandle(Argument) &&
+ Argument != NtCurrentProcess() &&
+ Argument != NtCurrentThread()
+ )
+ return STATUS_INVALID_HANDLE;
+ }
+
+ /* Reference the object. */
+ status = ObReferenceObjectByHandle(
+ Argument,
+ 0,
+ NULL,
+ KernelMode,
+ &object,
+ NULL
+ );
+
+ if (!NT_SUCCESS(status))
+ return status;
+
+ /* Get a pointer to the UNICODE_STRING containing the
+ * object type name.
+ */
+ objectType = KphGetObjectTypeNt(object);
+ objectTypeName = (PUNICODE_STRING)KVOFF(objectType, OffOtName);
+
+ /* Allocate a buffer for name information. */
+ objectNameInfo = (PUNICODE_STRING)ExAllocatePoolWithTag(
+ PagedPool,
+ CAPTURE_HANDLE_BUFFER_SIZE,
+ TAG_CAPTURE_TEMP_BUFFER
+ );
+
+ if (!objectNameInfo)
+ goto CleanupObject;
+
+ /* Query the name of the object. */
+ status = KphQueryNameObject(
+ object,
+ objectNameInfo,
+ CAPTURE_HANDLE_BUFFER_SIZE,
+ &returnLength
+ );
+
+ if (!NT_SUCCESS(status))
+ goto CleanupName;
+
+ /* Allocate an argument block. */
+ argumentBlock = KphpSsAllocateArgumentBlock(
+ sizeof(KPHSS_HANDLE) + sizeof(KPHSS_WSTRING) + sizeof(KPHSS_WSTRING) +
+ objectTypeName->Length + objectNameInfo->Length,
+ HandleArgument
+ );
+
+ if (!argumentBlock)
+ goto CleanupName;
+
+ handleInfo = &argumentBlock->Handle;
+ /* Calculate the offsets. */
+ handleInfo->TypeNameOffset = sizeof(KPHSS_HANDLE);
+ handleInfo->NameOffset =
+ handleInfo->TypeNameOffset + sizeof(KPHSS_WSTRING) +
+ objectTypeName->Length;
+
+ /* Copy the object type name into the block. */
+ wString = (PKPHSS_WSTRING)PTR_ADD_OFFSET(handleInfo, handleInfo->TypeNameOffset);
+ wString->Length = objectTypeName->Length;
+ memcpy(&wString->Buffer, objectTypeName->Buffer, wString->Length);
+
+ /* Copy the object name into the block. */
+ wString = (PKPHSS_WSTRING)PTR_ADD_OFFSET(handleInfo, handleInfo->NameOffset);
+ wString->Length = objectNameInfo->Length;
+ memcpy(&wString->Buffer, objectNameInfo->Buffer, wString->Length);
+
+ /* We may be able to get additional information for the
+ * object.
+ */
+
+ handleInfo->ClientId.UniqueProcess = NULL;
+ handleInfo->ClientId.UniqueThread = NULL;
+
+ if (objectType == *PsProcessType)
+ {
+ handleInfo->ClientId.UniqueProcess = PsGetProcessId((PEPROCESS)object);
+ }
+ else if (objectType == *PsThreadType)
+ {
+ handleInfo->ClientId.UniqueThread = PsGetThreadId((PETHREAD)object);
+ handleInfo->ClientId.UniqueProcess = PsGetProcessId(IoThreadToProcess((PETHREAD)object));
+ }
+
+ *ArgumentBlock = argumentBlock;
+
+CleanupName:
+ ExFreePoolWithTag(objectNameInfo, TAG_CAPTURE_TEMP_BUFFER);
+CleanupObject:
+ ObDereferenceObject(object);
+
+ return status;
+}
+
+/* KphpSsCaptureUnicodeStringArgument
+ *
+ * Captures a UNICODE_STRING argument.
+ */
+NTSTATUS KphpSsCaptureUnicodeStringArgument(
+ __out PKPHSS_ARGUMENT_BLOCK *ArgumentBlock,
+ __in PUNICODE_STRING Argument,
+ __in KPROCESSOR_MODE PreviousMode
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ PKPHSS_ARGUMENT_BLOCK argumentBlock;
+ UNICODE_STRING unicodeString;
+
+ /* Return if we have a NULL pointer. */
+ if (!Argument)
+ return STATUS_INVALID_PARAMETER_2;
+
+ /* Probe and copy the UNICODE_STRING structure. */
+ __try
+ {
+ if (PreviousMode != KernelMode)
+ ProbeForRead(Argument, sizeof(UNICODE_STRING), 1);
+
+ memcpy(&unicodeString, Argument, sizeof(UNICODE_STRING));
+
+ /* Probe the buffer, if present. */
+ if (unicodeString.Buffer && PreviousMode != KernelMode)
+ {
+ ProbeForRead(unicodeString.Buffer, unicodeString.Length, 1);
+ }
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ return GetExceptionCode();
+ }
+
+ /* Check if the string is too large. */
+ if (unicodeString.Length > CAPTURE_UNICODE_STRING_MAX_SIZE)
+ return STATUS_UNSUCCESSFUL;
+
+ /* Allocate an argument block. */
+ argumentBlock = KphpSsAllocateArgumentBlock(
+ sizeof(KPHSS_UNICODE_STRING) + unicodeString.Length,
+ UnicodeStringArgument
+ );
+
+ if (!argumentBlock)
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ /* Copy the string into the argument block. */
+ argumentBlock->UnicodeString.Length = unicodeString.Length;
+ argumentBlock->UnicodeString.MaximumLength = unicodeString.MaximumLength;
+ argumentBlock->UnicodeString.Pointer = unicodeString.Buffer;
+
+ if (unicodeString.Buffer)
+ {
+ __try
+ {
+ memcpy(argumentBlock->UnicodeString.Buffer, unicodeString.Buffer, unicodeString.Length);
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ KphpSsFreeArgumentBlock(argumentBlock);
+ return GetExceptionCode();
+ }
+ }
+
+ *ArgumentBlock = argumentBlock;
+
+ return status;
+}
+
+/* KphpSsCaptureObjectAttributesArgument
+ *
+ * Captures an OBJECT_ATTRIBUTES argument.
+ */
+NTSTATUS KphpSsCaptureObjectAttributesArgument(
+ __out PKPHSS_ARGUMENT_BLOCK *ArgumentBlock,
+ __in POBJECT_ATTRIBUTES Argument,
+ __in KPROCESSOR_MODE PreviousMode
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ PKPHSS_ARGUMENT_BLOCK argumentBlock;
+ OBJECT_ATTRIBUTES objectAttributes;
+ PKPHSS_ARGUMENT_BLOCK rootDirectoryArgumentBlock = NULL;
+ ULONG rootDirectoryArgumentBlockSize = 0;
+ PKPHSS_ARGUMENT_BLOCK objectNameArgumentBlock = NULL;
+ ULONG objectNameArgumentBlockSize = 0;
+
+ /* Return if we have a NULL pointer. */
+ if (!Argument)
+ return STATUS_INVALID_PARAMETER_2;
+
+ /* Probe and copy the OBJECT_ATTRIBUTES structure. */
+ __try
+ {
+ if (PreviousMode != KernelMode)
+ ProbeForRead(Argument, sizeof(OBJECT_ATTRIBUTES), 1);
+
+ memcpy(&objectAttributes, Argument, sizeof(OBJECT_ATTRIBUTES));
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ return GetExceptionCode();
+ }
+
+ /* If we have a root directory, create an argument block from it
+ * and copy it to our argument block.
+ */
+ if (objectAttributes.RootDirectory)
+ {
+ status = KphpSsCaptureHandleArgument(
+ &rootDirectoryArgumentBlock,
+ objectAttributes.RootDirectory,
+ PreviousMode
+ );
+
+ /* If we created the argument block, we need to calculate
+ * the size of the KPHSS_HANDLE structure.
+ */
+ if (NT_SUCCESS(status))
+ {
+ rootDirectoryArgumentBlockSize =
+ rootDirectoryArgumentBlock->Header.Size - KPHSS_ARGUMENT_BLOCK_OVERHEAD;
+ }
+ else
+ {
+ rootDirectoryArgumentBlock = NULL;
+ }
+ }
+
+ /* If we have a object name, create an argument block from it and
+ * copy it to our argument block.
+ */
+ if (objectAttributes.ObjectName)
+ {
+ status = KphpSsCaptureUnicodeStringArgument(
+ &objectNameArgumentBlock,
+ objectAttributes.ObjectName,
+ PreviousMode
+ );
+
+ /* If we created the argument block, we need to calculate
+ * the size of the KPHSS_UNICODE_STRING structure.
+ */
+ if (NT_SUCCESS(status))
+ {
+ objectNameArgumentBlockSize =
+ objectNameArgumentBlock->Header.Size - KPHSS_ARGUMENT_BLOCK_OVERHEAD;
+ }
+ else
+ {
+ objectNameArgumentBlock = NULL;
+ }
+ }
+
+ /* Allocate an argument block. */
+ argumentBlock = KphpSsAllocateArgumentBlock(
+ sizeof(KPHSS_OBJECT_ATTRIBUTES) + rootDirectoryArgumentBlockSize + objectNameArgumentBlockSize,
+ ObjectAttributesArgument
+ );
+
+ argumentBlock->ObjectAttributes.RootDirectoryOffset = 0;
+ argumentBlock->ObjectAttributes.ObjectNameOffset = 0;
+
+ /* Copy the object attributes fields. */
+ memcpy(
+ &argumentBlock->ObjectAttributes.ObjectAttributes,
+ &objectAttributes,
+ sizeof(OBJECT_ATTRIBUTES)
+ );
+
+ /* Copy the root directory structure, if we have one. */
+ if (rootDirectoryArgumentBlock)
+ {
+ ULONG rootDirectoryOffset;
+
+ /* It will go directly after the KPHSS_OBJECT_ATTRIBUTES structure. */
+ rootDirectoryOffset = sizeof(KPHSS_OBJECT_ATTRIBUTES);
+ argumentBlock->ObjectAttributes.RootDirectoryOffset = (USHORT)rootDirectoryOffset;
+ /* Copy it. */
+ memcpy(
+ PTR_ADD_OFFSET(&argumentBlock->ObjectAttributes, rootDirectoryOffset),
+ &rootDirectoryArgumentBlock->Handle,
+ rootDirectoryArgumentBlockSize
+ );
+ /* Free the block. */
+ KphpSsFreeArgumentBlock(rootDirectoryArgumentBlock);
+ }
+
+ /* Copy the object name structure, if we have one. */
+ if (objectNameArgumentBlock)
+ {
+ ULONG objectNameOffset;
+
+ /* We'll place the structure after the root directory structure,
+ * if present.
+ */
+ objectNameOffset = sizeof(KPHSS_OBJECT_ATTRIBUTES) + rootDirectoryArgumentBlockSize;
+
+ /* Make sure the offset isn't too large. */
+ if (objectNameOffset <= MAX_USHORT)
+ {
+ argumentBlock->ObjectAttributes.ObjectNameOffset = (USHORT)objectNameOffset;
+ /* Copy it. */
+ memcpy(
+ PTR_ADD_OFFSET(&argumentBlock->ObjectAttributes, objectNameOffset),
+ &objectNameArgumentBlock->UnicodeString,
+ objectNameArgumentBlockSize
+ );
+ }
+
+ /* Free the block. */
+ KphpSsFreeArgumentBlock(objectNameArgumentBlock);
+ }
+
+ *ArgumentBlock = argumentBlock;
+
+ return status;
+}
+
+/* KphpSsCaptureClientIdArgument
+ *
+ * Captures a CLIENT_ID argument.
+ */
+NTSTATUS KphpSsCaptureClientIdArgument(
+ __out PKPHSS_ARGUMENT_BLOCK *ArgumentBlock,
+ __in PCLIENT_ID Argument,
+ __in KPROCESSOR_MODE PreviousMode
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ CLIENT_ID clientId;
+ PKPHSS_ARGUMENT_BLOCK argumentBlock;
+
+ /* Check if we have a NULL pointer. */
+ if (!Argument)
+ return STATUS_INVALID_PARAMETER_2;
+
+ /* Probe and copy the CLIENT_ID structure. */
+ __try
+ {
+ if (PreviousMode != KernelMode)
+ ProbeForRead(Argument, sizeof(CLIENT_ID), 1);
+
+ memcpy(&clientId, Argument, sizeof(CLIENT_ID));
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ return GetExceptionCode();
+ }
+
+ /* Allocate an argument block. */
+ argumentBlock = KphpSsAllocateArgumentBlock(
+ sizeof(CLIENT_ID),
+ ClientIdArgument
+ );
+
+ if (!argumentBlock)
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ /* Fill in the argument block. */
+ memcpy(&argumentBlock->ClientId, &clientId, sizeof(CLIENT_ID));
+
+ *ArgumentBlock = argumentBlock;
+
+ return status;
+}
+
+/* KphpSsCaptureBytesArgument
+ *
+ * Captures a binary blob as an argument.
+ */
+NTSTATUS KphpSsCaptureBytesArgument(
+ __out PKPHSS_ARGUMENT_BLOCK *ArgumentBlock,
+ __in PVOID Argument,
+ __in ULONG Length,
+ __in KPROCESSOR_MODE PreviousMode
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ PKPHSS_ARGUMENT_BLOCK argumentBlock;
+
+ /* Check if we have a NULL pointer. */
+ if (!Argument)
+ return STATUS_INVALID_PARAMETER_2;
+
+ /* Make sure the length isn't too big. */
+ if (Length > CAPTURE_BYTES_MAX_SIZE)
+ return STATUS_INVALID_PARAMETER_3;
+
+ /* Probe the bytes. */
+ __try
+ {
+ if (PreviousMode != KernelMode)
+ ProbeForRead(Argument, Length, 1);
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ return GetExceptionCode();
+ }
+
+ /* Allocate an argument block. */
+ argumentBlock = KphpSsAllocateArgumentBlock(
+ sizeof(KPHSS_BYTES) + Length,
+ BytesArgument
+ );
+
+ if (!argumentBlock)
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ /* Copy the bytes. */
+ __try
+ {
+ memcpy(argumentBlock->Bytes.Buffer, Argument, Length);
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ KphpSsFreeArgumentBlock(argumentBlock);
+ return GetExceptionCode();
+ }
+
+ argumentBlock->Bytes.Length = (USHORT)Length;
+
+ *ArgumentBlock = argumentBlock;
+
+ return status;
+}
+
+/* KphpSsCreateArgumentBlock
+ *
+ * Allocates and initializes an argument block.
+ */
+NTSTATUS KphpSsCreateArgumentBlock(
+ __out PKPHSS_ARGUMENT_BLOCK *ArgumentBlock,
+ __in ULONG Number,
+ __in ULONG Argument,
+ __in ULONG Index,
+ __in_opt KPHSS_ARGUMENT_TYPE Type,
+ __in_opt PVOID Context
+ )
+{
+#ifdef _X86_
+ NTSTATUS status = STATUS_SUCCESS;
+ PKPHSS_ARGUMENT_BLOCK argumentBlock;
+ KPROCESSOR_MODE previousMode;
+ PKPHSS_CALL_ENTRY callEntry;
+ KPHSS_ARGUMENT_TYPE argumentType;
+
+ previousMode = ExGetPreviousMode();
+
+ /* Get a pointer to the call entry for the system service.
+ * If we don't have one, we can't proceed.
+ */
+ callEntry = KphSsLookupCallEntry(Number);
+
+ if (!callEntry)
+ return STATUS_INVALID_PARAMETER_2;
+
+ /* Validate the argument index. */
+ if (Index >= callEntry->NumberOfArguments)
+ return STATUS_INVALID_PARAMETER_3;
+
+ if (Type != 0)
+ argumentType = Type;
+ else
+ argumentType = callEntry->Arguments[Index];
+
+ /* Is this a normal argument? If so, there's no point
+ * creating an argument block since the data is already
+ * in the event block.
+ */
+ if (argumentType == NormalArgument)
+ return STATUS_UNSUCCESSFUL;
+
+ /* Capture the argument. */
+
+ switch (argumentType)
+ {
+ case Int8Argument:
+ case Int16Argument:
+ case Int32Argument:
+ case Int64Argument:
+ status = KphpSsCaptureSimpleArgument(
+ &argumentBlock,
+ (PVOID)Argument,
+ argumentType,
+ previousMode
+ );
+ break;
+ case HandleArgument:
+ status = KphpSsCaptureHandleArgument(
+ &argumentBlock,
+ (HANDLE)Argument,
+ previousMode
+ );
+ break;
+ case UnicodeStringArgument:
+ status = KphpSsCaptureUnicodeStringArgument(
+ &argumentBlock,
+ (PUNICODE_STRING)Argument,
+ previousMode
+ );
+ break;
+ case ObjectAttributesArgument:
+ status = KphpSsCaptureObjectAttributesArgument(
+ &argumentBlock,
+ (POBJECT_ATTRIBUTES)Argument,
+ previousMode
+ );
+ break;
+ case ClientIdArgument:
+ status = KphpSsCaptureClientIdArgument(
+ &argumentBlock,
+ (PCLIENT_ID)Argument,
+ previousMode
+ );
+ break;
+ case BytesArgument:
+ status = KphpSsCaptureBytesArgument(
+ &argumentBlock,
+ (PVOID)Argument,
+ (ULONG)Context,
+ previousMode
+ );
+ break;
+ default:
+ status = STATUS_NOT_IMPLEMENTED;
+ break;
+ }
+
+ if (!NT_SUCCESS(status))
+ return status;
+
+ /* Put the index in. */
+ argumentBlock->Index = (UCHAR)Index;
+
+ *ArgumentBlock = argumentBlock;
+
+ return status;
+#else
+ return STATUS_NOT_SUPPORTED;
+#endif
+}
+
+/* KphpSsAllocateArgumentBlock
+ *
+ * Allocates an argument block and initializes some fields.
+ */
+PKPHSS_ARGUMENT_BLOCK KphpSsAllocateArgumentBlock(
+ __in ULONG InnerSize,
+ __in KPHSS_ARGUMENT_TYPE Type
+ )
+{
+ PKPHSS_ARGUMENT_BLOCK argumentBlock;
+ ULONG size;
+
+ size = KPHSS_ARGUMENT_BLOCK_SIZE(InnerSize);
+
+ /* Make sure the size isn't too large. */
+ if (size > MAX_USHORT)
+ return NULL;
+
+ argumentBlock = ExAllocatePoolWithTag(
+ PagedPool,
+ size,
+ TAG_ARGUMENT_BLOCK
+ );
+
+ if (!argumentBlock)
+ return NULL;
+
+ argumentBlock->Header.Type = ArgumentBlockType;
+ argumentBlock->Header.Size = (USHORT)size;
+ argumentBlock->Type = Type;
+
+ return argumentBlock;
+}
+
+/* KphpSsFreeArgumentBlock
+ *
+ * Frees an argument block created by KphpSsCreateArgumentBlock.
+ */
+VOID KphpSsFreeArgumentBlock(
+ __in PKPHSS_ARGUMENT_BLOCK ArgumentBlock
+ )
+{
+ ExFreePoolWithTag(ArgumentBlock, TAG_ARGUMENT_BLOCK);
+}
+
+/* KphpSsWriteBlock
+ *
+ * Writes a block into client memory.
+ */
+NTSTATUS KphpSsWriteBlock(
+ __in PKPHSS_CLIENT_ENTRY ClientEntry,
+ __in_opt PKPHSS_BLOCK_HEADER Block,
+ __in KPHSS_SEQUENCE_MODE SequenceMode
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ LARGE_INTEGER zeroTimeout;
+ KPH_ATTACH_STATE attachState;
+ ULONG availableSpace;
+ HANDLE dupHandleInClient = NULL;
+
+ zeroTimeout.QuadPart = 0;
+
+ /* Take care of the sequence mode. If it isn't
+ * NoSequence, it is effectively a way for the caller
+ * to control the buffer mutex.
+ */
+ if (SequenceMode == StartSequence)
+ {
+ ExAcquireFastMutex(&ClientEntry->BufferMutex);
+ return STATUS_SUCCESS;
+ }
+ else if (SequenceMode == EndSequence)
+ {
+ ExReleaseFastMutex(&ClientEntry->BufferMutex);
+ return STATUS_SUCCESS;
+ }
+ else
+ {
+ /* If we aren't manipulating the mutex, we need
+ * a block to write.
+ */
+ if (!Block)
+ return STATUS_INVALID_PARAMETER_2;
+
+ /* If we're in a sequence, don't acquire the mutex
+ * because the caller would have acquired it using
+ * StartSequence already.
+ */
+ if (SequenceMode != InSequence)
+ ExAcquireFastMutex(&ClientEntry->BufferMutex);
+ }
+
+ /* Try to acquire the write semaphore. If we can't acquire
+ * it immediately, drop the block.
+ */
+ status = KeWaitForSingleObject(
+ ClientEntry->WriteSemaphore,
+ Executive,
+ KernelMode,
+ FALSE,
+ &zeroTimeout
+ );
+
+ if (!KPHSS_BLOCK_SUCCESS(status))
+ {
+ if (status == STATUS_TIMEOUT)
+ {
+ dprintf("Ss: WARNING: Dropped block (server %#x).\n", ClientEntry->BufferCursor);
+ ClientEntry->NumberOfBlocksDropped++;
+ }
+
+ goto CleanupBufferMutex;
+ }
+
+ availableSpace = ClientEntry->BufferSize - ClientEntry->BufferCursor;
+
+ /* Blocks are recorded in a circular buffer.
+ * In the case that there is not enough space for an entire block,
+ * we will record a reset block that tells the client to reset
+ * its read cursor to 0. In the case that there is not enough
+ * space for a block header, it is implied that the client will
+ * reset its read cursor.
+ */
+
+ /* Check if we have enough space for a block header. */
+ if (availableSpace < sizeof(KPHSS_BLOCK_HEADER))
+ {
+ /* Not enough space. Reset the cursor. */
+ dprintf("Ss: Implicit cursor reset (server %#x).\n", ClientEntry->BufferCursor);
+ ClientEntry->BufferCursor = 0;
+ availableSpace = ClientEntry->BufferSize;
+ }
+ /* Check if we have enough space for the block. */
+ else if (availableSpace < Block->Size)
+ {
+ KPHSS_RESET_BLOCK resetBlock;
+
+ /* Not enough space for the block, but enough space
+ * for a reset block. Write the reset block and reset
+ * the cursor.
+ */
+ resetBlock.Header.Size = sizeof(KPHSS_RESET_BLOCK);
+ resetBlock.Header.Type = ResetBlockType;
+
+ /* Attach to the client process and copy the block. */
+ KphAttachProcess(ClientEntry->Process, &attachState);
+
+ __try
+ {
+ memcpy(
+ PTR_ADD_OFFSET(ClientEntry->BufferBase, ClientEntry->BufferCursor),
+ &resetBlock,
+ resetBlock.Header.Size
+ );
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ KphDetachProcess(&attachState);
+ status = GetExceptionCode();
+ goto CleanupBufferMutex;
+ }
+
+ dprintf("Ss: Wrote reset block (server %#x).\n", ClientEntry->BufferCursor);
+ KphDetachProcess(&attachState);
+ ClientEntry->BufferCursor = 0;
+ availableSpace = ClientEntry->BufferSize;
+ }
+
+ /* Now that we have dealt with any end-of-buffer issues,
+ * we still have to check if we have enough space for the
+ * event. We may have a huge event or the client may have a
+ * tiny buffer.
+ */
+ if (availableSpace < Block->Size)
+ {
+ dfprintf("Ss: WARNING: Insufficient buffer size (server %#x).\n", ClientEntry->BufferCursor);
+ status = STATUS_BUFFER_TOO_SMALL;
+ goto CleanupBufferMutex;
+ }
+
+ /* Time to copy the block into the buffer.
+ */
+ KphAttachProcess(ClientEntry->Process, &attachState);
+
+ __try
+ {
+ memcpy(
+ PTR_ADD_OFFSET(ClientEntry->BufferBase, ClientEntry->BufferCursor),
+ Block,
+ Block->Size
+ );
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ dfprintf("Ss: ERROR: Could not write to the client buffer (server %#x)!\n", ClientEntry->BufferCursor);
+ KphDetachProcess(&attachState);
+ status = GetExceptionCode();
+ goto CleanupBufferMutex;
+ }
+
+ KphDetachProcess(&attachState);
+
+ /* Now that we have succesfully copied the block, we need to
+ * release the read semaphore to notify to the client that they have
+ * a block to read. We also need to advance our cursor.
+ */
+
+ /* May cause an exception (STATUS_SEMAPHORE_LIMIT_EXCEEDED). */
+ __try
+ {
+ KeReleaseSemaphore(ClientEntry->ReadSemaphore, 2, 1, FALSE);
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ dfprintf("Ss: ERROR: Could not release read semaphore (server %#x)!\n", ClientEntry->BufferCursor);
+ status = GetExceptionCode();
+ goto CleanupBufferMutex;
+ }
+
+ ClientEntry->BufferCursor += Block->Size;
+ ClientEntry->NumberOfBlocksWritten++;
+
+ dprintf("Ss: Wrote block (server %#x).\n", ClientEntry->BufferCursor);
+
+CleanupBufferMutex:
+ if (SequenceMode != InSequence)
+ ExReleaseFastMutex(&ClientEntry->BufferMutex);
+
+ return status;
+}
+
+/* KphpSsLogSystemServiceCall
+ *
+ * Logs a system service.
+ *
+ * WARNING: This function CANNOT make any system calls.
+ *
+ * IRQL: <= APC_LEVEL
+ */
+VOID NTAPI KphpSsLogSystemServiceCall(
+ __in ULONG Number,
+ __in ULONG *Arguments,
+ __in ULONG NumberOfArguments,
+ __in PKSERVICE_TABLE_DESCRIPTOR ServiceTable,
+ __in PKTHREAD Thread
+ )
+{
+#ifdef _X86_
+ NTSTATUS status = STATUS_SUCCESS;
+ KPROCESSOR_MODE previousMode;
+ PLIST_ENTRY currentListEntry;
+ PKPHSS_RULESET_ENTRY ruleSetEntryArray[KPHSS_RULESET_ENTRY_LIMIT];
+ ULONG ruleSetEntryCount;
+ PKPHSS_EVENT_BLOCK eventBlock;
+ PKPHSS_ARGUMENT_BLOCK argumentBlockArray[KPHSS_MAXIMUM_ARGUMENT_BLOCKS];
+ ULONG i, j;
+
+ previousMode = ExGetPreviousMode();
+ /* Ignore the Thread argument. Replace it with our own. */
+ Thread = KeGetCurrentThread();
+
+ /* First, some checks.
+ * * We can't operate at IRQL > APC_LEVEL because
+ * of restrictions on logging.
+ * * We can't operate on unknown service tables like the
+ * shadow service table (yet).
+ * * We have to make sure we aren't attempting to log
+ * a call to ZwContinue because we caused an exception
+ * last time we were logging something. This will cause
+ * a deadlock!
+ */
+
+ if (KeGetCurrentIrql() > APC_LEVEL)
+ return;
+ if (
+ ServiceTable->Base != __KeServiceDescriptorTable->Base ||
+ ServiceTable->Number != __KeServiceDescriptorTable->Number ||
+ ServiceTable->Limit != __KeServiceDescriptorTable->Limit
+ )
+ return;
+
+ /* Make sure we aren't logging ZwContinue if it's because
+ * we caused an exception somewhere. */
+ if (
+ ServiceTable->Base == __KeServiceDescriptorTable->Base &&
+ Number == SsNtContinue &&
+ NumberOfArguments == 2 &&
+ previousMode == KernelMode
+ )
+ {
+ /* "Reverse probe" the arguments. */
+ if (
+ (ULONG_PTR)Arguments > (ULONG_PTR)MmHighestUserAddress &&
+ Arguments[0] > (ULONG_PTR)MmHighestUserAddress
+ )
+ {
+ CONTEXT context;
+
+ /* The first argument contains the context. */
+ memcpy(&context, (PCONTEXT)Arguments[0], sizeof(CONTEXT));
+ /* Check if the context Eip points into the KPH module.
+ * If so, abort the logging.
+ */
+ if (
+ context.Eip >= (ULONG_PTR)KphDriverObject->DriverStart &&
+ context.Eip < (ULONG_PTR)KphDriverObject->DriverStart + KphDriverObject->DriverSize
+ )
+ return;
+ }
+ }
+
+ /* Build the ruleset entry array by going through the ruleset
+ * list, referencing each relevant one and copying them into
+ * the local array. This we way don't hold the lock for too
+ * long.
+ */
+
+ KeEnterCriticalRegion();
+ ExAcquirePushLockShared(&KphSsRuleSetListPushLock);
+
+ currentListEntry = KphSsRuleSetListHead.Flink;
+ ruleSetEntryCount = 0;
+
+ while (
+ currentListEntry != &KphSsRuleSetListHead &&
+ ruleSetEntryCount < KPHSS_RULESET_ENTRY_LIMIT
+ )
+ {
+ PKPHSS_RULESET_ENTRY ruleSetEntry = KPHSS_RULESET_ENTRY(currentListEntry);
+
+ if (KphpSsMatchRuleSetEntry(
+ ruleSetEntry,
+ Number,
+ Arguments,
+ NumberOfArguments,
+ ServiceTable,
+ Thread,
+ previousMode
+ ))
+ {
+ /* Reference and store the ruleset entry in the local array. */
+ if (KphReferenceObjectSafe(ruleSetEntry))
+ {
+ /* Make sure the client is enabled. */
+ if (ruleSetEntry->Client->Enabled)
+ {
+ ruleSetEntryArray[ruleSetEntryCount] = ruleSetEntry;
+ ruleSetEntryCount++;
+ }
+ else
+ {
+ /* We need to use defer delete here because we hold the
+ * ruleset list lock.
+ */
+ KphDereferenceObjectDeferDelete(ruleSetEntry);
+ }
+ }
+ }
+
+ currentListEntry = currentListEntry->Flink;
+ }
+
+ ExReleasePushLock(&KphSsRuleSetListPushLock);
+ KeLeaveCriticalRegion();
+
+ /* If we didn't find any ruleset entries, don't bother creating the
+ * event block.
+ */
+ if (ruleSetEntryCount == 0)
+ return;
+
+ /* We have work to do. Create an event block first. */
+ if (!NT_SUCCESS(KphpSsCreateEventBlock(
+ &eventBlock,
+ Thread,
+ Number,
+ Arguments,
+ NumberOfArguments
+ )))
+ {
+ dfprintf("Ss: ERROR: Unable to create an event block!\n");
+ return;
+ }
+
+ memset(argumentBlockArray, 0, sizeof(argumentBlockArray));
+
+ /* Process specific argument blocks. */
+ KphpSsProcessSpecificArguments(
+ argumentBlockArray,
+ Number,
+ Arguments,
+ NumberOfArguments,
+ previousMode
+ );
+
+ /* Create the (generic) argument blocks. If we fail to create one,
+ * set the array entry to NULL and we'll skip it later.
+ */
+
+ for (i = 0; i < NumberOfArguments && i < KPHSS_MAXIMUM_ARGUMENT_BLOCKS; i++)
+ {
+ ULONG argument;
+
+ /* If we already have a specific argument block already, skip this one. */
+ if (argumentBlockArray[i])
+ continue;
+
+ __try
+ {
+ /* We'll assume the arguments have already been probed
+ * since we created the event block successfully.
+ */
+ argument = Arguments[i];
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* Silently skip this argument. Even though it is 99% likely
+ * that we will fail to read the next argument, continue
+ * anyway.
+ */
+ argumentBlockArray[i] = NULL;
+ continue;
+ }
+
+ status = KphpSsCreateArgumentBlock(
+ &argumentBlockArray[i],
+ Number,
+ argument,
+ i,
+ 0,
+ NULL
+ );
+
+ if (!NT_SUCCESS(status))
+ argumentBlockArray[i] = NULL;
+ }
+
+ /* Go through the ruleset entry array and write the blocks to each
+ * client. While we're doing that we can also dereference each
+ * ruleset entry.
+ */
+ for (i = 0; i < ruleSetEntryCount; i++)
+ {
+ /* Begin a sequence. */
+ status = KphpSsWriteBlock(ruleSetEntryArray[i]->Client, NULL, StartSequence);
+
+ if (NT_SUCCESS(status))
+ {
+ /* Write the event block. */
+ KphpSsWriteBlock(ruleSetEntryArray[i]->Client, &eventBlock->Header, InSequence);
+
+ /* Write the argument blocks. */
+ for (j = 0; j < NumberOfArguments && j < KPHSS_MAXIMUM_ARGUMENT_BLOCKS; j++)
+ {
+ if (argumentBlockArray[j])
+ {
+ KphpSsWriteBlock(ruleSetEntryArray[i]->Client, &argumentBlockArray[j]->Header, InSequence);
+ }
+ }
+
+ /* End the sequence. */
+ KphpSsWriteBlock(ruleSetEntryArray[i]->Client, NULL, EndSequence);
+ }
+
+ KphDereferenceObject(ruleSetEntryArray[i]);
+ }
+
+ /* Free the event block. */
+ KphpSsFreeEventBlock(eventBlock);
+
+ /* Free the argument blocks. */
+ for (i = 0; i < NumberOfArguments && i < KPHSS_MAXIMUM_ARGUMENT_BLOCKS; i++)
+ {
+ if (argumentBlockArray[i])
+ KphpSsFreeArgumentBlock(argumentBlockArray[i]);
+ }
+#else
+ KeBugCheck(STATUS_NOT_SUPPORTED);
+#endif
+}
+
+#ifdef _X86_
+
+/* KphpSsNewKiFastCallEntry
+ *
+ * The hook function called from within the hooked KiFastCallEntry.
+ */
+__declspec(naked) VOID NTAPI KphpSsNewKiFastCallEntry()
+{
+ /* KiFastCallEntry handles system service calls. User-mode applications
+ * will perform system calls like this:
+ *
+ * Nt*:
+ * mov eax, SystemServiceNumber
+ * mov edx, 0x7ffe0300 <-- at 0x7ffe0300 we have a pointer to KiFastSystemCall
+ * call [edx]
+ * ret
+ *
+ * At KiFastSystemCall:
+ * mov edx, esp
+ * sysenter
+ */
+ /* This means that in KiFastCallEntry, eax will contain the system service
+ * number while edx will contain a pointer to the arguments for the system
+ * service. KiFastCallEntry will fill in edi with the service table, and
+ * esi will contain the caller KTHREAD.
+ *
+ * We cannot hook KiFastCallEntry from the beginning because it starts on the DPC
+ * stack. KiFastCallEntry switches to the proper thread stack, and we want to
+ * hook it just after it switches to the stack. That way we can avoid having to
+ * manually switch the thread stack ourselves.
+ *
+ * At this point:
+ * * eax contains the system service number.
+ * * edx contains a pointer to the user-supplied arguments for
+ * the system service.
+ * * edi contains a pointer to the service table associated with
+ * the system service number.
+ * * esi contains a pointer to the KTHREAD of the caller.
+ */
+ /* Some context:
+ *
+ * push edx
+ * push eax
+ * call [_KeGdiFlushUserBatch]
+ * pop eax
+ * pop edx
+ * inc dword ptr fs:[PbSystemCalls] <-- this gets overwritten with a jmp to here
+ * mov edi, edx
+ * mov ebx, [edi+...]
+ * ...
+ */
+ __asm
+ {
+ /* Save all registers first. */
+ push ebp
+ push edi
+ push esi
+ push edx
+ push ecx
+ push ebx
+ push eax
+
+ /* Since we overwrite the inc instruction when we did the hook,
+ * perform the job now - we have to increment the system calls
+ * counter.
+ */
+ lea ebx, KphSsKiFastCallEntryHook /* get a pointer to the hook structure */
+ mov ebx, dword ptr [ebx+KPH_HOOK.Bytes+3] /* get the PbSystemCalls offset from the original inc instruction */
+ inc dword ptr fs:[ebx] /* increment PbSystemCalls in the PRCB */
+
+ /* Get the number of arguments for this system service. */
+ mov ebx, dword ptr [edi+KSERVICE_TABLE_DESCRIPTOR.Number] /* ebx = a pointer to the argument table */
+ xor ecx, ecx
+ mov cl, [ebx+eax] /* ecx = size of the arguments, in bytes. */
+ shr ecx, 2 /* divide by 2 to get the number of arguments (all ULONGs) */
+
+ /* Call the KiFastCallEntry proc while maintaining the logger count
+ * so that the driver doesn't get unloaded while we're executing.
+ */
+ push esi /* Thread */
+ push edi /* ServiceTable */
+ push ecx /* NumberOfArguments */
+ push edx /* Arguments */
+ push eax /* Number */
+ lock inc dword ptr KphSsNumberOfActiveLoggers
+ call KphpSsLogSystemServiceCall
+ lock dec dword ptr KphSsNumberOfActiveLoggers
+
+ /* Restore the registers and resume execution in KiFastCallEntry. */
+ pop eax
+ pop ebx
+ pop ecx
+ pop edx
+ pop esi
+ pop edi
+ pop ebp
+
+ /* Luckily, KiFastCallEntry will overwrite ebx when we jump back, so it's safe to use it. */
+ lea ebx, __KiFastCallEntry
+ mov ebx, [ebx] /* ebx = KiFastCallEntry at the inc instruction */
+ add ebx, 7 /* skip the inc instruction */
+ jmp ebx /* jump back */
+ }
+}
+
+#else
+
+VOID NTAPI KphpSsNewKiFastCallEntry()
+{
+ KeBugCheck(STATUS_NOT_SUPPORTED);
+}
+
+#endif
diff --git a/2.x/trunk/KProcessHacker/sysservicedata.c b/2.x/trunk/KProcessHacker/sysservicedata.c
new file mode 100644
index 000000000..c30c36917
--- /dev/null
+++ b/2.x/trunk/KProcessHacker/sysservicedata.c
@@ -0,0 +1,513 @@
+/*
+ * Process Hacker Driver -
+ * system service logging (data)
+ *
+ * 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 .
+ */
+
+#define _SYSSERVICEDATA_PRIVATE
+#include "include/sysservicedata.h"
+
+PVOID KphpSsCallEntryAllocateRoutine(
+ __in PRTL_GENERIC_TABLE Table,
+ __in CLONG ByteSize
+ );
+
+RTL_GENERIC_COMPARE_RESULTS KphpSsCallEntryCompareRoutine(
+ __in PRTL_GENERIC_TABLE Table,
+ __in PVOID FirstStruct,
+ __in PVOID SecondStruct
+ );
+
+VOID KphpSsCallEntryFreeRoutine(
+ __in PRTL_GENERIC_TABLE Table,
+ __in PVOID Buffer
+ );
+
+KPHSS_CALL_ENTRY SsEntries[] =
+{
+ /* NTSTATUS NtAddAtom(PWSTR String, ULONG StringLength, PUSHORT Atom) */
+ { &SsNtAddAtom, "NtAddAtom", 3, { WStringArgument, 0, Int16Argument } },
+ /* NTSTATUS NtAlertResumeThread(HANDLE ThreadHandle, PULONG PreviousSuspendCount) */
+ { &SsNtAlertResumeThread, "NtAlertResumeThread", 2, { HandleArgument, 0 } },
+ /* NTSTATUS NtAlertThread(HANDLE ThreadHandle) */
+ { &SsNtAlertThread, "NtAlertThread", 1, { HandleArgument } },
+ /* NTSTATUS NtAllocateLocallyUniqueId(PLUID Luid) */
+ { &SsNtAllocateLocallyUniqueId, "NtAllocateLocallyUniqueId", 1, { 0 } },
+ /* NTSTATUS NtAllocateUserPhysicalPages(HANDLE ProcessHandle, PULONG NumberOfPages, PULONG PageFrameNumbers) */
+ { &SsNtAllocateUserPhysicalPages, "NtAllocateUserPhysicalPages", 3, { HandleArgument, Int32Argument, 0 } },
+ /* NTSTATUS NtAllocateUuids(PLARGE_INTEGER UuidLastTimeAllocated, PULONG UuidDeltaTime, PULONG UuidSequenceNumber,
+ * PUCHAR UuidSeed) */
+ { &SsNtAllocateUuids, "NtAllocateUuids", 4, { Int64Argument, 0, 0, 0 } },
+ /* NTSTATUS NtAllocateVirtualMemory(HANDLE ProcessHandle, PVOID *BaseAddress, ULONG ZeroBits,
+ * PULONG AllocationSize, ULONG AllocationType, ULONG Protect) */
+ { &SsNtAllocateVirtualMemory, "NtAllocateVirtualMemory", 6, { HandleArgument, Int32Argument, 0, Int32Argument, 0, 0 } },
+ /* NTSTATUS NtApphelpCacheControl(APPHELPCACHECONTROL ApphelpCacheControl, PUNICODE_STRING ApphelpCacheObject) */
+ { &SsNtApphelpCacheControl, "NtApphelpCacheControl", 2, { 0, UnicodeStringArgument } },
+ /* NTSTATUS NtAreMappedFilesTheSame(PVOID Address1, PVOID Address2) */
+ { &SsNtAreMappedFilesTheSame, "NtAreMappedFilesTheSame", 2, { 0, 0 } },
+ /* NTSTATUS NtAssignProcessToJobObject(HANDLE JobHandle, HANDLE ProcessHandle) */
+ { &SsNtAssignProcessToJobObject, "NtAssignProcessToJobObject", 2, { HandleArgument, HandleArgument } },
+ /* NTSTATUS NtCallbackReturn(PVOID Result, ULONG ResultLength, NTSTATUS Status) */
+ { &SsNtCallbackReturn, "NtCallbackReturn", 3, { 0, 0, 0 } },
+ /* NTSTATUS NtCancelDeviceWakeupRequest(HANDLE DeviceHandle) */
+ { &SsNtCancelDeviceWakeupRequest, "NtCancelDeviceWakeupRequest", 1, { HandleArgument } },
+ /* NTSTATUS NtCancelIoFile(HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock) */
+ { &SsNtCancelIoFile, "NtCancelIoFile", 2, { HandleArgument, 0 } },
+ /* NTSTATUS NtCancelTimer(HANDLE TimerHandle, PBOOLEAN CurrentState) */
+ { &SsNtCancelTimer, "NtCancelTimer", 2, { HandleArgument, 0 } },
+ /* NTSTATUS NtClearEvent(HANDLE EventHandle) */
+ { &SsNtClearEvent, "NtClearEvent", 1, { HandleArgument } },
+ /* NTSTATUS NtClose(HANDLE Handle) */
+ { &SsNtClose, "NtClose", 1, { HandleArgument } },
+ /* NTSTATUS NtContinue(PCONTEXT Context, BOOLEAN TestAlert) */
+ { &SsNtContinue, "NtContinue", 2, { ContextArgument, 0 } },
+ /* NTSTATUS NtCreateDebugObject(PHANDLE DebugObjectHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes,
+ * ULONG Flags) */
+ { &SsNtCreateDebugObject, "NtCreateDebugObject", 4, { 0, 0, ObjectAttributesArgument, 0 } },
+ /* NTSTATUS NtCreateDirectoryObject(PHANDLE DirectoryHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes) */
+ { &SsNtCreateDirectoryObject, "NtCreateDirectoryObject", 3, { 0, 0, ObjectAttributesArgument } },
+ /* NTSTATUS NtCreateEvent(PHANDLE EventHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes,
+ * EVENT_TYPE EventType, BOOLEAN InitialState) */
+ { &SsNtCreateEvent, "NtCreateEvent", 5, { 0, 0, ObjectAttributesArgument, 0, 0 } },
+ /* NTSTATUS NtCreateEventPair(PHANDLE EventPairHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes) */
+ { &SsNtCreateEventPair, "NtCreateEventPair", 3, { 0, 0, ObjectAttributesArgument } },
+ /* NTSTATUS NtCreateFile(PHANDLE FileHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes,
+ * PIO_STATUS_BLOCK IoStatusBlock, PLARGE_INTEGER AllocationSize, ULONG FileAttributes,
+ * ULONG ShareAccess, ULONG CreateDisposition, ULONG CreateOptions,
+ * PVOID EaBuffer, ULONG EaLength) */
+ { &SsNtCreateFile, "NtCreateFile", 11, { 0, 0, ObjectAttributesArgument, 0, Int64Argument, 0, 0, 0, 0, 0, 0 } },
+ /* NTSTATUS NtCreateIoCompletion(PHANDLE IoCompletionHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes,
+ * ULONG NumberOfConcurrentThreads) */
+ { &SsNtCreateIoCompletion, "NtCreateIoCompletion", 4, { 0, 0, ObjectAttributesArgument, 0 } },
+ /* NTSTATUS NtCreateJobObject(PHANDLE JobHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes) */
+ { &SsNtCreateJobObject, "NtCreateJobObject", 3, { 0, 0, ObjectAttributesArgument } },
+ /* NTSTATUS NtCreateJobSet(ULONG NumJob, IN PJOB_SET_ARRAY UserJobSet, IN ULONG Flags) */
+ { &SsNtCreateJobSet, "NtCreateJobSet", 3, { 0, 0, 0 } },
+ /* NTSTATUS NtCreateKey(PHANDLE KeyHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes,
+ * ULONG TitleIndex, PUNICODE_STRING Class, ULONG CreateOptions,
+ * PULONG Disposition) */
+ { &SsNtCreateKey, "NtCreateKey", 7, { 0, 0, ObjectAttributesArgument, 0, UnicodeStringArgument, 0, 0 } },
+ /* NTSTATUS NtCreateKeyedEvent(PHANDLE KeyedEventHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes,
+ * ULONG Flags) */
+ { &SsNtCreateKeyedEvent, "NtCreateKeyedEvent", 4, { 0, 0, ObjectAttributesArgument, 0 } },
+ /* NTSTATUS NtCreateMailslotFile(PHANDLE FileHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes,
+ * PIO_STATUS_BLOCK IoStatusBlock, ULONG CreateOptions, ULONG MailslotQuota,
+ * ULONG MaximumMessageSize, PLARGE_INTEGER ReadTimeout) */
+ { &SsNtCreateMailslotFile, "NtCreateMailslotFile", 8, { 0, 0, ObjectAttributesArgument, 0, 0, 0, 0, Int64Argument } },
+ /* NTSTATUS NtCreateMutant(PHANDLE MutantHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes,
+ * BOOLEAN InitialOwner) */
+ { &SsNtCreateMutant, "NtCreateMutant", 4, { 0, 0, ObjectAttributesArgument, 0 } },
+ /* NTSTATUS NtCreateNamedPipeFile(PHANDLE FileHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes,
+ * PIO_STATUS_BLOCK IoStatusBlock, ULONG ShareAccess, ULONG CreateDisposition,
+ * ULONG CreateOptions, BOOLEAN TypeMessage, BOOLEAN ReadmodeMessage,
+ * BOOLEAN Nonblocking, ULONG MaxInstances, ULONG InBufferSize,
+ * ULONG OutBufferSize, PLARGE_INTEGER DefaultTimeout) */
+ { &SsNtCreateNamedPipeFile, "NtCreateNamedPipeFile", 14, { 0, 0, ObjectAttributesArgument, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Int64Argument } },
+ /* NTSTATUS NtCreatePagingFile(PUNICODE_STRING FileName, PULARGE_INTEGER MinimumSize, PULARGE_INTEGER MaximumSize,
+ * ULONG Priority) */
+ { &SsNtCreatePagingFile, "NtCreatePagingFile", 4, { UnicodeStringArgument, Int64Argument, Int64Argument, 0 } },
+ /* NTSTATUS NtCreatePort(PHANDLE PortHandle, POBJECT_ATTRIBUTES ObjectAttributes, ULONG MaxConnectionInfoLength,
+ * ULONG MaxMessageLength, ULONG MaxPoolUsage) */
+ { &SsNtCreatePort, "NtCreatePort", 5, { 0, ObjectAttributesArgument, 0, 0, 0 } },
+ /* NTSTATUS NtCreatePrivateNamespace(PHANDLE PrivateNamespaceHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes,
+ * PBOUNDARY_DESCRIPTOR BoundaryDescriptor) */
+ { &SsNtCreatePrivateNamespace, "NtCreatePrivateNamespace", 4, { 0, 0, ObjectAttributesArgument, 0 } },
+ /* NTSTATUS NtCreateProcess(PHANDLE ProcessHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes,
+ * HANDLE InheritFromProcessHandle, BOOLEAN InheritHandles, HANDLE SectionHandle,
+ * HANDLE DebugPort, HANDLE ExceptionPort) */
+ { &SsNtCreateProcess, "NtCreateProcess", 8, { 0, 0, ObjectAttributesArgument, HandleArgument, 0, HandleArgument, HandleArgument, HandleArgument } },
+ /* NTSTATUS NtCreateProcessEx(PHANDLE ProcessHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes,
+ * HANDLE ParentProcess, ULONG Flags, HANDLE SectionHandle,
+ * HANDLE DebugPort, HANDLE ExceptionPort, ULONG JobMemberLevel */
+ { &SsNtCreateProcessEx, "NtCreateProcessEx", 9, { 0, 0, ObjectAttributesArgument, HandleArgument, 0, HandleArgument, HandleArgument, HandleArgument, 0 } },
+ /* NTSTATUS NtCreateProfile(PHANDLE ProfileHandle, HANDLE ProcessHandle, PVOID Base,
+ * ULONG Size, ULONG BucketShift, PULONG Buffer,
+ * ULONG BufferLength, KPROFILE_SOURCE Source, ULONG ProcessorMask) */
+ { &SsNtCreateProfile, "NtCreateProfile", 9, { 0, HandleArgument, 0, 0, 0, 0, 0, 0, 0 } },
+ /* NTSTATUS NtCreateSection(PHANDLE SectionHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes,
+ * PLARGE_INTEGER SectionSize, ULONG Protect, ULONG Attributes,
+ * HANDLE FileHandle) */
+ { &SsNtCreateSection, "NtCreateSection", 7, { 0, 0, ObjectAttributesArgument, Int64Argument, 0, 0, HandleArgument } },
+ /* NTSTATUS NtCreateSemaphore(PHANDLE SemaphoreHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes,
+ * LONG InitialCount, LONG MaximumCount) */
+ { &SsNtCreateSemaphore, "NtCreateSemaphore", 5, { 0, 0, ObjectAttributesArgument, 0, 0 } },
+ /* NTSTATUS NtCreateSymbolicLinkObject(PHANDLE SymbolicLinkHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes,
+ * PUNICODE_STRING TargetName) */
+ { &SsNtCreateSymbolicLinkObject, "NtCreateSymbolicLinkObject", 4, { 0, 0, ObjectAttributesArgument, UnicodeStringArgument } },
+ /* NTSTATUS NtCreateThread(PHANDLE ThreadHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes,
+ * HANDLE ProcessHandle, PCLIENT_ID ClientId, PCONTEXT ThreadContext,
+ * PINITIAL_TEB UserStack, BOOLEAN CreateSuspended) */
+ { &SsNtCreateThread, "NtCreateThread", 8, { 0, 0, ObjectAttributesArgument, HandleArgument, 0, ContextArgument, InitialTebArgument, 0 } },
+ /* NTSTATUS NtCreateTimer(PHANDLE TimerHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes,
+ * TIMER_TYPE TimerType) */
+ { &SsNtCreateTimer, "NtCreateTimer", 4, { 0, 0, ObjectAttributesArgument, 0 } },
+ /* NTSTATUS NtCreateToken(PHANDLE TokenHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes,
+ * TOKEN_TYPE Type, PLUID AuthenticationId, PLARGE_INTEGER ExpirationTime,
+ * PTOKEN_USER User, PTOKEN_GROUPS Groups, PTOKEN_PRIVILEGES Privileges,
+ * PTOKEN_OWNER Owner, PTOKEN_PRIMARY_GROUP PrimaryGroup, PTOKEN_DEFAULT_DACL DefaultDacl,
+ * PTOKEN_SOURCE Source) */
+ { &SsNtCreateToken, "NtCreateToken", 13, { 0, 0, ObjectAttributesArgument, 0, Int64Argument, Int64Argument, 0, 0, 0, 0, 0, 0, 0 } },
+ /* NTSTATUS NtCreateWaitablePort(PHANDLE PortHandle, POBJECT_ATTRIBUTES ObjectAttributes, ULONG MaxConnectionInfoLength,
+ * ULONG MaxMessageLength, ULONG MaxPoolUsage) */
+ { &SsNtCreateWaitablePort, "NtCreateWaitablePort", 5, { 0, ObjectAttributesArgument, 0, 0, 0 } },
+ /* NTSTATUS NtDebugActiveProcess(HANDLE ProcessHandle, HANDLE DebugObjectHandle) */
+ { &SsNtDebugActiveProcess, "NtDebugActiveProcess", 2, { HandleArgument, HandleArgument } },
+ /* NTSTATUS NtDebugContinue(HANDLE DebugObjectHandle, PCLIENT_ID ClientId, NTSTATUS ContinueStatus) */
+ { &SsNtDebugContinue, "NtDebugContinue", 3, { HandleArgument, ClientIdArgument, 0 } },
+ /* NTSTATUS NtDelayExecution(BOOLEAN Alertable, PLARGE_INTEGER Interval) */
+ { &SsNtDelayExecution, "NtDelayExecution", 2, { 0, Int64Argument } },
+ /* NTSTATUS NtDeleteAtom(USHORT Atom) */
+ { &SsNtDeleteAtom, "NtDeleteAtom", 1, { 0 } },
+ /* NTSTATUS NtDeleteBootEntry(ULONG Id) */
+ { &SsNtDeleteBootEntry, "NtDeleteBootEntry", 1, { 0 } },
+ /* NTSTATUS NtDeleteDriverEntry(ULONG Id) */
+ { &SsNtDeleteDriverEntry, "NtDeleteDriverEntry", 1, { 0 } },
+ /* NTSTATUS NtDeleteFile(POBJECT_ATTRIBUTES ObjectAttributes) */
+ { &SsNtDeleteFile, "NtDeleteFile", 1, { ObjectAttributesArgument } },
+ /* NTSTATUS NtDeleteKey(HANDLE KeyHandle) */
+ { &SsNtDeleteKey, "NtDeleteKey", 1, { HandleArgument } },
+ /* NTSTATUS NtDeleteObjectAuditAlarm(PUNICODE_STRING SubsystemName, PVOID HandleId, BOOLEAN GenerateOnClose) */
+ { &SsNtDeleteObjectAuditAlarm, "NtDeleteObjectAuditAlarm", 3, { UnicodeStringArgument, 0, 0 } },
+ /* NTSTATUS NtDeletePrivateNamespace(HANDLE PrivateNamespaceHandle) */
+ { &SsNtDeletePrivateNamespace, "NtDeletePrivateNamespace", 1, { HandleArgument } },
+ /* NTSTATUS NtDeleteValueKey(HANDLE KeyHandle, PUNICODE_STRING ValueName) */
+ { &SsNtDeleteValueKey, "NtDeleteValueKey", 2, { HandleArgument, UnicodeStringArgument } },
+ /* NTSTATUS NtDeviceIoControlFile(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine,
+ * PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, ULONG IoControlCode,
+ * PVOID InputBuffer, ULONG InputBufferLength, PVOID OutputBuffer,
+ * ULONG OutputBufferLength) */
+ { &SsNtDeviceIoControlFile, "NtDeviceIoControlFile", 10, { HandleArgument, HandleArgument, 0, 0, 0, 0, 0, 0, 0, 0 } },
+ /* NTSTATUS NtDisplayString(PUNICODE_STRING String) */
+ { &SsNtDisplayString, "NtDisplayString", 1, { UnicodeStringArgument } },
+ /* NTSTATUS NtDuplicateObject(HANDLE SourceProcessHandle, HANDLE SourceHandle, HANDLE TargetProcessHandle,
+ * PHANDLE TargetHandle, ACCESS_MASK DesiredAccess, ULONG Attributes,
+ * ULONG Options) */
+ { &SsNtDuplicateObject, "NtDuplicateObject", 7, { HandleArgument, HandleArgument, HandleArgument, 0, 0, 0, 0 } },
+ /* NTSTATUS NtDuplicateToken(HANDLE ExistingTokenHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes,
+ * BOOLEAN EffectiveOnly, TOKEN_TYPE TokenType, PHANDLE NewTokenHandle) */
+ { &SsNtDuplicateToken, "NtDuplicateToken", 6, { HandleArgument, 0, ObjectAttributesArgument, 0, 0, 0 } },
+ /* NTSTATUS NtEnumerateBootEntries(PVOID Buffer, PULONG BufferLength) */
+ { &SsNtEnumerateBootEntries, "NtEnumerateBootEntries", 2, { 0, Int32Argument } },
+ /* NTSTATUS NtEnumerateDriverEntries(PVOID Buffer, PULONG BufferLength) */
+ { &SsNtEnumerateDriverEntries, "NtEnumerateDriverEntries", 2, { 0, Int32Argument } },
+ /* NTSTATUS NtEnumerateKey(HANDLE KeyHandle, ULONG Index, KEY_INFORMATION_CLASS KeyInformationClass,
+ * PVOID KeyInformation, ULONG KeyInformationLength, PULONG ResultLength) */
+ { &SsNtEnumerateKey, "NtEnumerateKey", 6, { HandleArgument, 0, 0, 0, 0, 0 } },
+ /* NTSTATUS NtEnumerateSystemEnvironmentValuesEx(ULONG InformationClass, PVOID Buffer, PULONG BufferLength) */
+ { &SsNtEnumerateSystemEnvironmentValuesEx, "NtEnumerateSystemEnvironmentValuesEx", 3, { 0, 0, Int32Argument } },
+ /* NTSTATUS NtEnumerateValueKey(HANDLE KeyHandle, ULONG Index, KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass,
+ * PVOID KeyValueInformation, ULONG KeyValueInformationLength, PULONG ResultLength) */
+ { &SsNtEnumerateValueKey, "NtEnumerateValueKey", 6, { HandleArgument, 0, 0, 0, 0, 0 } },
+ /* NTSTATUS NtExtendSection(HANDLE SectionHandle, PLARGE_INTEGER SectionSize) */
+ { &SsNtExtendSection, "NtExtendSection", 2, { HandleArgument, Int64Argument } },
+ /* NTSTATUS NtFilterToken(HANDLE ExistingTokenHandle, ULONG Flags, PTOKEN_GROUPS SidsToDisable,
+ * PTOKEN_PRIVILEGES PrivilegesToDelete, PTOKEN_GROUPS SidsToRestricted, PHANDLE NewTokenHandle) */
+ { &SsNtFilterToken, "NtFilterToken", 6, { HandleArgument, 0, 0, 0, 0, 0 } },
+ /* NTSTATUS NtFindAtom(PWSTR String, ULONG StringLength, PUSHORT Atom) */
+ { &SsNtFindAtom, "NtFindAtom", 3, { WStringArgument, 0, 0 } },
+ /* NTSTATUS NtFlushBuffersFile(HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock) */
+ { &SsNtFlushBuffersFile, "NtFlushBuffersFile", 2, { HandleArgument, 0 } },
+ /* NTSTATUS NtFlushInstructionCache(HANDLE ProcessHandle, PVOID BaseAddress, ULONG FlushSize) */
+ { &SsNtFlushInstructionCache, "NtFlushInstructionCache", 3, { HandleArgument, 0, 0 } },
+ /* NTSTATUS NtFlushKey(HANDLE KeyHandle) */
+ { &SsNtFlushKey, "NtFlushKey", 1, { HandleArgument } },
+ /* NTSTATUS NtFlushProcessWriteBuffers() */
+ { &SsNtFlushProcessWriteBuffers, "NtFlushProcessWriteBuffers", 0 },
+ /* NTSTATUS NtFlushVirtualMemory(HANDLE ProcessHandle, PVOID *BaseAddress, PULONG FlushSize,
+ * PIO_STATUS_BLOCK IoStatusBlock) */
+ { &SsNtFlushVirtualMemory, "NtFlushVirtualMemory", 4, { HandleArgument, Int32Argument, Int32Argument, 0 } },
+ /* NTSTATUS NtFlushWriteBuffer() */
+ { &SsNtFlushWriteBuffer, "NtFlushWriteBuffer", 0 },
+ /* NTSTATUS NtFreeUserPhysicalPages(HANDLE ProcessHandle, PULONG NumberOfPages, PULONG PageFrameNumbers) */
+ { &SsNtFreeUserPhysicalPages, "NtFreeUserPhysicalPages", 3, { HandleArgument, Int32Argument, 0 } },
+ /* NTSTATUS NtFreeVirtualMemory(HANDLE ProcessHandle, PVOID *BaseAddress, PULONG FreeSize,
+ * ULONG FreeType) */
+ { &SsNtFreeVirtualMemory, "NtFreeVirtualMemory", 4, { HandleArgument, Int32Argument, Int32Argument, 0 } },
+ /* NTSTATUS NtFsControlFile(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine,
+ * PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, ULONG FsControlCode,
+ * PVOID InputBuffer, ULONG InputBufferLength, PVOID OutputBuffer,
+ * ULONG OutputBufferLength) */
+ { &SsNtFsControlFile, "NtFsControlFile", 10, { HandleArgument, HandleArgument, 0, 0, 0, 0, 0, 0, 0, 0 } },
+ /* NTSTATUS NtGetContextThread(HANDLE ThreadHandle, PCONTEXT Context) */
+ { &SsNtGetContextThread, "NtGetContextThread", 2, { HandleArgument, ContextArgument } },
+ /* NTSTATUS NtGetCurrentProcessorNumber() */
+ { &SsNtGetCurrentProcessorNumber, "NtGetCurrentProcessorNumber", 0 },
+ /* NTSTATUS NtGetDevicePowerState(HANDLE DeviceHandle, PDEVICE_POWER_STATE DevicePowerState) */
+ { &SsNtGetDevicePowerState, "NtGetDevicePowerState", 2, { HandleArgument, 0 } },
+ /* NTSTATUS NtGetNextProcess(HANDLE ProcessHandle, ACCESS_MASK DesiredAccess, ULONG HandleAttributes,
+ * ULONG Flags, PHANDLE NewProcessHandle) */
+ { &SsNtGetNextProcess, "NtGetNextProcess", 5, { HandleArgument, 0, 0, 0, 0 } },
+ /* NTSTATUS NtGetNextThread(HANDLE ProcessHandle, HANDLE ThreadHandle, ACCESS_MASK DesiredAccess,
+ * ULONG HandleAttributes, ULONG Flags, PHANDLE NewThreadHandle) */
+ { &SsNtGetNextThread, "NtGetNextThread", 6, { HandleArgument, HandleArgument, 0, 0, 0, 0 } },
+ /* NTSTATUS NtGetPlugPlayEvent(HANDLE EventHandle, PVOID Context, PVOID Buffer,
+ * ULONG BufferLength) */
+ { &SsNtGetPlugPlayEvent, "NtGetPlugPlayEvent", 4, { HandleArgument, 0, 0, 0 } },
+ /* NTSTATUS NtGetWriteWatch(HANDLE ProcessHandle, ULONG Flags, PVOID BaseAddress,
+ * ULONG RegionSize, PULONG Buffer, PULONG BufferEntries,
+ * PULONG Granularity) */
+ { &SsNtGetWriteWatch, "NtGetWriteWatch", 7, { HandleArgument, 0, 0, 0, 0, 0, 0 } },
+ /* NTSTATUS NtImpersonateAnonymousToken(HANDLE ThreadHandle) */
+ { &SsNtImpersonateAnonymousToken, "NtImpersonateAnonymousToken", 1, { HandleArgument } },
+ /* NTSTATUS NtImpersonateClientOfPort(HANDLE PortHandle, PPORT_MESSAGE Message) */
+ { &SsNtImpersonateClientOfPort, "SsNtImpersonateClientOfPort", 2, { HandleArgument, 0 } },
+ /* NTSTATUS NtImpersonateThread(HANDLE ThreadHandle, HANDLE TargetThreadHandle, PSECURITY_QUALITY_OF_SERVICE SecurityQos) */
+ { &SsNtImpersonateThread, "NtImpersonateThread", 3, { HandleArgument, HandleArgument, 0 } },
+ /* NTSTATUS NtInitiatePowerAction(POWER_ACTION SystemAction, SYSTEM_POWER_STATE MinSystemState, ULONG Flags,
+ * BOOLEAN Asynchronous) */
+ { &SsNtInitiatePowerAction, "NtInitiatePowerAction", 4, { 0, 0, 0, 0 } },
+ /* NTSTATUS NtIsProcessInJob(HANDLE ProcessHandle, HANDLE JobHandle) */
+ { &SsNtIsProcessInJob, "NtIsProcessInJob", 2, { HandleArgument, HandleArgument } },
+ /* NTSTATUS NtIsSystemResumeAutomatic() */
+ { &SsNtIsSystemResumeAutomatic, "NtIsSystemResumeAutomatic", 0 },
+ /* NTSTATUS NtListenPort(HANDLE PortHandle, PPORT_MESSAGE Message) */
+ { &SsNtListenPort, "NtListenPort", 2, { HandleArgument, 0 } },
+ /* NTSTATUS NtLoadDriver(PUNICODE_STRING DriverServiceName) */
+ { &SsNtLoadDriver, "NtLoadDriver", 1, { UnicodeStringArgument } },
+ /* NTSTATUS NtLoadKey(POBJECT_ATTRIBUTES KeyObjectAttributes, POBJECT_ATTRIBUTES FileObjectAttributes) */
+ { &SsNtLoadKey, "NtLoadKey", 2, { ObjectAttributesArgument, ObjectAttributesArgument } },
+ /* NTSTATUS NtLoadKey2(POBJECT_ATTRIBUTES KeyObjectAttributes, POBJECT_ATTRIBUTES FileObjectAttributes, ULONG Flags) */
+ { &SsNtLoadKey2, "NtLoadKey2", 3, { ObjectAttributesArgument, ObjectAttributesArgument, 0 } },
+ /* NTSTATUS NtLockFile(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine,
+ * PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, PULARGE_INTEGER LockOffset,
+ * PULARGE_INTEGER LockLength, ULONG Key, BOOLEAN FailImmediately,
+ * BOOLEAN ExclusiveLock) */
+ { &SsNtLockFile, "NtLockFile", 10, { HandleArgument, HandleArgument, 0, 0, 0, Int64Argument, Int64Argument, 0, 0, 0 } },
+ /* NTSTATUS NtLockVirtualMemory(HANDLE ProcessHandle, PVOID *BaseAddress, PULONG LockSize,
+ * ULONG LockType) */
+ { &SsNtLockVirtualMemory, "NtLockVirtualMemory", 4, { HandleArgument, Int32Argument, Int32Argument, 0 } },
+ /* NTSTATUS NtMakePermanentObject(HANDLE Handle) */
+ { &SsNtMakePermanentObject, "NtMakePermanentObject", 1, { HandleArgument } },
+ /* NTSTATUS NtMakeTemporaryObject(HANDLE Handle) */
+ { &SsNtMakeTemporaryObject, "NtMakeTemporaryObject", 1, { HandleArgument } },
+ /* NTSTATUS NtMapUserPhysicalPages(PVOID BaseAddress, PULONG NumberOfPages, PULONG PageFrameNumbers) */
+ { &SsNtMapUserPhysicalPages, "NtMapUserPhysicalPages", 3, { 0, Int32Argument, 0 } },
+ /* NTSTATUS NtMapUserPhysicalPagesScatter(PVOID BaseAddress, PULONG NumberOfPages, PULONG PageFrameNumbers) */
+ { &SsNtMapUserPhysicalPagesScatter, "NtMapUserPhysicalPagesScatter", 3, { 0, Int32Argument, 0 } },
+ /* NTSTATUS NtMapViewOfSection(HANDLE SectionHandle, HANDLE ProcessHandle, PVOID *BaseAddress,
+ * ULONG ZeroBits, ULONG CommitSize, PLARGE_INTEGER SectionOffset,
+ * PULONG ViewSize, SECTION_INHERIT InheritDisposition, ULONG AllocationType,
+ * ULONG Protect) */
+ { &SsNtMapViewOfSection, "NtMapViewOfSection", 10, { HandleArgument, HandleArgument, Int32Argument, 0, 0, Int64Argument, Int32Argument, 0, 0, 0 } },
+ /* NTSTATUS NtModifyBootEntry(PBOOT_ENTRY BootEntry) */
+ { &SsNtModifyBootEntry, "NtModifyBootEntry", 1, { 0 } },
+ /* NTSTATUS NtModifyDriverEntry(PEFI_DRIVER_ENTRY DriverEntry) */
+ { &SsNtModifyDriverEntry, "NtModifyDriverEntry", 1, { 0 } },
+ /* NTSTATUS NtNotifyChangeDirectoryFile(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine,
+ * PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, PFILE_NOTIFY_INFORMATION Buffer,
+ * ULONG BufferLength, ULONG NotifyFilter, BOOLEAN WatchSubtree) */
+ { &SsNtNotifyChangeDirectoryFile, "NtNotifyChangeDirectoryFile", 9, { HandleArgument, HandleArgument, 0, 0, 0, 0, 0, 0, 0 } },
+ /* NTSTATUS NtNotifyChangeKey(HANDLE KeyHandle, HANDLE EventHandle, PIO_APC_ROUTINE ApcRoutine,
+ * PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, ULONG NotifyFilter,
+ * BOOLEAN WatchSubtree, PVOID Buffer, ULONG BufferLength,
+ * BOOLEAN Asynchronous) */
+ { &SsNtNotifyChangeKey, "NtNotifyChangeKey", 10, { HandleArgument, HandleArgument, 0, 0, 0, 0, 0, 0, 0, 0 } },
+ /* NTSTATUS NtNotifyChangeMultipleKeys(HANDLE KeyHandle, ULONG Flags, POBJECT_ATTRIBUTES KeyObjectAttributes,
+ * HANDLE EventHandle, PIO_APC_ROUTINE ApcRoutine, PVOID ApcContext,
+ * PIO_STATUS_BLOCK IoStatusBlock, ULONG NotifyFilter, BOOLEAN WatchSubtree,
+ * PVOID Buffer, ULONG BufferLength, BOOLEAN Asynchronous) */
+ { &SsNtNotifyChangeMultipleKeys, "NtNotifyChangeMultipleKeys", 12, { HandleArgument, 0, ObjectAttributesArgument, HandleArgument, 0, 0, 0, 0, 0, 0, 0, 0 } },
+ /* NTSTATUS NtOpenDirectoryObject(PHANDLE DirectoryHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes) */
+ { &SsNtOpenDirectoryObject, "NtOpenDirectoryObject", 3, { 0, 0, ObjectAttributesArgument } },
+ /* NTSTATUS NtOpenEvent(PHANDLE EventHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes) */
+ { &SsNtOpenEvent, "NtOpenEvent", 3, { 0, 0, ObjectAttributesArgument } },
+ /* NTSTATUS NtOpenEventPair(PHANDLE EventPairHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes) */
+ { &SsNtOpenEventPair, "NtOpenEventPair", 3, { 0, 0, ObjectAttributesArgument } },
+ /* NTSTATUS NtOpenFile(PHANDLE FileHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes,
+ * PIO_STATUS_BLOCK IoStatusBlock, ULONG ShareAccess, ULONG OpenOptions) */
+ { &SsNtOpenFile, "NtOpenFile", 6, { 0, 0, ObjectAttributesArgument, 0, 0, 0 } },
+ /* NTSTATUS NtOpenIoCompletion(PHANDLE IoCompletionHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes) */
+ { &SsNtOpenIoCompletion, "NtOpenIoCompletion", 3, { 0, 0, ObjectAttributesArgument } },
+ /* NTSTATUS NtOpenJobObject(PHANDLE JobHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes) */
+ { &SsNtOpenJobObject, "NtOpenJobObject", 3, { 0, 0, ObjectAttributesArgument } },
+ /* NTSTATUS NtOpenKey(PHANDLE KeyHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes) */
+ { &SsNtOpenKey, "NtOpenKey", 3, { 0, 0, ObjectAttributesArgument } },
+ /* NTSTATUS NtOpenKeyedEvent(PHANDLE KeyedEventHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes) */
+ { &SsNtOpenKeyedEvent, "NtOpenKeyedEvent", 3, { 0, 0, ObjectAttributesArgument } },
+ /* NTSTATUS NtOpenMutant(PHANDLE MutantHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes) */
+ { &SsNtOpenMutant, "NtOpenMutant", 3, { 0, 0, ObjectAttributesArgument } },
+ /* NTSTATUS NtOpenObjectAuditAlarm(PUNICODE_STRING SubsystemName, PVOID *HandleId, PUNICODE_STRING ObjectTypeName,
+ * PUNICODE_STRING ObjectName, PSECURITY_DESCRIPTOR SecurityDescriptor, HANDLE TokenHandle,
+ * ACCESS_MASK DesiredAccess, ACCESS_MASK GrantedAccess, PPRIVILEGE_SET Privileges,
+ * BOOLEAN ObjectCreation, BOOLEAN AccessGranted, PBOOLEAN GenerateOnClose) */
+ { &SsNtOpenObjectAuditAlarm, "NtOpenObjectAuditAlarm", 12, { UnicodeStringArgument, Int32Argument, UnicodeStringArgument, UnicodeStringArgument, 0, HandleArgument, 0, 0, 0, 0, 0, 0 } },
+ /* NTSTATUS NtOpenProcess(PHANDLE ProcessHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes,
+ * PCLIENT_ID ClientId) */
+ { &SsNtOpenProcess, "NtOpenProcess", 4, { 0, 0, ObjectAttributesArgument, ClientIdArgument } },
+ /* NTSTATUS NtOpenProcessToken(HANDLE ProcessHandle, ACCESS_MASK DesiredAccess, PHANDLE TokenHandle) */
+ { &SsNtOpenProcessToken, "NtOpenProcessToken", 3, { HandleArgument, 0, 0 } },
+ /* NTSTATUS NtOpenProcessTokenEx(HANDLE ProcessHandle, ACCESS_MASK DesiredAccess, ULONG HandleAttributes,
+ * PHANDLE TokenHandle) */
+ { &SsNtOpenProcessTokenEx, "NtOpenProcessTokenEx", 4, { HandleArgument, 0, 0, 0 } },
+ /* NTSTATUS NtOpenSection(PHANDLE SectionHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes) */
+ { &SsNtOpenSection, "NtOpenSection", 3, { 0, 0, ObjectAttributesArgument } },
+ /* NTSTATUS NtOpenSemaphore(PHANDLE SemaphoreHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes) */
+ { &SsNtOpenSemaphore, "NtOpenSemaphore", 3, { 0, 0, ObjectAttributesArgument } },
+ /* NTSTATUS NtOpenSymbolicLinkObject(PHANDLE SymbolicLinkHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes) */
+ { &SsNtOpenSymbolicLinkObject, "NtOpenSymbolicLinkObject", 3, { 0, 0, ObjectAttributesArgument } },
+ /* NTSTATUS NtOpenThread(PHANDLE ThreadHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes,
+ * PCLIENT_ID ClientId) */
+ { &SsNtOpenThread, "NtOpenThread", 4, { 0, 0, ObjectAttributesArgument, ClientIdArgument } },
+ /* NTSTATUS NtOpenThreadToken(HANDLE ThreadHandle, ACCESS_MASK DesiredAccess, BOOLEAN OpenAsSelf,
+ * PHANDLE TokenHandle) */
+ { &SsNtOpenThreadToken, "NtOpenThreadToken", 4, { HandleArgument, 0, 0, 0 } },
+ /* NTSTATUS NtOpenThreadTokenEx(HANDLE ThreadHandle, ACCESS_MASK DesiredAccess, BOOLEAN OpenAsSelf,
+ * ULONG HandleAttributes, PHANDLE TokenHandle) */
+ { &SsNtOpenThreadTokenEx, "NtOpenThreadTokenEx", 5, { HandleArgument, 0, 0, 0, 0 } },
+ /* NTSTATUS NtOpenTimer(PHANDLE TimerHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes) */
+ { &SsNtOpenTimer, "NtOpenTimer", 3, { 0, 0, ObjectAttributesArgument } },
+ /* NTSTATUS NtReadFile(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine,
+ * PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, PVOID Buffer,
+ * ULONG Length, PLARGE_INTEGER ByteOffset, PULONG Key) */
+ { &SsNtReadFile, "NtReadFile", 9, { HandleArgument, HandleArgument, 0, 0, 0, 0, 0, Int64Argument, Int32Argument } },
+ /* NTSTATUS NtWriteFile(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine,
+ * PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, PVOID Buffer,
+ * ULONG Length, PLARGE_INTEGER ByteOffset, PULONG Key) */
+ { &SsNtWriteFile, "NtWriteFile", 9, { HandleArgument, HandleArgument, 0, 0, 0, 0, 0, Int64Argument, Int32Argument } },
+
+ { NULL, "Dummy", 0 }
+};
+
+RTL_GENERIC_TABLE KphSsCallTable;
+FAST_MUTEX KphSsCallTableMutex;
+
+/* KphSsDataInit
+ *
+ * Initializes all data structures so that system service entries
+ * can be looked up.
+ */
+VOID KphSsDataInit()
+{
+ ULONG i;
+
+ RtlInitializeGenericTable(
+ &KphSsCallTable,
+ KphpSsCallEntryCompareRoutine,
+ KphpSsCallEntryAllocateRoutine,
+ KphpSsCallEntryFreeRoutine,
+ NULL
+ );
+
+ for (i = 0; i < sizeof(SsEntries) / sizeof(KPHSS_CALL_ENTRY); i++)
+ {
+ /* Ignore the dummy entry. */
+ if (SsEntries[i].Number)
+ {
+ RtlInsertElementGenericTable(
+ &KphSsCallTable,
+ &SsEntries[i],
+ /* Save some space... */
+ FIELD_OFFSET(KPHSS_CALL_ENTRY, Arguments) +
+ SsEntries[i].NumberOfArguments * sizeof(KPHSS_ARGUMENT_TYPE),
+ NULL
+ );
+ }
+ }
+
+ ExInitializeFastMutex(&KphSsCallTableMutex);
+}
+
+/* KphSsDataDeinit
+ *
+ * Frees all memory associated with system service data.
+ */
+VOID KphSsDataDeinit()
+{
+ PKPHSS_CALL_ENTRY callEntry;
+
+ while (callEntry = (PKPHSS_CALL_ENTRY)RtlGetElementGenericTable(&KphSsCallTable, 0))
+ RtlDeleteElementGenericTable(&KphSsCallTable, callEntry);
+}
+
+/* KphSsLookupCallEntry
+ *
+ * Lookups up a system service entry by system service number.
+ */
+PKPHSS_CALL_ENTRY KphSsLookupCallEntry(
+ __in ULONG Number
+ )
+{
+ KPHSS_CALL_ENTRY callEntry;
+ PKPHSS_CALL_ENTRY foundEntry;
+
+ callEntry.Number = &Number;
+
+ ExAcquireFastMutex(&KphSsCallTableMutex);
+ foundEntry = (PKPHSS_CALL_ENTRY)RtlLookupElementGenericTable(
+ &KphSsCallTable,
+ &callEntry
+ );
+ ExReleaseFastMutex(&KphSsCallTableMutex);
+
+ return foundEntry;
+}
+
+/* KphpSsCallEntryAllocateRoutine
+ *
+ * Allocates storage for a system service entry.
+ */
+PVOID KphpSsCallEntryAllocateRoutine(
+ __in PRTL_GENERIC_TABLE Table,
+ __in CLONG ByteSize
+ )
+{
+ return ExAllocatePoolWithTag(
+ PagedPool,
+ ByteSize,
+ TAG_CALL_ENTRY
+ );
+}
+
+/* KphpSsCallEntryCompareRoutine
+ *
+ * Compares two system service entries.
+ */
+RTL_GENERIC_COMPARE_RESULTS KphpSsCallEntryCompareRoutine(
+ __in PRTL_GENERIC_TABLE Table,
+ __in PVOID FirstStruct,
+ __in PVOID SecondStruct
+ )
+{
+ PKPHSS_CALL_ENTRY callEntry1, callEntry2;
+
+ callEntry1 = (PKPHSS_CALL_ENTRY)FirstStruct;
+ callEntry2 = (PKPHSS_CALL_ENTRY)SecondStruct;
+
+ if (*(callEntry1->Number) < *(callEntry2->Number))
+ return GenericLessThan;
+ else if (*(callEntry1->Number) > *(callEntry2->Number))
+ return GenericGreaterThan;
+ else
+ return GenericEqual;
+}
+
+/* KphpSsCallEntryFreeRoutine
+ *
+ * Frees storage for a system service entry.
+ */
+VOID KphpSsCallEntryFreeRoutine(
+ __in PRTL_GENERIC_TABLE Table,
+ __in PVOID Buffer
+ )
+{
+ ExFreePoolWithTag(
+ Buffer,
+ TAG_CALL_ENTRY
+ );
+}
diff --git a/2.x/trunk/KProcessHacker/test.c b/2.x/trunk/KProcessHacker/test.c
new file mode 100644
index 000000000..ffc9d6016
--- /dev/null
+++ b/2.x/trunk/KProcessHacker/test.c
@@ -0,0 +1,71 @@
+/*
+ * Process Hacker Driver -
+ * testing 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/kph.h"
+
+static EX_PUSH_LOCK TestLock;
+
+VOID KphpTestPushLockThreadStart(
+ __in PVOID Context
+ );
+
+VOID KphTestPushLock()
+{
+ ULONG i;
+
+ ExInitializePushLock(&TestLock);
+
+ for (i = 0; i < 10; i++)
+ {
+ HANDLE threadHandle;
+ OBJECT_ATTRIBUTES objectAttributes;
+
+ InitializeObjectAttributes(&objectAttributes, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
+ PsCreateSystemThread(&threadHandle, 0, &objectAttributes, NULL, NULL, KphpTestPushLockThreadStart, NULL);
+ }
+}
+
+VOID KphpTestPushLockThreadStart(
+ __in PVOID Context
+ )
+{
+ ULONG i, j;
+
+ for (i = 0; i < 400000; i++)
+ {
+ ExAcquirePushLockShared(&TestLock);
+
+ for (j = 0; j < 1000; j++)
+ YieldProcessor();
+
+ ExReleasePushLock(&TestLock);
+
+ ExAcquirePushLockExclusive(&TestLock);
+
+ for (j = 0; j < 9000; j++)
+ YieldProcessor();
+
+ ExReleasePushLock(&TestLock);
+ }
+
+ PsTerminateSystemThread(STATUS_SUCCESS);
+}
diff --git a/2.x/trunk/KProcessHacker/trace.c b/2.x/trunk/KProcessHacker/trace.c
new file mode 100644
index 000000000..57fc98ede
--- /dev/null
+++ b/2.x/trunk/KProcessHacker/trace.c
@@ -0,0 +1,344 @@
+/*
+ * Process Hacker Driver -
+ * stack tracing
+ *
+ * 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/kph.h"
+
+BOOLEAN KphpCaptureAndAddStack(
+ __in PRTL_TRACE_DATABASE Database,
+ __in KPH_CAPTURE_AND_ADD_STACK_TYPE Type,
+ __out_opt PRTL_TRACE_BLOCK *TraceBlock
+ );
+
+VOID KphpTraceDatabaseDeleteProcedure(
+ __in PVOID Object,
+ __in ULONG Flags
+ );
+
+PKPH_OBJECT_TYPE KphTraceDatabaseType;
+
+/* KphTraceDatabaseInitialization
+ *
+ * Creates the TraceDatabase object type.
+ */
+NTSTATUS KphTraceDatabaseInitialization()
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ status = KphCreateObjectType(
+ &KphTraceDatabaseType,
+ PagedPool,
+ 0,
+ KphpTraceDatabaseDeleteProcedure
+ );
+
+ if (!NT_SUCCESS(status))
+ return status;
+
+ return status;
+}
+
+/* KphCaptureStackBackTrace
+ *
+ * Walks the stack, capturing the return address from each frame.
+ *
+ * Return value: the number of captured addresses in the buffer.
+ */
+ULONG KphCaptureStackBackTrace(
+ __in ULONG FramesToSkip,
+ __in ULONG FramesToCapture,
+ __in_opt ULONG Flags,
+ __out_ecount(FramesToCapture) PVOID *BackTrace,
+ __out_opt PULONG BackTraceHash
+ )
+{
+ PVOID backTrace[MAX_STACK_DEPTH];
+ ULONG framesFound;
+ ULONG hash;
+ ULONG i;
+
+ /* Skip the current frame (for this function). */
+ FramesToSkip++;
+
+ /* Check the input. */
+ /* Ensure we won't overrun the buffer. */
+ if (FramesToCapture + FramesToSkip > MAX_STACK_DEPTH)
+ return 0;
+ /* Make sure the flags are correct. */
+ if ((Flags & RTL_WALK_VALID_FLAGS) != Flags)
+ return 0;
+
+ /* Walk the frame chain. */
+ framesFound = RtlWalkFrameChain(
+ backTrace,
+ FramesToCapture + FramesToSkip,
+ Flags
+ );
+ /* Return if we found fewer frames than we wanted to skip. */
+ if (framesFound <= FramesToSkip)
+ return 0;
+
+ /* Copy over the stack trace.
+ * At the same time we calculate the stack trace hash by
+ * summing the addresses.
+ */
+ for (i = 0, hash = 0; i < FramesToCapture; i++)
+ {
+ if (FramesToSkip + i >= framesFound)
+ break;
+
+ BackTrace[i] = backTrace[FramesToSkip + i];
+ hash += PtrToUlong(BackTrace[i]);
+ }
+
+ /* Pass the hash back if the caller requested it. */
+ if (BackTraceHash)
+ *BackTraceHash = hash;
+
+ /* Return the number of addresses we copied. */
+ return i;
+}
+
+/* KphCaptureAndAddStack
+ *
+ * Captures a stack trace and adds it to a trace database.
+ */
+BOOLEAN KphCaptureAndAddStack(
+ __in PKPH_TRACE_DATABASE Database,
+ __in KPH_CAPTURE_AND_ADD_STACK_TYPE Type,
+ __out_opt PRTL_TRACE_BLOCK *TraceBlock
+ )
+{
+ return KphpCaptureAndAddStack(
+ Database->Database,
+ Type,
+ TraceBlock
+ );
+}
+
+/* KphCreateTraceDatabase
+ *
+ * Creates a trace database.
+ */
+NTSTATUS KphCreateTraceDatabase(
+ __out PKPH_TRACE_DATABASE *Database,
+ __in_opt SIZE_T MaximumSize,
+ __in ULONG Flags,
+ __in ULONG Tag
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ PRTL_TRACE_DATABASE rtlDatabase;
+ PKPH_TRACE_DATABASE database;
+
+ /* Create the trace database. */
+ rtlDatabase = RtlTraceDatabaseCreate(
+ 8,
+ MaximumSize,
+ Flags,
+ Tag,
+ NULL
+ );
+
+ if (!rtlDatabase)
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ /* Create the object. */
+ status = KphCreateObject(
+ &database,
+ sizeof(KPH_TRACE_DATABASE),
+ 0,
+ KphTraceDatabaseType,
+ 0
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ /* Destroy the trace database, since we can't use it. */
+ RtlTraceDatabaseDestroy(rtlDatabase);
+
+ return status;
+ }
+
+ /* Set up the trace database object. */
+ database->Database = rtlDatabase;
+ *Database = database;
+
+ return status;
+}
+
+NTSTATUS KphQueryTraceDatabase(
+ __in PKPH_TRACE_DATABASE Database,
+ __out_bcount_opt(BufferLength) PKPH_TRACEDB_INFORMATION Buffer,
+ __in_opt ULONG BufferLength,
+ __out_opt PULONG ReturnLength,
+ __in KPROCESSOR_MODE AccessMode
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ PRTL_TRACE_DATABASE rtlDatabase = Database->Database;
+ PKPH_TRACEDB_INFORMATION nextEntry;
+ RTL_TRACE_ENUMERATE enumContext = { 0 };
+ PRTL_TRACE_BLOCK currentBlock;
+
+ /* Probe buffers. */
+ if (AccessMode != KernelMode)
+ {
+ __try
+ {
+ if (Buffer)
+ ProbeForWrite(Buffer, BufferLength, 1);
+ if (ReturnLength)
+ ProbeForWrite(ReturnLength, sizeof(ULONG), 1);
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ return GetExceptionCode();
+ }
+ }
+
+ /* First entry to write to. */
+ /* Note that this is completely safe if Buffer is NULL. */
+ nextEntry = Buffer;
+
+ /* Enumerate the trace blocks. */
+ while (RtlTraceDatabaseEnumerate(rtlDatabase, &enumContext, ¤tBlock))
+ {
+ PKPH_TRACEDB_INFORMATION currentEntry;
+
+ /* Save the pointer to the entry we are about to write to. */
+ currentEntry = nextEntry;
+ /* Compute the location of the next entry. */
+ nextEntry = (PKPH_TRACEDB_INFORMATION)(
+ (ULONG_PTR)currentEntry + /* Current entry plus */
+ sizeof(KPH_TRACEDB_INFORMATION) - /* the size of the current entry minus */
+ sizeof(PVOID) + /* the extra PVOID in the Trace array plus */
+ currentBlock->Size * sizeof(PVOID) /* the size of the stack trace. */
+ );
+
+ if (
+ /* If we got an error last time we tried to write to the buffer,
+ * don't try again this time. */
+ NT_SUCCESS(status) &&
+ /* Make sure the buffer isn't NULL. */
+ Buffer &&
+ /* Make sure we don't exceed the buffer length. */
+ ((ULONG_PTR)nextEntry - (ULONG_PTR)Buffer) <= BufferLength
+ )
+ {
+ __try
+ {
+ currentEntry->NextEntryOffset = (ULONG)((ULONG_PTR)nextEntry - (ULONG_PTR)currentEntry);
+ currentEntry->Count = currentBlock->Count;
+ currentEntry->TraceSize = currentBlock->Size;
+ memcpy(currentEntry->Trace, currentBlock->Trace, currentBlock->Size * sizeof(PVOID));
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ status = GetExceptionCode();
+ }
+ }
+ else
+ {
+ status = STATUS_BUFFER_TOO_SMALL;
+ }
+ }
+
+ if (ReturnLength)
+ {
+ __try
+ {
+ *ReturnLength = (ULONG)((ULONG_PTR)nextEntry - (ULONG_PTR)Buffer);
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ status = GetExceptionCode();
+ }
+ }
+
+ return status;
+}
+
+/* KphCaptureAndAddStack
+ *
+ * Captures a stack trace and adds it to a trace database.
+ */
+BOOLEAN KphpCaptureAndAddStack(
+ __in PRTL_TRACE_DATABASE Database,
+ __in KPH_CAPTURE_AND_ADD_STACK_TYPE Type,
+ __out_opt PRTL_TRACE_BLOCK *TraceBlock
+ )
+{
+ PVOID trace[MAX_STACK_DEPTH * 2];
+ ULONG kmodeFramesFound = 0;
+ ULONG umodeFramesFound = 0;
+
+ /* Check input. */
+ if (Type >= KphCaptureAndAddMaximum)
+ return FALSE;
+
+ /* Capture the kernel-mode stack if needed. */
+ if (
+ Type == KphCaptureAndAddKModeStack ||
+ Type == KphCaptureAndAddBothStacks
+ )
+ kmodeFramesFound = KphCaptureStackBackTrace(
+ 1,
+ MAX_STACK_DEPTH - 1,
+ 0,
+ trace,
+ NULL
+ );
+ /* Capture the user-mode stack if needed. */
+ if (
+ Type == KphCaptureAndAddUModeStack ||
+ Type == KphCaptureAndAddBothStacks
+ )
+ umodeFramesFound = KphCaptureStackBackTrace(
+ 0,
+ MAX_STACK_DEPTH - 1,
+ RTL_WALK_USER_MODE_STACK,
+ &trace[kmodeFramesFound],
+ NULL
+ );
+
+ /* Add the trace to the database. */
+ return RtlTraceDatabaseAdd(
+ Database,
+ kmodeFramesFound + umodeFramesFound,
+ trace,
+ TraceBlock
+ );
+}
+
+/* KphpTraceDatabaseDeleteProcedure
+ *
+ * Destroys a trace database.
+ */
+VOID KphpTraceDatabaseDeleteProcedure(
+ __in PVOID Object,
+ __in ULONG Flags
+ )
+{
+ PKPH_TRACE_DATABASE database = (PKPH_TRACE_DATABASE)Object;
+
+ RtlTraceDatabaseDestroy(database->Database);
+}
diff --git a/2.x/trunk/KProcessHacker/util.c b/2.x/trunk/KProcessHacker/util.c
new file mode 100644
index 000000000..61e3b3ecf
--- /dev/null
+++ b/2.x/trunk/KProcessHacker/util.c
@@ -0,0 +1,115 @@
+/*
+ * Process Hacker Driver -
+ * utility functions
+ *
+ * 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/util.h"
+
+/* KphInitializeStream
+ *
+ * Initializes a stream.
+ *
+ * Stream: The stream to initialize.
+ * Buffer: The buffer to use.
+ * Length: The maximum number of bytes that can be stored in
+ * the buffer. If an attempt is made to overrun or underrun
+ * the buffer, an exception will be raised.
+ */
+VOID KphInitializeStream(
+ __out PKPH_STREAM Stream,
+ __in PVOID Buffer,
+ __in ULONG Length
+ )
+{
+ ASSERT(Length > 0);
+
+ Stream->Buffer = Buffer;
+ Stream->Length = Length;
+ Stream->Position = 0;
+}
+
+/* KphSeekStream
+ *
+ * Changes the position of a stream.
+ */
+ULONG KphSeekStream(
+ __inout PKPH_STREAM Stream,
+ __in LONG Offset,
+ __in KPH_STREAM_ORIGIN Origin
+ )
+{
+ ULONG newPosition;
+
+ switch (Origin)
+ {
+ case StartOrigin:
+ {
+ /* Can't seek to before the start of the buffer. */
+ if (Offset < 0)
+ ExRaiseStatus(STATUS_INVALID_PARAMETER_2);
+
+ newPosition = Offset;
+ }
+ break;
+
+ case CurrentOrigin:
+ {
+ newPosition = Stream->Position + Offset;
+ }
+ break;
+
+ case EndOrigin:
+ {
+ newPosition = Stream->Length - Offset - 1;
+ }
+ break;
+ }
+
+ /* Check the new position and raise an exception if
+ * appropriate.
+ */
+ KphCheckStreamPosition(Stream, newPosition);
+ Stream->Position = newPosition;
+
+ return newPosition;
+}
+
+/* KphWriteDataStream
+ *
+ * Writes data to a stream.
+ */
+ULONG KphWriteDataStream(
+ __inout PKPH_STREAM Stream,
+ __in PVOID Data,
+ __in ULONG Length
+ )
+{
+ /* Check if we are going to overrun the buffer. */
+ KphCheckStreamPosition(Stream, Stream->Position + Length);
+ /* Copy the data. */
+ memcpy(
+ PTR_ADD_OFFSET(Stream->Buffer, Stream->Position),
+ Data,
+ Length
+ );
+
+ /* Increase the position. */
+ return Stream->Position += Length;
+}
diff --git a/2.x/trunk/KProcessHacker/version.c b/2.x/trunk/KProcessHacker/version.c
new file mode 100644
index 000000000..ef2e9bb2b
--- /dev/null
+++ b/2.x/trunk/KProcessHacker/version.c
@@ -0,0 +1,611 @@
+/*
+ * Process Hacker Driver -
+ * Windows version-specific data
+ *
+ * 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 .
+ */
+
+#define _VERSION_PRIVATE
+#include "include/version.h"
+#include "include/debug.h"
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE, KvInit)
+#pragma alloc_text(PAGE, KvScanProc)
+#pragma alloc_text(PAGE, KvVerifyPrologue)
+#endif
+
+/*
+ * mov edi, edi
+ * push ebp
+ * mov ebp, esp
+ */
+static char StandardPrologue[] = { 0x8b, 0xff, 0x55, 0x8b, 0xec };
+
+/* KiFastCallEntry */
+/*
+ * Note that this scan will get the address of
+ * mov esi, edx
+ * within KiFastCallEntry, not the start of KiFastCallEntry.
+ * We will then subtract 7 to get the address of
+ * inc dword ptr fs:PbSystemCalls
+ * See sysservice.c for more details.
+ */
+static char KiFastCallEntry51[] =
+{
+ 0x8b, 0xf2, 0x8b, 0x5f, 0x0c, 0x33, 0xc9, 0x8a,
+ 0x0c, 0x18, 0x8b, 0x3f, 0x8b, 0x1c, 0x87, 0x2b
+};
+static char KiFastCallEntry52[] =
+{
+ 0x8b, 0xf2, 0x8b, 0x5f, 0x0c, 0x33, 0xc9, 0x8a,
+ 0x0c, 0x18, 0x8b, 0x3f, 0x8b, 0x1c, 0x87, 0x2b
+}; /* same as 5.1 */
+static char KiFastCallEntry60[] =
+{
+ 0x8b, 0xf2, 0x33, 0xc9, 0x8b, 0x57, 0x0c, 0x8b,
+ 0x3f, 0x8a, 0x0c, 0x10, 0x8b, 0x14, 0x87, 0x2b
+};
+static char KiFastCallEntry61[] =
+{
+ 0x8b, 0xf2, 0x33, 0xc9, 0x8b, 0x57, 0x0c, 0x8b,
+ 0x3f, 0x8a, 0x0c, 0x10, 0x8b, 0x14, 0x87, 0x2b
+}; /* same as 6.0 */
+/* Below is the scan to find the start of KiFastCallEntry. */
+/* static char KiFastCallEntry[] =
+{
+ 0xb9, 0x23, 0x00, 0x00, 0x00, 0x6a, 0x30, 0x0f,
+ 0xa1, 0x8e, 0xd9, 0x8e, 0xc1, 0x64, 0x8b, 0x0d
+}; */
+
+/* PsExitSpecialApc */
+static char PsExitSpecialApc51[] =
+{
+ 0x8b, 0xff, 0x55, 0x8b, 0xec, 0x64, 0xa1, 0x24,
+ 0x01, 0x00, 0x00, 0x8b, 0x45, 0x08, 0xf6, 0x40
+};
+static char PsExitSpecialApc60[] =
+{
+ 0x8b, 0xff, 0x55, 0x8b, 0xec, 0x83, 0xe4, 0xf8,
+ 0x51, 0x8b, 0x45, 0x08, 0xf6, 0x40, 0x28, 0x01
+};
+static char PsExitSpecialApc61[] =
+{
+ 0x8b, 0xff, 0x55, 0x8b, 0xec, 0x83, 0xe4, 0xf8,
+ 0x51, 0x8b, 0x45, 0x08, 0xf6, 0x40, 0x28, 0x01
+}; /* same as 6.0 */
+
+/* PsTerminateProcess/PspTerminateProcess */
+static char PspTerminateProcess51[] =
+{
+ 0x8b, 0xff, 0x55, 0x8b, 0xec, 0x56, 0x64, 0xa1,
+ 0x24, 0x01, 0x00, 0x00, 0x8b, 0x75, 0x08, 0x3b
+};
+static char PspTerminateProcess52[] =
+{
+ 0x8b, 0xff, 0x55, 0x8b, 0xec, 0x56, 0x8b, 0x75,
+ 0x08, 0x57, 0x8d, 0xbe, 0x40, 0x02, 0x00, 0x00
+};
+static char PsTerminateProcess60[] =
+{
+ 0x8b, 0xff, 0x55, 0x8b, 0xec, 0x53, 0x56, 0x57,
+ 0x33, 0xd2, 0x6a, 0x08, 0x42, 0x5e, 0x8d, 0xb9
+};
+static char PsTerminateProcess61[] =
+{
+ 0x8b, 0xff, 0x55, 0x8b, 0xec, 0x51, 0x51, 0x53,
+ 0x56, 0x64, 0x8b, 0x35, 0x24, 0x01, 0x00, 0x00,
+ 0x66, 0xff, 0x8e, 0x84, 0x00, 0x00, 0x00, 0x57,
+ 0xc7, 0x45, 0xfc
+}; /* a lot of functions seem to share the first
+ * 16 bytes of the Windows 7 PsTerminateProcess,
+ * and a few even share the first 24 bytes.
+ */
+
+/* PspTerminateThreadByPointer */
+static char PspTerminateThreadByPointer51[] =
+{
+ 0x8b, 0xff, 0x55, 0x8b, 0xec, 0x83, 0xec, 0x0c,
+ 0x83, 0x4d, 0xf8, 0xff, 0x56, 0x57, 0x8b, 0x7d
+};
+static char PspTerminateThreadByPointer52[] =
+{
+ 0x8b, 0xff, 0x55, 0x8b, 0xec, 0x53, 0x56, 0x57,
+ 0x8b, 0x7d, 0x08, 0x8d, 0xb7, 0x40, 0x02, 0x00
+};
+static char PspTerminateThreadByPointer60[] =
+{
+ 0x8b, 0xff, 0x55, 0x8b, 0xec, 0x83, 0xe4, 0xf8,
+ 0x51, 0x53, 0x56, 0x8b, 0x75, 0x08, 0x57, 0x8d,
+ 0xbe, 0x60, 0x02, 0x00, 0x00, 0xf6, 0x07, 0x40
+};
+static char PspTerminateThreadByPointer61[] =
+{
+ 0x8b, 0xff, 0x55, 0x8b, 0xec, 0x83, 0xe4, 0xf8,
+ 0x51, 0x53, 0x56, 0x8b, 0x75, 0x08, 0x57, 0x8d,
+ 0xbe, 0x80, 0x02, 0x00, 0x00, 0xf6, 0x07, 0x40
+};
+
+/* The following offsets took me a long time to work out, so
+ please do not steal them. If you want to use them, please
+ license your project under the GNU GPL (although you are
+ not legally required to).
+ */
+NTSTATUS KvInit()
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ ULONG majorVersion, minorVersion, servicePack, buildNumber;
+
+ /* Get Windows version information. */
+
+ RtlWindowsVersion.dwOSVersionInfoSize = sizeof(RtlWindowsVersion);
+ status = RtlGetVersion((PRTL_OSVERSIONINFOW)&RtlWindowsVersion);
+
+ if (!NT_SUCCESS(status))
+ return status;
+
+ majorVersion = RtlWindowsVersion.dwMajorVersion;
+ minorVersion = RtlWindowsVersion.dwMinorVersion;
+ servicePack = RtlWindowsVersion.wServicePackMajor;
+ buildNumber = RtlWindowsVersion.dwBuildNumber;
+ dfprintf("Windows %d.%d, SP%d.%d, build %d\n",
+ majorVersion, minorVersion, servicePack,
+ RtlWindowsVersion.wServicePackMinor, buildNumber
+ );
+
+ __NtClose = GetSystemRoutineAddress(L"NtClose");
+
+ /* NtClose is used as a reference point for most addresses
+ dependent on where the kernel is loaded, so if we don't
+ have it, we can't proceed.
+ */
+ if (!__NtClose)
+ return STATUS_NOT_SUPPORTED;
+
+ /* We also need the address of ZwClose to get KiFastCallEntry. */
+ __ZwClose = GetSystemRoutineAddress(L"ZwClose");
+
+ if (!__ZwClose)
+ return STATUS_NOT_SUPPORTED;
+
+ /* Windows XP */
+ if (majorVersion == 5 && minorVersion == 1)
+ {
+ ULONG_PTR searchOffset = (ULONG_PTR)__NtClose;
+
+ WindowsVersion = WINDOWS_XP;
+ ProcessAllAccess = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xfff;
+ ThreadAllAccess = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x3ff;
+
+ OffEtClientId = 0x1ec;
+ OffEtSpareByteForSs = 0x256; /* Padding, last */
+ OffEtStartAddress = 0x224;
+ OffEtWin32StartAddress = 0x228;
+ OffEpJob = 0x134;
+ OffEpObjectTable = 0xc4;
+ OffEpProtectedProcessOff = 0;
+ OffEpProtectedProcessBit = 0;
+ OffEpRundownProtect = 0x80;
+ OffOhBody = 0x18;
+ OffOtName = 0x40;
+ OffOtiGenericMapping = 0x60 + 0x8;
+ OffOtiOpenProcedure = 0x60 + 0x30;
+
+ SsNtContinue = 0x20;
+
+ /* KiFastCallEntry isn't hooked properly yet. Disabled for now. */
+ /* INIT_SCAN(
+ KiFastCallEntryScan,
+ KiFastCallEntry51,
+ sizeof(KiFastCallEntry51),
+ (ULONG_PTR)__ZwClose, SCAN_LENGTH, -6
+ ); */
+ /* We are scanning for PspTerminateProcess which has
+ the same signature as PsTerminateProcess because
+ PsTerminateProcess is simply a wrapper on XP.
+ */
+ INIT_SCAN(
+ PsTerminateProcessScan,
+ PspTerminateProcess51,
+ sizeof(PspTerminateProcess51),
+ searchOffset, SCAN_LENGTH, 0
+ );
+ INIT_SCAN(
+ PspTerminateThreadByPointerScan,
+ PspTerminateThreadByPointer51,
+ sizeof(PspTerminateThreadByPointer51),
+ searchOffset, SCAN_LENGTH, 0
+ );
+
+ /* Windows XP SP0 and 1 are not supported */
+ if (servicePack == 0)
+ {
+ return STATUS_NOT_SUPPORTED;
+ }
+ else if (servicePack == 1)
+ {
+ return STATUS_NOT_SUPPORTED;
+ }
+ else if (servicePack == 2)
+ {
+ }
+ else if (servicePack == 3)
+ {
+ }
+ else
+ {
+ return STATUS_NOT_SUPPORTED;
+ }
+
+ dprintf("Initialized version-specific data for Windows XP SP%d\n", servicePack);
+ }
+ /* Windows Server 2003 */
+ else if (majorVersion == 5 && minorVersion == 2)
+ {
+ ULONG_PTR psSearchOffset = (ULONG_PTR)GetSystemRoutineAddress(L"RtlCreateHeap");
+
+ WindowsVersion = WINDOWS_SERVER_2003;
+ ProcessAllAccess = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xfff;
+ ThreadAllAccess = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x3ff;
+
+ OffEtClientId = 0x1e4;
+ OffEtSpareByteForSs = 0x24f; /* Padding, last */
+ OffEtStartAddress = 0x21c;
+ OffEtWin32StartAddress = 0x220;
+ OffEpJob = 0x120;
+ OffEpObjectTable = 0xd4;
+ OffEpProtectedProcessOff = 0;
+ OffEpProtectedProcessBit = 0;
+ OffEpRundownProtect = 0x90;
+ OffOhBody = 0x18;
+ OffOtName = 0x40;
+ OffOtiGenericMapping = 0x60 + 0x8;
+ OffOtiOpenProcedure = 0x60 + 0x30;
+
+ SsNtContinue = 0x22;
+
+ /* Can't find on ntoskrnl *and* ntkrnlpa. Disabled for now. */
+ /* INIT_SCAN(
+ KiFastCallEntryScan,
+ KiFastCallEntry52,
+ sizeof(KiFastCallEntry52),
+ (ULONG_PTR)__ZwClose, SCAN_LENGTH, -7
+ ); */
+ /* We are scanning for PspTerminateProcess which has
+ the same signature as PsTerminateProcess because
+ PsTerminateProcess is simply a wrapper on Server 2003.
+ */
+ INIT_SCAN(
+ PsTerminateProcessScan,
+ PspTerminateProcess52,
+ sizeof(PspTerminateProcess52),
+ psSearchOffset - 0x50000, SCAN_LENGTH, 0
+ );
+ INIT_SCAN(
+ PspTerminateThreadByPointerScan,
+ PspTerminateThreadByPointer52,
+ sizeof(PspTerminateThreadByPointer52),
+ psSearchOffset - 0x20000, SCAN_LENGTH, 0
+ );
+
+ if (servicePack == 0)
+ {
+ }
+ else if (servicePack == 1)
+ {
+ }
+ else if (servicePack == 2)
+ {
+ }
+ else
+ {
+ return STATUS_NOT_SUPPORTED;
+ }
+
+ dprintf("Initialized version-specific data for Windows Server 2003 SP%d\n", servicePack);
+ }
+ /* Windows Vista, Windows Server 2008 */
+ else if (majorVersion == 6 && minorVersion == 0)
+ {
+ ULONG_PTR searchOffset = (ULONG_PTR)__NtClose;
+
+ WindowsVersion = WINDOWS_VISTA;
+ ProcessAllAccess = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x1fff;
+ ThreadAllAccess = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xfff;
+
+ OffEtClientId = 0x20c;
+ OffEtSpareByteForSs = 0x26f; /* Padding, second-last */
+ OffEtStartAddress = 0x1f8;
+ OffEtWin32StartAddress = 0x240;
+ OffEpJob = 0x10c;
+ OffEpObjectTable = 0xdc;
+ OffEpProtectedProcessOff = 0x224;
+ OffEpProtectedProcessBit = 0xb;
+ OffEpRundownProtect = 0x98;
+ OffOhBody = 0x18;
+
+ INIT_SCAN(
+ KiFastCallEntryScan,
+ KiFastCallEntry60,
+ sizeof(KiFastCallEntry60),
+ (ULONG_PTR)__ZwClose, SCAN_LENGTH, -7
+ );
+ INIT_SCAN(
+ PsTerminateProcessScan,
+ PsTerminateProcess60,
+ sizeof(PsTerminateProcess60),
+ searchOffset, SCAN_LENGTH, 0
+ );
+ INIT_SCAN(
+ PspTerminateThreadByPointerScan,
+ PspTerminateThreadByPointer60,
+ sizeof(PspTerminateThreadByPointer60),
+ searchOffset - 0x50000, SCAN_LENGTH, 0
+ );
+
+ /* SP0 */
+ if (servicePack == 0)
+ {
+ OffOtName = 0x40;
+ OffOtiGenericMapping = 0x60 + 0xc;
+ OffOtiOpenProcedure = 0x60 + 0x30;
+
+ SsNtContinue = 0x36;
+ }
+ /* SP1 */
+ else if (servicePack == 1)
+ {
+ OffOtName = 0x8;
+ OffOtiGenericMapping = 0x28 + 0xc; /* They got rid of the Mutex (an ERESOURCE) */
+ OffOtiOpenProcedure = 0x28 + 0x34;
+
+ SsNtContinue = 0x37;
+ }
+ /* SP2 */
+ else if (servicePack == 2)
+ {
+ OffOtName = 0x8;
+ OffOtiGenericMapping = 0x28 + 0xc;
+ OffOtiOpenProcedure = 0x28 + 0x34;
+
+ SsNtAddAtom = 0x8;
+ SsNtAlertResumeThread = 0xd;
+ SsNtAlertThread = 0xe;
+ SsNtAllocateLocallyUniqueId = 0xf;
+ SsNtAllocateUserPhysicalPages = 0x10;
+ SsNtAllocateUuids = 0x11;
+ SsNtAllocateVirtualMemory = 0x12;
+ SsNtApphelpCacheControl = 0x28;
+ SsNtAreMappedFilesTheSame = 0x29;
+ SsNtAssignProcessToJobObject = 0x2a;
+ SsNtCallbackReturn = 0x2b;
+ SsNtCancelDeviceWakeupRequest = 0x2c;
+ SsNtCancelIoFile = 0x2d;
+ SsNtCancelTimer = 0x2e;
+ SsNtClearEvent = 0x2f;
+ SsNtClose = 0x30;
+ SsNtContinue = 0x37;
+ SsNtCreateDebugObject = 0x38;
+ SsNtCreateDirectoryObject = 0x39;
+ SsNtCreateEvent = 0x3a;
+ SsNtCreateEventPair = 0x3b;
+ SsNtCreateFile = 0x3c;
+ SsNtCreateIoCompletion = 0x3d;
+ SsNtCreateJobObject = 0x3e;
+ SsNtCreateJobSet = 0x3f;
+ SsNtCreateKey = 0x40;
+ SsNtCreateKeyedEvent = 0x168;
+ SsNtCreateMailslotFile = 0x42;
+ SsNtCreateMutant = 0x43;
+ SsNtCreateNamedPipeFile = 0x44;
+ SsNtCreatePagingFile = 0x46;
+ SsNtCreatePort = 0x47;
+ SsNtCreatePrivateNamespace = 0x45;
+ SsNtCreateProcess = 0x48;
+ SsNtCreateProcessEx = 0x49;
+ SsNtCreateProfile = 0x4a;
+ SsNtCreateSection = 0x4b;
+ SsNtCreateSemaphore = 0x4c;
+ SsNtCreateSymbolicLinkObject = 0x4d;
+ SsNtCreateThread = 0x4e;
+ SsNtCreateTimer = 0x4f;
+ SsNtCreateToken = 0x50;
+ SsNtCreateUserProcess = 0x17f;
+ SsNtCreateWaitablePort = 0x73;
+ SsNtDebugActiveProcess = 0x74;
+ SsNtDebugContinue = 0x75;
+ SsNtDelayExecution = 0x76;
+ SsNtDeleteAtom = 0x77;
+ SsNtDeleteBootEntry = 0x78;
+ SsNtDeleteDriverEntry = 0x79;
+ SsNtDeleteFile = 0x7a;
+ SsNtDeleteKey = 0x7b;
+ SsNtDeletePrivateNamespace = 0x7c;
+ SsNtDeleteObjectAuditAlarm = 0x7d;
+ SsNtDeleteValueKey = 0x7e;
+ SsNtDeviceIoControlFile = 0x7f;
+ SsNtDisplayString = 0x80;
+ SsNtDuplicateObject = 0x81;
+ SsNtDuplicateToken = 0x82;
+ SsNtEnumerateBootEntries = 0x83;
+ SsNtEnumerateDriverEntries = 0x84;
+ SsNtEnumerateKey = 0x85;
+ SsNtEnumerateSystemEnvironmentValuesEx = 0x86;
+ SsNtEnumerateValueKey = 0x88;
+ SsNtExtendSection = 0x89;
+ SsNtFilterToken = 0x8a;
+ SsNtFindAtom = 0x8b;
+ SsNtFlushBuffersFile = 0x8c;
+ SsNtFlushInstructionCache = 0x8d;
+ SsNtFlushKey = 0x8e;
+ SsNtFlushProcessWriteBuffers = 0x8f;
+ SsNtFlushVirtualMemory = 0x90;
+ SsNtFlushWriteBuffer = 0x91;
+ SsNtFreeUserPhysicalPages = 0x92;
+ SsNtFreeVirtualMemory = 0x93;
+ SsNtFsControlFile = 0x96;
+ SsNtGetContextThread = 0x97;
+ SsNtGetDevicePowerState = 0x98;
+ SsNtGetPlugPlayEvent = 0x9a;
+ SsNtGetWriteWatch = 0x9b;
+ SsNtImpersonateAnonymousToken = 0x9c;
+ SsNtImpersonateClientOfPort = 0x9d;
+ SsNtImpersonateThread = 0x9e;
+ SsNtInitiatePowerAction = 0xa1;
+ SsNtIsProcessInJob = 0xa2;
+ SsNtIsSystemResumeAutomatic = 0xa3;
+ SsNtListenPort = 0xa4;
+ SsNtLoadDriver = 0xa5;
+ SsNtLoadKey = 0xa6;
+ SsNtLoadKey2 = 0xa7;
+ SsNtLockFile = 0xa9;
+ SsNtLockVirtualMemory = 0xac;
+ SsNtMakePermanentObject = 0xad;
+ SsNtMakeTemporaryObject = 0xae;
+ SsNtMapUserPhysicalPages = 0xaf;
+ SsNtMapUserPhysicalPagesScatter = 0xb0;
+ SsNtMapViewOfSection = 0xb1;
+ SsNtModifyBootEntry = 0xb2;
+ SsNtModifyDriverEntry = 0xb3;
+ SsNtNotifyChangeDirectoryFile = 0xb4;
+ SsNtNotifyChangeKey = 0xb5;
+ SsNtNotifyChangeMultipleKeys = 0xb6;
+ SsNtOpenDirectoryObject = 0xb7;
+ SsNtOpenEvent = 0xb8;
+ SsNtOpenEventPair = 0xb9;
+ SsNtOpenFile = 0xba;
+ SsNtOpenIoCompletion = 0xbb;
+ SsNtOpenJobObject = 0xbc;
+ SsNtOpenKey = 0xbd;
+ SsNtOpenKeyedEvent = 0x169;
+ SsNtOpenMutant = 0xbf;
+ SsNtOpenObjectAuditAlarm = 0xc1;
+ SsNtOpenProcess = 0xc2;
+ SsNtOpenProcessToken = 0xc3;
+ SsNtOpenProcessTokenEx = 0xc4;
+ SsNtOpenSection = 0xc5;
+ SsNtOpenSemaphore = 0xc6;
+ SsNtOpenSymbolicLinkObject = 0xc8;
+ SsNtOpenThread = 0xc9;
+ SsNtOpenThreadToken = 0xca;
+ SsNtOpenThreadTokenEx = 0xcb;
+ SsNtOpenTimer = 0xcc;
+ SsNtReadFile = 0x102;
+ SsNtWriteFile = 0x163;
+ }
+ else
+ {
+ return STATUS_NOT_SUPPORTED;
+ }
+
+ dprintf("Initialized version-specific data for Windows Vista SP%d/Windows Server 2008\n", servicePack);
+ }
+ /* Windows 7, Windows Server 2008 R2 */
+ else if (majorVersion == 6 && minorVersion == 1)
+ {
+ ULONG_PTR psSearchOffset = (ULONG_PTR)GetSystemRoutineAddress(L"PsSetCreateProcessNotifyRoutine");
+ ULONG psScanLength = 0x200000;
+
+ if (!psSearchOffset)
+ return STATUS_NOT_SUPPORTED;
+
+ WindowsVersion = WINDOWS_7;
+ ProcessAllAccess = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x1fff;
+ ThreadAllAccess = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xfff;
+
+ OffEtClientId = 0x22c;
+ OffEtSpareByteForSs = 0x2b4; /* Padding, last */
+ OffEtStartAddress = 0x218;
+ OffEtWin32StartAddress = 0x260;
+ OffEpJob = 0x124;
+ OffEpObjectTable = 0xf4;
+ OffEpProtectedProcessOff = 0x26c;
+ OffEpProtectedProcessBit = 0xb;
+ OffEpRundownProtect = 0xb0;
+ OffOhBody = 0x18;
+ OffOtName = 0x8;
+ OffOtiGenericMapping = 0x28 + 0xc;
+ OffOtiOpenProcedure = 0x28 + 0x34;
+
+ SsNtContinue = 0x3c;
+
+ INIT_SCAN(
+ KiFastCallEntryScan,
+ KiFastCallEntry61,
+ sizeof(KiFastCallEntry61),
+ (ULONG_PTR)__ZwClose, SCAN_LENGTH, -7
+ );
+ INIT_SCAN(
+ PsTerminateProcessScan,
+ PsTerminateProcess61,
+ sizeof(PsTerminateProcess61),
+ psSearchOffset, psScanLength, 0
+ );
+ INIT_SCAN(
+ PspTerminateThreadByPointerScan,
+ PspTerminateThreadByPointer61,
+ sizeof(PspTerminateThreadByPointer61),
+ psSearchOffset, psScanLength, 0
+ );
+
+ /* SP0 */
+ if (servicePack == 0)
+ {
+ }
+ else
+ {
+ return STATUS_NOT_SUPPORTED;
+ }
+
+ dprintf("Initialized version-specific data for Windows 7 SP%d\n", servicePack);
+ }
+ else
+ {
+ return STATUS_NOT_SUPPORTED;
+ }
+
+ return status;
+}
+
+PVOID KvScanProc(
+ PKV_SCANPROC ScanProc
+ )
+{
+ PUCHAR bytes = ScanProc->Bytes;
+ ULONG length = ScanProc->Length;
+ ULONG_PTR endAddress = ScanProc->StartAddress + ScanProc->ScanLength;
+ ULONG_PTR i;
+
+ for (i = ScanProc->StartAddress; i < endAddress; i++)
+ {
+ if (memcmp((PVOID)i, bytes, length) == 0)
+ return (PVOID)(i + ScanProc->Displacement);
+ }
+
+ return NULL;
+}
+
+PVOID KvVerifyPrologue(
+ PVOID Address
+ )
+{
+ if (memcmp(Address, StandardPrologue, 5) == 0)
+ return Address;
+ else
+ return NULL;
+}