HyperDbg/hyperdbg/hyperkd/code/driver/Ioctl.c
sina 5bccbff58b
Some checks are pending
vs2026-ci / win-amd64-build (debug, x64) (push) Waiting to run
vs2026-ci / win-amd64-build (release, x64) (push) Waiting to run
vs2026-ci / Deploy release (push) Blocked by required conditions
fix IPT kernel structure based on the new model
2026-07-01 19:44:15 +02:00

1814 lines
64 KiB
C

/**
* @file Ioctl.c
* @author Sina Karvandi (sina@hyperdbg.org)
* @brief IOCTL Functions form user mode and other parts
* @details
*
* @version 0.1
* @date 2020-06-01
*
* @copyright This project is released under the GNU Public License v3.
*
*/
#include "pch.h"
/**
* @brief Validates amd adjusts the parameters of an IOCTL request
* @param BufferSize The expected size of the input buffer
* @param Irp The IRP representing the IOCTL request
* @IrpStack The current stack location of the IRP
* @InBuffLength Output parameter to receive the actual input buffer length
* @OutBuffLength Output parameter to receive the actual output buffer length
*
* @return TRUE if the parameters are valid, FALSE otherwise
*/
BOOLEAN
DrvValidateAndAdjustIoctlParameter(UINT32 BufferSize,
PVOID * TargetBuffer,
PIRP Irp,
PIO_STACK_LOCATION IrpStack,
ULONG * InBuffLength,
ULONG * OutBuffLength)
{
//
// First validate the parameters
//
if (IrpStack->Parameters.DeviceIoControl.InputBufferLength < BufferSize || Irp->AssociatedIrp.SystemBuffer == NULL)
{
LogError("Err, invalid parameter to IOCTL dispatcher");
return FALSE;
}
*InBuffLength = IrpStack->Parameters.DeviceIoControl.InputBufferLength;
*OutBuffLength = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
if (!*InBuffLength || !*OutBuffLength)
{
return FALSE;
}
//
// Set the target buffer to the system buffer of the IRP
//
*TargetBuffer = Irp->AssociatedIrp.SystemBuffer;
//
// Validation was successful
//
return TRUE;
}
/**
* @brief Adjusts the status and output buffer size for an IOCTL request
*
* @param ExpectedOutputBufferSize The expected size of the output buffer
* @param DoNotChangeInformation Output parameter to indicate whether to change the information field of the IRP's I/O status block
* @param Irp The IRP representing the IOCTL request
* @param Status Output parameter to receive the status to be set in the IRP's I/O status block
*
* @return VOID
*/
VOID
DrvAdjustStatusAndSetOutputSize(UINT32 ExpectedOutputBufferSize,
BOOLEAN * DoNotChangeInformation,
PIRP Irp,
NTSTATUS * Status)
{
Irp->IoStatus.Information = ExpectedOutputBufferSize;
*Status = STATUS_SUCCESS;
//
// Avoid zeroing it
//
*DoNotChangeInformation = TRUE;
}
/**
* @brief Checks whether the IOCTL request is allowed based on the current state of the driver and the system
* @param Ioctl The IOCTL code of the request
*
* @return BOOLEAN TRUE if the IOCTL request is allowed, FALSE otherwise
*/
BOOLEAN
IoctlCheckIoctlAllowed(ULONG Ioctl)
{
ULONG IoctlFunction = CTL_CODE_FUNCTION(Ioctl);
//
// First 100 IOCTLs are about loading and initializing modules
//
if (IoctlFunction > IOCTL_BASIC_IOCTL && IoctlFunction <= IOCTL_BASIC_IOCTL + 0x100)
{
//
// Always allow these IOCTLs even if we don't allow IOCTL from user-mode, because they are used for loading and initializing the driver and its components
//
return TRUE;
}
else if (IoctlFunction > IOCTL_KD_IOCTL && IoctlFunction <= IOCTL_KD_IOCTL + 0x100)
{
//
// Allow if the KD module is initialized
//
return g_KdInitialized;
}
else if (IoctlFunction > IOCTL_VMM_IOCTL && IoctlFunction <= IOCTL_VMM_IOCTL + 0x100)
{
//
// Allow if the VMM module is initialized
//
return g_VmmInitialized;
}
else if (IoctlFunction > IOCTL_HYPERTRACE_IOCTL && IoctlFunction <= IOCTL_HYPERTRACE_IOCTL + 0x100)
{
//
// Allow if the HyperTrace module is initialized
//
return g_HyperTraceInitialized;
}
else
{
//
// For other (unknown) IOCTLs, we don't allow them
//
return FALSE;
}
}
/**
* @brief Resolve a process id to the CR3 the Intel PT engine should match.
*
* @details Intel PT's CR3 filter compares the live CR3, which differs between
* user and kernel mode when KVA shadowing (KPTI) is enabled:
* - kernel-mode runs under _KPROCESS.DirectoryTableBase
* - user-mode runs under _KPROCESS.UserDirectoryTableBase (shadow)
* So pick the kernel CR3 for kernel-only traces, otherwise the user
* (shadow) CR3 — falling back to the kernel CR3 when KVA shadowing is
* off (UserDirectoryTableBase has a zero page base in that case, i.e.
* user-mode also runs under the kernel CR3).
*
* @param ProcessId Target process id
* @param TraceUser Whether CPL>0 will be traced
* @param TraceKernel Whether CPL==0 will be traced
*
* @return UINT64 CR3 page base (low 12 bits cleared), or 0 if the pid is gone
*/
static UINT64
DrvResolvePtTargetCr3(UINT32 ProcessId, BOOLEAN TraceUser, BOOLEAN TraceKernel)
{
//
// _KPROCESS.UserDirectoryTableBase offset (x64 Windows 10 1803+ / 11).
// Only this one constant is build-specific; adjust it if the user CR3
// ever reads wrong on a newer kernel.
//
const ULONG UserDirTableBaseOffset = 0x388;
PEPROCESS TargetProcess;
UINT64 KernelCr3;
UINT64 UserCr3;
UINT64 Chosen;
if (PsLookupProcessByProcessId((HANDLE)(ULONG_PTR)ProcessId, &TargetProcess) != STATUS_SUCCESS)
{
return 0;
}
KernelCr3 = (UINT64)((NT_KPROCESS *)TargetProcess)->DirectoryTableBase;
UserCr3 = *(UINT64 *)((UCHAR *)TargetProcess + UserDirTableBaseOffset);
ObDereferenceObject(TargetProcess);
if (TraceKernel && !TraceUser)
{
//
// Kernel-only trace — match the kernel CR3
//
Chosen = KernelCr3;
}
else if ((UserCr3 & ~0xFFFULL) != 0)
{
//
// KVA shadowing on — user mode runs under the shadow CR3
//
Chosen = UserCr3;
}
else
{
//
// KVA shadowing off — user mode runs under the kernel CR3
//
Chosen = KernelCr3;
}
return Chosen & ~0xFFFULL;
}
/**
* @brief IOCTL Dispatcher for Basic IOCTLs (initialization and event registration)
*
* @param Irp
* @param IrpStack
* @param DoNotChangeInformation
* @return NTSTATUS
*/
NTSTATUS
DrvDispatchBasicIoControl(PIRP Irp, PIO_STACK_LOCATION IrpStack, BOOLEAN * DoNotChangeInformation)
{
PREGISTER_NOTIFY_BUFFER RegisterEventRequest;
PDEBUGGER_INIT_VMM_PACKET InitVmmRequest;
PDEBUGGER_INIT_HYPERTRACE_PACKET InitHyperTraceRequest;
ULONG InBuffLength;
ULONG OutBuffLength;
NTSTATUS Status = STATUS_SUCCESS;
UINT32 Ioctl = IrpStack->Parameters.DeviceIoControl.IoControlCode;
switch (Ioctl)
{
case IOCTL_INIT_VMM:
//
// Validate and adjust the parameters, and set the target buffer to the system buffer of the IRP
//
if (!DrvValidateAndAdjustIoctlParameter(SIZEOF_DEBUGGER_INIT_VMM_PACKET,
(PVOID *)&InitVmmRequest,
Irp,
IrpStack,
&InBuffLength,
&OutBuffLength))
{
Status = STATUS_INVALID_PARAMETER;
break;
}
//
// Initialize the debugger and the vmm
//
if (LoaderInitDebuggerAndVmm(InitVmmRequest))
{
Status = STATUS_SUCCESS;
}
else
{
//
// There was a problem, so not loaded
//
Status = STATUS_UNSUCCESSFUL;
}
//
// Adjust the status and output size
//
DrvAdjustStatusAndSetOutputSize(SIZEOF_DEBUGGER_INIT_VMM_PACKET, DoNotChangeInformation, Irp, &Status);
break;
case IOCTL_INIT_HYPERTRACE:
//
// Validate and adjust the parameters, and set the target buffer to the system buffer of the IRP
//
if (!DrvValidateAndAdjustIoctlParameter(SIZEOF_DEBUGGER_INIT_HYPERTRACE_PACKET,
(PVOID *)&InitHyperTraceRequest,
Irp,
IrpStack,
&InBuffLength,
&OutBuffLength))
{
Status = STATUS_INVALID_PARAMETER;
break;
}
//
// Initialize the HyperTrace (if supported by the processor)
//
LoaderInitHyperTrace(InitHyperTraceRequest, TRUE);
//
// Adjust the status and output size
//
DrvAdjustStatusAndSetOutputSize(SIZEOF_DEBUGGER_INIT_HYPERTRACE_PACKET, DoNotChangeInformation, Irp, &Status);
break;
case IOCTL_REGISTER_EVENT:
//
// First validate the parameters.
//
if (IrpStack->Parameters.DeviceIoControl.InputBufferLength < SIZEOF_REGISTER_EVENT || Irp->AssociatedIrp.SystemBuffer == NULL)
{
Status = STATUS_INVALID_PARAMETER;
LogError("Err, invalid parameter to IOCTL dispatcher");
break;
}
//
// IRPs supply a pointer to a buffer at Irp->AssociatedIrp.SystemBuffer.
// This buffer represents both the input buffer and the output buffer that
// are specified in calls to DeviceIoControl
//
RegisterEventRequest = (PREGISTER_NOTIFY_BUFFER)Irp->AssociatedIrp.SystemBuffer;
switch (RegisterEventRequest->Type)
{
case IRP_BASED:
LogRegisterIrpBasedNotification((PVOID)Irp, &Status);
break;
case EVENT_BASED:
if (LogRegisterEventBasedNotification((PVOID)Irp))
{
Status = STATUS_SUCCESS;
}
else
{
Status = STATUS_UNSUCCESSFUL;
}
break;
default:
LogError("Err, unknown notification type from user-mode");
Status = STATUS_INVALID_PARAMETER;
break;
}
break;
case IOCTL_RETURN_IRP_PENDING_PACKETS_AND_DISALLOW_IOCTL:
//
// Send an immediate message, and we're no longer get new IRP
//
LogCallbackSendBuffer(OPERATION_HYPERVISOR_DRIVER_END_OF_IRPS,
"$",
sizeof(CHAR),
TRUE);
Status = STATUS_SUCCESS;
break;
default:
LogError("Err, unknown IOCTL");
Status = STATUS_NOT_IMPLEMENTED;
break;
}
return Status;
}
/**
* @brief IOCTL Dispatcher for KD (Kernel Debugger) IOCTLs
*
* @param Irp
* @param IrpStack
* @param DoNotChangeInformation
* @return NTSTATUS
*/
NTSTATUS
DrvDispatchKdIoControl(PIRP Irp, PIO_STACK_LOCATION IrpStack, BOOLEAN * DoNotChangeInformation)
{
NTSTATUS Status = STATUS_SUCCESS;
UINT32 Ioctl = IrpStack->Parameters.DeviceIoControl.IoControlCode;
UNREFERENCED_PARAMETER(Irp);
UNREFERENCED_PARAMETER(DoNotChangeInformation);
switch (Ioctl)
{
default:
LogError("Err, unknown IOCTL");
Status = STATUS_NOT_IMPLEMENTED;
break;
}
return Status;
}
/**
* @brief IOCTL Dispatcher for VMM IOCTLs
*
* @param Irp
* @param IrpStack
* @param DoNotChangeInformation
* @return NTSTATUS
*/
NTSTATUS
DrvDispatchVmmIoControl(PIRP Irp, PIO_STACK_LOCATION IrpStack, BOOLEAN * DoNotChangeInformation)
{
PDEBUGGER_READ_MEMORY DebuggerReadMemRequest;
PDEBUGGER_READ_AND_WRITE_ON_MSR DebuggerReadOrWriteMsrRequest;
PDEBUGGER_HIDE_AND_TRANSPARENT_DEBUGGER_MODE DebuggerHideAndUnhideRequest;
PDEBUGGER_READ_PAGE_TABLE_ENTRIES_DETAILS DebuggerPteRequest;
PDEBUGGER_PAGE_IN_REQUEST DebuggerPageinRequest;
PDEBUGGEE_PCITREE_REQUEST_RESPONSE_PACKET PcitreeRequest;
PDEBUGGEE_PCIDEVINFO_REQUEST_RESPONSE_PACKET PcidevinfoRequest;
PDEBUGGER_VA2PA_AND_PA2VA_COMMANDS DebuggerVa2paAndPa2vaRequest;
PDEBUGGER_EDIT_MEMORY DebuggerEditMemoryRequest;
PDEBUGGER_SEARCH_MEMORY DebuggerSearchMemoryRequest;
PDEBUGGER_GENERAL_EVENT_DETAIL DebuggerNewEventRequest;
PDEBUGGER_MODIFY_EVENTS DebuggerModifyEventRequest;
PDEBUGGER_FLUSH_LOGGING_BUFFERS DebuggerFlushBuffersRequest;
PDEBUGGER_PREALLOC_COMMAND DebuggerReservePreallocPoolRequest;
PDEBUGGER_PREACTIVATE_COMMAND DebuggerPreactivationRequest;
PDEBUGGER_APIC_REQUEST DebuggerApicRequest;
PINTERRUPT_DESCRIPTOR_TABLE_ENTRIES_PACKETS DebuggerQueryIdtRequest;
PDEBUGGEE_BP_PACKET DebuggerBreakpointRequest;
PDEBUGGER_UD_COMMAND_PACKET DebuggerUdCommandRequest;
PUSERMODE_LOADED_MODULE_DETAILS DebuggerUsermodeModulesRequest;
PDEBUGGER_QUERY_ACTIVE_PROCESSES_OR_THREADS DebuggerUsermodeProcessOrThreadQueryRequest;
PDEBUGGEE_DETAILS_AND_SWITCH_PROCESS_PACKET GetInformationProcessRequest;
PREVERSING_MACHINE_RECONSTRUCT_MEMORY_REQUEST RevServiceRequest;
PDEBUGGEE_DETAILS_AND_SWITCH_THREAD_PACKET GetInformationThreadRequest;
PDEBUGGER_PERFORM_KERNEL_TESTS DebuggerKernelTestRequest;
PDEBUGGER_SEND_COMMAND_EXECUTION_FINISHED_SIGNAL DebuggerCommandExecutionFinishedRequest;
PDEBUGGER_SEND_USERMODE_MESSAGES_TO_DEBUGGER DebuggerSendUsermodeMessageRequest;
PDEBUGGEE_SEND_GENERAL_PACKET_FROM_DEBUGGEE_TO_DEBUGGER DebuggerSendBufferFromDebuggeeToDebuggerRequest;
PDEBUGGER_ATTACH_DETACH_USER_MODE_PROCESS DebuggerAttachOrDetachToThreadRequest;
PDEBUGGER_PREPARE_DEBUGGEE DebuggeeRequest;
PDEBUGGER_PAUSE_PACKET_RECEIVED DebuggerPauseKernelRequest;
PDEBUGGER_GENERAL_ACTION DebuggerNewActionRequest;
PSMI_OPERATION_PACKETS SmiOperationRequest;
PVOID BufferToStoreThreadsAndProcessesDetails;
ULONG InBuffLength; // Input buffer length
ULONG OutBuffLength; // Output buffer length
SIZE_T ReturnSize;
NTSTATUS Status = STATUS_SUCCESS;
UINT32 Ioctl = IrpStack->Parameters.DeviceIoControl.IoControlCode;
switch (Ioctl)
{
case IOCTL_TERMINATE_VMX:
//
// Uninitialize the VMM and the debugger
//
LoaderUninitVmmAndDebugger();
Status = STATUS_SUCCESS;
break;
case IOCTL_DEBUGGER_READ_MEMORY:
//
// Validate and adjust the parameters, and set the target buffer to the system buffer of the IRP
//
if (!DrvValidateAndAdjustIoctlParameter(SIZEOF_DEBUGGER_READ_MEMORY,
(PVOID *)&DebuggerReadMemRequest,
Irp,
IrpStack,
&InBuffLength,
&OutBuffLength))
{
Status = STATUS_INVALID_PARAMETER;
break;
}
if (DebuggerCommandReadMemory(DebuggerReadMemRequest,
((CHAR *)DebuggerReadMemRequest) + SIZEOF_DEBUGGER_READ_MEMORY,
&ReturnSize) == TRUE)
{
//
// Return the header a read bytes
//
DrvAdjustStatusAndSetOutputSize((UINT32)(ReturnSize + SIZEOF_DEBUGGER_READ_MEMORY), DoNotChangeInformation, Irp, &Status);
}
else
{
//
// Just return the header to the user-mode
//
DrvAdjustStatusAndSetOutputSize(SIZEOF_DEBUGGER_READ_MEMORY, DoNotChangeInformation, Irp, &Status);
}
break;
case IOCTL_DEBUGGER_READ_OR_WRITE_MSR:
//
// Validate and adjust the parameters, and set the target buffer to the system buffer of the IRP
//
if (!DrvValidateAndAdjustIoctlParameter(SIZEOF_DEBUGGER_READ_AND_WRITE_ON_MSR,
(PVOID *)&DebuggerReadOrWriteMsrRequest,
Irp,
IrpStack,
&InBuffLength,
&OutBuffLength))
{
Status = STATUS_INVALID_PARAMETER;
break;
}
//
// Both usermode and to send to usermode and the coming buffer are
// at the same place
//
Status = DebuggerReadOrWriteMsr(DebuggerReadOrWriteMsrRequest, (UINT64 *)DebuggerReadOrWriteMsrRequest, &ReturnSize);
//
// Set the size
//
if (Status == STATUS_SUCCESS)
{
//
// Adjust the status and output size
//
DrvAdjustStatusAndSetOutputSize((UINT32)ReturnSize, DoNotChangeInformation, Irp, &Status);
}
break;
case IOCTL_DEBUGGER_READ_PAGE_TABLE_ENTRIES_DETAILS:
//
// Validate and adjust the parameters, and set the target buffer to the system buffer of the IRP
//
if (!DrvValidateAndAdjustIoctlParameter(SIZEOF_DEBUGGER_READ_PAGE_TABLE_ENTRIES_DETAILS,
(PVOID *)&DebuggerPteRequest,
Irp,
IrpStack,
&InBuffLength,
&OutBuffLength))
{
Status = STATUS_INVALID_PARAMETER;
break;
}
//
// Both usermode and to send to usermode and the coming buffer are
// at the same place (it's not in vmx-root)
//
ExtensionCommandPte(DebuggerPteRequest, FALSE);
//
// Adjust the status and output size
//
DrvAdjustStatusAndSetOutputSize(SIZEOF_DEBUGGER_READ_PAGE_TABLE_ENTRIES_DETAILS, DoNotChangeInformation, Irp, &Status);
break;
case IOCTL_DEBUGGER_REGISTER_EVENT:
//
// Validate and adjust the parameters, and set the target buffer to the system buffer of the IRP
//
if (!DrvValidateAndAdjustIoctlParameter(SIZEOF_DEBUGGER_GENERAL_EVENT_DETAIL,
(PVOID *)&DebuggerNewEventRequest,
Irp,
IrpStack,
&InBuffLength,
&OutBuffLength))
{
Status = STATUS_INVALID_PARAMETER;
break;
}
//
// Both usermode and to send to usermode and the coming buffer are
// at the same place (not coming from the VMX-root mode)
//
DebuggerParseEvent(DebuggerNewEventRequest,
(PDEBUGGER_EVENT_AND_ACTION_RESULT)Irp->AssociatedIrp.SystemBuffer,
FALSE);
//
// Adjust the status and output size
//
DrvAdjustStatusAndSetOutputSize(sizeof(DEBUGGER_EVENT_AND_ACTION_RESULT), DoNotChangeInformation, Irp, &Status);
break;
case IOCTL_DEBUGGER_ADD_ACTION_TO_EVENT:
//
// Validate and adjust the parameters, and set the target buffer to the system buffer of the IRP
//
if (!DrvValidateAndAdjustIoctlParameter(SIZEOF_DEBUGGER_GENERAL_ACTION,
(PVOID *)&DebuggerNewActionRequest,
Irp,
IrpStack,
&InBuffLength,
&OutBuffLength))
{
Status = STATUS_INVALID_PARAMETER;
break;
}
//
// Both usermode and to send to usermode and the coming buffer are
// at the same place
//
DebuggerParseAction(DebuggerNewActionRequest,
(PDEBUGGER_EVENT_AND_ACTION_RESULT)Irp->AssociatedIrp.SystemBuffer,
FALSE);
//
// Adjust the status and output size
//
DrvAdjustStatusAndSetOutputSize(sizeof(DEBUGGER_EVENT_AND_ACTION_RESULT), DoNotChangeInformation, Irp, &Status);
break;
case IOCTL_DEBUGGER_HIDE_AND_UNHIDE_TO_TRANSPARENT_THE_DEBUGGER:
//
// Validate and adjust the parameters, and set the target buffer to the system buffer of the IRP
//
if (!DrvValidateAndAdjustIoctlParameter(SIZEOF_DEBUGGER_HIDE_AND_TRANSPARENT_DEBUGGER_MODE,
(PVOID *)&DebuggerHideAndUnhideRequest,
Irp,
IrpStack,
&InBuffLength,
&OutBuffLength))
{
Status = STATUS_INVALID_PARAMETER;
break;
}
//
// check if it's a !hide or !unhide command
//
if (DebuggerHideAndUnhideRequest->IsHide == TRUE)
{
//
// It's a hide request
//
TransparentHideDebuggerWrapper(DebuggerHideAndUnhideRequest);
}
else
{
//
// It's a unhide request
//
TransparentUnhideDebuggerWrapper(DebuggerHideAndUnhideRequest);
}
//
// Adjust the status and output size
//
DrvAdjustStatusAndSetOutputSize(SIZEOF_DEBUGGER_HIDE_AND_TRANSPARENT_DEBUGGER_MODE, DoNotChangeInformation, Irp, &Status);
break;
case IOCTL_DEBUGGER_VA2PA_AND_PA2VA_COMMANDS:
//
// Validate and adjust the parameters, and set the target buffer to the system buffer of the IRP
//
if (!DrvValidateAndAdjustIoctlParameter(SIZEOF_DEBUGGER_VA2PA_AND_PA2VA_COMMANDS,
(PVOID *)&DebuggerVa2paAndPa2vaRequest,
Irp,
IrpStack,
&InBuffLength,
&OutBuffLength))
{
Status = STATUS_INVALID_PARAMETER;
break;
}
//
// Both usermode and to send to usermode and the coming buffer are
// at the same place (we're not in vmx-root here)
//
ExtensionCommandVa2paAndPa2va(DebuggerVa2paAndPa2vaRequest, FALSE);
//
// Adjust the status and output size
//
DrvAdjustStatusAndSetOutputSize(SIZEOF_DEBUGGER_VA2PA_AND_PA2VA_COMMANDS, DoNotChangeInformation, Irp, &Status);
break;
case IOCTL_DEBUGGER_EDIT_MEMORY:
//
// Validate and adjust the parameters, and set the target buffer to the system buffer of the IRP
//
if (!DrvValidateAndAdjustIoctlParameter(SIZEOF_DEBUGGER_EDIT_MEMORY,
(PVOID *)&DebuggerEditMemoryRequest,
Irp,
IrpStack,
&InBuffLength,
&OutBuffLength))
{
Status = STATUS_INVALID_PARAMETER;
break;
}
//
// Here we should validate whether the input parameter is
// valid or in other words whether we received enough space or not
//
if (IrpStack->Parameters.DeviceIoControl.InputBufferLength != SIZEOF_DEBUGGER_EDIT_MEMORY + DebuggerEditMemoryRequest->CountOf64Chunks * sizeof(UINT64))
{
Status = STATUS_INVALID_PARAMETER;
break;
}
//
// Both usermode and to send to usermode and the coming buffer are
// at the same place
//
DebuggerCommandEditMemory(DebuggerEditMemoryRequest);
//
// Adjust the status and output size
//
DrvAdjustStatusAndSetOutputSize(SIZEOF_DEBUGGER_EDIT_MEMORY, DoNotChangeInformation, Irp, &Status);
break;
case IOCTL_DEBUGGER_SEARCH_MEMORY:
//
// Validate and adjust the parameters, and set the target buffer to the system buffer of the IRP
//
if (!DrvValidateAndAdjustIoctlParameter(SIZEOF_DEBUGGER_SEARCH_MEMORY,
(PVOID *)&DebuggerSearchMemoryRequest,
Irp,
IrpStack,
&InBuffLength,
&OutBuffLength))
{
Status = STATUS_INVALID_PARAMETER;
break;
}
//
// The OutBuffLength should have at least MaximumSearchResults * sizeof(UINT64)
// free space to store the results
//
if (OutBuffLength < MaximumSearchResults * sizeof(UINT64))
{
Status = STATUS_INVALID_PARAMETER;
break;
}
//
// Here we should validate whether the input parameter is
// valid or in other words whether we received enough space or not
//
if (IrpStack->Parameters.DeviceIoControl.InputBufferLength != SIZEOF_DEBUGGER_SEARCH_MEMORY + DebuggerSearchMemoryRequest->CountOf64Chunks * sizeof(UINT64))
{
Status = STATUS_INVALID_PARAMETER;
break;
}
//
// Both usermode and to send to usermode and the coming buffer are
// at the same place
//
if (DebuggerCommandSearchMemory(DebuggerSearchMemoryRequest) != STATUS_SUCCESS)
{
//
// It is because it was not valid in any of the ways to the function
// then we're sure that the usermode code won't interpret it's previous
// buffer as a valid buffer and will not show it to the user
//
RtlZeroMemory(DebuggerSearchMemoryRequest, MaximumSearchResults * sizeof(UINT64));
}
//
// Configure IRP status, and also we send the results
// buffer, with it's null values (if any)
//
DrvAdjustStatusAndSetOutputSize(MaximumSearchResults * sizeof(UINT64), DoNotChangeInformation, Irp, &Status);
break;
case IOCTL_DEBUGGER_MODIFY_EVENTS:
//
// Validate and adjust the parameters, and set the target buffer to the system buffer of the IRP
//
if (!DrvValidateAndAdjustIoctlParameter(SIZEOF_DEBUGGER_MODIFY_EVENTS,
(PVOID *)&DebuggerModifyEventRequest,
Irp,
IrpStack,
&InBuffLength,
&OutBuffLength))
{
Status = STATUS_INVALID_PARAMETER;
break;
}
//
// Both usermode and to send to usermode and the coming buffer are
// at the same place
//
DebuggerParseEventsModification(DebuggerModifyEventRequest, FALSE, EnableInstantEventMechanism ? g_KernelDebuggerState : FALSE);
//
// Adjust the status and output size
//
DrvAdjustStatusAndSetOutputSize(SIZEOF_DEBUGGER_MODIFY_EVENTS, DoNotChangeInformation, Irp, &Status);
break;
case IOCTL_DEBUGGER_FLUSH_LOGGING_BUFFERS:
//
// Validate and adjust the parameters, and set the target buffer to the system buffer of the IRP
//
if (!DrvValidateAndAdjustIoctlParameter(SIZEOF_DEBUGGER_FLUSH_LOGGING_BUFFERS,
(PVOID *)&DebuggerFlushBuffersRequest,
Irp,
IrpStack,
&InBuffLength,
&OutBuffLength))
{
Status = STATUS_INVALID_PARAMETER;
break;
}
//
// Perform the flush
//
DebuggerCommandFlush(DebuggerFlushBuffersRequest);
//
// Adjust the status and output size
//
DrvAdjustStatusAndSetOutputSize(SIZEOF_DEBUGGER_FLUSH_LOGGING_BUFFERS, DoNotChangeInformation, Irp, &Status);
break;
case IOCTL_DEBUGGER_ATTACH_DETACH_USER_MODE_PROCESS:
//
// Validate and adjust the parameters, and set the target buffer to the system buffer of the IRP
//
if (!DrvValidateAndAdjustIoctlParameter(SIZEOF_DEBUGGER_ATTACH_DETACH_USER_MODE_PROCESS,
(PVOID *)&DebuggerAttachOrDetachToThreadRequest,
Irp,
IrpStack,
&InBuffLength,
&OutBuffLength))
{
Status = STATUS_INVALID_PARAMETER;
break;
}
//
// Perform the attach to the target process
//
AttachingTargetProcess(DebuggerAttachOrDetachToThreadRequest);
//
// Adjust the status and output size
//
DrvAdjustStatusAndSetOutputSize(SIZEOF_DEBUGGER_ATTACH_DETACH_USER_MODE_PROCESS, DoNotChangeInformation, Irp, &Status);
break;
case IOCTL_PREPARE_DEBUGGEE:
//
// Validate and adjust the parameters, and set the target buffer to the system buffer of the IRP
//
if (!DrvValidateAndAdjustIoctlParameter(SIZEOF_DEBUGGER_PREPARE_DEBUGGEE,
(PVOID *)&DebuggeeRequest,
Irp,
IrpStack,
&InBuffLength,
&OutBuffLength))
{
Status = STATUS_INVALID_PARAMETER;
break;
}
//
// Perform the action
//
SerialConnectionPrepare(DebuggeeRequest);
//
// Adjust the status and output size
//
DrvAdjustStatusAndSetOutputSize(SIZEOF_DEBUGGER_PREPARE_DEBUGGEE, DoNotChangeInformation, Irp, &Status);
break;
case IOCTL_PAUSE_PACKET_RECEIVED:
//
// Validate and adjust the parameters, and set the target buffer to the system buffer of the IRP
//
if (!DrvValidateAndAdjustIoctlParameter(SIZEOF_DEBUGGER_PAUSE_PACKET_RECEIVED,
(PVOID *)&DebuggerPauseKernelRequest,
Irp,
IrpStack,
&InBuffLength,
&OutBuffLength))
{
Status = STATUS_INVALID_PARAMETER;
break;
}
//
// Perform the action
//
KdHaltSystem(DebuggerPauseKernelRequest);
//
// Adjust the status and output size
//
DrvAdjustStatusAndSetOutputSize(SIZEOF_DEBUGGER_PAUSE_PACKET_RECEIVED, DoNotChangeInformation, Irp, &Status);
break;
case IOCTL_SEND_SIGNAL_EXECUTION_IN_DEBUGGEE_FINISHED:
//
// Validate and adjust the parameters, and set the target buffer to the system buffer of the IRP
//
if (!DrvValidateAndAdjustIoctlParameter(SIZEOF_DEBUGGER_SEND_COMMAND_EXECUTION_FINISHED_SIGNAL,
(PVOID *)&DebuggerCommandExecutionFinishedRequest,
Irp,
IrpStack,
&InBuffLength,
&OutBuffLength))
{
Status = STATUS_INVALID_PARAMETER;
break;
}
//
// Perform the signal operation
//
DebuggerCommandSignalExecutionState(DebuggerCommandExecutionFinishedRequest);
//
// Adjust the status and output size
//
DrvAdjustStatusAndSetOutputSize(SIZEOF_DEBUGGER_SEND_COMMAND_EXECUTION_FINISHED_SIGNAL, DoNotChangeInformation, Irp, &Status);
break;
case IOCTL_SEND_USERMODE_MESSAGES_TO_DEBUGGER:
//
// Validate and adjust the parameters, and set the target buffer to the system buffer of the IRP
//
if (!DrvValidateAndAdjustIoctlParameter(SIZEOF_DEBUGGER_SEND_USERMODE_MESSAGES_TO_DEBUGGER,
(PVOID *)&DebuggerSendUsermodeMessageRequest,
Irp,
IrpStack,
&InBuffLength,
&OutBuffLength))
{
Status = STATUS_INVALID_PARAMETER;
break;
}
//
// Second validation phase
//
if (DebuggerSendUsermodeMessageRequest->Length == NULL_ZERO ||
IrpStack->Parameters.DeviceIoControl.InputBufferLength != SIZEOF_DEBUGGER_SEND_USERMODE_MESSAGES_TO_DEBUGGER + DebuggerSendUsermodeMessageRequest->Length)
{
Status = STATUS_INVALID_PARAMETER;
break;
}
//
// Perform the signal operation
//
DebuggerCommandSendMessage(DebuggerSendUsermodeMessageRequest);
//
// Adjust the status and output size
//
DrvAdjustStatusAndSetOutputSize(SIZEOF_DEBUGGER_SEND_USERMODE_MESSAGES_TO_DEBUGGER, DoNotChangeInformation, Irp, &Status);
break;
case IOCTL_SEND_GENERAL_BUFFER_FROM_DEBUGGEE_TO_DEBUGGER:
//
// Validate and adjust the parameters, and set the target buffer to the system buffer of the IRP
//
if (!DrvValidateAndAdjustIoctlParameter(SIZEOF_DEBUGGEE_SEND_GENERAL_PACKET_FROM_DEBUGGEE_TO_DEBUGGER,
(PVOID *)&DebuggerSendBufferFromDebuggeeToDebuggerRequest,
Irp,
IrpStack,
&InBuffLength,
&OutBuffLength))
{
Status = STATUS_INVALID_PARAMETER;
break;
}
//
// Second validation phase
//
if (DebuggerSendBufferFromDebuggeeToDebuggerRequest->LengthOfBuffer == NULL_ZERO ||
IrpStack->Parameters.DeviceIoControl.InputBufferLength != SIZEOF_DEBUGGEE_SEND_GENERAL_PACKET_FROM_DEBUGGEE_TO_DEBUGGER + DebuggerSendBufferFromDebuggeeToDebuggerRequest->LengthOfBuffer)
{
Status = STATUS_INVALID_PARAMETER;
break;
}
//
// Perform the signal operation
//
DebuggerCommandSendGeneralBufferToDebugger(DebuggerSendBufferFromDebuggeeToDebuggerRequest);
//
// Adjust the status and output size
//
DrvAdjustStatusAndSetOutputSize(SIZEOF_DEBUGGEE_SEND_GENERAL_PACKET_FROM_DEBUGGEE_TO_DEBUGGER, DoNotChangeInformation, Irp, &Status);
break;
case IOCTL_PERFORM_KERNEL_SIDE_TESTS:
//
// Validate and adjust the parameters, and set the target buffer to the system buffer of the IRP
//
if (!DrvValidateAndAdjustIoctlParameter(SIZEOF_DEBUGGER_PERFORM_KERNEL_TESTS,
(PVOID *)&DebuggerKernelTestRequest,
Irp,
IrpStack,
&InBuffLength,
&OutBuffLength))
{
Status = STATUS_INVALID_PARAMETER;
break;
}
//
// Perform the kernel-side tests
//
TestKernelPerformTests(DebuggerKernelTestRequest);
//
// Adjust the status and output size
//
DrvAdjustStatusAndSetOutputSize(SIZEOF_DEBUGGER_PERFORM_KERNEL_TESTS, DoNotChangeInformation, Irp, &Status);
break;
case IOCTL_RESERVE_PRE_ALLOCATED_POOLS:
//
// Validate and adjust the parameters, and set the target buffer to the system buffer of the IRP
//
if (!DrvValidateAndAdjustIoctlParameter(SIZEOF_DEBUGGER_PREALLOC_COMMAND,
(PVOID *)&DebuggerReservePreallocPoolRequest,
Irp,
IrpStack,
&InBuffLength,
&OutBuffLength))
{
Status = STATUS_INVALID_PARAMETER;
break;
}
//
// Perform the reservation pools
//
DebuggerCommandReservePreallocatedPools(DebuggerReservePreallocPoolRequest);
//
// Adjust the status and output size
//
DrvAdjustStatusAndSetOutputSize(SIZEOF_DEBUGGER_PREALLOC_COMMAND, DoNotChangeInformation, Irp, &Status);
break;
case IOCTL_PREACTIVATE_FUNCTIONALITY:
//
// Validate and adjust the parameters, and set the target buffer to the system buffer of the IRP
//
if (!DrvValidateAndAdjustIoctlParameter(SIZEOF_DEBUGGER_PREACTIVATE_COMMAND,
(PVOID *)&DebuggerPreactivationRequest,
Irp,
IrpStack,
&InBuffLength,
&OutBuffLength))
{
Status = STATUS_INVALID_PARAMETER;
break;
}
//
// Perform the activation of the functionality
//
DebuggerCommandPreactivateFunctionality(DebuggerPreactivationRequest);
//
// Adjust the status and output size
//
DrvAdjustStatusAndSetOutputSize(SIZEOF_DEBUGGER_PREACTIVATE_COMMAND, DoNotChangeInformation, Irp, &Status);
break;
case IOCTL_PERFORM_ACTIONS_ON_APIC:
//
// Validate and adjust the parameters, and set the target buffer to the system buffer of the IRP
//
if (!DrvValidateAndAdjustIoctlParameter(SIZEOF_DEBUGGER_APIC_REQUEST,
(PVOID *)&DebuggerApicRequest,
Irp,
IrpStack,
&InBuffLength,
&OutBuffLength))
{
Status = STATUS_INVALID_PARAMETER;
break;
}
//
// Adjust the status and output size
//
DrvAdjustStatusAndSetOutputSize(ExtensionCommandPerformActionsForApicRequests(DebuggerApicRequest), DoNotChangeInformation, Irp, &Status);
break;
case IOCTL_QUERY_IDT_ENTRY:
//
// Validate and adjust the parameters, and set the target buffer to the system buffer of the IRP
//
if (!DrvValidateAndAdjustIoctlParameter(SIZEOF_INTERRUPT_DESCRIPTOR_TABLE_ENTRIES_PACKETS,
(PVOID *)&DebuggerQueryIdtRequest,
Irp,
IrpStack,
&InBuffLength,
&OutBuffLength))
{
Status = STATUS_INVALID_PARAMETER;
break;
}
//
// Perform the query of IDT entries (not from vmx-root)
//
ExtensionCommandPerformQueryIdtEntriesRequest(DebuggerQueryIdtRequest, FALSE);
//
// Adjust the status and output size
//
DrvAdjustStatusAndSetOutputSize(SIZEOF_INTERRUPT_DESCRIPTOR_TABLE_ENTRIES_PACKETS, DoNotChangeInformation, Irp, &Status);
break;
case IOCTL_SET_BREAKPOINT_USER_DEBUGGER:
//
// Validate and adjust the parameters, and set the target buffer to the system buffer of the IRP
//
if (!DrvValidateAndAdjustIoctlParameter(SIZEOF_DEBUGGEE_BP_PACKET,
(PVOID *)&DebuggerBreakpointRequest,
Irp,
IrpStack,
&InBuffLength,
&OutBuffLength))
{
Status = STATUS_INVALID_PARAMETER;
break;
}
//
// Perform setting the breakpoint (for the user mode debugger)
// Switching to the target process memory is needed as we are
// in HyperDbg's process memory layout and we need to switch to
// the target process memory layout to set the breakpoint
//
BreakpointAddNew(DebuggerBreakpointRequest, TRUE);
//
// Adjust the status and output size
//
DrvAdjustStatusAndSetOutputSize(SIZEOF_DEBUGGEE_BP_PACKET, DoNotChangeInformation, Irp, &Status);
break;
case IOCTL_PERFORM_SMI_OPERATION:
//
// Validate and adjust the parameters, and set the target buffer to the system buffer of the IRP
//
if (!DrvValidateAndAdjustIoctlParameter(SIZEOF_SMI_OPERATION_PACKETS,
(PVOID *)&SmiOperationRequest,
Irp,
IrpStack,
&InBuffLength,
&OutBuffLength))
{
Status = STATUS_INVALID_PARAMETER;
break;
}
//
// Perform the SMI operation (it's not from vmx-root)
//
VmFuncSmmPerformSmiOperation(SmiOperationRequest, FALSE);
//
// Adjust the status and output size
//
DrvAdjustStatusAndSetOutputSize(SIZEOF_SMI_OPERATION_PACKETS, DoNotChangeInformation, Irp, &Status);
break;
case IOCTL_SEND_USER_DEBUGGER_COMMANDS:
//
// Validate and adjust the parameters, and set the target buffer to the system buffer of the IRP
//
if (!DrvValidateAndAdjustIoctlParameter(SIZEOF_DEBUGGER_UD_COMMAND_PACKET,
(PVOID *)&DebuggerUdCommandRequest,
Irp,
IrpStack,
&InBuffLength,
&OutBuffLength))
{
Status = STATUS_INVALID_PARAMETER;
break;
}
//
// Perform the dispatching of user debugger command
//
UdDispatchUsermodeCommands(DebuggerUdCommandRequest, InBuffLength, OutBuffLength);
//
// Adjust the status and output size
//
DrvAdjustStatusAndSetOutputSize(OutBuffLength, DoNotChangeInformation, Irp, &Status);
break;
case IOCTL_GET_DETAIL_OF_ACTIVE_THREADS_AND_PROCESSES:
OutBuffLength = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
if (!OutBuffLength)
{
Status = STATUS_INVALID_PARAMETER;
break;
}
//
// Both usermode and to send to usermode is here
//
BufferToStoreThreadsAndProcessesDetails = (PVOID)Irp->AssociatedIrp.SystemBuffer;
//
// Perform the dispatching of user debugger command
//
AttachingQueryDetailsOfActiveDebuggingThreadsAndProcesses(BufferToStoreThreadsAndProcessesDetails, OutBuffLength);
//
// Adjust the status and output size
//
DrvAdjustStatusAndSetOutputSize(OutBuffLength, DoNotChangeInformation, Irp, &Status);
break;
case IOCTL_GET_USER_MODE_MODULE_DETAILS:
//
// Validate and adjust the parameters, and set the target buffer to the system buffer of the IRP
//
if (!DrvValidateAndAdjustIoctlParameter(SIZEOF_USERMODE_LOADED_MODULE_DETAILS,
(PVOID *)&DebuggerUsermodeModulesRequest,
Irp,
IrpStack,
&InBuffLength,
&OutBuffLength))
{
Status = STATUS_INVALID_PARAMETER;
break;
}
//
// Getting the modules details
//
UserAccessGetLoadedModules(DebuggerUsermodeModulesRequest, OutBuffLength);
//
// Adjust the status and output size
//
DrvAdjustStatusAndSetOutputSize(OutBuffLength, DoNotChangeInformation, Irp, &Status);
break;
case IOCTL_QUERY_COUNT_OF_ACTIVE_PROCESSES_OR_THREADS:
//
// Validate and adjust the parameters, and set the target buffer to the system buffer of the IRP
//
if (!DrvValidateAndAdjustIoctlParameter(SIZEOF_DEBUGGER_QUERY_ACTIVE_PROCESSES_OR_THREADS,
(PVOID *)&DebuggerUsermodeProcessOrThreadQueryRequest,
Irp,
IrpStack,
&InBuffLength,
&OutBuffLength))
{
Status = STATUS_INVALID_PARAMETER;
break;
}
//
// Getting the count result
//
if (DebuggerUsermodeProcessOrThreadQueryRequest->QueryType == DEBUGGER_QUERY_ACTIVE_PROCESSES_OR_THREADS_QUERY_PROCESS_COUNT)
{
ProcessQueryCount(DebuggerUsermodeProcessOrThreadQueryRequest);
}
else if (DebuggerUsermodeProcessOrThreadQueryRequest->QueryType == DEBUGGER_QUERY_ACTIVE_PROCESSES_OR_THREADS_QUERY_THREAD_COUNT)
{
ThreadQueryCount(DebuggerUsermodeProcessOrThreadQueryRequest);
}
//
// Adjust the status and output size
//
DrvAdjustStatusAndSetOutputSize(SIZEOF_DEBUGGER_QUERY_ACTIVE_PROCESSES_OR_THREADS, DoNotChangeInformation, Irp, &Status);
break;
case IOCTL_GET_LIST_OF_THREADS_AND_PROCESSES:
//
// Validate and adjust the parameters, and set the target buffer to the system buffer of the IRP
//
if (!DrvValidateAndAdjustIoctlParameter(SIZEOF_DEBUGGER_QUERY_ACTIVE_PROCESSES_OR_THREADS,
(PVOID *)&DebuggerUsermodeProcessOrThreadQueryRequest,
Irp,
IrpStack,
&InBuffLength,
&OutBuffLength))
{
Status = STATUS_INVALID_PARAMETER;
break;
}
//
// Getting the list of processes or threads
//
if (DebuggerUsermodeProcessOrThreadQueryRequest->QueryType == DEBUGGER_QUERY_ACTIVE_PROCESSES_OR_THREADS_QUERY_PROCESS_LIST)
{
ProcessQueryList(DebuggerUsermodeProcessOrThreadQueryRequest,
DebuggerUsermodeProcessOrThreadQueryRequest,
OutBuffLength);
}
else if (DebuggerUsermodeProcessOrThreadQueryRequest->QueryType == DEBUGGER_QUERY_ACTIVE_PROCESSES_OR_THREADS_QUERY_THREAD_LIST)
{
ThreadQueryList(DebuggerUsermodeProcessOrThreadQueryRequest,
DebuggerUsermodeProcessOrThreadQueryRequest,
OutBuffLength);
}
//
// Adjust the status and output size
//
DrvAdjustStatusAndSetOutputSize(OutBuffLength, DoNotChangeInformation, Irp, &Status);
break;
case IOCTL_QUERY_CURRENT_THREAD:
//
// Validate and adjust the parameters, and set the target buffer to the system buffer of the IRP
//
if (!DrvValidateAndAdjustIoctlParameter(SIZEOF_DEBUGGEE_DETAILS_AND_SWITCH_THREAD_PACKET,
(PVOID *)&GetInformationThreadRequest,
Irp,
IrpStack,
&InBuffLength,
&OutBuffLength))
{
Status = STATUS_INVALID_PARAMETER;
break;
}
//
// Get the information
//
ThreadQueryDetails(GetInformationThreadRequest);
//
// Adjust the status and output size
//
DrvAdjustStatusAndSetOutputSize(SIZEOF_DEBUGGEE_DETAILS_AND_SWITCH_THREAD_PACKET, DoNotChangeInformation, Irp, &Status);
break;
case IOCTL_QUERY_CURRENT_PROCESS:
//
// Validate and adjust the parameters, and set the target buffer to the system buffer of the IRP
//
if (!DrvValidateAndAdjustIoctlParameter(SIZEOF_DEBUGGEE_DETAILS_AND_SWITCH_PROCESS_PACKET,
(PVOID *)&GetInformationProcessRequest,
Irp,
IrpStack,
&InBuffLength,
&OutBuffLength))
{
Status = STATUS_INVALID_PARAMETER;
break;
}
//
// Get the information
//
ProcessQueryDetails(GetInformationProcessRequest);
//
// Adjust the status and output size
//
DrvAdjustStatusAndSetOutputSize(SIZEOF_DEBUGGEE_DETAILS_AND_SWITCH_PROCESS_PACKET, DoNotChangeInformation, Irp, &Status);
break;
case IOCTL_REQUEST_REV_MACHINE_SERVICE:
//
// Validate and adjust the parameters, and set the target buffer to the system buffer of the IRP
//
if (!DrvValidateAndAdjustIoctlParameter(SIZEOF_REVERSING_MACHINE_RECONSTRUCT_MEMORY_REQUEST,
(PVOID *)&RevServiceRequest,
Irp,
IrpStack,
&InBuffLength,
&OutBuffLength))
{
Status = STATUS_INVALID_PARAMETER;
break;
}
//
// Perform the service request
//
ConfigureInitializeExecTrapOnAllProcessors();
//
// Adjust the status and output size
//
DrvAdjustStatusAndSetOutputSize(SIZEOF_REVERSING_MACHINE_RECONSTRUCT_MEMORY_REQUEST, DoNotChangeInformation, Irp, &Status);
break;
case IOCTL_DEBUGGER_BRING_PAGES_IN:
//
// Validate and adjust the parameters, and set the target buffer to the system buffer of the IRP
//
if (!DrvValidateAndAdjustIoctlParameter(SIZEOF_DEBUGGER_PAGE_IN_REQUEST,
(PVOID *)&DebuggerPageinRequest,
Irp,
IrpStack,
&InBuffLength,
&OutBuffLength))
{
Status = STATUS_INVALID_PARAMETER;
break;
}
//
// Both usermode and to send to usermode and the coming buffer are
// at the same place (it's in VMI-mode)
//
DebuggerCommandBringPagein(DebuggerPageinRequest);
//
// Adjust the status and output size
//
DrvAdjustStatusAndSetOutputSize(SIZEOF_DEBUGGER_PAGE_IN_REQUEST, DoNotChangeInformation, Irp, &Status);
break;
case IOCTL_PCIE_ENDPOINT_ENUM:
//
// Validate and adjust the parameters, and set the target buffer to the system buffer of the IRP
//
if (!DrvValidateAndAdjustIoctlParameter(SIZEOF_DEBUGGEE_PCITREE_REQUEST_RESPONSE_PACKET,
(PVOID *)&PcitreeRequest,
Irp,
IrpStack,
&InBuffLength,
&OutBuffLength))
{
Status = STATUS_INVALID_PARAMETER;
break;
}
//
// Both usermode and to send to usermode and the coming buffer are
// at the same place (it's in VMI-mode)
//
ExtensionCommandPcitree(PcitreeRequest, FALSE);
//
// Adjust the status and output size
//
DrvAdjustStatusAndSetOutputSize(SIZEOF_DEBUGGEE_PCITREE_REQUEST_RESPONSE_PACKET, DoNotChangeInformation, Irp, &Status);
break;
case IOCTL_PCIDEVINFO_ENUM:
//
// Validate and adjust the parameters, and set the target buffer to the system buffer of the IRP
//
if (!DrvValidateAndAdjustIoctlParameter(SIZEOF_DEBUGGEE_PCIDEVINFO_REQUEST_RESPONSE_PACKET,
(PVOID *)&PcidevinfoRequest,
Irp,
IrpStack,
&InBuffLength,
&OutBuffLength))
{
Status = STATUS_INVALID_PARAMETER;
break;
}
//
// Both usermode and to send to usermode and the coming buffer are
// at the same place (it's in VMI-mode)
//
ExtensionCommandPcidevinfo(PcidevinfoRequest, FALSE);
//
// Adjust the status and output size
//
DrvAdjustStatusAndSetOutputSize(SIZEOF_DEBUGGEE_PCIDEVINFO_REQUEST_RESPONSE_PACKET, DoNotChangeInformation, Irp, &Status);
break;
default:
LogError("Err, unknown IOCTL");
Status = STATUS_NOT_IMPLEMENTED;
break;
}
return Status;
}
/**
* @brief IOCTL Dispatcher for HyperTrace IOCTLs
*
* @param Irp
* @param IrpStack
* @param DoNotChangeInformation
* @return NTSTATUS
*/
NTSTATUS
DrvDispatchHyperTraceIoControl(PIRP Irp, PIO_STACK_LOCATION IrpStack, BOOLEAN * DoNotChangeInformation)
{
PHYPERTRACE_LBR_OPERATION_PACKETS HyperTraceLbrOperationRequest;
PHYPERTRACE_LBR_DUMP_PACKETS HyperTraceLbrdumpRequest;
PHYPERTRACE_PT_OPERATION_PACKETS HyperTracePtOperationRequest;
PHYPERTRACE_PT_MMAP_PACKETS HyperTracePtMmapRequest;
ULONG InBuffLength;
ULONG OutBuffLength;
NTSTATUS Status = STATUS_SUCCESS;
UINT32 Ioctl = IrpStack->Parameters.DeviceIoControl.IoControlCode;
switch (Ioctl)
{
case IOCTL_PERFORM_HYPERTRACE_UNLOAD:
//
// Perform the unload of HyperTrace (there is no parameter for this IOCTL)
//
LoaderUninitHyperTrace();
//
// Adjust the status and output size
//
DrvAdjustStatusAndSetOutputSize(0, DoNotChangeInformation, Irp, &Status);
break;
case IOCTL_PERFORM_HYPERTRACE_LBR_OPERATION:
//
// Validate and adjust the parameters, and set the target buffer to the system buffer of the IRP
//
if (!DrvValidateAndAdjustIoctlParameter(SIZEOF_HYPERTRACE_LBR_OPERATION_PACKETS,
(PVOID *)&HyperTraceLbrOperationRequest,
Irp,
IrpStack,
&InBuffLength,
&OutBuffLength))
{
Status = STATUS_INVALID_PARAMETER;
break;
}
//
// Perform the HyperTrace LBR operation
//
HyperTraceLbrPerformOperation(HyperTraceLbrOperationRequest);
//
// Adjust the status and output size
//
DrvAdjustStatusAndSetOutputSize(SIZEOF_HYPERTRACE_LBR_OPERATION_PACKETS, DoNotChangeInformation, Irp, &Status);
break;
case IOCTL_PERFORM_HYPERTRACE_LBR_DUMP:
//
// Validate and adjust the parameters, and set the target buffer to the system buffer of the IRP
//
if (!DrvValidateAndAdjustIoctlParameter(SIZEOF_HYPERTRACE_LBR_DUMP_PACKETS,
(PVOID *)&HyperTraceLbrdumpRequest,
Irp,
IrpStack,
&InBuffLength,
&OutBuffLength))
{
Status = STATUS_INVALID_PARAMETER;
break;
}
//
// Perform the HyperTrace LBR dump operation
//
HyperTraceLbrPerformDump(HyperTraceLbrdumpRequest);
//
// Adjust the status and output size
//
DrvAdjustStatusAndSetOutputSize(SIZEOF_HYPERTRACE_LBR_DUMP_PACKETS, DoNotChangeInformation, Irp, &Status);
break;
case IOCTL_PERFORM_HYPERTRACE_PT_OPERATION:
//
// Validate and adjust the parameters, and set the target buffer to the system buffer of the IRP
//
if (!DrvValidateAndAdjustIoctlParameter(SIZEOF_HYPERTRACE_PT_OPERATION_PACKETS,
(PVOID *)&HyperTracePtOperationRequest,
Irp,
IrpStack,
&InBuffLength,
&OutBuffLength))
{
Status = STATUS_INVALID_PARAMETER;
break;
}
//
// If the caller asked to filter by a process id (and didn't
// already provide an explicit CR3), resolve the PID to the CR3
// the PT engine should match here — hyperkd owns the NT_KPROCESS
// layout, whereas the hypertrace engine only consumes a CR3. The
// kernel/user CR3 is chosen based on the requested trace mode so
// it works whether or not KVA shadowing (KPTI) is enabled.
//
if (HyperTracePtOperationRequest->EnableOptions.Pid != 0 &&
HyperTracePtOperationRequest->EnableOptions.Cr3 == 0)
{
HyperTracePtOperationRequest->EnableOptions.Cr3 =
DrvResolvePtTargetCr3(HyperTracePtOperationRequest->EnableOptions.Pid,
(BOOLEAN)(HyperTracePtOperationRequest->FilterOptions.TraceUser != 0),
(BOOLEAN)(HyperTracePtOperationRequest->FilterOptions.TraceKernel != 0));
}
//
// Perform the HyperTrace PT operation
//
HyperTracePtPerformOperation(HyperTracePtOperationRequest);
//
// Adjust the status and output size
//
DrvAdjustStatusAndSetOutputSize(SIZEOF_HYPERTRACE_PT_OPERATION_PACKETS, DoNotChangeInformation, Irp, &Status);
break;
case IOCTL_PERFORM_HYPERTRACE_PT_MMAP:
//
// Validate and adjust the parameters, and set the target buffer to the system buffer of the IRP
//
if (!DrvValidateAndAdjustIoctlParameter(SIZEOF_HYPERTRACE_PT_MMAP_PACKETS,
(PVOID *)&HyperTracePtMmapRequest,
Irp,
IrpStack,
&InBuffLength,
&OutBuffLength))
{
Status = STATUS_INVALID_PARAMETER;
break;
}
//
// Map the per-CPU PT output buffers into the calling user process
//
HyperTracePtMmap(HyperTracePtMmapRequest);
//
// Adjust the status and output size
//
DrvAdjustStatusAndSetOutputSize(SIZEOF_HYPERTRACE_PT_MMAP_PACKETS, DoNotChangeInformation, Irp, &Status);
break;
default:
LogError("Err, unknown IOCTL");
Status = STATUS_NOT_IMPLEMENTED;
break;
}
return Status;
}
/**
* @brief Driver IOCTL Dispatcher
*
* @param DeviceObject
* @param Irp
* @return NTSTATUS
*/
NTSTATUS
DrvDispatchIoControl(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
UNREFERENCED_PARAMETER(DeviceObject);
PIO_STACK_LOCATION IrpStack;
NTSTATUS Status = STATUS_SUCCESS;
BOOLEAN DoNotChangeInformation = FALSE;
UINT32 Ioctl = 0;
ULONG IoctlFunction = 0;
//
// Here's the best place to see if there is any allocation pending
// to be allocated as we're in PASSIVE_LEVEL
//
PoolManagerCheckAndPerformAllocationAndDeallocation();
//
// Get the current stack location of the IRP to access the parameters of the IOCTL request
//
IrpStack = IoGetCurrentIrpStackLocation(Irp);
//
// Get the IOCTL code from the parameters
//
Ioctl = IrpStack->Parameters.DeviceIoControl.IoControlCode;
//
// If we don't allow IOCTL from user-mode, we just complete the request with success, and return
//
if (!IoctlCheckIoctlAllowed(Ioctl))
{
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
//
// Dispatch to the appropriate handler based on the IOCTL range
//
IoctlFunction = CTL_CODE_FUNCTION(Ioctl);
if (IoctlFunction > IOCTL_BASIC_IOCTL && IoctlFunction <= IOCTL_BASIC_IOCTL + 0x100)
{
Status = DrvDispatchBasicIoControl(Irp, IrpStack, &DoNotChangeInformation);
}
else if (IoctlFunction > IOCTL_KD_IOCTL && IoctlFunction <= IOCTL_KD_IOCTL + 0x100)
{
Status = DrvDispatchKdIoControl(Irp, IrpStack, &DoNotChangeInformation);
}
else if (IoctlFunction > IOCTL_VMM_IOCTL && IoctlFunction <= IOCTL_VMM_IOCTL + 0x100)
{
Status = DrvDispatchVmmIoControl(Irp, IrpStack, &DoNotChangeInformation);
}
else if (IoctlFunction > IOCTL_HYPERTRACE_IOCTL && IoctlFunction <= IOCTL_HYPERTRACE_IOCTL + 0x100)
{
Status = DrvDispatchHyperTraceIoControl(Irp, IrpStack, &DoNotChangeInformation);
}
else
{
Status = STATUS_NOT_IMPLEMENTED;
}
if (Status != STATUS_PENDING)
{
Irp->IoStatus.Status = Status;
if (!DoNotChangeInformation)
{
Irp->IoStatus.Information = 0;
}
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
return Status;
}