mirror of
https://github.com/mirror/processhacker
synced 2026-06-08 16:03:24 +00:00
abb8fb6915
git-svn-id: svn://svn.code.sf.net/p/processhacker/code@1718 21ef857c-d57f-4fe0-8362-d861dc6d29cd
2409 lines
70 KiB
C
2409 lines
70 KiB
C
/*
|
|
* Process Hacker Driver -
|
|
* main driver code
|
|
*
|
|
* Copyright (C) 2009 wj32
|
|
*
|
|
* This file is part of Process Hacker.
|
|
*
|
|
* Process Hacker is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* Process Hacker is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "include/kprocesshacker.h"
|
|
#include "include/debug.h"
|
|
|
|
#include "include/kph.h"
|
|
#include "include/protect.h"
|
|
#include "include/ps.h"
|
|
#include "include/sysservice.h"
|
|
#include "include/version.h"
|
|
|
|
#define CHECK_IN_LENGTH \
|
|
if (inLength < sizeof(*args)) \
|
|
{ \
|
|
status = STATUS_BUFFER_TOO_SMALL; \
|
|
goto IoControlEnd; \
|
|
}
|
|
#define CHECK_OUT_LENGTH \
|
|
if (outLength < sizeof(*ret)) \
|
|
{ \
|
|
status = STATUS_BUFFER_TOO_SMALL; \
|
|
goto IoControlEnd; \
|
|
}
|
|
#define CHECK_IN_OUT_LENGTH \
|
|
if (inLength < sizeof(*args) || outLength < sizeof(*ret)) \
|
|
{ \
|
|
status = STATUS_BUFFER_TOO_SMALL; \
|
|
goto IoControlEnd; \
|
|
}
|
|
|
|
PDRIVER_OBJECT KphDriverObject;
|
|
|
|
static PKPH_OBJECT_TYPE ClientEntryType;
|
|
static LIST_ENTRY ClientListHead;
|
|
static EX_PUSH_LOCK ClientListLock;
|
|
|
|
static BOOLEAN ProtectionInitialized = FALSE;
|
|
static FAST_MUTEX ProtectionMutex;
|
|
|
|
static ULONG SsStartCount = 0;
|
|
static FAST_MUTEX SsMutex;
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE, DriverEntry)
|
|
#pragma alloc_text(PAGE, DriverUnload)
|
|
#pragma alloc_text(PAGE, KphDispatchCreate)
|
|
#pragma alloc_text(PAGE, KphDispatchClose)
|
|
#pragma alloc_text(PAGE, KphDispatchDeviceControl)
|
|
#pragma alloc_text(PAGE, KphDispatchRead)
|
|
#pragma alloc_text(PAGE, KphUnsupported)
|
|
#endif
|
|
|
|
NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
int i;
|
|
PDEVICE_OBJECT deviceObject = NULL;
|
|
UNICODE_STRING deviceName, dosDeviceName;
|
|
|
|
KphDriverObject = DriverObject;
|
|
|
|
/* Initialize version information. */
|
|
status = KvInit();
|
|
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
if (status == STATUS_NOT_SUPPORTED)
|
|
dprintf("Your operating system is not supported by KProcessHacker\n");
|
|
|
|
return status;
|
|
}
|
|
|
|
/* Initialize NT KPH. */
|
|
status = KphNtInit();
|
|
|
|
if (!NT_SUCCESS(status))
|
|
return status;
|
|
|
|
/* Initialize hooking. */
|
|
status = KphHookInit();
|
|
|
|
if (!NT_SUCCESS(status))
|
|
return status;
|
|
|
|
/* Initialize the KPH object manager. */
|
|
status = KphRefInit();
|
|
|
|
if (!NT_SUCCESS(status))
|
|
return status;
|
|
|
|
/* Initialize system service logging. */
|
|
status = KphSsLogInit();
|
|
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
KphRefDeinit();
|
|
return status;
|
|
}
|
|
|
|
/* Initialize trace databases. */
|
|
status = KphTraceDatabaseInitialization();
|
|
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
KphRefDeinit();
|
|
return status;
|
|
}
|
|
|
|
/* Initialize client list structures. */
|
|
InitializeListHead(&ClientListHead);
|
|
ExInitializePushLock(&ClientListLock);
|
|
|
|
status = KphCreateObjectType(
|
|
&ClientEntryType,
|
|
PagedPool,
|
|
0,
|
|
ClientEntryDeleteProcedure
|
|
);
|
|
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
KphRefDeinit();
|
|
return status;
|
|
}
|
|
|
|
/* Initialize process protection. */
|
|
ExInitializeFastMutex(&ProtectionMutex);
|
|
/* Initialize the system service logging mutex. */
|
|
ExInitializeFastMutex(&SsMutex);
|
|
|
|
RtlInitUnicodeString(&deviceName, KPH_DEVICE_NAME);
|
|
RtlInitUnicodeString(&dosDeviceName, KPH_DEVICE_DOS_NAME);
|
|
|
|
/* Create the KProcessHacker device. */
|
|
status = IoCreateDevice(DriverObject, 0, &deviceName,
|
|
FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &deviceObject);
|
|
|
|
/* Set up the major functions. */
|
|
for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)
|
|
DriverObject->MajorFunction[i] = NULL;
|
|
|
|
DriverObject->MajorFunction[IRP_MJ_CLOSE] = KphDispatchClose;
|
|
DriverObject->MajorFunction[IRP_MJ_CREATE] = KphDispatchCreate;
|
|
DriverObject->MajorFunction[IRP_MJ_READ] = KphDispatchRead;
|
|
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = KphDispatchDeviceControl;
|
|
DriverObject->DriverUnload = DriverUnload;
|
|
|
|
deviceObject->Flags |= DO_BUFFERED_IO;
|
|
deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
|
|
|
|
IoCreateSymbolicLink(&dosDeviceName, &deviceName);
|
|
|
|
dprintf("Driver loaded\n");
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
VOID DriverUnload(PDRIVER_OBJECT DriverObject)
|
|
{
|
|
UNICODE_STRING dosDeviceName;
|
|
|
|
RtlInitUnicodeString(&dosDeviceName, KPH_DEVICE_DOS_NAME);
|
|
IoDeleteSymbolicLink(&dosDeviceName);
|
|
IoDeleteDevice(DriverObject->DeviceObject);
|
|
|
|
ExAcquireFastMutex(&ProtectionMutex);
|
|
|
|
if (ProtectionInitialized)
|
|
{
|
|
KphProtectDeinit();
|
|
ProtectionInitialized = FALSE;
|
|
}
|
|
|
|
ExReleaseFastMutex(&ProtectionMutex);
|
|
|
|
/* Make sure system service logging is disabled. */
|
|
if (SsStartCount > 0)
|
|
SsUnref(SsStartCount);
|
|
|
|
/* Free system service logging structures. */
|
|
KphSsLogDeinit();
|
|
|
|
/* Free all objects in the object manager. */
|
|
KphRefDeinit();
|
|
|
|
dprintf("Driver unloaded\n");
|
|
}
|
|
|
|
NTSTATUS KphDispatchCreate(PDEVICE_OBJECT DeviceObject, PIRP Irp)
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
|
|
#ifdef KPH_REQUIRE_DEBUG_PRIVILEGE
|
|
if (!SeSinglePrivilegeCheck(SeExports->SeDebugPrivilege, UserMode))
|
|
{
|
|
dprintf("Client (PID %d) was refused\n", PsGetCurrentProcessId());
|
|
Irp->IoStatus.Status = STATUS_PRIVILEGE_NOT_HELD;
|
|
|
|
return STATUS_PRIVILEGE_NOT_HELD;
|
|
}
|
|
#endif
|
|
|
|
/* Add a client entry. Note that we don't dereference it because
|
|
* we keep one reference for it being on the client list.
|
|
*/
|
|
if (!CreateClientEntry(NULL))
|
|
{
|
|
Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
dprintf("Client (PID %d) connected\n", PsGetCurrentProcessId());
|
|
dprintf("Base IOCTL is 0x%08x\n", KPH_CTL_CODE(0));
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS KphDispatchClose(PDEVICE_OBJECT DeviceObject, PIRP Irp)
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
PKPH_CLIENT_ENTRY clientEntry;
|
|
|
|
ExAcquireFastMutex(&ProtectionMutex);
|
|
|
|
if (ProtectionInitialized)
|
|
{
|
|
ULONG count = KphProtectRemoveByTag(PsGetCurrentProcessId());
|
|
dprintf("Removed %d protection entries\n", count);
|
|
}
|
|
|
|
ExReleaseFastMutex(&ProtectionMutex);
|
|
|
|
/* Get the current client entry and dereference it twice to remove it. */
|
|
clientEntry = ReferenceClientEntry(NULL);
|
|
|
|
if (clientEntry)
|
|
KphDereferenceObjectEx(clientEntry, 2, FALSE);
|
|
|
|
dprintf("Client (PID %d) disconnected\n", PsGetCurrentProcessId());
|
|
|
|
return status;
|
|
}
|
|
|
|
VOID InitProtection()
|
|
{
|
|
ExAcquireFastMutex(&ProtectionMutex);
|
|
|
|
if (!ProtectionInitialized)
|
|
{
|
|
if (NT_SUCCESS(KphProtectInit()))
|
|
ProtectionInitialized = TRUE;
|
|
}
|
|
|
|
ExReleaseFastMutex(&ProtectionMutex);
|
|
}
|
|
|
|
VOID SsRef(LONG count)
|
|
{
|
|
LONG oldRefCount;
|
|
|
|
ASSERT(count >= 0);
|
|
|
|
if (count == 0)
|
|
return;
|
|
|
|
ExAcquireFastMutex(&SsMutex);
|
|
|
|
/* Add references. */
|
|
oldRefCount = InterlockedExchangeAdd(&SsStartCount, count);
|
|
ASSERT(oldRefCount >= 0);
|
|
|
|
/* Start system service logging if this was the first bunch of references. */
|
|
if (oldRefCount == 0)
|
|
KphSsLogStart();
|
|
|
|
ExReleaseFastMutex(&SsMutex);
|
|
}
|
|
|
|
VOID SsUnref(LONG count)
|
|
{
|
|
LONG oldRefCount;
|
|
|
|
ASSERT(count >= 0);
|
|
|
|
if (count == 0)
|
|
return;
|
|
|
|
ExAcquireFastMutex(&SsMutex);
|
|
|
|
oldRefCount = InterlockedExchangeAdd(&SsStartCount, -count);
|
|
ASSERT(oldRefCount > 0);
|
|
|
|
if (oldRefCount - count == 0)
|
|
KphSsLogStop();
|
|
|
|
ExReleaseFastMutex(&SsMutex);
|
|
}
|
|
|
|
VOID NTAPI ClientEntryDeleteProcedure(
|
|
__in PVOID Object,
|
|
__in ULONG Flags
|
|
)
|
|
{
|
|
PKPH_CLIENT_ENTRY entry = (PKPH_CLIENT_ENTRY)Object;
|
|
|
|
/* Lower the SS start count. */
|
|
SsUnref(entry->SsStartCount);
|
|
|
|
/* Free the handle table. */
|
|
KphFreeHandleTable(entry->HandleTable);
|
|
|
|
/* Remove the entry from the client list. */
|
|
KeEnterCriticalRegion();
|
|
ExAcquirePushLockExclusive(&ClientListLock);
|
|
RemoveEntryList(&entry->ClientListEntry);
|
|
ExReleasePushLock(&ClientListLock);
|
|
KeLeaveCriticalRegion();
|
|
}
|
|
|
|
PKPH_CLIENT_ENTRY CreateClientEntry(
|
|
__in_opt HANDLE ProcessId
|
|
)
|
|
{
|
|
PKPH_CLIENT_ENTRY entry;
|
|
PKPH_HANDLE_TABLE handleTable;
|
|
|
|
/* If the PID wasn't specified, use the current one. */
|
|
if (!ProcessId)
|
|
ProcessId = PsGetCurrentProcessId();
|
|
|
|
if (!NT_SUCCESS(KphCreateHandleTable(
|
|
&handleTable,
|
|
KPH_CLIENT_MAXHANDLES,
|
|
sizeof(KPH_HANDLE_TABLE_ENTRY),
|
|
TAG_CLIENT_HANDLETABLE
|
|
)))
|
|
return NULL;
|
|
|
|
if (!NT_SUCCESS(KphCreateObject(
|
|
&entry,
|
|
sizeof(KPH_CLIENT_ENTRY),
|
|
0,
|
|
ClientEntryType,
|
|
0
|
|
)))
|
|
{
|
|
KphFreeHandleTable(handleTable);
|
|
return NULL;
|
|
}
|
|
|
|
/* Initialize the entry. */
|
|
entry->ProcessId = ProcessId;
|
|
entry->HandleTable = handleTable;
|
|
KphInitializeGuardedLock(&entry->SsLock, FALSE);
|
|
entry->SsStartCount = 0;
|
|
|
|
/* Insert the entry into the client list. */
|
|
KeEnterCriticalRegion();
|
|
ExAcquirePushLockExclusive(&ClientListLock);
|
|
InsertHeadList(&ClientListHead, &entry->ClientListEntry);
|
|
ExReleasePushLock(&ClientListLock);
|
|
KeLeaveCriticalRegion();
|
|
|
|
return entry;
|
|
}
|
|
|
|
PKPH_CLIENT_ENTRY ReferenceClientEntry(
|
|
__in_opt HANDLE ProcessId
|
|
)
|
|
{
|
|
PLIST_ENTRY entry = ClientListHead.Flink;
|
|
|
|
/* If the PID wasn't specified, use the current one. */
|
|
if (!ProcessId)
|
|
ProcessId = PsGetCurrentProcessId();
|
|
|
|
KeEnterCriticalRegion();
|
|
ExAcquirePushLockShared(&ClientListLock);
|
|
|
|
/* Find the client entry. */
|
|
while (entry != &ClientListHead)
|
|
{
|
|
PKPH_CLIENT_ENTRY clientEntry =
|
|
CONTAINING_RECORD(entry, KPH_CLIENT_ENTRY, ClientListEntry);
|
|
|
|
if (clientEntry->ProcessId == ProcessId)
|
|
{
|
|
PKPH_CLIENT_ENTRY returnEntry = NULL;
|
|
|
|
/* Reference and return the entry. */
|
|
if (KphReferenceObjectSafe(clientEntry))
|
|
{
|
|
returnEntry = clientEntry;
|
|
}
|
|
|
|
ExReleasePushLock(&ClientListLock);
|
|
KeLeaveCriticalRegion();
|
|
|
|
return returnEntry;
|
|
}
|
|
|
|
entry = entry->Flink;
|
|
}
|
|
|
|
ExReleasePushLock(&ClientListLock);
|
|
KeLeaveCriticalRegion();
|
|
|
|
return NULL;
|
|
}
|
|
|
|
NTSTATUS CloseClientHandle(
|
|
__in_opt HANDLE ProcessId,
|
|
__in HANDLE Handle
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
PKPH_CLIENT_ENTRY clientEntry;
|
|
|
|
clientEntry = ReferenceClientEntry(ProcessId);
|
|
|
|
if (!clientEntry)
|
|
return STATUS_UNSUCCESSFUL;
|
|
|
|
status = KphCloseHandle(clientEntry->HandleTable, Handle);
|
|
KphDereferenceObject(clientEntry);
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS CreateClientHandle(
|
|
__in_opt HANDLE ProcessId,
|
|
__in PVOID Object,
|
|
__out PHANDLE Handle
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
PKPH_CLIENT_ENTRY clientEntry;
|
|
|
|
clientEntry = ReferenceClientEntry(ProcessId);
|
|
|
|
if (!clientEntry)
|
|
return STATUS_UNSUCCESSFUL;
|
|
|
|
status = KphCreateHandle(clientEntry->HandleTable, Object, Handle);
|
|
KphDereferenceObject(clientEntry);
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS ReferenceClientHandle(
|
|
__in_opt HANDLE ProcessId,
|
|
__in HANDLE Handle,
|
|
__in PKPH_OBJECT_TYPE ObjectType,
|
|
__out PVOID *Object
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
PKPH_CLIENT_ENTRY clientEntry;
|
|
|
|
clientEntry = ReferenceClientEntry(ProcessId);
|
|
|
|
if (!clientEntry)
|
|
return STATUS_UNSUCCESSFUL;
|
|
|
|
status = KphReferenceObjectByHandle(
|
|
clientEntry->HandleTable,
|
|
Handle,
|
|
ObjectType,
|
|
Object
|
|
);
|
|
KphDereferenceObject(clientEntry);
|
|
|
|
return status;
|
|
}
|
|
|
|
PCHAR GetIoControlName(ULONG ControlCode)
|
|
{
|
|
switch (ControlCode)
|
|
{
|
|
case KPH_CLOSEHANDLE:
|
|
return "Client Close Handle";
|
|
case KPH_SSQUERYCLIENTENTRY:
|
|
return "SsQueryClientEntry";
|
|
case KPH_GETFILEOBJECTNAME:
|
|
return "Get File Object Name";
|
|
case KPH_OPENPROCESS:
|
|
return "KphOpenProcess";
|
|
case KPH_OPENTHREAD:
|
|
return "KphOpenThread";
|
|
case KPH_OPENPROCESSTOKEN:
|
|
return "KphOpenProcessTokenEx";
|
|
case KPH_GETPROCESSPROTECTED:
|
|
return "Get Process Protected";
|
|
case KPH_SETPROCESSPROTECTED:
|
|
return "Set Process Protected";
|
|
case KPH_TERMINATEPROCESS:
|
|
return "KphTerminateProcess";
|
|
case KPH_SUSPENDPROCESS:
|
|
return "KphSuspendProcess";
|
|
case KPH_RESUMEPROCESS:
|
|
return "KphResumeProcess";
|
|
case KPH_READVIRTUALMEMORY:
|
|
return "KphReadVirtualMemory";
|
|
case KPH_WRITEVIRTUALMEMORY:
|
|
return "KphWriteVirtualMemory";
|
|
case KPH_SETPROCESSTOKEN:
|
|
return "Set Process Token";
|
|
case KPH_GETTHREADSTARTADDRESS:
|
|
return "Get Thread Start Address";
|
|
case KPH_SETHANDLEATTRIBUTES:
|
|
return "Set Handle Attributes";
|
|
case KPH_GETHANDLEOBJECTNAME:
|
|
return "Get Handle Object Name";
|
|
case KPH_OPENPROCESSJOB:
|
|
return "KphOpenProcessJob";
|
|
case KPH_GETCONTEXTTHREAD:
|
|
return "KphGetContextThread";
|
|
case KPH_SETCONTEXTTHREAD:
|
|
return "KphSetContextThread";
|
|
case KPH_GETTHREADWIN32THREAD:
|
|
return "KphGetThreadWin32Thread";
|
|
case KPH_DUPLICATEOBJECT:
|
|
return "KphDuplicateObject";
|
|
case KPH_ZWQUERYOBJECT:
|
|
return "ZwQueryObject";
|
|
case KPH_GETPROCESSID:
|
|
return "KphGetProcessId";
|
|
case KPH_GETTHREADID:
|
|
return "KphGetThreadId";
|
|
case KPH_TERMINATETHREAD:
|
|
return "KphTerminateThread";
|
|
case KPH_GETFEATURES:
|
|
return "Get Features";
|
|
case KPH_SETHANDLEGRANTEDACCESS:
|
|
return "KphSetHandleGrantedAccess";
|
|
case KPH_ASSIGNIMPERSONATIONTOKEN:
|
|
return "KphAssignImpersonationToken";
|
|
case KPH_PROTECTADD:
|
|
return "Add Process Protection";
|
|
case KPH_PROTECTREMOVE:
|
|
return "Remove Process Protection";
|
|
case KPH_PROTECTQUERY:
|
|
return "Query Process Protection";
|
|
case KPH_UNSAFEREADVIRTUALMEMORY:
|
|
return "KphUnsafeReadVirtualMemory";
|
|
case KPH_SETEXECUTEOPTIONS:
|
|
return "Set Execute Options";
|
|
case KPH_QUERYPROCESSHANDLES:
|
|
return "KphQueryProcessHandles";
|
|
case KPH_OPENTHREADPROCESS:
|
|
return "KphOpenThreadProcess";
|
|
case KPH_CAPTURESTACKBACKTRACETHREAD:
|
|
return "KphCaptureStackBackTraceThread";
|
|
case KPH_DANGEROUSTERMINATETHREAD:
|
|
return "KphDangerousTerminateThread";
|
|
case KPH_OPENDEVICE:
|
|
return "KphOpenDevice";
|
|
case KPH_OPENDRIVER:
|
|
return "KphOpenDriver";
|
|
case KPH_QUERYINFORMATIONDRIVER:
|
|
return "KphQueryInformationDriver";
|
|
case KPH_OPENDIRECTORYOBJECT:
|
|
return "KphOpenDirectoryObject";
|
|
case KPH_SSREF:
|
|
return "SsRef";
|
|
case KPH_SSUNREF:
|
|
return "SsUnref";
|
|
case KPH_SSCREATECLIENTENTRY:
|
|
return "SsCreateClientEntry";
|
|
case KPH_SSCREATERULESETENTRY:
|
|
return "SsCreateRuleSetEntry";
|
|
case KPH_SSREMOVERULE:
|
|
return "SsRemoveRule";
|
|
case KPH_SSADDPROCESSIDRULE:
|
|
return "SsAddProcessIdRule";
|
|
case KPH_SSADDTHREADIDRULE:
|
|
return "SsAddThreadIdRule";
|
|
case KPH_SSADDPREVIOUSMODERULE:
|
|
return "SsAddPreviousModeRule";
|
|
case KPH_SSADDNUMBERRULE:
|
|
return "SsAddNumberRule";
|
|
case KPH_SSENABLECLIENTENTRY:
|
|
return "SsEnableClientEntry";
|
|
default:
|
|
return "Unknown";
|
|
}
|
|
}
|
|
|
|
NTSTATUS KphDispatchDeviceControl(PDEVICE_OBJECT DeviceObject, PIRP Irp)
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
PIO_STACK_LOCATION ioStackIrp = NULL;
|
|
PVOID dataBuffer;
|
|
ULONG controlCode;
|
|
ULONG inLength = 0;
|
|
ULONG outLength = 0;
|
|
ULONG retLength = 0;
|
|
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
ioStackIrp = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
if (ioStackIrp == NULL)
|
|
{
|
|
status = STATUS_INTERNAL_ERROR;
|
|
goto IoControlEnd;
|
|
}
|
|
|
|
dataBuffer = Irp->AssociatedIrp.SystemBuffer;
|
|
|
|
if (dataBuffer == NULL && (inLength != 0 || outLength != 0))
|
|
{
|
|
status = STATUS_BUFFER_TOO_SMALL;
|
|
goto IoControlEnd;
|
|
}
|
|
|
|
inLength = ioStackIrp->Parameters.DeviceIoControl.InputBufferLength;
|
|
outLength = ioStackIrp->Parameters.DeviceIoControl.OutputBufferLength;
|
|
controlCode = ioStackIrp->Parameters.DeviceIoControl.IoControlCode;
|
|
|
|
dprintf("IoControl 0x%08x (%s)\n", controlCode, GetIoControlName(controlCode));
|
|
|
|
/* 1-byte packing for KPH input/output structures. */
|
|
#include <pshpack1.h>
|
|
|
|
switch (controlCode)
|
|
{
|
|
/* Client Close Handle
|
|
*
|
|
* Closes a handle opened by the client.
|
|
*/
|
|
case KPH_CLOSEHANDLE:
|
|
{
|
|
struct
|
|
{
|
|
HANDLE Handle;
|
|
} *args = dataBuffer;
|
|
PKPH_CLIENT_ENTRY clientEntry;
|
|
|
|
CHECK_IN_LENGTH;
|
|
|
|
status = CloseClientHandle(NULL, args->Handle);
|
|
}
|
|
break;
|
|
|
|
/* SsQueryClientEntry
|
|
*
|
|
* Queries information about a client entry.
|
|
*/
|
|
case KPH_SSQUERYCLIENTENTRY:
|
|
{
|
|
struct
|
|
{
|
|
HANDLE ClientEntryHandle;
|
|
PKPHSS_CLIENT_INFORMATION ClientInformation;
|
|
ULONG ClientInformationLength;
|
|
PULONG ReturnLength;
|
|
} *args = dataBuffer;
|
|
PKPHSS_CLIENT_ENTRY clientEntry;
|
|
|
|
CHECK_IN_LENGTH;
|
|
|
|
/* Reference the client entry. */
|
|
status = ReferenceClientHandle(
|
|
NULL,
|
|
args->ClientEntryHandle,
|
|
KphSsClientEntryType,
|
|
&clientEntry
|
|
);
|
|
|
|
if (!NT_SUCCESS(status))
|
|
goto IoControlEnd;
|
|
|
|
/* Query the client entry. */
|
|
status = KphSsQueryClientEntry(
|
|
clientEntry,
|
|
args->ClientInformation,
|
|
args->ClientInformationLength,
|
|
args->ReturnLength,
|
|
UserMode
|
|
);
|
|
KphDereferenceObject(clientEntry);
|
|
}
|
|
break;
|
|
|
|
/* Get File Object Name
|
|
*
|
|
* Gets the file name of the specified handle. The handle can be remote;
|
|
* in that case the process ID must be specified. Otherwise, specify the
|
|
* current process ID.
|
|
*/
|
|
case KPH_GETFILEOBJECTNAME:
|
|
{
|
|
struct
|
|
{
|
|
HANDLE Handle;
|
|
HANDLE ProcessId;
|
|
} *args = dataBuffer;
|
|
KPH_ATTACH_STATE attachState;
|
|
PFILE_OBJECT object;
|
|
|
|
CHECK_IN_LENGTH;
|
|
|
|
status = KphAttachProcessId(args->ProcessId, &attachState);
|
|
|
|
if (!NT_SUCCESS(status))
|
|
goto IoControlEnd;
|
|
|
|
/* See the block for KPH_ZWQUERYOBJECT for information. */
|
|
if (attachState.Process == PsInitialSystemProcess)
|
|
MakeKernelHandle(args->Handle);
|
|
|
|
status = ObReferenceObjectByHandle(args->Handle, 0,
|
|
*IoFileObjectType, KernelMode, &object, NULL);
|
|
KphDetachProcess(&attachState);
|
|
|
|
if (!NT_SUCCESS(status))
|
|
{
|
|
goto IoControlEnd;
|
|
}
|
|
|
|
status = KphQueryNameObject(
|
|
object,
|
|
dataBuffer,
|
|
outLength,
|
|
&retLength
|
|
);
|
|
ObDereferenceObject(object);
|
|
}
|
|
break;
|
|
|
|
/* KphOpenProcess
|
|
*
|
|
* Opens the specified process. This call will never fail unless:
|
|
* 1. PsLookupProcessByProcessId, ObOpenObjectByPointer or some lower-level
|
|
* function is hooked, or
|
|
* 2. The process is protected.
|
|
*/
|
|
case KPH_OPENPROCESS:
|
|
{
|
|
struct
|
|
{
|
|
HANDLE ProcessId;
|
|
ACCESS_MASK DesiredAccess;
|
|
} *args = dataBuffer;
|
|
struct
|
|
{
|
|
HANDLE ProcessHandle;
|
|
} *ret = dataBuffer;
|
|
OBJECT_ATTRIBUTES objectAttributes = { 0 };
|
|
CLIENT_ID clientId;
|
|
|
|
CHECK_IN_OUT_LENGTH;
|
|
|
|
clientId.UniqueThread = 0;
|
|
clientId.UniqueProcess = args->ProcessId;
|
|
status = KphOpenProcess(
|
|
&ret->ProcessHandle,
|
|
args->DesiredAccess,
|
|
&objectAttributes,
|
|
&clientId,
|
|
KernelMode
|
|
);
|
|
|
|
if (!NT_SUCCESS(status))
|
|
goto IoControlEnd;
|
|
|
|
retLength = sizeof(*ret);
|
|
}
|
|
break;
|
|
|
|
/* KphOpenThread
|
|
*
|
|
* Opens the specified thread. This call will never fail unless:
|
|
* 1. PsLookupProcessThreadByCid, ObOpenObjectByPointer or some lower-level
|
|
* function is hooked, or
|
|
* 2. The thread's process is protected.
|
|
*/
|
|
case KPH_OPENTHREAD:
|
|
{
|
|
struct
|
|
{
|
|
HANDLE ThreadId;
|
|
ACCESS_MASK DesiredAccess;
|
|
} *args = dataBuffer;
|
|
struct
|
|
{
|
|
HANDLE ThreadHandle;
|
|
} *ret = dataBuffer;
|
|
OBJECT_ATTRIBUTES objectAttributes = { 0 };
|
|
CLIENT_ID clientId;
|
|
|
|
CHECK_IN_OUT_LENGTH;
|
|
|
|
clientId.UniqueThread = args->ThreadId;
|
|
clientId.UniqueProcess = 0;
|
|
status = KphOpenThread(
|
|
&ret->ThreadHandle,
|
|
args->DesiredAccess,
|
|
&objectAttributes,
|
|
&clientId,
|
|
KernelMode
|
|
);
|
|
|
|
if (!NT_SUCCESS(status))
|
|
goto IoControlEnd;
|
|
|
|
retLength = sizeof(*ret);
|
|
}
|
|
break;
|
|
|
|
/* KphOpenProcessToken
|
|
*
|
|
* Opens the specified process' token. This call will never fail unless
|
|
* a low-level function is hooked.
|
|
*/
|
|
case KPH_OPENPROCESSTOKEN:
|
|
{
|
|
struct
|
|
{
|
|
HANDLE ProcessHandle;
|
|
ACCESS_MASK DesiredAccess;
|
|
} *args = dataBuffer;
|
|
struct
|
|
{
|
|
HANDLE TokenHandle;
|
|
} *ret = dataBuffer;
|
|
|
|
CHECK_IN_OUT_LENGTH;
|
|
|
|
status = KphOpenProcessTokenEx(
|
|
args->ProcessHandle,
|
|
args->DesiredAccess,
|
|
0,
|
|
&ret->TokenHandle,
|
|
KernelMode
|
|
);
|
|
|
|
if (!NT_SUCCESS(status))
|
|
goto IoControlEnd;
|
|
|
|
retLength = sizeof(*ret);
|
|
}
|
|
break;
|
|
|
|
/* Get Process Protected
|
|
*
|
|
* Gets whether the process is protected.
|
|
*/
|
|
case KPH_GETPROCESSPROTECTED:
|
|
{
|
|
struct
|
|
{
|
|
HANDLE ProcessId;
|
|
} *args = dataBuffer;
|
|
struct
|
|
{
|
|
BOOLEAN IsProtected;
|
|
} *ret = dataBuffer;
|
|
PEPROCESS processObject;
|
|
|
|
CHECK_IN_OUT_LENGTH;
|
|
|
|
status = PsLookupProcessByProcessId(args->ProcessId, &processObject);
|
|
|
|
if (!NT_SUCCESS(status))
|
|
goto IoControlEnd;
|
|
|
|
ret->IsProtected =
|
|
(CHAR)GET_BIT(
|
|
*(PULONG)KVOFF(processObject, OffEpProtectedProcessOff),
|
|
OffEpProtectedProcessBit
|
|
);
|
|
ObDereferenceObject(processObject);
|
|
retLength = sizeof(*ret);
|
|
}
|
|
break;
|
|
|
|
/* Set Process Protected
|
|
*
|
|
* Sets whether the process is protected.
|
|
*/
|
|
case KPH_SETPROCESSPROTECTED:
|
|
{
|
|
struct
|
|
{
|
|
HANDLE ProcessId;
|
|
BOOLEAN IsProtected;
|
|
} *args = dataBuffer;
|
|
PEPROCESS processObject;
|
|
|
|
CHECK_IN_LENGTH;
|
|
|
|
status = PsLookupProcessByProcessId(args->ProcessId, &processObject);
|
|
|
|
if (!NT_SUCCESS(status))
|
|
goto IoControlEnd;
|
|
|
|
if (args->IsProtected)
|
|
{
|
|
SET_BIT(
|
|
*(PULONG)KVOFF(processObject, OffEpProtectedProcessOff),
|
|
OffEpProtectedProcessBit
|
|
);
|
|
}
|
|
else
|
|
{
|
|
CLEAR_BIT(
|
|
*(PULONG)KVOFF(processObject, OffEpProtectedProcessOff),
|
|
OffEpProtectedProcessBit
|
|
);
|
|
}
|
|
|
|
ObDereferenceObject(processObject);
|
|
}
|
|
break;
|
|
|
|
/* KphTerminateProcess
|
|
*
|
|
* Terminates the specified process. This call will never fail unless
|
|
* PsTerminateProcess could not be located and Zw/NtTerminateProcess
|
|
* is hooked, or an attempt was made to terminate the current process.
|
|
* In that case, the call will fail with STATUS_CANT_TERMINATE_SELF.
|
|
*/
|
|
case KPH_TERMINATEPROCESS:
|
|
{
|
|
struct
|
|
{
|
|
HANDLE ProcessHandle;
|
|
NTSTATUS ExitStatus;
|
|
} *args = dataBuffer;
|
|
|
|
CHECK_IN_LENGTH;
|
|
|
|
status = KphTerminateProcess(args->ProcessHandle, args->ExitStatus);
|
|
}
|
|
break;
|
|
|
|
/* KphSuspendProcess
|
|
*
|
|
* Suspends the specified process. This call will fail on Windows XP
|
|
* and below.
|
|
*/
|
|
case KPH_SUSPENDPROCESS:
|
|
{
|
|
struct
|
|
{
|
|
HANDLE ProcessHandle;
|
|
} *args = dataBuffer;
|
|
|
|
CHECK_IN_LENGTH;
|
|
|
|
status = KphSuspendProcess(args->ProcessHandle);
|
|
}
|
|
break;
|
|
|
|
/* KphResumeProcess
|
|
*
|
|
* Resumes the specified process. This call will fail on Windows XP
|
|
* and below.
|
|
*/
|
|
case KPH_RESUMEPROCESS:
|
|
{
|
|
struct
|
|
{
|
|
HANDLE ProcessHandle;
|
|
} *args = dataBuffer;
|
|
|
|
CHECK_IN_LENGTH;
|
|
|
|
status = KphResumeProcess(args->ProcessHandle);
|
|
}
|
|
break;
|
|
|
|
/* KphReadVirtualMemory
|
|
*
|
|
* Reads process memory.
|
|
*/
|
|
case KPH_READVIRTUALMEMORY:
|
|
{
|
|
struct
|
|
{
|
|
HANDLE ProcessHandle;
|
|
PVOID BaseAddress;
|
|
PVOID Buffer;
|
|
ULONG BufferLength;
|
|
PULONG ReturnLength;
|
|
} *args = dataBuffer;
|
|
|
|
CHECK_IN_LENGTH;
|
|
|
|
status = KphReadVirtualMemory(
|
|
args->ProcessHandle,
|
|
args->BaseAddress,
|
|
args->Buffer,
|
|
args->BufferLength,
|
|
args->ReturnLength,
|
|
UserMode
|
|
);
|
|
}
|
|
break;
|
|
|
|
/* KphWriteVirtualMemory
|
|
*
|
|
* Writes to process memory.
|
|
*/
|
|
case KPH_WRITEVIRTUALMEMORY:
|
|
{
|
|
struct
|
|
{
|
|
HANDLE ProcessHandle;
|
|
PVOID BaseAddress;
|
|
PVOID Buffer;
|
|
ULONG BufferLength;
|
|
PULONG ReturnLength;
|
|
} *args = dataBuffer;
|
|
|
|
CHECK_IN_LENGTH;
|
|
|
|
status = KphWriteVirtualMemory(
|
|
args->ProcessHandle,
|
|
args->BaseAddress,
|
|
args->Buffer,
|
|
args->BufferLength,
|
|
args->ReturnLength,
|
|
UserMode
|
|
);
|
|
}
|
|
break;
|
|
|
|
/* Set Process Token
|
|
*
|
|
* Assigns the primary token of a source process to a target process.
|
|
*/
|
|
case KPH_SETPROCESSTOKEN:
|
|
{
|
|
struct
|
|
{
|
|
HANDLE SourceProcessId;
|
|
HANDLE TargetProcessId;
|
|
} *args = dataBuffer;
|
|
|
|
CHECK_IN_LENGTH;
|
|
|
|
status = SetProcessToken(args->SourceProcessId, args->TargetProcessId);
|
|
}
|
|
break;
|
|
|
|
/* Get Thread Start Address
|
|
*
|
|
* Gets the specified thread's start address.
|
|
*/
|
|
case KPH_GETTHREADSTARTADDRESS:
|
|
{
|
|
struct
|
|
{
|
|
HANDLE ThreadHandle;
|
|
} *args = dataBuffer;
|
|
struct
|
|
{
|
|
PVOID StartAddress;
|
|
} *ret = dataBuffer;
|
|
PETHREAD threadObject;
|
|
|
|
CHECK_IN_OUT_LENGTH;
|
|
|
|
status = ObReferenceObjectByHandle(args->ThreadHandle, 0, *PsThreadType, KernelMode, &threadObject, NULL);
|
|
|
|
if (!NT_SUCCESS(status))
|
|
goto IoControlEnd;
|
|
|
|
/* Get the Win32StartAddress */
|
|
if (!(ret->StartAddress = *(PVOID *)KVOFF(threadObject, OffEtWin32StartAddress)))
|
|
{
|
|
/* If that failed, get the StartAddress */
|
|
ret->StartAddress = *(PVOID *)KVOFF(threadObject, OffEtStartAddress);
|
|
}
|
|
|
|
ObDereferenceObject(threadObject);
|
|
retLength = sizeof(*ret);
|
|
}
|
|
break;
|
|
|
|
/* Set Handle Attributes
|
|
*
|
|
* Sets handle flags in the specified process.
|
|
*/
|
|
case KPH_SETHANDLEATTRIBUTES:
|
|
{
|
|
struct
|
|
{
|
|
HANDLE ProcessHandle;
|
|
HANDLE Handle;
|
|
ULONG Flags;
|
|
} *args = dataBuffer;
|
|
KPH_ATTACH_STATE attachState;
|
|
OBJECT_HANDLE_FLAG_INFORMATION handleFlags = { 0 };
|
|
|
|
CHECK_IN_LENGTH;
|
|
|
|
status = KphAttachProcessHandle(args->ProcessHandle, &attachState);
|
|
|
|
if (!NT_SUCCESS(status))
|
|
goto IoControlEnd;
|
|
|
|
if (args->Flags & OBJ_PROTECT_CLOSE)
|
|
handleFlags.ProtectFromClose = TRUE;
|
|
if (args->Flags & OBJ_INHERIT)
|
|
handleFlags.Inherit = TRUE;
|
|
|
|
status = ObSetHandleAttributes(args->Handle, &handleFlags, UserMode);
|
|
KphDetachProcess(&attachState);
|
|
}
|
|
break;
|
|
|
|
/* Get Handle Object Name
|
|
*
|
|
* Gets the name of the specified handle. The handle can be remote; in
|
|
* that case a valid process handle must be passed. Otherwise, set the
|
|
* process handle to -1 (NtCurrentProcess()).
|
|
*/
|
|
case KPH_GETHANDLEOBJECTNAME:
|
|
{
|
|
struct
|
|
{
|
|
HANDLE ProcessHandle;
|
|
HANDLE Handle;
|
|
} *args = dataBuffer;
|
|
KPH_ATTACH_STATE attachState;
|
|
PVOID object;
|
|
|
|
CHECK_IN_LENGTH;
|
|
|
|
status = KphAttachProcessHandle(args->ProcessHandle, &attachState);
|
|
|
|
if (!NT_SUCCESS(status))
|
|
goto IoControlEnd;
|
|
|
|
/* See the block for KPH_ZWQUERYOBJECT for information. */
|
|
if (attachState.Process == PsInitialSystemProcess)
|
|
MakeKernelHandle(args->Handle);
|
|
|
|
status = ObReferenceObjectByHandle(args->Handle, 0, NULL, KernelMode, &object, NULL);
|
|
KphDetachProcess(&attachState);
|
|
|
|
if (!NT_SUCCESS(status))
|
|
goto IoControlEnd;
|
|
|
|
status = ObQueryNameString(object, (POBJECT_NAME_INFORMATION)dataBuffer, outLength, &retLength);
|
|
ObDereferenceObject(object);
|
|
}
|
|
break;
|
|
|
|
/* KphOpenProcessJob
|
|
*
|
|
* Opens the job object that the process is assigned to. If the process is
|
|
* not assigned to any job object, the call will fail with STATUS_PROCESS_NOT_IN_JOB.
|
|
*/
|
|
case KPH_OPENPROCESSJOB:
|
|
{
|
|
struct
|
|
{
|
|
HANDLE ProcessHandle;
|
|
ACCESS_MASK DesiredAccess;
|
|
} *args = dataBuffer;
|
|
struct
|
|
{
|
|
HANDLE JobHandle;
|
|
} *ret = dataBuffer;
|
|
|
|
CHECK_IN_OUT_LENGTH;
|
|
|
|
status = KphOpenProcessJob(args->ProcessHandle, args->DesiredAccess, &ret->JobHandle, KernelMode);
|
|
|
|
if (!NT_SUCCESS(status))
|
|
goto IoControlEnd;
|
|
|
|
retLength = sizeof(*ret);
|
|
}
|
|
break;
|
|
|
|
/* KphGetContextThread
|
|
*
|
|
* Gets the context of the specified thread.
|
|
*/
|
|
case KPH_GETCONTEXTTHREAD:
|
|
{
|
|
struct
|
|
{
|
|
HANDLE ThreadHandle;
|
|
PCONTEXT ThreadContext;
|
|
} *args = dataBuffer;
|
|
|
|
CHECK_IN_LENGTH;
|
|
|
|
status = KphGetContextThread(args->ThreadHandle, args->ThreadContext, UserMode);
|
|
}
|
|
break;
|
|
|
|
/* KphSetContextThread
|
|
*
|
|
* Sets the context of the specified thread.
|
|
*/
|
|
case KPH_SETCONTEXTTHREAD:
|
|
{
|
|
struct
|
|
{
|
|
HANDLE ThreadHandle;
|
|
PCONTEXT ThreadContext;
|
|
} *args = dataBuffer;
|
|
|
|
CHECK_IN_LENGTH;
|
|
|
|
status = KphSetContextThread(args->ThreadHandle, args->ThreadContext, UserMode);
|
|
}
|
|
break;
|
|
|
|
/* KphGetThreadWin32Thread
|
|
*
|
|
* Gets a pointer to the specified thread's Win32Thread structure.
|
|
*/
|
|
case KPH_GETTHREADWIN32THREAD:
|
|
{
|
|
struct
|
|
{
|
|
HANDLE ThreadHandle;
|
|
} *args = dataBuffer;
|
|
struct
|
|
{
|
|
PVOID Win32Thread;
|
|
} *ret = dataBuffer;
|
|
|
|
CHECK_IN_OUT_LENGTH;
|
|
|
|
status = KphGetThreadWin32Thread(args->ThreadHandle, &ret->Win32Thread, KernelMode);
|
|
|
|
if (!NT_SUCCESS(status))
|
|
goto IoControlEnd;
|
|
|
|
retLength = sizeof(*ret);
|
|
}
|
|
break;
|
|
|
|
/* KphDuplicateObject
|
|
*
|
|
* Duplicates the specified handle from the source process to the target process.
|
|
* Do not use this call to duplicate file handles; it may freeze indefinitely if
|
|
* the file is a named pipe.
|
|
*/
|
|
case KPH_DUPLICATEOBJECT:
|
|
{
|
|
struct
|
|
{
|
|
HANDLE SourceProcessHandle;
|
|
HANDLE SourceHandle;
|
|
HANDLE TargetProcessHandle;
|
|
PHANDLE TargetHandle;
|
|
ACCESS_MASK DesiredAccess;
|
|
ULONG HandleAttributes;
|
|
ULONG Options;
|
|
} *args = dataBuffer;
|
|
|
|
CHECK_IN_LENGTH;
|
|
|
|
status = KphDuplicateObject(
|
|
args->SourceProcessHandle,
|
|
args->SourceHandle,
|
|
args->TargetProcessHandle,
|
|
args->TargetHandle,
|
|
args->DesiredAccess,
|
|
args->HandleAttributes,
|
|
args->Options,
|
|
UserMode
|
|
);
|
|
}
|
|
break;
|
|
|
|
/* ZwQueryObject
|
|
*
|
|
* Performs ZwQueryObject in the context of another process.
|
|
*/
|
|
case KPH_ZWQUERYOBJECT:
|
|
{
|
|
struct
|
|
{
|
|
HANDLE ProcessHandle;
|
|
HANDLE Handle;
|
|
OBJECT_INFORMATION_CLASS ObjectInformationClass;
|
|
} *args = dataBuffer;
|
|
struct
|
|
{
|
|
NTSTATUS Status;
|
|
ULONG ReturnLength;
|
|
PVOID BufferBase;
|
|
CHAR Buffer[1];
|
|
} *ret = dataBuffer;
|
|
NTSTATUS status2 = STATUS_SUCCESS;
|
|
KPH_ATTACH_STATE attachState;
|
|
BOOLEAN attached;
|
|
|
|
if (inLength < sizeof(*args) || outLength < sizeof(*ret) - sizeof(CHAR))
|
|
{
|
|
status = STATUS_BUFFER_TOO_SMALL;
|
|
goto IoControlEnd;
|
|
}
|
|
|
|
status = KphAttachProcessHandle(args->ProcessHandle, &attachState);
|
|
|
|
if (!NT_SUCCESS(status))
|
|
goto IoControlEnd;
|
|
|
|
/* Are we attached to the system process? If we are,
|
|
* we must set the high bit in the handle to indicate
|
|
* that it is a kernel handle - a new check for this
|
|
* was added in Windows 7.
|
|
*/
|
|
if (attachState.Process == PsInitialSystemProcess)
|
|
MakeKernelHandle(args->Handle);
|
|
|
|
status2 = ZwQueryObject(
|
|
args->Handle,
|
|
args->ObjectInformationClass,
|
|
ret->Buffer,
|
|
outLength - (sizeof(*ret) - sizeof(CHAR)),
|
|
&retLength
|
|
);
|
|
KphDetachProcess(&attachState);
|
|
|
|
ret->ReturnLength = retLength;
|
|
ret->BufferBase = ret->Buffer;
|
|
|
|
if (NT_SUCCESS(status2))
|
|
retLength += sizeof(*ret) - sizeof(CHAR);
|
|
else
|
|
retLength = sizeof(*ret) - sizeof(CHAR);
|
|
|
|
ret->Status = status2;
|
|
}
|
|
break;
|
|
|
|
/* KphGetProcessId
|
|
*
|
|
* Gets the process ID of a process handle in the context of another process.
|
|
*/
|
|
case KPH_GETPROCESSID:
|
|
{
|
|
struct
|
|
{
|
|
HANDLE ProcessHandle;
|
|
HANDLE Handle;
|
|
} *args = dataBuffer;
|
|
struct
|
|
{
|
|
HANDLE ProcessId;
|
|
} *ret = dataBuffer;
|
|
KPH_ATTACH_STATE attachState;
|
|
|
|
CHECK_IN_OUT_LENGTH;
|
|
|
|
status = KphAttachProcessHandle(args->ProcessHandle, &attachState);
|
|
|
|
if (!NT_SUCCESS(status))
|
|
goto IoControlEnd;
|
|
|
|
if (attachState.Process == PsInitialSystemProcess)
|
|
MakeKernelHandle(args->Handle);
|
|
|
|
ret->ProcessId = KphGetProcessId(args->Handle);
|
|
KphDetachProcess(&attachState);
|
|
retLength = sizeof(*ret);
|
|
}
|
|
break;
|
|
|
|
/* KphGetThreadId
|
|
*
|
|
* Gets the thread ID of a thread handle in the context of another process.
|
|
*/
|
|
case KPH_GETTHREADID:
|
|
{
|
|
struct
|
|
{
|
|
HANDLE ProcessHandle;
|
|
HANDLE Handle;
|
|
} *args = dataBuffer;
|
|
struct
|
|
{
|
|
HANDLE ThreadId;
|
|
HANDLE ProcessId;
|
|
} *ret = dataBuffer;
|
|
KPH_ATTACH_STATE attachState;
|
|
|
|
CHECK_IN_OUT_LENGTH;
|
|
|
|
status = KphAttachProcessHandle(args->ProcessHandle, &attachState);
|
|
|
|
if (!NT_SUCCESS(status))
|
|
goto IoControlEnd;
|
|
|
|
if (attachState.Process == PsInitialSystemProcess)
|
|
MakeKernelHandle(args->Handle);
|
|
|
|
ret->ThreadId = KphGetThreadId(args->Handle, &ret->ProcessId);
|
|
KphDetachProcess(&attachState);
|
|
retLength = sizeof(*ret);
|
|
}
|
|
break;
|
|
|
|
/* KphTerminateThread
|
|
*
|
|
* Terminates the specified thread. This call will fail if
|
|
* PspTerminateThreadByPointer could not be located or if an attempt
|
|
* was made to terminate the current thread. In that case, the call
|
|
* will return STATUS_CANT_TERMINATE_SELF.
|
|
*/
|
|
case KPH_TERMINATETHREAD:
|
|
{
|
|
struct
|
|
{
|
|
HANDLE ThreadHandle;
|
|
NTSTATUS ExitStatus;
|
|
} *args = dataBuffer;
|
|
|
|
CHECK_IN_LENGTH;
|
|
|
|
status = KphTerminateThread(args->ThreadHandle, args->ExitStatus);
|
|
}
|
|
break;
|
|
|
|
/* Get Features
|
|
*
|
|
* Gets the features supported by the driver.
|
|
*/
|
|
case KPH_GETFEATURES:
|
|
{
|
|
struct
|
|
{
|
|
ULONG Features;
|
|
} *ret = dataBuffer;
|
|
ULONG features = 0;
|
|
|
|
CHECK_OUT_LENGTH;
|
|
|
|
if (__PsTerminateProcess)
|
|
features |= KPHF_PSTERMINATEPROCESS;
|
|
if (__PspTerminateThreadByPointer)
|
|
features |= KPHF_PSPTERMINATETHREADBPYPOINTER;
|
|
|
|
ret->Features = features;
|
|
retLength = sizeof(*ret);
|
|
}
|
|
break;
|
|
|
|
/* KphSetHandleGrantedAccess
|
|
*
|
|
* Sets the granted access for a handle.
|
|
*/
|
|
case KPH_SETHANDLEGRANTEDACCESS:
|
|
{
|
|
struct
|
|
{
|
|
HANDLE Handle;
|
|
ACCESS_MASK GrantedAccess;
|
|
} *args = dataBuffer;
|
|
|
|
CHECK_IN_LENGTH;
|
|
|
|
status = KphSetHandleGrantedAccess(
|
|
PsGetCurrentProcess(),
|
|
args->Handle,
|
|
args->GrantedAccess
|
|
);
|
|
}
|
|
break;
|
|
|
|
/* KphAssignImpersonationToken
|
|
*
|
|
* Assigns an impersonation token to a thread.
|
|
*/
|
|
case KPH_ASSIGNIMPERSONATIONTOKEN:
|
|
{
|
|
struct
|
|
{
|
|
HANDLE ThreadHandle;
|
|
HANDLE TokenHandle;
|
|
} *args = dataBuffer;
|
|
|
|
CHECK_IN_LENGTH;
|
|
|
|
status = KphAssignImpersonationToken(args->ThreadHandle, args->TokenHandle);
|
|
}
|
|
break;
|
|
|
|
/* Add Process Protection */
|
|
case KPH_PROTECTADD:
|
|
{
|
|
struct
|
|
{
|
|
HANDLE ProcessHandle;
|
|
LOGICAL AllowKernelMode;
|
|
ACCESS_MASK ProcessAllowMask;
|
|
ACCESS_MASK ThreadAllowMask;
|
|
} *args = dataBuffer;
|
|
PEPROCESS processObject;
|
|
|
|
CHECK_IN_LENGTH;
|
|
|
|
status = ObReferenceObjectByHandle(
|
|
args->ProcessHandle,
|
|
0,
|
|
*PsProcessType,
|
|
KernelMode,
|
|
&processObject,
|
|
NULL
|
|
);
|
|
ObDereferenceObject(processObject);
|
|
|
|
if (!NT_SUCCESS(status))
|
|
goto IoControlEnd;
|
|
|
|
InitProtection();
|
|
|
|
/* Don't protect the same process twice. */
|
|
if (KphProtectFindEntry(processObject, NULL, NULL))
|
|
{
|
|
status = STATUS_NOT_SUPPORTED;
|
|
goto IoControlEnd;
|
|
}
|
|
|
|
if (!KphProtectAddEntry(
|
|
processObject,
|
|
PsGetCurrentProcessId(),
|
|
args->AllowKernelMode,
|
|
args->ProcessAllowMask,
|
|
args->ThreadAllowMask
|
|
))
|
|
{
|
|
status = STATUS_UNSUCCESSFUL;
|
|
goto IoControlEnd;
|
|
}
|
|
}
|
|
break;
|
|
|
|
/* Remove Process Protection */
|
|
case KPH_PROTECTREMOVE:
|
|
{
|
|
struct
|
|
{
|
|
HANDLE ProcessHandle;
|
|
} *args = dataBuffer;
|
|
PEPROCESS processObject;
|
|
|
|
/* Can't remove anything if process protection hasn't been initialized -
|
|
there isn't anything to remove. */
|
|
if (!ProtectionInitialized)
|
|
{
|
|
status = STATUS_INVALID_PARAMETER;
|
|
goto IoControlEnd;
|
|
}
|
|
|
|
CHECK_IN_LENGTH;
|
|
|
|
status = ObReferenceObjectByHandle(
|
|
args->ProcessHandle,
|
|
0,
|
|
*PsProcessType,
|
|
KernelMode,
|
|
&processObject,
|
|
NULL
|
|
);
|
|
ObDereferenceObject(processObject);
|
|
|
|
if (!NT_SUCCESS(status))
|
|
goto IoControlEnd;
|
|
|
|
if (!KphProtectRemoveByProcess(processObject))
|
|
{
|
|
status = STATUS_UNSUCCESSFUL;
|
|
goto IoControlEnd;
|
|
}
|
|
}
|
|
break;
|
|
|
|
/* Query Process Protection */
|
|
case KPH_PROTECTQUERY:
|
|
{
|
|
struct
|
|
{
|
|
HANDLE ProcessHandle;
|
|
PLOGICAL AllowKernelMode;
|
|
PACCESS_MASK ProcessAllowMask;
|
|
PACCESS_MASK ThreadAllowMask;
|
|
} *args = dataBuffer;
|
|
PEPROCESS processObject;
|
|
KPH_PROCESS_ENTRY processEntry;
|
|
|
|
/* Can't query anything if process protection hasn't been initialized -
|
|
there isn't anything to query. */
|
|
if (!ProtectionInitialized)
|
|
{
|
|
status = STATUS_INVALID_PARAMETER;
|
|
goto IoControlEnd;
|
|
}
|
|
|
|
CHECK_IN_LENGTH;
|
|
|
|
__try
|
|
{
|
|
ProbeForWrite(args->AllowKernelMode, sizeof(LOGICAL), 1);
|
|
ProbeForWrite(args->ProcessAllowMask, sizeof(ACCESS_MASK), 1);
|
|
ProbeForWrite(args->ThreadAllowMask, sizeof(ACCESS_MASK), 1);
|
|
}
|
|
__except (EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
status = GetExceptionCode();
|
|
goto IoControlEnd;
|
|
}
|
|
|
|
status = ObReferenceObjectByHandle(
|
|
args->ProcessHandle,
|
|
0,
|
|
*PsProcessType,
|
|
KernelMode,
|
|
&processObject,
|
|
NULL
|
|
);
|
|
ObDereferenceObject(processObject);
|
|
|
|
if (!NT_SUCCESS(status))
|
|
goto IoControlEnd;
|
|
|
|
if (!KphProtectFindEntry(processObject, NULL, &processEntry))
|
|
{
|
|
status = STATUS_UNSUCCESSFUL;
|
|
goto IoControlEnd;
|
|
}
|
|
|
|
__try
|
|
{
|
|
*(args->AllowKernelMode) = processEntry.AllowKernelMode;
|
|
*(args->ProcessAllowMask) = processEntry.ProcessAllowMask;
|
|
*(args->ThreadAllowMask) = processEntry.ThreadAllowMask;
|
|
}
|
|
__except (EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
status = GetExceptionCode();
|
|
}
|
|
}
|
|
break;
|
|
|
|
/* KphUnsafeReadVirtualMemory
|
|
*
|
|
* Reads process memory or kernel memory.
|
|
*/
|
|
case KPH_UNSAFEREADVIRTUALMEMORY:
|
|
{
|
|
struct
|
|
{
|
|
HANDLE ProcessHandle;
|
|
PVOID BaseAddress;
|
|
PVOID Buffer;
|
|
ULONG BufferLength;
|
|
PULONG ReturnLength;
|
|
} *args = dataBuffer;
|
|
|
|
CHECK_IN_LENGTH;
|
|
|
|
status = KphUnsafeReadVirtualMemory(
|
|
args->ProcessHandle,
|
|
args->BaseAddress,
|
|
args->Buffer,
|
|
args->BufferLength,
|
|
args->ReturnLength,
|
|
UserMode
|
|
);
|
|
}
|
|
break;
|
|
|
|
/* Set Execute Options
|
|
*
|
|
* Sets NX status for a process.
|
|
*/
|
|
case KPH_SETEXECUTEOPTIONS:
|
|
{
|
|
struct
|
|
{
|
|
HANDLE ProcessHandle;
|
|
ULONG ExecuteOptions;
|
|
} *args = dataBuffer;
|
|
KPH_ATTACH_STATE attachState;
|
|
|
|
CHECK_IN_LENGTH;
|
|
|
|
status = KphAttachProcessHandle(args->ProcessHandle, &attachState);
|
|
|
|
if (!NT_SUCCESS(status))
|
|
goto IoControlEnd;
|
|
|
|
status = ZwSetInformationProcess(
|
|
NtCurrentProcess(),
|
|
ProcessExecuteFlags,
|
|
&args->ExecuteOptions,
|
|
sizeof(ULONG)
|
|
);
|
|
KphDetachProcess(&attachState);
|
|
}
|
|
break;
|
|
|
|
/* KphQueryProcessHandles
|
|
*
|
|
* Gets the handles in a process handle table.
|
|
*/
|
|
case KPH_QUERYPROCESSHANDLES:
|
|
{
|
|
struct
|
|
{
|
|
HANDLE ProcessHandle;
|
|
PVOID Buffer;
|
|
ULONG BufferLength;
|
|
PULONG ReturnLength;
|
|
} *args = dataBuffer;
|
|
|
|
CHECK_IN_LENGTH;
|
|
|
|
status = KphQueryProcessHandles(
|
|
args->ProcessHandle,
|
|
(PPROCESS_HANDLE_INFORMATION)args->Buffer,
|
|
args->BufferLength,
|
|
args->ReturnLength,
|
|
UserMode
|
|
);
|
|
}
|
|
break;
|
|
|
|
/* KphOpenThreadProcess
|
|
*
|
|
* Opens the process associated with the specified thread.
|
|
*/
|
|
case KPH_OPENTHREADPROCESS:
|
|
{
|
|
struct
|
|
{
|
|
HANDLE ThreadHandle;
|
|
ACCESS_MASK DesiredAccess;
|
|
} *args = dataBuffer;
|
|
struct
|
|
{
|
|
HANDLE ProcessHandle;
|
|
} *ret = dataBuffer;
|
|
|
|
CHECK_IN_OUT_LENGTH;
|
|
|
|
status = KphOpenThreadProcess(
|
|
args->ThreadHandle,
|
|
args->DesiredAccess,
|
|
&ret->ProcessHandle,
|
|
KernelMode
|
|
);
|
|
|
|
if (!NT_SUCCESS(status))
|
|
goto IoControlEnd;
|
|
|
|
retLength = sizeof(*ret);
|
|
}
|
|
break;
|
|
|
|
/* KphCaptureStackBackTraceThread
|
|
*
|
|
* Captures a kernel stack trace for the specified thread.
|
|
*/
|
|
case KPH_CAPTURESTACKBACKTRACETHREAD:
|
|
{
|
|
struct
|
|
{
|
|
HANDLE ThreadHandle;
|
|
ULONG FramesToSkip;
|
|
ULONG FramesToCapture;
|
|
PVOID *BackTrace;
|
|
PULONG CapturedFrames;
|
|
PULONG BackTraceHash;
|
|
} *args = dataBuffer;
|
|
|
|
CHECK_IN_LENGTH;
|
|
|
|
status = KphCaptureStackBackTraceThread(
|
|
args->ThreadHandle,
|
|
args->FramesToSkip,
|
|
args->FramesToCapture,
|
|
args->BackTrace,
|
|
args->CapturedFrames,
|
|
args->BackTraceHash,
|
|
UserMode
|
|
);
|
|
}
|
|
break;
|
|
|
|
/* KphDangerousTerminateThread
|
|
*
|
|
* Terminates the specified thread. This operation may cause a bugcheck.
|
|
*/
|
|
case KPH_DANGEROUSTERMINATETHREAD:
|
|
{
|
|
struct
|
|
{
|
|
HANDLE ThreadHandle;
|
|
NTSTATUS ExitStatus;
|
|
} *args = dataBuffer;
|
|
|
|
CHECK_IN_LENGTH;
|
|
|
|
status = KphDangerousTerminateThread(args->ThreadHandle, args->ExitStatus);
|
|
}
|
|
break;
|
|
|
|
/* KphOpenDevice
|
|
*
|
|
* Opens a device object.
|
|
*/
|
|
case KPH_OPENDEVICE:
|
|
{
|
|
struct
|
|
{
|
|
PHANDLE DeviceHandle;
|
|
POBJECT_ATTRIBUTES ObjectAttributes;
|
|
} *args = dataBuffer;
|
|
|
|
CHECK_IN_LENGTH;
|
|
|
|
status = KphOpenDevice(args->DeviceHandle, args->ObjectAttributes, UserMode);
|
|
}
|
|
break;
|
|
|
|
/* KphOpenDriver
|
|
*
|
|
* Opens a driver object.
|
|
*/
|
|
case KPH_OPENDRIVER:
|
|
{
|
|
struct
|
|
{
|
|
PHANDLE DriverHandle;
|
|
POBJECT_ATTRIBUTES ObjectAttributes;
|
|
} *args = dataBuffer;
|
|
|
|
CHECK_IN_LENGTH;
|
|
|
|
status = KphOpenDriver(args->DriverHandle, args->ObjectAttributes, UserMode);
|
|
}
|
|
break;
|
|
|
|
/* KphQueryInformationDriver
|
|
*
|
|
* Queries information about a driver object.
|
|
*/
|
|
case KPH_QUERYINFORMATIONDRIVER:
|
|
{
|
|
struct
|
|
{
|
|
HANDLE DriverHandle;
|
|
DRIVER_INFORMATION_CLASS DriverInformationClass;
|
|
PVOID DriverInformation;
|
|
ULONG DriverInformationLength;
|
|
PULONG ReturnLength;
|
|
} *args = dataBuffer;
|
|
|
|
CHECK_IN_LENGTH;
|
|
|
|
status = KphQueryInformationDriver(
|
|
args->DriverHandle,
|
|
args->DriverInformationClass,
|
|
args->DriverInformation,
|
|
args->DriverInformationLength,
|
|
args->ReturnLength,
|
|
UserMode
|
|
);
|
|
}
|
|
break;
|
|
|
|
/* KphOpenDirectoryObject
|
|
*
|
|
* Opens a directory object.
|
|
*/
|
|
case KPH_OPENDIRECTORYOBJECT:
|
|
{
|
|
struct
|
|
{
|
|
PHANDLE DirectoryObjectHandle;
|
|
ACCESS_MASK DesiredAccess;
|
|
POBJECT_ATTRIBUTES ObjectAttributes;
|
|
} *args = dataBuffer;
|
|
|
|
CHECK_IN_LENGTH;
|
|
|
|
status = KphOpenDirectoryObject(
|
|
args->DirectoryObjectHandle,
|
|
args->DesiredAccess,
|
|
args->ObjectAttributes,
|
|
UserMode
|
|
);
|
|
}
|
|
break;
|
|
|
|
/* SsRef
|
|
*
|
|
* Adds a system service logging reference.
|
|
*/
|
|
case KPH_SSREF:
|
|
{
|
|
PKPH_CLIENT_ENTRY clientEntry = ReferenceClientEntry(NULL);
|
|
|
|
if (!clientEntry)
|
|
{
|
|
status = STATUS_INTERNAL_ERROR;
|
|
goto IoControlEnd;
|
|
}
|
|
|
|
KphAcquireGuardedLock(&clientEntry->SsLock);
|
|
|
|
if (clientEntry->SsStartCount < KPH_CLIENT_SSMAXCOUNT)
|
|
{
|
|
clientEntry->SsStartCount++;
|
|
SsRef(1);
|
|
}
|
|
else
|
|
{
|
|
status = STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
KphReleaseGuardedLock(&clientEntry->SsLock);
|
|
|
|
KphDereferenceObject(clientEntry);
|
|
}
|
|
break;
|
|
|
|
/* SsUnref
|
|
*
|
|
* Removes a system service logging reference.
|
|
*/
|
|
case KPH_SSUNREF:
|
|
{
|
|
PKPH_CLIENT_ENTRY clientEntry = ReferenceClientEntry(NULL);
|
|
|
|
if (!clientEntry)
|
|
{
|
|
status = STATUS_INTERNAL_ERROR;
|
|
goto IoControlEnd;
|
|
}
|
|
|
|
KphAcquireGuardedLock(&clientEntry->SsLock);
|
|
|
|
if (clientEntry->SsStartCount > 0)
|
|
{
|
|
clientEntry->SsStartCount--;
|
|
SsUnref(1);
|
|
}
|
|
else
|
|
{
|
|
status = STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
KphReleaseGuardedLock(&clientEntry->SsLock);
|
|
|
|
KphDereferenceObject(clientEntry);
|
|
}
|
|
break;
|
|
|
|
/* SsCreateClientEntry
|
|
*
|
|
* Creates a system service logging client entry.
|
|
*/
|
|
case KPH_SSCREATECLIENTENTRY:
|
|
{
|
|
struct
|
|
{
|
|
HANDLE ProcessHandle;
|
|
HANDLE EventHandle;
|
|
HANDLE SemaphoreHandle;
|
|
PVOID BufferBase;
|
|
ULONG BufferSize;
|
|
} *args = dataBuffer;
|
|
struct
|
|
{
|
|
HANDLE ClientEntryHandle;
|
|
} *ret = dataBuffer;
|
|
PKPHSS_CLIENT_ENTRY clientEntry;
|
|
|
|
CHECK_IN_OUT_LENGTH;
|
|
|
|
status = KphSsCreateClientEntry(
|
|
&clientEntry,
|
|
args->ProcessHandle,
|
|
args->EventHandle,
|
|
args->SemaphoreHandle,
|
|
args->BufferBase,
|
|
args->BufferSize,
|
|
UserMode
|
|
);
|
|
|
|
if (!NT_SUCCESS(status))
|
|
goto IoControlEnd;
|
|
|
|
status = CreateClientHandle(NULL, clientEntry, &ret->ClientEntryHandle);
|
|
KphDereferenceObject(clientEntry);
|
|
retLength = sizeof(*ret);
|
|
}
|
|
break;
|
|
|
|
/* SsCreateRuleSetEntry
|
|
*
|
|
* Creates a system service logging ruleset entry.
|
|
*/
|
|
case KPH_SSCREATERULESETENTRY:
|
|
{
|
|
struct
|
|
{
|
|
HANDLE ClientEntryHandle;
|
|
KPHSS_FILTER_TYPE DefaultFilterType;
|
|
KPHSS_RULESET_ACTION Action;
|
|
} *args = dataBuffer;
|
|
struct
|
|
{
|
|
HANDLE RuleSetEntryHandle;
|
|
} *ret = dataBuffer;
|
|
PKPHSS_CLIENT_ENTRY clientEntry;
|
|
PKPHSS_RULESET_ENTRY ruleSetEntry;
|
|
|
|
CHECK_IN_OUT_LENGTH;
|
|
|
|
/* Reference the client entry. */
|
|
status = ReferenceClientHandle(
|
|
NULL,
|
|
args->ClientEntryHandle,
|
|
KphSsClientEntryType,
|
|
&clientEntry
|
|
);
|
|
|
|
if (!NT_SUCCESS(status))
|
|
goto IoControlEnd;
|
|
|
|
/* Create the ruleset entry. */
|
|
status = KphSsCreateRuleSetEntry(
|
|
&ruleSetEntry,
|
|
clientEntry,
|
|
args->DefaultFilterType,
|
|
args->Action
|
|
);
|
|
KphDereferenceObject(clientEntry);
|
|
|
|
if (!NT_SUCCESS(status))
|
|
goto IoControlEnd;
|
|
|
|
/* Create and return a handle to the ruleset entry. */
|
|
status = CreateClientHandle(NULL, ruleSetEntry, &ret->RuleSetEntryHandle);
|
|
KphDereferenceObject(ruleSetEntry);
|
|
retLength = sizeof(*ret);
|
|
}
|
|
break;
|
|
|
|
/* SsRemoveRule
|
|
*
|
|
* Removes a rule from a ruleset.
|
|
*/
|
|
case KPH_SSREMOVERULE:
|
|
{
|
|
struct
|
|
{
|
|
HANDLE RuleSetEntryHandle;
|
|
HANDLE RuleEntryHandle;
|
|
} *args = dataBuffer;
|
|
PKPHSS_RULESET_ENTRY ruleSetEntry;
|
|
|
|
CHECK_IN_LENGTH;
|
|
|
|
/* Reference the ruleset entry. */
|
|
status = ReferenceClientHandle(
|
|
NULL,
|
|
args->RuleSetEntryHandle,
|
|
KphSsRuleSetEntryType,
|
|
&ruleSetEntry
|
|
);
|
|
|
|
if (!NT_SUCCESS(status))
|
|
goto IoControlEnd;
|
|
|
|
/* Remove the rule. */
|
|
status = KphSsRemoveRule(ruleSetEntry, args->RuleEntryHandle);
|
|
KphDereferenceObject(ruleSetEntry);
|
|
}
|
|
break;
|
|
|
|
/* SsAddProcessIdRule
|
|
*
|
|
* Adds a process ID rule to a ruleset.
|
|
*/
|
|
case KPH_SSADDPROCESSIDRULE:
|
|
{
|
|
struct
|
|
{
|
|
HANDLE RuleSetEntryHandle;
|
|
KPHSS_FILTER_TYPE FilterType;
|
|
HANDLE ProcessId;
|
|
} *args = dataBuffer;
|
|
struct
|
|
{
|
|
HANDLE RuleEntryHandle;
|
|
} *ret = dataBuffer;
|
|
PKPHSS_RULESET_ENTRY ruleSetEntry;
|
|
PKPHSS_RULE_ENTRY ruleEntry;
|
|
|
|
CHECK_IN_OUT_LENGTH;
|
|
|
|
/* Reference the client entry. */
|
|
status = ReferenceClientHandle(
|
|
NULL,
|
|
args->RuleSetEntryHandle,
|
|
KphSsRuleSetEntryType,
|
|
&ruleSetEntry
|
|
);
|
|
|
|
if (!NT_SUCCESS(status))
|
|
goto IoControlEnd;
|
|
|
|
/* Add a process ID rule. */
|
|
status = KphSsAddProcessIdRule(
|
|
&ruleEntry,
|
|
ruleSetEntry,
|
|
args->FilterType,
|
|
args->ProcessId
|
|
);
|
|
KphDereferenceObject(ruleSetEntry);
|
|
|
|
if (!NT_SUCCESS(status))
|
|
goto IoControlEnd;
|
|
|
|
/* Return the rule handle. */
|
|
ret->RuleEntryHandle = KphSsGetHandleRule(ruleEntry);
|
|
KphDereferenceObject(ruleEntry);
|
|
retLength = sizeof(*ret);
|
|
}
|
|
break;
|
|
|
|
/* SsAddThreadIdRule
|
|
*
|
|
* Adds a thread ID rule to a ruleset.
|
|
*/
|
|
case KPH_SSADDTHREADIDRULE:
|
|
{
|
|
struct
|
|
{
|
|
HANDLE RuleSetEntryHandle;
|
|
KPHSS_FILTER_TYPE FilterType;
|
|
HANDLE ThreadId;
|
|
} *args = dataBuffer;
|
|
struct
|
|
{
|
|
HANDLE RuleEntryHandle;
|
|
} *ret = dataBuffer;
|
|
PKPHSS_RULESET_ENTRY ruleSetEntry;
|
|
PKPHSS_RULE_ENTRY ruleEntry;
|
|
|
|
CHECK_IN_OUT_LENGTH;
|
|
|
|
/* Reference the client entry. */
|
|
status = ReferenceClientHandle(
|
|
NULL,
|
|
args->RuleSetEntryHandle,
|
|
KphSsRuleSetEntryType,
|
|
&ruleSetEntry
|
|
);
|
|
|
|
if (!NT_SUCCESS(status))
|
|
goto IoControlEnd;
|
|
|
|
/* Add a thread ID rule. */
|
|
status = KphSsAddThreadIdRule(
|
|
&ruleEntry,
|
|
ruleSetEntry,
|
|
args->FilterType,
|
|
args->ThreadId
|
|
);
|
|
KphDereferenceObject(ruleSetEntry);
|
|
|
|
if (!NT_SUCCESS(status))
|
|
goto IoControlEnd;
|
|
|
|
/* Return the rule handle. */
|
|
ret->RuleEntryHandle = KphSsGetHandleRule(ruleEntry);
|
|
KphDereferenceObject(ruleEntry);
|
|
retLength = sizeof(*ret);
|
|
}
|
|
break;
|
|
|
|
/* SsAddPreviousModeRule
|
|
*
|
|
* Adds a previous mode rule to a ruleset.
|
|
*/
|
|
case KPH_SSADDPREVIOUSMODERULE:
|
|
{
|
|
struct
|
|
{
|
|
HANDLE RuleSetEntryHandle;
|
|
KPHSS_FILTER_TYPE FilterType;
|
|
KPROCESSOR_MODE PreviousMode;
|
|
} *args = dataBuffer;
|
|
struct
|
|
{
|
|
HANDLE RuleEntryHandle;
|
|
} *ret = dataBuffer;
|
|
PKPHSS_RULESET_ENTRY ruleSetEntry;
|
|
PKPHSS_RULE_ENTRY ruleEntry;
|
|
|
|
CHECK_IN_OUT_LENGTH;
|
|
|
|
/* Reference the client entry. */
|
|
status = ReferenceClientHandle(
|
|
NULL,
|
|
args->RuleSetEntryHandle,
|
|
KphSsRuleSetEntryType,
|
|
&ruleSetEntry
|
|
);
|
|
|
|
if (!NT_SUCCESS(status))
|
|
goto IoControlEnd;
|
|
|
|
/* Add a previous mode rule. */
|
|
status = KphSsAddPreviousModeRule(
|
|
&ruleEntry,
|
|
ruleSetEntry,
|
|
args->FilterType,
|
|
args->PreviousMode
|
|
);
|
|
KphDereferenceObject(ruleSetEntry);
|
|
|
|
if (!NT_SUCCESS(status))
|
|
goto IoControlEnd;
|
|
|
|
/* Return the rule handle. */
|
|
ret->RuleEntryHandle = KphSsGetHandleRule(ruleEntry);
|
|
KphDereferenceObject(ruleEntry);
|
|
retLength = sizeof(*ret);
|
|
}
|
|
break;
|
|
|
|
/* SsAddNumberRule
|
|
*
|
|
* Adds a system service number rule to a ruleset.
|
|
*/
|
|
case KPH_SSADDNUMBERRULE:
|
|
{
|
|
struct
|
|
{
|
|
HANDLE RuleSetEntryHandle;
|
|
KPHSS_FILTER_TYPE FilterType;
|
|
ULONG Number;
|
|
} *args = dataBuffer;
|
|
struct
|
|
{
|
|
HANDLE RuleEntryHandle;
|
|
} *ret = dataBuffer;
|
|
PKPHSS_RULESET_ENTRY ruleSetEntry;
|
|
PKPHSS_RULE_ENTRY ruleEntry;
|
|
|
|
CHECK_IN_OUT_LENGTH;
|
|
|
|
/* Reference the client entry. */
|
|
status = ReferenceClientHandle(
|
|
NULL,
|
|
args->RuleSetEntryHandle,
|
|
KphSsRuleSetEntryType,
|
|
&ruleSetEntry
|
|
);
|
|
|
|
if (!NT_SUCCESS(status))
|
|
goto IoControlEnd;
|
|
|
|
/* Add a number rule. */
|
|
status = KphSsAddNumberRule(
|
|
&ruleEntry,
|
|
ruleSetEntry,
|
|
args->FilterType,
|
|
args->Number
|
|
);
|
|
KphDereferenceObject(ruleSetEntry);
|
|
|
|
if (!NT_SUCCESS(status))
|
|
goto IoControlEnd;
|
|
|
|
/* Return the rule handle. */
|
|
ret->RuleEntryHandle = KphSsGetHandleRule(ruleEntry);
|
|
KphDereferenceObject(ruleEntry);
|
|
retLength = sizeof(*ret);
|
|
}
|
|
break;
|
|
|
|
/* SsEnableClientEntry
|
|
*
|
|
* Enables or disables a client entry.
|
|
*/
|
|
case KPH_SSENABLECLIENTENTRY:
|
|
{
|
|
struct
|
|
{
|
|
HANDLE ClientEntryHandle;
|
|
BOOLEAN Enable;
|
|
} *args = dataBuffer;
|
|
PKPHSS_CLIENT_ENTRY clientEntry;
|
|
|
|
CHECK_IN_LENGTH;
|
|
|
|
/* Reference the client entry. */
|
|
status = ReferenceClientHandle(
|
|
NULL,
|
|
args->ClientEntryHandle,
|
|
KphSsClientEntryType,
|
|
&clientEntry
|
|
);
|
|
|
|
if (!NT_SUCCESS(status))
|
|
goto IoControlEnd;
|
|
|
|
/* Enable/disable the client entry. */
|
|
status = KphSsEnableClientEntry(clientEntry, args->Enable);
|
|
KphDereferenceObject(clientEntry);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
{
|
|
dprintf("Unrecognized IOCTL code 0x%08x\n", controlCode);
|
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|
}
|
|
break;
|
|
}
|
|
|
|
/* Restore the old packing. */
|
|
#include <poppack.h>
|
|
|
|
IoControlEnd:
|
|
Irp->IoStatus.Information = retLength;
|
|
Irp->IoStatus.Status = status;
|
|
dprintf("IOCTL 0x%08x result was 0x%08x\n", controlCode, status);
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS KphDispatchRead(PDEVICE_OBJECT DeviceObject, PIRP Irp)
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
PIO_STACK_LOCATION ioStackIrp = NULL;
|
|
ULONG retLength = 0;
|
|
|
|
ioStackIrp = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
if (ioStackIrp != NULL)
|
|
{
|
|
PCHAR readDataBuffer = (PCHAR)Irp->AssociatedIrp.SystemBuffer;
|
|
ULONG readLength = ioStackIrp->Parameters.Read.Length;
|
|
|
|
if (readDataBuffer != NULL)
|
|
{
|
|
dprintf("Client read %d bytes!\n", readLength);
|
|
|
|
if (readLength == 4)
|
|
{
|
|
*(ULONG *)readDataBuffer = KPH_CTL_CODE(0);
|
|
retLength = 4;
|
|
}
|
|
else
|
|
{
|
|
status = STATUS_INFO_LENGTH_MISMATCH;
|
|
}
|
|
}
|
|
}
|
|
|
|
Irp->IoStatus.Information = retLength;
|
|
Irp->IoStatus.Status = status;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS KphUnsupported(PDEVICE_OBJECT DeviceObject, PIRP Irp)
|
|
{
|
|
dfprintf("Unsupported function called.\n");
|
|
|
|
return STATUS_NOT_SUPPORTED;
|
|
}
|