mirror of
https://github.com/HyperDbg/HyperDbg.git
synced 2026-07-13 11:09:32 +00:00
409 lines
9.5 KiB
C
409 lines
9.5 KiB
C
/**
|
|
* @file Callback.c
|
|
* @author Sina Karvandi (sina@hyperdbg.org)
|
|
* @brief VMM callback interface routines
|
|
* @details
|
|
*
|
|
* @version 0.2
|
|
* @date 2023-01-29
|
|
*
|
|
* @copyright This project is released under the GNU Public License v3.
|
|
*
|
|
*/
|
|
#include "pch.h"
|
|
|
|
/**
|
|
* @brief routines callback to trigger events
|
|
* @param EventType
|
|
* @param CallingStage
|
|
* @param Context
|
|
* @param PostEventRequired
|
|
* @param Regs
|
|
*
|
|
* @return VMM_CALLBACK_TRIGGERING_EVENT_STATUS_TYPE
|
|
*/
|
|
VMM_CALLBACK_TRIGGERING_EVENT_STATUS_TYPE
|
|
VmmCallbackTriggerEvents(VMM_EVENT_TYPE_ENUM EventType,
|
|
VMM_CALLBACK_EVENT_CALLING_STAGE_TYPE CallingStage,
|
|
PVOID Context,
|
|
BOOLEAN * PostEventRequired,
|
|
GUEST_REGS * Regs)
|
|
{
|
|
if (g_Callbacks.VmmCallbackTriggerEvents == NULL)
|
|
{
|
|
return VMM_CALLBACK_TRIGGERING_EVENT_STATUS_SUCCESSFUL_NO_INITIALIZED;
|
|
}
|
|
|
|
return g_Callbacks.VmmCallbackTriggerEvents(EventType, CallingStage, Context, PostEventRequired, Regs);
|
|
}
|
|
|
|
/**
|
|
* @brief routine callback to set last error
|
|
* @param LastError
|
|
*
|
|
* @return VOID
|
|
*/
|
|
VOID
|
|
VmmCallbackSetLastError(UINT32 LastError)
|
|
{
|
|
if (g_Callbacks.VmmCallbackSetLastError == NULL)
|
|
{
|
|
//
|
|
// Ignore setting the last error
|
|
//
|
|
return;
|
|
}
|
|
|
|
g_Callbacks.VmmCallbackSetLastError(LastError);
|
|
}
|
|
|
|
/**
|
|
* @brief routine callback to handle external VMCALLs
|
|
*
|
|
* @param CoreId
|
|
* @param VmcallNumber
|
|
* @param OptionalParam1
|
|
* @param OptionalParam2
|
|
* @param OptionalParam3
|
|
*
|
|
* @return BOOLEAN
|
|
*/
|
|
BOOLEAN
|
|
VmmCallbackVmcallHandler(UINT32 CoreId,
|
|
UINT64 VmcallNumber,
|
|
UINT64 OptionalParam1,
|
|
UINT64 OptionalParam2,
|
|
UINT64 OptionalParam3)
|
|
{
|
|
if (g_Callbacks.VmmCallbackVmcallHandler == NULL)
|
|
{
|
|
//
|
|
// Ignore handling external VMCALLs
|
|
//
|
|
return FALSE;
|
|
}
|
|
|
|
return g_Callbacks.VmmCallbackVmcallHandler(CoreId, VmcallNumber, OptionalParam1, OptionalParam2, OptionalParam3);
|
|
}
|
|
|
|
/**
|
|
* @brief routine callback to handle NMI requests
|
|
*
|
|
* @param CoreId
|
|
* @param IsOnVmxNmiHandler
|
|
*
|
|
* @return VOID
|
|
*/
|
|
VOID
|
|
VmmCallbackNmiBroadcastRequestHandler(UINT32 CoreId, BOOLEAN IsOnVmxNmiHandler)
|
|
{
|
|
if (g_Callbacks.VmmCallbackNmiBroadcastRequestHandler == NULL)
|
|
{
|
|
//
|
|
// ignore it
|
|
//
|
|
return;
|
|
}
|
|
|
|
g_Callbacks.VmmCallbackNmiBroadcastRequestHandler(CoreId, IsOnVmxNmiHandler);
|
|
}
|
|
|
|
/**
|
|
* @brief routine callback to query for termination of protected resources
|
|
*
|
|
* @param CoreId
|
|
* @param ResourceType
|
|
* @param Context
|
|
* @param PassOver
|
|
*
|
|
* @return BOOLEAN
|
|
*/
|
|
BOOLEAN
|
|
VmmCallbackQueryTerminateProtectedResource(UINT32 CoreId,
|
|
PROTECTED_HV_RESOURCES_TYPE ResourceType,
|
|
PVOID Context,
|
|
PROTECTED_HV_RESOURCES_PASSING_OVERS PassOver)
|
|
{
|
|
if (g_Callbacks.VmmCallbackQueryTerminateProtectedResource == NULL)
|
|
{
|
|
//
|
|
// ignore it
|
|
//
|
|
return FALSE;
|
|
}
|
|
|
|
return g_Callbacks.VmmCallbackQueryTerminateProtectedResource(CoreId, ResourceType, Context, PassOver);
|
|
}
|
|
|
|
/**
|
|
* @brief routine callback to restore EPT state
|
|
* @param CoreId
|
|
*
|
|
* @return BOOLEAN
|
|
*/
|
|
BOOLEAN
|
|
VmmCallbackRestoreEptState(UINT32 CoreId)
|
|
{
|
|
if (g_Callbacks.VmmCallbackRestoreEptState == NULL)
|
|
{
|
|
//
|
|
// ignore it as it's not handled
|
|
//
|
|
return FALSE;
|
|
}
|
|
|
|
return g_Callbacks.VmmCallbackRestoreEptState(CoreId);
|
|
}
|
|
|
|
/**
|
|
* @brief routine callback to handle unhandled EPT violations
|
|
* @param CoreId
|
|
* @param ViolationQualification
|
|
* @param GuestPhysicalAddr
|
|
*
|
|
* @return BOOLEAN
|
|
*/
|
|
BOOLEAN
|
|
VmmCallbackUnhandledEptViolation(UINT32 CoreId,
|
|
UINT64 ViolationQualification,
|
|
UINT64 GuestPhysicalAddr)
|
|
{
|
|
if (g_Callbacks.VmmCallbackCheckUnhandledEptViolations == NULL)
|
|
{
|
|
//
|
|
// ignore it as it's not handled
|
|
//
|
|
return FALSE;
|
|
}
|
|
|
|
return g_Callbacks.VmmCallbackCheckUnhandledEptViolations(CoreId, ViolationQualification, GuestPhysicalAddr);
|
|
}
|
|
|
|
/**
|
|
* @brief routine callback to handle MTF callback
|
|
* @param CoreId
|
|
*
|
|
* @return BOOLEAN
|
|
*/
|
|
BOOLEAN
|
|
VmmCallbackHandleMtfCallback(UINT32 CoreId)
|
|
{
|
|
if (g_Callbacks.VmmCallbackHandleMtfCallback == NULL)
|
|
{
|
|
//
|
|
// ignore it as it's not handled
|
|
//
|
|
return FALSE;
|
|
}
|
|
|
|
return g_Callbacks.VmmCallbackHandleMtfCallback(CoreId);
|
|
}
|
|
|
|
/**
|
|
* @brief routine callback to check if LBR is supported and get the LBR capacity if supported
|
|
*
|
|
* @param Capacity
|
|
* @param IsArchLbr
|
|
*
|
|
* @return BOOLEAN
|
|
*/
|
|
BOOLEAN
|
|
HyperTraceCallbackLbrIsSupported(UINT32 * Capacity, BOOLEAN * IsArchLbr)
|
|
{
|
|
if (g_Callbacks.HyperTraceCallbackLbrIsSupported == NULL)
|
|
{
|
|
//
|
|
// ignore it as it's not handled
|
|
//
|
|
return FALSE;
|
|
}
|
|
return g_Callbacks.HyperTraceCallbackLbrIsSupported(Capacity, IsArchLbr);
|
|
}
|
|
|
|
/**
|
|
* @brief routine callback to handle breakpoint exception
|
|
*
|
|
* @param CoreId
|
|
*
|
|
* @return BOOLEAN
|
|
*/
|
|
BOOLEAN
|
|
DebuggingCallbackHandleBreakpointException(UINT32 CoreId)
|
|
{
|
|
if (g_Callbacks.DebuggingCallbackHandleBreakpointException == NULL)
|
|
{
|
|
//
|
|
// re-inject it to not disrupt system normal execution
|
|
//
|
|
return FALSE;
|
|
}
|
|
|
|
return g_Callbacks.DebuggingCallbackHandleBreakpointException(CoreId);
|
|
}
|
|
|
|
/**
|
|
* @brief routine callback to handle debug breakpoint exception
|
|
*
|
|
* @param CoreId
|
|
*
|
|
* @return BOOLEAN
|
|
*/
|
|
BOOLEAN
|
|
DebuggingCallbackHandleDebugBreakpointException(UINT32 CoreId)
|
|
{
|
|
if (g_Callbacks.DebuggingCallbackHandleDebugBreakpointException == NULL)
|
|
{
|
|
//
|
|
// re-inject it to not disrupt system normal execution
|
|
//
|
|
return FALSE;
|
|
}
|
|
|
|
return g_Callbacks.DebuggingCallbackHandleDebugBreakpointException(CoreId);
|
|
}
|
|
|
|
/**
|
|
* @brief routine callback to handle thread interception
|
|
*
|
|
* @param CoreId
|
|
*
|
|
* @return BOOLEAN
|
|
*/
|
|
BOOLEAN
|
|
DebuggingCallbackCheckThreadInterception(UINT32 CoreId)
|
|
{
|
|
if (g_Callbacks.DebuggingCallbackCheckThreadInterception == NULL)
|
|
{
|
|
//
|
|
// not handled by user debugger
|
|
//
|
|
return FALSE;
|
|
}
|
|
|
|
return g_Callbacks.DebuggingCallbackCheckThreadInterception(CoreId);
|
|
}
|
|
|
|
/**
|
|
* @brief routine callback to trigger on clock and IPI events for checking process or thread change
|
|
*
|
|
* @param CoreId
|
|
*
|
|
* @return BOOLEAN
|
|
*/
|
|
BOOLEAN
|
|
DebuggingCallbackTriggerOnClockAndIpiEvents(UINT32 CoreId)
|
|
{
|
|
if (g_Callbacks.DebuggingCallbackTriggerOnClockAndIpiEvents == NULL)
|
|
{
|
|
//
|
|
// not handled by user debugger
|
|
//
|
|
return FALSE;
|
|
}
|
|
return g_Callbacks.DebuggingCallbackTriggerOnClockAndIpiEvents(CoreId);
|
|
}
|
|
|
|
/**
|
|
* @brief routine callback to ignore handling mov 2 debug registers
|
|
* @param CoreId
|
|
*
|
|
* @return BOOLEAN
|
|
*/
|
|
BOOLEAN
|
|
DebuggingCallbackIgnoreHandlingMov2DebugRegs(UINT32 CoreId)
|
|
{
|
|
if (g_Callbacks.DebuggingCallbackIgnoreHandlingMov2DebugRegs == NULL)
|
|
{
|
|
//
|
|
// not handled by user debugger
|
|
//
|
|
return FALSE;
|
|
}
|
|
return g_Callbacks.DebuggingCallbackIgnoreHandlingMov2DebugRegs(CoreId);
|
|
}
|
|
|
|
/**
|
|
* @brief routine callback to request pool allocation
|
|
*
|
|
* @param Size
|
|
* @param Count
|
|
* @param Intention The intention of the buffer (buffer tag)
|
|
*
|
|
* @return BOOLEAN
|
|
*/
|
|
BOOLEAN
|
|
PoolManagerCallbackRequestAllocation(SIZE_T Size, UINT32 Count, POOL_ALLOCATION_INTENTION Intention)
|
|
{
|
|
if (g_Callbacks.PoolManagerCallbackRequestAllocation == NULL)
|
|
{
|
|
//
|
|
// ignore it as it's not handled
|
|
//
|
|
return FALSE;
|
|
}
|
|
return g_Callbacks.PoolManagerCallbackRequestAllocation(Size, Count, Intention);
|
|
}
|
|
|
|
/**
|
|
* @brief routine callback to request pool
|
|
*
|
|
* @param Intention The intention why we need this pool for (buffer tag)
|
|
* @param RequestNewPool Create a request to allocate a new pool with the same size, next time
|
|
* that it's safe to allocate (this way we never ran out of pools for this "Intention")
|
|
* @param Size If the RequestNewPool is true the we should specify a size for the new pool
|
|
*
|
|
* @return UINT64 Returns a pool address or returns null if there was an error
|
|
*/
|
|
UINT64
|
|
PoolManagerCallbackRequestPool(POOL_ALLOCATION_INTENTION Intention, BOOLEAN RequestNewPool, UINT32 Size)
|
|
{
|
|
if (g_Callbacks.PoolManagerCallbackRequestPool == NULL)
|
|
{
|
|
//
|
|
// ignore it as it's not handled
|
|
//
|
|
return 0;
|
|
}
|
|
return g_Callbacks.PoolManagerCallbackRequestPool(Intention, RequestNewPool, Size);
|
|
}
|
|
|
|
/**
|
|
* @brief routine callback to free pool
|
|
*
|
|
* @param AddressToFree
|
|
*
|
|
* @return BOOLEAN
|
|
*/
|
|
BOOLEAN
|
|
PoolManagerCallbackFreePool(UINT64 AddressToFree)
|
|
{
|
|
if (g_Callbacks.PoolManagerCallbackFreePool == NULL)
|
|
{
|
|
//
|
|
// ignore it as it's not handled
|
|
//
|
|
return FALSE;
|
|
}
|
|
return g_Callbacks.PoolManagerCallbackFreePool(AddressToFree);
|
|
}
|
|
|
|
/**
|
|
* @brief routine callback to handle cr3 process change
|
|
*
|
|
* @param CoreId
|
|
*
|
|
* @return VOID
|
|
*/
|
|
VOID
|
|
InterceptionCallbackTriggerCr3ProcessChange(UINT32 CoreId)
|
|
{
|
|
if (g_Callbacks.InterceptionCallbackTriggerCr3ProcessChange == NULL)
|
|
{
|
|
//
|
|
// ignore it
|
|
//
|
|
return;
|
|
}
|
|
|
|
g_Callbacks.InterceptionCallbackTriggerCr3ProcessChange(CoreId);
|
|
}
|