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:
wj32
2010-04-08 04:09:49 +00:00
parent 77adf9d7cb
commit 581ee8f8ef
52 changed files with 16341 additions and 0 deletions
+67
View File
@@ -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.
+7
View File
@@ -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
+2
View File
@@ -0,0 +1,2 @@
@echo off
auto & sc stop kprocesshacker & sc start kprocesshacker
+355
View File
@@ -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;
}
+408
View File
@@ -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.
+35
View File
@@ -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
+262
View File
@@ -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
+78
View File
@@ -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
+144
View File
@@ -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
+108
View File
@@ -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
+34
View File
@@ -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
+95
View File
@@ -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
+506
View File
@@ -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
+37
View File
@@ -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
+168
View File
@@ -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
+151
View File
@@ -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
+113
View File
@@ -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
+137
View File
@@ -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
+55
View File
@@ -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
+320
View File
@@ -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
+30
View File
@@ -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
+188
View File
@@ -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
+7
View File
@@ -0,0 +1,7 @@
#ifndef _TYPES_H
#define _TYPES_H
#include <ntifs.h>
#include "version.h"
#endif
+133
View File
@@ -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
+241
View File
@@ -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
+68
View File
@@ -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
+265
View File
@@ -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;
}
}
+414
View File
@@ -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
+1
View File
@@ -0,0 +1 @@
!INCLUDE $(NTMAKEENV)\makefile.def
+703
View File
@@ -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;
}
+872
View File
@@ -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;
}
+457
View File
@@ -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
+574
View File
@@ -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
);
}
+53
View File
@@ -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
+102
View File
@@ -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;
}
+29
View File
@@ -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
+312
View File
@@ -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
+513
View File
@@ -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
);
}
+71
View File
@@ -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);
}
+344
View File
@@ -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, &currentBlock))
{
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);
}
+115
View File
@@ -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;
}
+611
View File
@@ -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;
}