/** * @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); }