HyperDbg/hyperdbg/hyperkd/code/debugger/events/ValidateEvents.c
2024-06-24 18:05:54 +09:00

315 lines
9.8 KiB
C

/**
* @file ValidateEvents.c
* @author Sina Karvandi (sina@hyperdbg.org)
* @brief Implementation of debugger functions for validating events
* @details
*
* @version 0.7
* @date 2023-10-15
*
* @copyright This project is released under the GNU Public License v3.
*
*/
#include "pch.h"
/**
* @brief Validating monitor memory hook events
*
* @param Event The created event object
* @param ResultsToReturn Result buffer that should be returned to
* the user-mode
* @param InputFromVmxRoot Whether the input comes from VMX root-mode or IOCTL
*
* @return BOOLEAN
*/
BOOLEAN
ValidateEventMonitor(PDEBUGGER_GENERAL_EVENT_DETAIL EventDetails,
PDEBUGGER_EVENT_AND_ACTION_RESULT ResultsToReturn,
BOOLEAN InputFromVmxRoot)
{
UINT32 TempPid;
//
// First check if the address are valid
//
TempPid = EventDetails->ProcessId;
if (TempPid == DEBUGGER_EVENT_APPLY_TO_ALL_PROCESSES)
{
TempPid = HANDLE_TO_UINT32(PsGetCurrentProcessId());
}
//
// Check if input is coming from VMX-root or not
// If it's coming from VMX-root, then as switching
// to another process is not possible, we'll return
// an error
//
if (InputFromVmxRoot && TempPid != HANDLE_TO_UINT32(PsGetCurrentProcessId()))
{
ResultsToReturn->IsSuccessful = FALSE;
ResultsToReturn->Error = DEBUGGER_ERROR_PROCESS_ID_CANNOT_BE_SPECIFIED_WHILE_APPLYING_EVENT_FROM_VMX_ROOT_MODE;
return FALSE;
}
//
// Check whether address is valid or not based on whether the event needs
// to be applied directly from VMX-root mode or not
//
if ((DEBUGGER_HOOK_MEMORY_TYPE)EventDetails->Options.OptionalParam3 == DEBUGGER_MEMORY_HOOK_PHYSICAL_ADDRESS)
{
//
// Validation of a physical address
//
if (CheckAddressPhysical(EventDetails->Options.OptionalParam1) == FALSE ||
CheckAddressPhysical(EventDetails->Options.OptionalParam2) == FALSE)
{
//
// Physical address is invalid (Set the error)
//
ResultsToReturn->IsSuccessful = FALSE;
ResultsToReturn->Error = DEBUGGER_ERROR_INVALID_PHYSICAL_ADDRESS;
return FALSE;
}
}
else
{
//
// Validation of a virtual address
//
if (InputFromVmxRoot)
{
if (VirtualAddressToPhysicalAddressOnTargetProcess((PVOID)EventDetails->Options.OptionalParam1) == (UINT64)NULL ||
VirtualAddressToPhysicalAddressOnTargetProcess((PVOID)EventDetails->Options.OptionalParam2) == (UINT64)NULL)
{
//
// Virtual address is invalid (Set the error)
//
ResultsToReturn->IsSuccessful = FALSE;
ResultsToReturn->Error = DEBUGGER_ERROR_INVALID_ADDRESS;
return FALSE;
}
}
else
{
if (VirtualAddressToPhysicalAddressByProcessId((PVOID)EventDetails->Options.OptionalParam1, TempPid) == (UINT64)NULL ||
VirtualAddressToPhysicalAddressByProcessId((PVOID)EventDetails->Options.OptionalParam2, TempPid) == (UINT64)NULL)
{
//
// Address is invalid (Set the error)
//
ResultsToReturn->IsSuccessful = FALSE;
ResultsToReturn->Error = DEBUGGER_ERROR_INVALID_ADDRESS;
return FALSE;
}
}
}
//
// Check if the 'to' is greater that 'from'
//
if (EventDetails->Options.OptionalParam1 >= EventDetails->Options.OptionalParam2)
{
ResultsToReturn->IsSuccessful = FALSE;
ResultsToReturn->Error = DEBUGGER_ERROR_INVALID_ADDRESS;
return FALSE;
}
//
// The event parameters are valid at this stage
//
return TRUE;
}
/**
* @brief Validating exception events
*
* @param Event The created event object
* @param ResultsToReturn Result buffer that should be returned to
* the user-mode
* @param InputFromVmxRoot Whether the input comes from VMX root-mode or IOCTL
*
* @return BOOLEAN
*/
BOOLEAN
ValidateEventException(PDEBUGGER_GENERAL_EVENT_DETAIL EventDetails,
PDEBUGGER_EVENT_AND_ACTION_RESULT ResultsToReturn,
BOOLEAN InputFromVmxRoot)
{
UNREFERENCED_PARAMETER(InputFromVmxRoot);
//
// Check if the exception entry doesn't exceed the first 32 entry (start from zero)
//
if (EventDetails->Options.OptionalParam1 != DEBUGGER_EVENT_EXCEPTIONS_ALL_FIRST_32_ENTRIES && EventDetails->Options.OptionalParam1 >= 31)
{
//
// We don't support entries other than first 32 IDT indexes,
// it is because we use exception bitmaps and in order to support
// more than 32 indexes we should use pin-based external interrupt
// exiting which is completely different
//
ResultsToReturn->IsSuccessful = FALSE;
ResultsToReturn->Error = DEBUGGER_ERROR_EXCEPTION_INDEX_EXCEED_FIRST_32_ENTRIES;
return FALSE;
}
//
// The event parameters are valid at this stage
//
return TRUE;
}
/**
* @brief Validating interrupt events
*
* @param Event The created event object
* @param ResultsToReturn Result buffer that should be returned to
* the user-mode
* @param InputFromVmxRoot Whether the input comes from VMX root-mode or IOCTL
*
* @return BOOLEAN
*/
BOOLEAN
ValidateEventInterrupt(PDEBUGGER_GENERAL_EVENT_DETAIL EventDetails,
PDEBUGGER_EVENT_AND_ACTION_RESULT ResultsToReturn,
BOOLEAN InputFromVmxRoot)
{
UNREFERENCED_PARAMETER(InputFromVmxRoot);
//
// Check if the exception entry is between 32 to 255
//
if (!(EventDetails->Options.OptionalParam1 >= 32 && EventDetails->Options.OptionalParam1 <= 0xff))
{
//
// The IDT Entry is either invalid or is not in the range
// of the pin-based external interrupt exiting controls
//
ResultsToReturn->IsSuccessful = FALSE;
ResultsToReturn->Error = DEBUGGER_ERROR_INTERRUPT_INDEX_IS_NOT_VALID;
return FALSE;
}
//
// The event parameters are valid at this stage
//
return TRUE;
}
/**
* @brief Validating trap exec events
*
* @param Event The created event object
* @param ResultsToReturn Result buffer that should be returned to
* the user-mode
* @param InputFromVmxRoot Whether the input comes from VMX root-mode or IOCTL
*
* @return BOOLEAN
*/
BOOLEAN
ValidateEventTrapExec(PDEBUGGER_GENERAL_EVENT_DETAIL EventDetails,
PDEBUGGER_EVENT_AND_ACTION_RESULT ResultsToReturn,
BOOLEAN InputFromVmxRoot)
{
UNREFERENCED_PARAMETER(InputFromVmxRoot);
//
// Check if the execution mode is valid or not
//
if (EventDetails->Options.OptionalParam1 != DEBUGGER_EVENT_MODE_TYPE_USER_MODE &&
EventDetails->Options.OptionalParam1 != DEBUGGER_EVENT_MODE_TYPE_KERNEL_MODE &&
EventDetails->Options.OptionalParam1 != DEBUGGER_EVENT_MODE_TYPE_USER_MODE_AND_KERNEL_MODE)
{
//
// The execution mode is not correctly applied
//
ResultsToReturn->IsSuccessful = FALSE;
ResultsToReturn->Error = DEBUGGER_ERROR_MODE_EXECUTION_IS_INVALID;
return FALSE;
}
//
// The event parameters are valid at this stage
//
return TRUE;
}
/**
* @brief Validating EPT hook exec (hidden breakpoint and inline hook) events
*
* @param Event The created event object
* @param ResultsToReturn Result buffer that should be returned to
* the user-mode
* @param InputFromVmxRoot Whether the input comes from VMX root-mode or IOCTL
*
* @return BOOLEAN
*/
BOOLEAN
ValidateEventEptHookHiddenBreakpointAndInlineHooks(PDEBUGGER_GENERAL_EVENT_DETAIL EventDetails,
PDEBUGGER_EVENT_AND_ACTION_RESULT ResultsToReturn,
BOOLEAN InputFromVmxRoot)
{
UINT32 TempPid;
//
// First check if the address are valid
//
TempPid = EventDetails->ProcessId;
if (TempPid == DEBUGGER_EVENT_APPLY_TO_ALL_PROCESSES)
{
TempPid = HANDLE_TO_UINT32(PsGetCurrentProcessId());
}
//
// Check if input is coming from VMX-root or not
// If it's coming from VMX-root, then as switching
// to another process is not possible, we'll return
// an error
//
if (InputFromVmxRoot && TempPid != HANDLE_TO_UINT32(PsGetCurrentProcessId()))
{
ResultsToReturn->IsSuccessful = FALSE;
ResultsToReturn->Error = DEBUGGER_ERROR_PROCESS_ID_CANNOT_BE_SPECIFIED_WHILE_APPLYING_EVENT_FROM_VMX_ROOT_MODE;
return FALSE;
}
//
// Check whether address is valid or not based on whether the event needs
// to be applied directly from VMX-root mode or not
//
if (InputFromVmxRoot)
{
if (VirtualAddressToPhysicalAddressOnTargetProcess((PVOID)EventDetails->Options.OptionalParam1) == (UINT64)NULL)
{
//
// Address is invalid (Set the error)
//
ResultsToReturn->IsSuccessful = FALSE;
ResultsToReturn->Error = DEBUGGER_ERROR_INVALID_ADDRESS;
return FALSE;
}
}
else
{
if (VirtualAddressToPhysicalAddressByProcessId((PVOID)EventDetails->Options.OptionalParam1, TempPid) == (UINT64)NULL)
{
//
// Address is invalid (Set the error)
//
ResultsToReturn->IsSuccessful = FALSE;
ResultsToReturn->Error = DEBUGGER_ERROR_INVALID_ADDRESS;
return FALSE;
}
}
//
// The event parameters are valid at this stage
//
return TRUE;
}