/** * @file ApplyEvents.c * @author Sina Karvandi (sina@hyperdbg.org) * @brief Implementation of debugger functions for applying events * @details * * @version 0.7 * @date 2023-10-15 * * @copyright This project is released under the GNU Public License v3. * */ #include "pch.h" /** * @brief Applying 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 ApplyEventMonitorEvent(PDEBUGGER_EVENT Event, PDEBUGGER_EVENT_AND_ACTION_RESULT ResultsToReturn, BOOLEAN InputFromVmxRoot) { UINT32 TempProcessId; BOOLEAN ResultOfApplyingEvent = FALSE; UINT64 RemainingSize; UINT64 PagesBytes; UINT64 ConstEndAddress; UINT64 TempStartAddress; UINT64 TempEndAddress; UINT64 TempNextPageAddr; EPT_HOOKS_ADDRESS_DETAILS_FOR_MEMORY_MONITOR HookingAddresses = {0}; if (InputFromVmxRoot) { TempProcessId = NULL_ZERO; // Process Id does not make sense in the Debugger Mode } else { // // Check if process id is equal to DEBUGGER_EVENT_APPLY_TO_ALL_PROCESSES // or if process id is 0 then we use the cr3 of current process // if (Event->ProcessId == DEBUGGER_EVENT_APPLY_TO_ALL_PROCESSES || Event->ProcessId == 0) { TempProcessId = HANDLE_TO_UINT32(PsGetCurrentProcessId()); } else { TempProcessId = Event->ProcessId; } } // // In all the cases we should set both read/write, even if it's only // read we should set the write too! // Also execute bit has the same conditions here, because if write is set // read should be also set // switch (Event->EventType) { case HIDDEN_HOOK_READ_AND_WRITE_AND_EXECUTE: case HIDDEN_HOOK_READ_AND_EXECUTE: HookingAddresses.SetHookForRead = TRUE; HookingAddresses.SetHookForWrite = TRUE; HookingAddresses.SetHookForExec = TRUE; break; case HIDDEN_HOOK_WRITE_AND_EXECUTE: HookingAddresses.SetHookForRead = FALSE; HookingAddresses.SetHookForWrite = TRUE; HookingAddresses.SetHookForExec = FALSE; break; case HIDDEN_HOOK_READ_AND_WRITE: case HIDDEN_HOOK_READ: HookingAddresses.SetHookForRead = TRUE; HookingAddresses.SetHookForWrite = TRUE; HookingAddresses.SetHookForExec = FALSE; break; case HIDDEN_HOOK_WRITE: HookingAddresses.SetHookForRead = FALSE; HookingAddresses.SetHookForWrite = TRUE; HookingAddresses.SetHookForExec = FALSE; break; case HIDDEN_HOOK_EXECUTE: HookingAddresses.SetHookForRead = FALSE; HookingAddresses.SetHookForWrite = FALSE; HookingAddresses.SetHookForExec = TRUE; break; default: LogError("Err, Invalid monitor hook type"); ResultsToReturn->IsSuccessful = FALSE; ResultsToReturn->Error = DEBUGGER_ERROR_EVENT_TYPE_IS_INVALID; goto EventNotApplied; break; } // // Set the tag // HookingAddresses.Tag = Event->Tag; TempStartAddress = Event->InitOptions.OptionalParam1; TempEndAddress = Event->InitOptions.OptionalParam2; ConstEndAddress = TempEndAddress; PagesBytes = (UINT64)PAGE_ALIGN(TempStartAddress); PagesBytes = TempEndAddress - PagesBytes; PagesBytes = PagesBytes / PAGE_SIZE; RemainingSize = TempEndAddress - TempStartAddress; // LogInfo("Start address: %llx, end address: %llx", TempStartAddress, TempEndAddress, RemainingSize); for (SIZE_T i = 0; i <= PagesBytes; i++) { if (RemainingSize >= PAGE_SIZE) { TempEndAddress = (TempStartAddress + ((UINT64)PAGE_ALIGN(TempStartAddress + PAGE_SIZE) - TempStartAddress)) - 1; RemainingSize = ConstEndAddress - TempEndAddress - 1; } else { TempNextPageAddr = (UINT64)PAGE_ALIGN(TempStartAddress + RemainingSize); // // Check if by adding the remaining size, we'll go to the next // page boundary or not // if (TempNextPageAddr > ((UINT64)PAGE_ALIGN(TempStartAddress))) { // // It goes to the next page boundary // TempEndAddress = TempNextPageAddr - 1; RemainingSize = RemainingSize - (TempEndAddress - TempStartAddress) - 1; } else { TempEndAddress = TempStartAddress + RemainingSize; RemainingSize = 0; } } // LogInfo("Start address: %llx, end address: %llx, remaining size: %llx", // TempStartAddress, // TempEndAddress, // RemainingSize); // // Setup hooking addresses // HookingAddresses.StartAddress = TempStartAddress; HookingAddresses.EndAddress = TempEndAddress; if ((DEBUGGER_HOOK_MEMORY_TYPE)Event->InitOptions.OptionalParam3 == DEBUGGER_MEMORY_HOOK_PHYSICAL_ADDRESS) { HookingAddresses.MemoryType = DEBUGGER_MEMORY_HOOK_PHYSICAL_ADDRESS; } else { HookingAddresses.MemoryType = DEBUGGER_MEMORY_HOOK_VIRTUAL_ADDRESS; } // // Apply the hook // ResultOfApplyingEvent = DebuggerEventEnableMonitorReadWriteExec(&HookingAddresses, TempProcessId, InputFromVmxRoot); if (!ResultOfApplyingEvent) { // // The event is not applied, won't apply other EPT modifications // as we want to remove this event // // // Now we should restore the previously applied events (if any) // if (InputFromVmxRoot) { // // EPT hooking tag is same as event tag, so we can use it to unhook // TerminateEptHookUnHookAllHooksByHookingTagFromVmxRootAndApplyInvalidation(Event->Tag); } else { // // EPT hooking tag is same as event tag, so we can use it to unhook // ConfigureEptHookUnHookAllByHookingTag(Event->Tag); } // // Break from the loop // break; } else { // // We applied the hook and the pre-allocated buffers are used // for this hook, as here is a safe PASSIVE_LEVEL we can force // the Windows to reallocate some pools for us, thus, if this // hook is continued to other pages, we still have pre-allocated // buffers ready for our future hooks // if (!InputFromVmxRoot) { PoolManagerCheckAndPerformAllocationAndDeallocation(); } } // // Swap the temporary start address and temporary end address // TempStartAddress = TempEndAddress + 1; } // // If applied directly from VMX root-mode, // As the call to hook adjuster was successful, we have to // invalidate the TLB of EPT caches for all cores here // if (InputFromVmxRoot) { HaltedBroadcastInvalidateSingleContextAllCores(); } // // Check if address is virtual or physical // if ((DEBUGGER_HOOK_MEMORY_TYPE)Event->Options.OptionalParam3 == DEBUGGER_MEMORY_HOOK_PHYSICAL_ADDRESS) { // // It's a physical address so we just save the addresses without conversion // Event->Options.OptionalParam1 = Event->InitOptions.OptionalParam1; Event->Options.OptionalParam2 = Event->InitOptions.OptionalParam2; } else { // // It's a virtual address, we convert the Event's optional parameters physical address // because vm-exit occurs and we have the physical address to compare in the case of // hidden hook rw events // if (InputFromVmxRoot) { Event->Options.OptionalParam1 = VirtualAddressToPhysicalAddressOnTargetProcess((PVOID)Event->InitOptions.OptionalParam1); Event->Options.OptionalParam2 = VirtualAddressToPhysicalAddressOnTargetProcess((PVOID)Event->InitOptions.OptionalParam2); } else { Event->Options.OptionalParam1 = VirtualAddressToPhysicalAddressByProcessId((PVOID)Event->InitOptions.OptionalParam1, TempProcessId); Event->Options.OptionalParam2 = VirtualAddressToPhysicalAddressByProcessId((PVOID)Event->InitOptions.OptionalParam2, TempProcessId); } } // // The initial options are also recorded // Event->Options.OptionalParam3 = Event->InitOptions.OptionalParam1; Event->Options.OptionalParam4 = Event->InitOptions.OptionalParam2; Event->Options.OptionalParam5 = Event->InitOptions.OptionalParam3; // This parameter shows whether the address is physical or virtual // // Check if we should restore the event if it was not successful // if (!ResultOfApplyingEvent) { ResultsToReturn->IsSuccessful = FALSE; ResultsToReturn->Error = DebuggerGetLastError(); goto EventNotApplied; } // // Applying event was successful // return TRUE; EventNotApplied: return FALSE; } /** * @brief Applying EPT hook execution (hidden breakpoints) 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 ApplyEventEptHookExecCcEvent(PDEBUGGER_EVENT Event, PDEBUGGER_EVENT_AND_ACTION_RESULT ResultsToReturn, BOOLEAN InputFromVmxRoot) { UINT32 TempProcessId; if (InputFromVmxRoot) { // // *** apply the hook directly from VMX root-mode *** // // // First, breakpoints have to be intercepted as the caller to the // direct hook function have to broadcast it by its own // HaltedBroadcastSetExceptionBitmapAllCores(EXCEPTION_VECTOR_BREAKPOINT); // // Invoke the hooker // if (!ConfigureEptHookFromVmxRoot((PVOID)Event->InitOptions.OptionalParam1)) { // // There was an error applying this event, so we're setting // the event // ResultsToReturn->IsSuccessful = FALSE; ResultsToReturn->Error = DebuggerGetLastError(); goto EventNotApplied; } else { // // As the call to hook adjuster was successful, we have to // invalidate the TLB of EPT caches for all cores here // HaltedBroadcastInvalidateSingleContextAllCores(); } } else { // // *** apply the hook from VMX non root-mode *** // // // Check if process id is equal to DEBUGGER_EVENT_APPLY_TO_ALL_PROCESSES // or if process id is 0 then we use the cr3 of current process // if (Event->ProcessId == DEBUGGER_EVENT_APPLY_TO_ALL_PROCESSES || Event->ProcessId == 0) { TempProcessId = HANDLE_TO_UINT32(PsGetCurrentProcessId()); } else { TempProcessId = Event->ProcessId; } // // Invoke the hooker // if (!ConfigureEptHook((PVOID)Event->InitOptions.OptionalParam1, TempProcessId)) { // // There was an error applying this event, so we're setting // the event // ResultsToReturn->IsSuccessful = FALSE; ResultsToReturn->Error = DebuggerGetLastError(); goto EventNotApplied; } } // // We set events OptionalParam1 here to make sure that our event is // executed not for all hooks but for this special hook // Event->Options.OptionalParam1 = Event->InitOptions.OptionalParam1; // // Applying event was successful // return TRUE; EventNotApplied: return FALSE; } /** * @brief Applying EPT hook trampoline (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 ApplyEventEpthookInlineEvent(PDEBUGGER_EVENT Event, PDEBUGGER_EVENT_AND_ACTION_RESULT ResultsToReturn, BOOLEAN InputFromVmxRoot) { UINT32 TempProcessId; if (InputFromVmxRoot) { // // *** apply the hook directly from VMX root-mode *** // // // We set events OptionalParam1 here to make sure that our event is // executed not for all hooks but for this special hook // Also, we are sure that this is not null because we checked it before // Event->Options.OptionalParam1 = VirtualAddressToPhysicalAddressOnTargetProcess((PVOID)Event->InitOptions.OptionalParam1); // // Invoke the hooker // if (!ConfigureEptHook2FromVmxRoot(KeGetCurrentProcessorNumberEx(NULL), (PVOID)Event->InitOptions.OptionalParam1, NULL)) { // // There was an error applying this event, so we're setting // the event // ResultsToReturn->IsSuccessful = FALSE; ResultsToReturn->Error = DebuggerGetLastError(); goto EventNotApplied; } else { // // As the call to hook adjuster was successful, we have to // invalidate the TLB of EPT caches for all cores here // HaltedBroadcastInvalidateSingleContextAllCores(); } } else { // // *** apply the hook from VMX non root-mode *** // // // Check if process id is equal to DEBUGGER_EVENT_APPLY_TO_ALL_PROCESSES // or if process id is 0 then we use the cr3 of current process // if (Event->ProcessId == DEBUGGER_EVENT_APPLY_TO_ALL_PROCESSES || Event->ProcessId == 0) { TempProcessId = HANDLE_TO_UINT32(PsGetCurrentProcessId()); } else { TempProcessId = Event->ProcessId; } // // We set events OptionalParam1 here to make sure that our event is // executed not for all hooks but for this special hook // Also, we are sure that this is not null because we checked it before // Event->Options.OptionalParam1 = VirtualAddressToPhysicalAddressByProcessId((PVOID)Event->InitOptions.OptionalParam1, TempProcessId); // // Invoke the hooker // if (!ConfigureEptHook2(KeGetCurrentProcessorNumberEx(NULL), (PVOID)Event->InitOptions.OptionalParam1, NULL, TempProcessId)) { // // There was an error applying this event, so we're setting // the event // ResultsToReturn->IsSuccessful = FALSE; ResultsToReturn->Error = DebuggerGetLastError(); goto EventNotApplied; } } // // Applying event was successful // return TRUE; EventNotApplied: return FALSE; } /** * @brief Applying RDMSR execution 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 VOID */ VOID ApplyEventRdmsrExecutionEvent(PDEBUGGER_EVENT Event, PDEBUGGER_EVENT_AND_ACTION_RESULT ResultsToReturn, BOOLEAN InputFromVmxRoot) { UNREFERENCED_PARAMETER(ResultsToReturn); // // Let's see if it is for all cores or just one core // if (Event->CoreId == DEBUGGER_EVENT_APPLY_TO_ALL_CORES) { // // All cores // if (InputFromVmxRoot) { HaltedBroadcastChangeAllMsrBitmapReadAllCores(Event->InitOptions.OptionalParam1); } else { ExtensionCommandChangeAllMsrBitmapReadAllCores(Event->InitOptions.OptionalParam1); } } else { // // Just one core // if (InputFromVmxRoot) { HaltedRoutineChangeAllMsrBitmapReadOnSingleCore(Event->CoreId, Event->InitOptions.OptionalParam1); } else { ConfigureChangeMsrBitmapReadOnSingleCore(Event->CoreId, Event->InitOptions.OptionalParam1); } } // // Setting an indicator to MSR // Event->Options.OptionalParam1 = Event->InitOptions.OptionalParam1; } /** * @brief Applying WRMSR execution 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 VOID */ VOID ApplyEventWrmsrExecutionEvent(PDEBUGGER_EVENT Event, PDEBUGGER_EVENT_AND_ACTION_RESULT ResultsToReturn, BOOLEAN InputFromVmxRoot) { UNREFERENCED_PARAMETER(ResultsToReturn); // // Let's see if it is for all cores or just one core // if (Event->CoreId == DEBUGGER_EVENT_APPLY_TO_ALL_CORES) { // // All cores // if (InputFromVmxRoot) { HaltedBroadcastChangeAllMsrBitmapWriteAllCores(Event->InitOptions.OptionalParam1); } else { ExtensionCommandChangeAllMsrBitmapWriteAllCores(Event->InitOptions.OptionalParam1); } } else { // // Just one core // if (InputFromVmxRoot) { HaltedRoutineChangeAllMsrBitmapWriteOnSingleCore(Event->CoreId, Event->InitOptions.OptionalParam1); } else { ConfigureChangeMsrBitmapWriteOnSingleCore(Event->CoreId, Event->InitOptions.OptionalParam1); } } // // Setting an indicator to MSR // Event->Options.OptionalParam1 = Event->InitOptions.OptionalParam1; } /** * @brief Applying IN/OUT instructions execution 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 VOID */ VOID ApplyEventInOutExecutionEvent(PDEBUGGER_EVENT Event, PDEBUGGER_EVENT_AND_ACTION_RESULT ResultsToReturn, BOOLEAN InputFromVmxRoot) { UNREFERENCED_PARAMETER(ResultsToReturn); // // Let's see if it is for all cores or just one core // if (Event->CoreId == DEBUGGER_EVENT_APPLY_TO_ALL_CORES) { // // All cores // if (InputFromVmxRoot) { HaltedBroadcastChangeAllIoBitmapAllCores(Event->InitOptions.OptionalParam1); } else { ExtensionCommandIoBitmapChangeAllCores(Event->InitOptions.OptionalParam1); } } else { // // Just one core // if (InputFromVmxRoot) { HaltedRoutineChangeIoBitmapOnSingleCore(Event->CoreId, Event->InitOptions.OptionalParam1); } else { ConfigureChangeIoBitmapOnSingleCore(Event->CoreId, Event->InitOptions.OptionalParam1); } } // // Setting an indicator to MSR // Event->Options.OptionalParam1 = Event->InitOptions.OptionalParam1; } /** * @brief Applying RDTSC/RDTSCP instructions execution 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 VOID */ VOID ApplyEventTscExecutionEvent(PDEBUGGER_EVENT Event, PDEBUGGER_EVENT_AND_ACTION_RESULT ResultsToReturn, BOOLEAN InputFromVmxRoot) { UNREFERENCED_PARAMETER(ResultsToReturn); // // Let's see if it is for all cores or just one core // if (Event->CoreId == DEBUGGER_EVENT_APPLY_TO_ALL_CORES) { // // All cores // if (InputFromVmxRoot) { HaltedBroadcastEnableRdtscExitingAllCores(); } else { ExtensionCommandEnableRdtscExitingAllCores(); } } else { // // Just one core // if (InputFromVmxRoot) { HaltedRoutineEnableRdtscExitingOnSingleCore(Event->CoreId); } else { ConfigureEnableRdtscExitingOnSingleCore(Event->CoreId); } } } /** * @brief Applying RDPMC instruction execution 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 VOID */ VOID ApplyEventRdpmcExecutionEvent(PDEBUGGER_EVENT Event, PDEBUGGER_EVENT_AND_ACTION_RESULT ResultsToReturn, BOOLEAN InputFromVmxRoot) { UNREFERENCED_PARAMETER(ResultsToReturn); // // Let's see if it is for all cores or just one core // if (Event->CoreId == DEBUGGER_EVENT_APPLY_TO_ALL_CORES) { // // All cores // if (InputFromVmxRoot) { HaltedBroadcastEnableRdpmcExitingAllCores(); } else { ExtensionCommandEnableRdpmcExitingAllCores(); } } else { // // Just one core // if (InputFromVmxRoot) { HaltedRoutineEnableRdpmcExitingOnSingleCore(Event->CoreId); } else { ConfigureEnableRdpmcExitingOnSingleCore(Event->CoreId); } } } /** * @brief Applying mov 2 debug registers 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 VOID */ VOID ApplyEventMov2DebugRegExecutionEvent(PDEBUGGER_EVENT Event, PDEBUGGER_EVENT_AND_ACTION_RESULT ResultsToReturn, BOOLEAN InputFromVmxRoot) { UNREFERENCED_PARAMETER(InputFromVmxRoot); // // Let's see if it is for all cores or just one core // if (Event->CoreId == DEBUGGER_EVENT_APPLY_TO_ALL_CORES) { // // All cores // if (ResultsToReturn) { HaltedBroadcastEnableMov2DebugRegsExitingAllCores(); } else { ExtensionCommandEnableMovDebugRegistersExitingAllCores(); } } else { // // Just one core // if (ResultsToReturn) { HaltedRoutineEnableMov2DebugRegsExitingOnSingleCore(Event->CoreId); } else { ConfigureEnableMovToDebugRegistersExitingOnSingleCore(Event->CoreId); } } } /** * @brief Applying control registers accessed 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 VOID */ VOID ApplyEventControlRegisterAccessedEvent(PDEBUGGER_EVENT Event, PDEBUGGER_EVENT_AND_ACTION_RESULT ResultsToReturn, BOOLEAN InputFromVmxRoot) { UNREFERENCED_PARAMETER(ResultsToReturn); // // Setting an indicator to CR // Event->Options.OptionalParam1 = Event->InitOptions.OptionalParam1; Event->Options.OptionalParam2 = Event->InitOptions.OptionalParam2; // // Let's see if it is for all cores or just one core // if (Event->CoreId == DEBUGGER_EVENT_APPLY_TO_ALL_CORES) { // // All cores // if (InputFromVmxRoot) { HaltedBroadcastEnableMovToCrExitingAllCores(&Event->Options); } else { ExtensionCommandEnableMovControlRegisterExitingAllCores(Event); } } else { // // Just one core // if (InputFromVmxRoot) { HaltedRoutineEnableMovToCrExitingOnSingleCore(Event->CoreId, &Event->Options); } else { ConfigureEnableMovToControlRegisterExitingOnSingleCore(Event->CoreId, &Event->Options); } } } /** * @brief Applying 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 VOID */ VOID ApplyEventExceptionEvent(PDEBUGGER_EVENT Event, PDEBUGGER_EVENT_AND_ACTION_RESULT ResultsToReturn, BOOLEAN InputFromVmxRoot) { UNREFERENCED_PARAMETER(ResultsToReturn); // // Let's see if it is for all cores or just one core // if (Event->CoreId == DEBUGGER_EVENT_APPLY_TO_ALL_CORES) { // // All cores // if (InputFromVmxRoot) { HaltedBroadcastSetExceptionBitmapAllCores(Event->InitOptions.OptionalParam1); } else { ExtensionCommandSetExceptionBitmapAllCores(Event->InitOptions.OptionalParam1); } } else { // // Just one core // if (InputFromVmxRoot) { HaltedRoutineSetExceptionBitmapOnSingleCore(Event->CoreId, Event->InitOptions.OptionalParam1); } else { ConfigureSetExceptionBitmapOnSingleCore(Event->CoreId, (UINT32)Event->InitOptions.OptionalParam1); } } // // Set the event's target exception // Event->Options.OptionalParam1 = Event->InitOptions.OptionalParam1; } /** * @brief Applying interrupt interception 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 VOID */ VOID ApplyEventInterruptEvent(PDEBUGGER_EVENT Event, PDEBUGGER_EVENT_AND_ACTION_RESULT ResultsToReturn, BOOLEAN InputFromVmxRoot) { UNREFERENCED_PARAMETER(ResultsToReturn); // // Let's see if it is for all cores or just one core // if (Event->CoreId == DEBUGGER_EVENT_APPLY_TO_ALL_CORES) { // // All cores // if (InputFromVmxRoot) { HaltedBroadcastEnableExternalInterruptExitingAllCores(); } else { ExtensionCommandSetExternalInterruptExitingAllCores(); } } else { // // Just one core // if (InputFromVmxRoot) { HaltedRoutineEnableExternalInterruptExiting(Event->CoreId); } else { ConfigureSetExternalInterruptExitingOnSingleCore(Event->CoreId); } } // // Set the event's target interrupt // Event->Options.OptionalParam1 = Event->InitOptions.OptionalParam1; } /** * @brief Applying EFER SYSCALL 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 VOID */ VOID ApplyEventEferSyscallHookEvent(PDEBUGGER_EVENT Event, PDEBUGGER_EVENT_AND_ACTION_RESULT ResultsToReturn, BOOLEAN InputFromVmxRoot) { UNREFERENCED_PARAMETER(ResultsToReturn); DEBUGGER_EVENT_SYSCALL_SYSRET_TYPE SyscallHookType = DEBUGGER_EVENT_SYSCALL_SYSRET_SAFE_ACCESS_MEMORY; // // whether it's a !syscall2 or !sysret2 // if (Event->InitOptions.OptionalParam2 == DEBUGGER_EVENT_SYSCALL_SYSRET_HANDLE_ALL_UD) { SyscallHookType = DEBUGGER_EVENT_SYSCALL_SYSRET_HANDLE_ALL_UD; } else if (Event->InitOptions.OptionalParam2 == DEBUGGER_EVENT_SYSCALL_SYSRET_SAFE_ACCESS_MEMORY) { SyscallHookType = DEBUGGER_EVENT_SYSCALL_SYSRET_SAFE_ACCESS_MEMORY; } // // Set hook type // ConfigureSetEferSyscallOrSysretHookType(SyscallHookType); // // Let's see if it is for all cores or just one core // if (Event->CoreId == DEBUGGER_EVENT_APPLY_TO_ALL_CORES) { // // All cores // if (InputFromVmxRoot) { HaltedBroadcastEnableEferSyscallHookAllCores(); } else { DebuggerEventEnableEferOnAllProcessors(); } } else { if (InputFromVmxRoot) { HaltedRoutineEnableEferSyscallHookOnSingleCore(Event->CoreId); } else { ConfigureEnableEferSyscallHookOnSingleCore(Event->CoreId); } } // // Set the event's target syscall number and save the approach // of handling event details // Event->Options.OptionalParam1 = Event->InitOptions.OptionalParam1; Event->Options.OptionalParam2 = SyscallHookType; } /** * @brief Applying EFER SYSRET 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 VOID */ VOID ApplyEventEferSysretHookEvent(PDEBUGGER_EVENT Event, PDEBUGGER_EVENT_AND_ACTION_RESULT ResultsToReturn, BOOLEAN InputFromVmxRoot) { UNREFERENCED_PARAMETER(ResultsToReturn); DEBUGGER_EVENT_SYSCALL_SYSRET_TYPE SyscallHookType = DEBUGGER_EVENT_SYSCALL_SYSRET_SAFE_ACCESS_MEMORY; // // whether it's a !syscall2 or !sysret2 // if (Event->InitOptions.OptionalParam2 == DEBUGGER_EVENT_SYSCALL_SYSRET_HANDLE_ALL_UD) { SyscallHookType = DEBUGGER_EVENT_SYSCALL_SYSRET_HANDLE_ALL_UD; } else if (Event->InitOptions.OptionalParam2 == DEBUGGER_EVENT_SYSCALL_SYSRET_SAFE_ACCESS_MEMORY) { SyscallHookType = DEBUGGER_EVENT_SYSCALL_SYSRET_SAFE_ACCESS_MEMORY; } // // Set hook type // ConfigureSetEferSyscallOrSysretHookType(SyscallHookType); // // Let's see if it is for all cores or just one core // if (Event->CoreId == DEBUGGER_EVENT_APPLY_TO_ALL_CORES) { // // All cores // if (InputFromVmxRoot) { HaltedBroadcastEnableEferSyscallHookAllCores(); } else { DebuggerEventEnableEferOnAllProcessors(); } } else { // // Just one core // if (InputFromVmxRoot) { HaltedRoutineEnableEferSyscallHookOnSingleCore(Event->CoreId); } else { ConfigureEnableEferSyscallHookOnSingleCore(Event->CoreId); } } // // Set the event's target syscall number and save the approach // of handling event details // Event->Options.OptionalParam1 = Event->InitOptions.OptionalParam1; Event->Options.OptionalParam2 = SyscallHookType; } /** * @brief Applying VMCALL instruction execution 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 VOID */ VOID ApplyEventVmcallExecutionEvent(PDEBUGGER_EVENT Event, PDEBUGGER_EVENT_AND_ACTION_RESULT ResultsToReturn, BOOLEAN InputFromVmxRoot) { UNREFERENCED_PARAMETER(Event); UNREFERENCED_PARAMETER(ResultsToReturn); UNREFERENCED_PARAMETER(InputFromVmxRoot); // // Enable triggering events for VMCALLs. This event doesn't support custom optional // parameter(s) because it's unconditional users can use condition(s) to check for // their custom optional parameters // VmFuncSetTriggerEventForVmcalls(TRUE); } /** * @brief Applying trap mode change 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 ApplyEventTrapModeChangeEvent(PDEBUGGER_EVENT Event, PDEBUGGER_EVENT_AND_ACTION_RESULT ResultsToReturn, BOOLEAN InputFromVmxRoot) { // // Set the event's mode of execution // Event->Options.OptionalParam1 = Event->InitOptions.OptionalParam1; if (InputFromVmxRoot) { // // The event registration is coming from VMX root-mode, we // cannot initialize this event in VMX-root mode, so we need // to check whether it's already activated (using the 'preactivate' command) // or not and if it's activated then we can just add the current process // to the watchlist, otherwise the user needs to preactivate this event // if (VmFuncQueryModeExecTrap()) { // // Add the process to the watching list // ConfigureExecTrapAddProcessToWatchingList(Event->ProcessId); } else { // // The mode exec trap is not initialized // ResultsToReturn->IsSuccessful = FALSE; ResultsToReturn->Error = DEBUGGER_ERROR_THE_MODE_EXEC_TRAP_IS_NOT_INITIALIZED; return FALSE; } } else { // // The event registration is coming from VMX non-root mode so we // can initialize this mechanism if it's not already initialized // // // Add the process to the watching list // ConfigureExecTrapAddProcessToWatchingList(Event->ProcessId); // // Enable triggering events for user-mode execution traps. This event doesn't // support custom optional parameter(s) because it's unconditional users can // use condition(s) to check for their custom optional parameters // ConfigureInitializeExecTrapOnAllProcessors(); } // // It was successfully applied // return TRUE; } /** * @brief Applying CPUID instruction execution 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 VOID */ VOID ApplyEventCpuidExecutionEvent(PDEBUGGER_EVENT Event, PDEBUGGER_EVENT_AND_ACTION_RESULT ResultsToReturn, BOOLEAN InputFromVmxRoot) { UNREFERENCED_PARAMETER(Event); UNREFERENCED_PARAMETER(ResultsToReturn); UNREFERENCED_PARAMETER(InputFromVmxRoot); // // Enable triggering events for CPUIDs. This event doesn't support custom optional // parameter(s) because it's unconditional users can use condition(s) to check for // their custom optional parameters // VmFuncSetTriggerEventForCpuids(TRUE); // // Setting an indicator to CPUID EAX index (if any) // Event->Options.OptionalParam1 = Event->InitOptions.OptionalParam1; Event->Options.OptionalParam2 = Event->InitOptions.OptionalParam2; } /** * @brief Applying trace 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 VOID */ VOID ApplyEventTracingEvent(PDEBUGGER_EVENT Event, PDEBUGGER_EVENT_AND_ACTION_RESULT ResultsToReturn, BOOLEAN InputFromVmxRoot) { UNREFERENCED_PARAMETER(ResultsToReturn); UNREFERENCED_PARAMETER(InputFromVmxRoot); // // This is a dependent-event thus, it will be activated later by // another event and nothing needs to be initiated at this stage // // // Save the type of the trace // Event->Options.OptionalParam1 = Event->InitOptions.OptionalParam1; } /** * @brief Applying XSETBV instruction execution 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 VOID */ VOID ApplyEventXsetbvExecutionEvent(PDEBUGGER_EVENT Event, PDEBUGGER_EVENT_AND_ACTION_RESULT ResultsToReturn, BOOLEAN InputFromVmxRoot) { UNREFERENCED_PARAMETER(Event); UNREFERENCED_PARAMETER(ResultsToReturn); UNREFERENCED_PARAMETER(InputFromVmxRoot); // // Enable triggering events for XSETBVs. This event doesn't support custom optional // parameter(s) because it's unconditional. Users can use condition(s) to check for // their custom optional parameters // VmFuncSetTriggerEventForXsetbvs(TRUE); }