mirror of
https://github.com/mirror/processhacker
synced 2026-06-08 16:03:24 +00:00
copied KProcessHacker to ProcessHacker2 directory
git-svn-id: svn://svn.code.sf.net/p/processhacker/code@3040 21ef857c-d57f-4fe0-8362-d861dc6d29cd
This commit is contained in:
@@ -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
|
||||
Binary file not shown.
@@ -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
|
||||
@@ -0,0 +1,2 @@
|
||||
@echo off
|
||||
auto & sc stop kprocesshacker & sc start kprocesshacker
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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;
|
||||
}
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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;
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _TEST_H
|
||||
#define _TEST_H
|
||||
|
||||
#include "kph.h"
|
||||
|
||||
VOID KphTestPushLock();
|
||||
|
||||
#endif
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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
|
||||
@@ -0,0 +1,7 @@
|
||||
#ifndef _TYPES_H
|
||||
#define _TYPES_H
|
||||
|
||||
#include <ntifs.h>
|
||||
#include "version.h"
|
||||
|
||||
#endif
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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;
|
||||
}
|
||||
}
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1 @@
|
||||
!INCLUDE $(NTMAKEENV)\makefile.def
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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;
|
||||
}
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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;
|
||||
}
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
#include <windows.h>
|
||||
|
||||
#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
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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());
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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
|
||||
);
|
||||
}
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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);
|
||||
}
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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);
|
||||
}
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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;
|
||||
}
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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;
|
||||
}
|
||||
Reference in New Issue
Block a user