mirror of
https://github.com/HyperDbg/HyperDbg.git
synced 2026-07-10 01:29:59 +00:00
429 lines
9.4 KiB
C
429 lines
9.4 KiB
C
/**
|
|
* @file Tracing.c
|
|
* @author Hari Mishal (harimishal6@gmail.com)
|
|
* @brief Tracing routines for HyperTrace module
|
|
* @details
|
|
* @version 0.18
|
|
* @date 2025-12-02
|
|
*
|
|
* @copyright This project is released under the GNU Public License v3.
|
|
*/
|
|
#include "pch.h"
|
|
|
|
/**
|
|
* @brief Example of performing LBR trace
|
|
*
|
|
* @param ApplyFromVmxRootMode
|
|
* @param ApplyByVmcall
|
|
*
|
|
* @return BOOLEAN
|
|
*/
|
|
VOID
|
|
HyperTraceExamplePerformLbrTrace(BOOLEAN ApplyFromVmxRootMode, BOOLEAN ApplyByVmcall)
|
|
{
|
|
LBR_IOCTL_REQUEST Request = {0};
|
|
|
|
KAFFINITY Affinity = 1;
|
|
KeSetSystemAffinityThread(Affinity);
|
|
|
|
LbrInitialize();
|
|
|
|
if (!LbrCheck())
|
|
{
|
|
return;
|
|
}
|
|
|
|
Request.LbrConfig.Pid = 0;
|
|
Request.LbrConfig.LbrSelect = LBR_SELECT;
|
|
|
|
if (LbrStartLbr(&Request, ApplyFromVmxRootMode, ApplyByVmcall))
|
|
{
|
|
for (volatile int i = 0; i < 50; i++)
|
|
{
|
|
if (i % 2)
|
|
{
|
|
int a = i * 2;
|
|
a += 5;
|
|
}
|
|
else
|
|
{
|
|
__nop();
|
|
__nop();
|
|
}
|
|
}
|
|
|
|
LBR_STATE * State = LbrFindLbrState(0);
|
|
|
|
if (State)
|
|
{
|
|
LbrGetLbr(State, ApplyFromVmxRootMode, ApplyByVmcall);
|
|
}
|
|
|
|
LogInfo("Dumping LBR Buffer...\n");
|
|
|
|
LbrDumpLbr(&Request, ApplyFromVmxRootMode, ApplyByVmcall);
|
|
LbrStopLbr(&Request, ApplyFromVmxRootMode, ApplyByVmcall);
|
|
}
|
|
|
|
KeRevertToUserAffinityThread();
|
|
}
|
|
|
|
/**
|
|
* @brief Start LBR tracing for HyperTrace
|
|
* @param ApplyFromVmxRootMode
|
|
* @param ApplyByVmcall
|
|
*
|
|
* @return BOOLEAN
|
|
*/
|
|
BOOLEAN
|
|
HyperTraceStartLbr(BOOLEAN ApplyFromVmxRootMode, BOOLEAN ApplyByVmcall)
|
|
{
|
|
LBR_IOCTL_REQUEST Request = {0};
|
|
|
|
Request.LbrConfig.Pid = 0;
|
|
Request.LbrConfig.LbrSelect = LBR_SELECT;
|
|
|
|
return LbrStartLbr(&Request, ApplyFromVmxRootMode, ApplyByVmcall);
|
|
}
|
|
|
|
/**
|
|
* @brief Stop LBR tracing for HyperTrace
|
|
* @param ApplyFromVmxRootMode
|
|
* @param ApplyByVmcall
|
|
*
|
|
* @return BOOLEAN
|
|
*/
|
|
BOOLEAN
|
|
HyperTraceStopLbr(BOOLEAN ApplyFromVmxRootMode, BOOLEAN ApplyByVmcall)
|
|
{
|
|
LBR_IOCTL_REQUEST Request = {0};
|
|
|
|
Request.LbrConfig.Pid = 0;
|
|
Request.LbrConfig.LbrSelect = LBR_SELECT;
|
|
|
|
LBR_STATE * State = LbrFindLbrState(0);
|
|
|
|
if (State)
|
|
{
|
|
LbrGetLbr(State, ApplyFromVmxRootMode, ApplyByVmcall);
|
|
}
|
|
|
|
LogInfo("Dumping LBR Buffer...\n");
|
|
LbrDumpLbr(&Request, ApplyFromVmxRootMode, ApplyByVmcall);
|
|
|
|
return LbrStopLbr(&Request, ApplyFromVmxRootMode, ApplyByVmcall);
|
|
}
|
|
|
|
/**
|
|
* @brief Initialize the hyper trace module callbacks
|
|
* @details This only for callback initialization, not for LBR initialization
|
|
*
|
|
* @param HypertraceCallbacks
|
|
*
|
|
* @return BOOLEAN
|
|
*/
|
|
BOOLEAN
|
|
HyperTraceInitCallback(HYPERTRACE_CALLBACKS * HypertraceCallbacks)
|
|
{
|
|
ULONG ProcessorsCount;
|
|
|
|
//
|
|
// Check if the LBR is supported on this CPU before initializing the hypertrace module,
|
|
//
|
|
if (!LbrCheck())
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Check if any of the required callbacks are NULL
|
|
//
|
|
for (UINT32 i = 0; i < sizeof(HYPERTRACE_CALLBACKS) / sizeof(UINT64); i++)
|
|
{
|
|
if (((PVOID *)HypertraceCallbacks)[i] == NULL)
|
|
{
|
|
//
|
|
// The callback has null entry, so we cannot proceed
|
|
//
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Save the callbacks
|
|
//
|
|
RtlCopyMemory(&g_Callbacks, HypertraceCallbacks, sizeof(HYPERTRACE_CALLBACKS));
|
|
|
|
//
|
|
// Read number of cores
|
|
//
|
|
ProcessorsCount = KeQueryActiveProcessorCount(0);
|
|
|
|
//
|
|
// Initialize the memory for LBR requests on all cores
|
|
//
|
|
g_LbrRequestState = PlatformAllocateMemory(sizeof(LBR_IOCTL_REQUEST) * ProcessorsCount);
|
|
|
|
//
|
|
// It is initialized, but LBR is disabled at this stage
|
|
//
|
|
g_LastBranchRecordEnabled = FALSE;
|
|
|
|
//
|
|
// Enable callbacks and set the initialized flag
|
|
//
|
|
g_HyperTraceCallbacksInitialized = TRUE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* @brief Enable LBR tracing for HyperTrace
|
|
*
|
|
* @param HyperTraceOperationRequest
|
|
* @param ApplyFromVmxRootMode
|
|
*
|
|
* @return BOOLEAN
|
|
*/
|
|
BOOLEAN
|
|
HyperTraceEnableLbrTracing(HYPERTRACE_OPERATION_PACKETS * HyperTraceOperationRequest,
|
|
BOOLEAN ApplyFromVmxRootMode)
|
|
{
|
|
UNREFERENCED_PARAMETER(ApplyFromVmxRootMode);
|
|
|
|
ULONG ProcessorsCount;
|
|
|
|
//
|
|
// Check if LBR is already enabled or not
|
|
//
|
|
if (g_LastBranchRecordEnabled)
|
|
{
|
|
HyperTraceOperationRequest->KernelStatus = DEBUGGER_ERROR_LBR_ALREADY_ENABLED;
|
|
return FALSE;
|
|
}
|
|
|
|
if (!LbrCheck())
|
|
{
|
|
HyperTraceOperationRequest->KernelStatus = DEBUGGER_ERROR_LBR_NOT_SUPPORTED;
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Enabling LBR
|
|
//
|
|
LbrInitialize();
|
|
|
|
//
|
|
// Read number of cores
|
|
//
|
|
ProcessorsCount = KeQueryActiveProcessorCount(0);
|
|
|
|
for (size_t i = 0; i < ProcessorsCount; i++)
|
|
{
|
|
g_LbrRequestState[i].LbrConfig.Pid = 0;
|
|
g_LbrRequestState[i].LbrConfig.LbrSelect = LBR_SELECT;
|
|
}
|
|
|
|
//
|
|
// Broadcast enabling LBR on all cores
|
|
//
|
|
BroadcastEnableLbrOnAllCores();
|
|
|
|
//
|
|
// Set the flag to indicate that LBR tracing is enabled
|
|
//
|
|
g_LastBranchRecordEnabled = TRUE;
|
|
|
|
//
|
|
// Set successful status
|
|
//
|
|
HyperTraceOperationRequest->KernelStatus = DEBUGGER_OPERATION_WAS_SUCCESSFUL;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* @brief Disable LBR tracing for HyperTrace
|
|
*
|
|
* @param HyperTraceOperationRequest
|
|
* @param ApplyFromVmxRootMode
|
|
*
|
|
* @return BOOLEAN
|
|
*/
|
|
BOOLEAN
|
|
HyperTraceDisableLbrTracing(HYPERTRACE_OPERATION_PACKETS * HyperTraceOperationRequest,
|
|
BOOLEAN ApplyFromVmxRootMode)
|
|
{
|
|
UNREFERENCED_PARAMETER(ApplyFromVmxRootMode);
|
|
|
|
//
|
|
// Check if LBR is already disabled or not
|
|
//
|
|
if (!g_LastBranchRecordEnabled)
|
|
{
|
|
if (HyperTraceOperationRequest != NULL)
|
|
{
|
|
HyperTraceOperationRequest->KernelStatus = DEBUGGER_ERROR_LBR_ALREADY_DISABLED;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Broadcast disabling LBR on all cores
|
|
//
|
|
BroadcastDisableLbrOnAllCores();
|
|
|
|
//
|
|
// Disabling LBR
|
|
//
|
|
g_LastBranchRecordEnabled = FALSE;
|
|
|
|
//
|
|
// Set successful status
|
|
//
|
|
if (HyperTraceOperationRequest != NULL)
|
|
{
|
|
HyperTraceOperationRequest->KernelStatus = DEBUGGER_OPERATION_WAS_SUCCESSFUL;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* @brief Show LBR tracing for HyperTrace
|
|
*
|
|
* @param HyperTraceOperationRequest
|
|
* @param ApplyFromVmxRootMode
|
|
*
|
|
* @return BOOLEAN
|
|
*/
|
|
BOOLEAN
|
|
HyperTraceShowLbrTracing(HYPERTRACE_OPERATION_PACKETS * HyperTraceOperationRequest,
|
|
BOOLEAN ApplyFromVmxRootMode)
|
|
{
|
|
UNREFERENCED_PARAMETER(ApplyFromVmxRootMode);
|
|
|
|
LBR_IOCTL_REQUEST * CurrentRequest;
|
|
|
|
//
|
|
// Check if LBR is already disabled or not
|
|
//
|
|
if (!g_LastBranchRecordEnabled)
|
|
{
|
|
if (HyperTraceOperationRequest != NULL)
|
|
{
|
|
HyperTraceOperationRequest->KernelStatus = DEBUGGER_ERROR_LBR_ALREADY_DISABLED;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Get the current request (for current core)
|
|
//
|
|
CurrentRequest = &g_LbrRequestState[KeGetCurrentProcessorNumberEx(NULL)];
|
|
|
|
LBR_STATE * State = LbrFindLbrState(0);
|
|
|
|
if (State)
|
|
{
|
|
LbrGetLbr(State, TRUE, TRUE);
|
|
}
|
|
|
|
LogInfo("Dumping LBR Buffer...\n");
|
|
|
|
LbrDumpLbr(CurrentRequest, TRUE, TRUE);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* @brief Uninitialize the hyper trace module
|
|
*
|
|
* @return VOID
|
|
*/
|
|
VOID
|
|
HyperTraceUninit()
|
|
{
|
|
//
|
|
// Disable LBR tracing if it is still enabled
|
|
//
|
|
HyperTraceDisableLbrTracing(NULL, FALSE);
|
|
|
|
//
|
|
// Set callbacks to not initialized
|
|
//
|
|
g_HyperTraceCallbacksInitialized = FALSE;
|
|
|
|
//
|
|
// UnAllocate the state buffer
|
|
//
|
|
PlatformFreeMemory(g_LbrRequestState);
|
|
|
|
//
|
|
// Set LBR request buffer to zero
|
|
//
|
|
g_LbrRequestState = NULL64_ZERO;
|
|
}
|
|
|
|
/**
|
|
* @brief Perform actions related to HyperTrace
|
|
*
|
|
* @param HyperTraceOperationRequest
|
|
* @param ApplyFromVmxRootMode
|
|
*
|
|
* @return BOOLEAN
|
|
*/
|
|
BOOLEAN
|
|
HyperTracePerformOperation(HYPERTRACE_OPERATION_PACKETS * HyperTraceOperationRequest,
|
|
BOOLEAN ApplyFromVmxRootMode)
|
|
{
|
|
BOOLEAN Status = TRUE;
|
|
|
|
//
|
|
// Check if the hypertrace module is initialized before performing any operation
|
|
//
|
|
if (!g_HyperTraceCallbacksInitialized)
|
|
{
|
|
HyperTraceOperationRequest->KernelStatus = DEBUGGER_ERROR_HYPERTRACE_NOT_INITIALIZED;
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Perform the requested operation
|
|
//
|
|
switch (HyperTraceOperationRequest->HyperTraceOperationType)
|
|
{
|
|
case HYPERTRACE_LBR_OPERATION_REQUEST_TYPE_ENABLE:
|
|
|
|
LogInfo("HyperTrace: Enabling LBR tracing...\n");
|
|
|
|
HyperTraceEnableLbrTracing(HyperTraceOperationRequest, ApplyFromVmxRootMode);
|
|
|
|
break;
|
|
|
|
case HYPERTRACE_LBR_OPERATION_REQUEST_TYPE_DISABLE:
|
|
|
|
LogInfo("HyperTrace: Disabling LBR tracing...\n");
|
|
|
|
HyperTraceDisableLbrTracing(HyperTraceOperationRequest, ApplyFromVmxRootMode);
|
|
|
|
break;
|
|
|
|
case HYPERTRACE_LBR_OPERATION_REQUEST_TYPE_SHOW:
|
|
|
|
LogInfo("HyperTrace: Showing LBR tracing...\n");
|
|
|
|
HyperTraceShowLbrTracing(HyperTraceOperationRequest, ApplyFromVmxRootMode);
|
|
|
|
break;
|
|
|
|
default:
|
|
Status = FALSE;
|
|
HyperTraceOperationRequest->KernelStatus = DEBUGGER_ERROR_INVALID_HYPERTRACE_OPERATION_TYPE;
|
|
break;
|
|
}
|
|
|
|
return Status;
|
|
}
|