HyperDbg/hyperdbg/hyperkd/code/driver/Loader.c

452 lines
14 KiB
C
Raw Permalink Normal View History

2023-01-15 05:18:44 +09:00
/**
* @file Loader.c
* @author Sina Karvandi (sina@hyperdbg.org)
* @brief The functions used in loading the debugger and VMM
* @version 0.2
* @date 2023-01-15
*
* @copyright This project is released under the GNU Public License v3.
*
*/
#include "pch.h"
2026-04-05 22:56:59 +02:00
/**
* @brief Initialize the hyper trace module
*
* @param RunningOnHypervisorEnvironment Whether the initialization is being done for hypervisor environment or not
*
2026-04-05 22:56:59 +02:00
* @return BOOLEAN
*/
BOOLEAN
2026-05-28 20:26:33 +02:00
LoaderInitHyperTrace(PDEBUGGER_INIT_HYPERTRACE_PACKET InitHyperTracePacket, BOOLEAN RunningOnHypervisorEnvironment)
2026-04-05 22:56:59 +02:00
{
HYPERTRACE_CALLBACKS HyperTraceCallbacks = {0};
//
// *** Fill the callbacks for using hypertrace ***
//
//
// Fill the callbacks for using hyperlog in hypertrace
// We use the callbacks directly to avoid two calls to the same function
//
HyperTraceCallbacks.LogCallbackPrepareAndSendMessageToQueueWrapper = LogCallbackPrepareAndSendMessageToQueueWrapper;
HyperTraceCallbacks.LogCallbackSendMessageToQueue = LogCallbackSendMessageToQueue;
HyperTraceCallbacks.LogCallbackSendBuffer = LogCallbackSendBuffer;
HyperTraceCallbacks.LogCallbackCheckIfBufferIsFull = LogCallbackCheckIfBufferIsFull;
//
// Fill the callbacks for using hyperhv in hypertrace
//
HyperTraceCallbacks.VmFuncVmxGetCurrentExecutionMode = VmFuncVmxGetCurrentExecutionMode;
//
// *** Legacy LBR callbacks ***
//
2026-05-01 18:40:39 +02:00
HyperTraceCallbacks.VmFuncCheckCpuSupportForSaveAndLoadDebugControls = VmFuncCheckCpuSupportForSaveAndLoadDebugControls;
HyperTraceCallbacks.VmFuncGetDebugctl = VmFuncGetDebugctl;
HyperTraceCallbacks.VmFuncGetDebugctlVmcallOnTargetCore = VmFuncGetDebugctlVmcallOnTargetCore;
HyperTraceCallbacks.VmFuncSetDebugctl = VmFuncSetDebugctl;
HyperTraceCallbacks.VmFuncSetDebugctlVmcallOnTargetCore = VmFuncSetDebugctlVmcallOnTargetCore;
HyperTraceCallbacks.VmFuncSetLoadDebugControls = VmFuncSetLoadDebugControls;
HyperTraceCallbacks.VmFuncSetLoadDebugControlsVmcallOnTargetCore = VmFuncSetLoadDebugControlsVmcallOnTargetCore;
HyperTraceCallbacks.VmFuncSetSaveDebugControls = VmFuncSetSaveDebugControls;
HyperTraceCallbacks.VmFuncSetSaveDebugControlsVmcallOnTargetCore = VmFuncSetSaveDebugControlsVmcallOnTargetCore;
HyperTraceCallbacks.VmFuncSetLbrSelect = VmFuncSetLbrSelect;
HyperTraceCallbacks.VmFuncSetLbrSelectVmcallOnTargetCore = VmFuncSetLbrSelectVmcallOnTargetCore;
//
// *** Architectural LBR callbacks ***
//
HyperTraceCallbacks.VmFuncCheckCpuSupportForLoadAndClearGuestIa32LbrCtlControls = VmFuncCheckCpuSupportForLoadAndClearGuestIa32LbrCtlControls;
HyperTraceCallbacks.VmFuncGetGuestIa32LbrCtl = VmFuncGetGuestIa32LbrCtl;
HyperTraceCallbacks.VmFuncGetGuestIa32LbrCtlVmcallOnTargetCore = VmFuncGetGuestIa32LbrCtlVmcallOnTargetCore;
HyperTraceCallbacks.VmFuncSetGuestIa32LbrCtl = VmFuncSetGuestIa32LbrCtl;
HyperTraceCallbacks.VmFuncSetGuestIa32LbrCtlVmcallOnTargetCore = VmFuncSetGuestIa32LbrCtlVmcallOnTargetCore;
HyperTraceCallbacks.VmFuncSetLoadGuestIa32LbrCtl = VmFuncSetLoadGuestIa32LbrCtl;
HyperTraceCallbacks.VmFuncSetLoadGuestIa32LbrCtlVmcallOnTargetCore = VmFuncSetLoadGuestIa32LbrCtlVmcallOnTargetCore;
HyperTraceCallbacks.VmFuncSetClearGuestIa32LbrCtl = VmFuncSetClearGuestIa32LbrCtl;
HyperTraceCallbacks.VmFuncSetClearGuestIa32LbrCtlVmcallOnTargetCore = VmFuncSetClearGuestIa32LbrCtlVmcallOnTargetCore;
2026-04-05 22:56:59 +02:00
//
// Initialize hypertrace module
//
if (HyperTraceInitCallback(&HyperTraceCallbacks, RunningOnHypervisorEnvironment))
2026-04-05 22:56:59 +02:00
{
LogDebugInfo("HyperDbg's hypertrace loaded successfully");
2026-05-28 20:26:33 +02:00
//
// Mark hypertrace as initialized
//
g_HyperTraceInitialized = TRUE;
//
// Set the kernel status to success
//
InitHyperTracePacket->KernelStatus = DEBUGGER_OPERATION_WAS_SUCCESSFUL;
2026-04-05 22:56:59 +02:00
return TRUE;
}
else
{
//
// We won't fail the loading just because of hypertrace, so we just log the error and continue without loading hypertrace
//
LogDebugInfo("Err, HyperDbg's hypertrace was not loaded");
2026-05-28 20:26:33 +02:00
//
// Set the kernel status to indicate failure
//
InitHyperTracePacket->KernelStatus = DEBUGGER_ERROR_HYPERTRACE_NOT_INITIALIZED;
2026-04-05 22:56:59 +02:00
return FALSE;
}
}
2023-01-15 05:18:44 +09:00
/**
2026-05-27 20:21:21 +02:00
* @brief Initialize the hyper log module
2023-01-15 05:18:44 +09:00
*
2023-01-15 06:58:56 +09:00
* @return BOOLEAN
2023-01-15 05:18:44 +09:00
*/
BOOLEAN
2026-05-27 20:21:21 +02:00
LoaderInitHyperLog()
2023-01-15 05:18:44 +09:00
{
2023-01-15 16:05:21 +09:00
MESSAGE_TRACING_CALLBACKS MsgTracingCallbacks = {0};
//
2026-02-08 04:09:47 +01:00
// *** Fill the callbacks for the message tracer ***
//
MsgTracingCallbacks.VmxOperationCheck = VmFuncVmxGetCurrentExecutionMode;
2023-01-15 16:05:21 +09:00
MsgTracingCallbacks.CheckImmediateMessageSending = KdCheckImmediateMessagingMechanism;
MsgTracingCallbacks.SendImmediateMessage = KdLoggingResponsePacketToDebugger;
2026-05-27 20:21:21 +02:00
//
// Initialize message tracer (if not already initialized)
//
if (g_HyperLogInitialized == FALSE && LogInitialize(&MsgTracingCallbacks))
{
g_HyperLogInitialized = TRUE;
LogDebugInfo("HyperDbg's hyperlog loaded successfully");
return TRUE;
}
else
{
//
// We use DbgPrint here because if the hyperlog is not loaded we can't use it to log the error
// so we just log the error with DbgPrint and continue without loading hyperlog
//
DbgPrint("Err, HyperDbg's hyperlog was not loaded or already loaded");
return FALSE;
}
}
/**
* @brief Initialize the VMM
2026-05-27 20:21:21 +02:00
*
2026-05-28 20:26:33 +02:00
* @param InitVmmPacket The packet to fill the result of the initialization
*
2026-05-27 20:21:21 +02:00
* @return BOOLEAN
*/
BOOLEAN
LoaderInitVmm(PDEBUGGER_INIT_VMM_PACKET InitVmmPacket)
2026-05-27 20:21:21 +02:00
{
VMM_CALLBACKS VmmCallbacks = {0};
//
// Check if KD is not already initialized, if so we cannot initialize VMM
//
if (!g_KdInitialized)
{
InitVmmPacket->KernelStatus = DEBUGGER_ERROR_VMM_CANNOT_BE_INITIALIZED_IF_DEBUGGER_IS_NOT_LOADED;
return FALSE;
}
2026-05-28 20:26:33 +02:00
//
// Check if HyperTrace is already initialized, if so we cannot initialize VMM
//
if (g_HyperTraceInitialized)
{
InitVmmPacket->KernelStatus = DEBUGGER_ERROR_VMM_CANNOT_BE_INITIALIZED_IF_HYPERTRACE_IS_LOADED;
return FALSE;
}
2023-01-15 05:18:44 +09:00
//
2026-02-08 04:09:47 +01:00
// *** Fill the callbacks for using hyperlog in VMM ***
2023-01-15 05:18:44 +09:00
//
2023-01-29 07:12:19 +09:00
VmmCallbacks.LogCallbackPrepareAndSendMessageToQueueWrapper = LogCallbackPrepareAndSendMessageToQueueWrapper;
VmmCallbacks.LogCallbackSendMessageToQueue = LogCallbackSendMessageToQueue;
VmmCallbacks.LogCallbackSendBuffer = LogCallbackSendBuffer;
VmmCallbacks.LogCallbackCheckIfBufferIsFull = LogCallbackCheckIfBufferIsFull;
2023-01-19 21:34:45 +09:00
//
// Fill the HyperTrace callback(s)
//
2026-06-09 01:37:48 +02:00
VmmCallbacks.HyperTraceCallbackLbrIsSupported = HyperTraceLbrIsSupported;
2023-01-19 21:34:45 +09:00
//
2023-01-29 08:52:22 +09:00
// Fill the VMM callbacks
2023-01-19 21:34:45 +09:00
//
2023-01-29 08:52:22 +09:00
VmmCallbacks.VmmCallbackTriggerEvents = DebuggerTriggerEvents;
VmmCallbacks.VmmCallbackSetLastError = DebuggerSetLastError;
VmmCallbacks.VmmCallbackVmcallHandler = DebuggerVmcallHandler;
VmmCallbacks.VmmCallbackNmiBroadcastRequestHandler = KdHandleNmiBroadcastDebugBreaks;
VmmCallbacks.VmmCallbackQueryTerminateProtectedResource = TerminateQueryDebuggerResource;
VmmCallbacks.VmmCallbackRestoreEptState = UserAccessCheckForLoadedModuleDetails;
VmmCallbacks.VmmCallbackCheckUnhandledEptViolations = AttachingCheckUnhandledEptViolation;
2026-06-09 01:37:48 +02:00
VmmCallbacks.VmmCallbackHandleMtfCallback = KdHandleMtfCallback;
//
2023-01-29 08:52:22 +09:00
// Fill the debugging callbacks
//
2026-06-09 15:04:20 +02:00
VmmCallbacks.DebuggingCallbackHandleBreakpointException = BreakpointHandleBreakpoints;
VmmCallbacks.DebuggingCallbackHandleDebugBreakpointException = BreakpointCheckAndHandleDebugBreakpoint;
VmmCallbacks.DebuggingCallbackCheckThreadInterception = AttachingCheckThreadInterceptionWithUserDebugger;
VmmCallbacks.DebuggingCallbackTriggerOnClockAndIpiEvents = DebuggerCheckProcessOrThreadChange;
VmmCallbacks.DebuggingCallbackIgnoreHandlingMov2DebugRegs = KdQueryIgnoreHandlingMov2DebugRegs;
2023-01-15 05:18:44 +09:00
//
// Fill the pool manager callbacks
//
2026-06-09 01:37:48 +02:00
VmmCallbacks.PoolManagerCallbackRequestAllocation = PoolManagerRequestAllocation;
VmmCallbacks.PoolManagerCallbackRequestPool = PoolManagerRequestPool;
VmmCallbacks.PoolManagerCallbackFreePool = PoolManagerFreePool;
2023-01-29 08:52:22 +09:00
//
// Fill the interception callbacks
//
VmmCallbacks.InterceptionCallbackTriggerCr3ProcessChange = ProcessTriggerCr3ProcessChange;
2023-01-15 05:18:44 +09:00
//
2026-05-27 20:21:21 +02:00
// Initialize VMX
2023-01-15 05:18:44 +09:00
//
2026-05-27 20:21:21 +02:00
if (VmFuncInitVmm(&VmmCallbacks))
2023-01-15 05:18:44 +09:00
{
2026-05-27 20:21:21 +02:00
LogDebugInfo("HyperDbg's hypervisor loaded successfully");
//
2026-06-04 00:55:05 +02:00
// Initialize VMM opeartions (event related state from the debugger)
//
2026-06-04 00:55:05 +02:00
if (!DebuggerInitializeVmmOperations())
{
return FALSE;
}
2023-01-15 05:18:44 +09:00
//
// VMM module initialized
2023-01-15 05:18:44 +09:00
//
g_VmmInitialized = TRUE;
2026-05-28 20:26:33 +02:00
return TRUE;
2023-01-15 05:18:44 +09:00
}
else
{
2026-05-27 20:21:21 +02:00
LogError("Err, HyperDbg's hypervisor was not loaded");
2023-01-15 05:18:44 +09:00
}
return FALSE;
}
2023-01-15 06:58:56 +09:00
/**
* @brief Initialize the debugger
*
* @return BOOLEAN
*/
BOOLEAN
LoaderInitKd()
{
//
// If the debugger is already initialized, we don't need to initialize it again
// and simply return true
//
if (g_KdInitialized)
{
return TRUE;
}
//
// The debugger is not initialized, so we try to initialize it
//
if (DebuggerInitialize())
{
LogDebugInfo("HyperDbg's debugger loaded successfully");
//
// KD module initialized
//
g_KdInitialized = TRUE;
return TRUE;
}
LogError("Err, HyperDbg's debugger was not loaded");
return FALSE;
}
/**
2026-06-04 00:55:05 +02:00
* @brief Initialize the debugger and the vmm
*
* @param InitVmmPacket The packet to fill the result of the initialization
*
* @return BOOLEAN
*/
BOOLEAN
2026-06-04 00:55:05 +02:00
LoaderInitDebuggerAndVmm(PDEBUGGER_INIT_VMM_PACKET InitVmmPacket)
{
//
// First we need to initialize the debugger
// because the VMM relies on the debugger for some of its functionalities,
// so if we cannot initialize the debugger we cannot initialize the VMM
//
if (!LoaderInitKd())
{
//
// Unable to initialize the debugger, so we cannot initialize the VMM, and we return false
//
InitVmmPacket->KernelStatus = DEBUGGER_ERROR_CANNOT_INITIALIZE_DEBUGGER;
return FALSE;
}
//
// Now we can initialize the VMM
//
if (!LoaderInitVmm(InitVmmPacket))
{
return FALSE;
}
//
// Set the kernel status to success
//
InitVmmPacket->KernelStatus = DEBUGGER_OPERATION_WAS_SUCCESSFUL;
return TRUE;
}
2026-06-04 00:55:05 +02:00
/**
* @brief Uninitialize the hyper trace module
2026-06-04 00:55:05 +02:00
*
* @return VOID
*/
VOID
LoaderUninitHyperTrace()
2026-06-04 00:55:05 +02:00
{
//
// Mark hypertrace as uninitialized before uninitializing it to avoid any potential reentrancy issues during the uninitialization process
2026-06-04 00:55:05 +02:00
//
g_HyperTraceInitialized = FALSE;
2026-06-04 00:55:05 +02:00
//
// Uninitialize the hypertrace
2026-06-04 00:55:05 +02:00
//
HyperTraceUninit();
2026-06-04 00:55:05 +02:00
}
2026-06-06 17:18:14 +02:00
/**
* @brief Uninitialize the VMM
2026-06-06 17:18:14 +02:00
*
* @return VOID
*/
VOID
LoaderUninitVmm()
2026-06-06 17:18:14 +02:00
{
//
// Mark VMM as uninitialized before uninitializing it to avoid any potential reentrancy issues during the uninitialization process
2026-06-06 17:18:14 +02:00
//
g_VmmInitialized = FALSE;
2026-06-06 17:18:14 +02:00
//
// Uninitialize the HyperTrace (if it was initialized)
2026-06-06 17:18:14 +02:00
//
// If the trace module is currently loaded, it must be unloaded before the VMM module can be unloaded
// HyperTrace can operate both with and without the VMM module. When loaded after the VMM module, HyperTrace can make
// use of hypervisor-specific features. Otherwise, it will operate normally, but those features will not be available
// The trace module will be unloaded automatically and may be reloaded later if needed
//
// Note: The user mode should automatically request to unload the 'trace' module if it is already loaded
// however, here we also unload it just in case if this function is directly called or the user mode
// code did not unload it
//
LoaderUninitHyperTrace();
//
// First remove all VMM related state from the debugger
//
DebuggerUninitializeVmmOperations();
//
// Terminate VMM and its sub-mechanisms
//
VmFuncUninitVmm();
2026-06-06 17:18:14 +02:00
}
2026-06-04 00:55:05 +02:00
/**
* @brief Uninitialize the debugger
*
* @return VOID
*/
VOID
LoaderUninitKd()
{
//
// Mark KD as uninitialized before uninitializing it to avoid any potential reentrancy issues during the uninitialization process
//
g_KdInitialized = FALSE;
//
// Uninitialize the debugger and its sub-mechanisms
//
DebuggerUninitialize();
}
/**
* @brief Uninitialize the VMM and the debugger
*
* @return VOID
*/
VOID
LoaderUninitVmmAndDebugger()
{
//
// Uninitialize the VMM first because it relies on the debugger for some
//
LoaderUninitVmm();
//
// Uninitialize the debugger
//
LoaderUninitKd();
}
2023-01-15 06:58:56 +09:00
/**
* @brief Uninitialize the log tracer
2023-01-15 06:58:56 +09:00
*
* @return VOID
*/
VOID
2026-06-04 00:55:05 +02:00
LoaderUninitLogTracer()
2023-01-15 06:58:56 +09:00
{
#if !UseDbgPrintInsteadOfUsermodeMessageTracking
2026-05-27 20:21:21 +02:00
LogDebugInfo("Unloading hyperlog...\n");
2023-01-15 06:58:56 +09:00
//
2026-05-27 20:21:21 +02:00
// Uinitialize log buffer if it was initialized
2023-01-15 06:58:56 +09:00
//
2026-05-27 20:21:21 +02:00
if (g_HyperLogInitialized)
{
g_HyperLogInitialized = FALSE;
LogUnInitialize();
}
2023-01-15 06:58:56 +09:00
#endif
}