mirror of
https://github.com/Idov31/NovaHypervisor
synced 2026-06-06 15:54:26 +00:00
217 lines
6.3 KiB
C++
217 lines
6.3 KiB
C++
#include "pch.h"
|
|
#include "EventInjection.h"
|
|
|
|
namespace EventHandler {
|
|
constexpr UINT32 EVENT_VALID_MASK = 1u << 31;
|
|
constexpr UINT32 EVENT_ERROR_CODE_VALID_MASK = 1u << 11;
|
|
constexpr UINT32 VM_ENTRY_EVENT_MASK = EVENT_VALID_MASK | EVENT_ERROR_CODE_VALID_MASK | 0x7ffu;
|
|
|
|
/*
|
|
* Description:
|
|
* IsSoftwareEvent is responsible for checking whether an injected event consumes the VM-exit instruction length.
|
|
*
|
|
* Parameters:
|
|
* @interruptionType [_In_ INTERRUPT_TYPE] -- The VMX interruption type.
|
|
*
|
|
* Returns:
|
|
* @isSoftwareEvent [bool] -- True if the event is software-delivered.
|
|
*/
|
|
bool IsSoftwareEvent(_In_ INTERRUPT_TYPE interruptionType) {
|
|
return interruptionType == INTERRUPT_TYPE_SOFTWARE_INTERRUPT ||
|
|
interruptionType == INTERRUPT_TYPE_PRIVILEGED_SOFTWARE_INTERRUPT ||
|
|
interruptionType == INTERRUPT_TYPE_SOFTWARE_EXCEPTION;
|
|
}
|
|
|
|
/*
|
|
* Description:
|
|
* ClearPendingInjection is responsible for clearing any pending event injection.
|
|
*
|
|
* Parameters:
|
|
* There are no parameters.
|
|
*
|
|
* Returns:
|
|
* There is no return value.
|
|
*/
|
|
void ClearPendingInjection() {
|
|
__vmx_vmwrite(VM_ENTRY_INTR_INFO_FIELD, 0);
|
|
__vmx_vmwrite(VM_ENTRY_EXCEPTION_ERROR_CODE, 0);
|
|
__vmx_vmwrite(VM_ENTRY_INSTRUCTION_LEN, 0);
|
|
}
|
|
|
|
/*
|
|
* Description:
|
|
* SetupInstructionLength is responsible for setting up the VM-entry instruction length based on the VM-exit instruction length.
|
|
*
|
|
* Parameters:
|
|
* There are no parameters.
|
|
*
|
|
* Returns:
|
|
* There is no return value.
|
|
*/
|
|
void SetupInstructionLength() {
|
|
SIZE_T exitInstractionLength = 0;
|
|
__vmx_vmread(VM_EXIT_INSTRUCTION_LEN, &exitInstractionLength);
|
|
__vmx_vmwrite(VM_ENTRY_INSTRUCTION_LEN, exitInstractionLength);
|
|
}
|
|
|
|
/*
|
|
* Description:
|
|
* ReinjectEventFromIdtVectoring is responsible for reinjecting an event from IDT vectoring information.
|
|
*
|
|
* Parameters:
|
|
* There are no parameters.
|
|
*
|
|
* Returns:
|
|
* @bool -- True if the event was reinjected, otherwise false.
|
|
*/
|
|
bool ReinjectEventFromIdtVectoring() {
|
|
SIZE_T vmEntryInfo = 0;
|
|
SIZE_T idtVectoringInfo = 0;
|
|
__vmx_vmread(VM_ENTRY_INTR_INFO_FIELD, &vmEntryInfo);
|
|
__vmx_vmread(IDT_VECTORING_INFO_FIELD, &idtVectoringInfo);
|
|
|
|
if ((vmEntryInfo & EVENT_VALID_MASK) || !(idtVectoringInfo & EVENT_VALID_MASK))
|
|
return false;
|
|
|
|
__vmx_vmwrite(VM_ENTRY_INTR_INFO_FIELD, idtVectoringInfo & VM_ENTRY_EVENT_MASK);
|
|
|
|
if (idtVectoringInfo & EVENT_ERROR_CODE_VALID_MASK) {
|
|
SIZE_T errorCode = 0;
|
|
__vmx_vmread(IDT_VECTORING_ERROR_CODE, &errorCode);
|
|
__vmx_vmwrite(VM_ENTRY_EXCEPTION_ERROR_CODE, errorCode);
|
|
}
|
|
|
|
const INTERRUPT_TYPE interruptionType =
|
|
static_cast<INTERRUPT_TYPE>((idtVectoringInfo >> 8) & 0x7);
|
|
if (IsSoftwareEvent(interruptionType))
|
|
SetupInstructionLength();
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
* Description
|
|
* InjectEventFromVmExitInterruption is responsible for injecting an event from VM-exit interruption information.
|
|
*
|
|
* Parameters:
|
|
* @interruptExit [_In_ VMEXIT_INTERRUPT_INFO] -- The VM-exit interruption information.
|
|
*
|
|
* Returns:
|
|
* @bool -- True if the event was injected, otherwise false.
|
|
*/
|
|
bool InjectEventFromVmExitInterruption(_In_ VMEXIT_INTERRUPT_INFO interruptExit) {
|
|
if (!interruptExit.Valid)
|
|
return false;
|
|
|
|
__vmx_vmwrite(VM_ENTRY_INTR_INFO_FIELD, interruptExit.Flags & VM_ENTRY_EVENT_MASK);
|
|
|
|
if (interruptExit.ErrorCodeValid) {
|
|
SIZE_T errorCode = 0;
|
|
__vmx_vmread(VM_EXIT_INTR_ERROR_CODE, &errorCode);
|
|
__vmx_vmwrite(VM_ENTRY_EXCEPTION_ERROR_CODE, errorCode);
|
|
}
|
|
else {
|
|
__vmx_vmwrite(VM_ENTRY_EXCEPTION_ERROR_CODE, 0);
|
|
}
|
|
|
|
const INTERRUPT_TYPE interruptionType =
|
|
static_cast<INTERRUPT_TYPE>(interruptExit.InterruptionType);
|
|
if (IsSoftwareEvent(interruptionType))
|
|
SetupInstructionLength();
|
|
else
|
|
__vmx_vmwrite(VM_ENTRY_INSTRUCTION_LEN, 0);
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
* Description:
|
|
* InjectInterruption is responsible for injecting an interruption to the guest.
|
|
*
|
|
* Parameters:
|
|
* @interruptionType [_In_ INTERRUPT_TYPE] -- The VMX interruption type.
|
|
* @vector [_In_ EXCEPTION_VECTORS] -- The interruption vector to inject.
|
|
* @deliverErrorCode [_In_ bool] -- Indicates whether to deliver an error code with the interruption.
|
|
* @errorCode [_In_ ULONG32] -- The error code to deliver with the interruption, if applicable.
|
|
*
|
|
* Returns:
|
|
* There is no return value.
|
|
*/
|
|
void InjectInterruption(_In_ INTERRUPT_TYPE interruptionType,
|
|
_In_ EXCEPTION_VECTORS vector,
|
|
_In_ bool deliverErrorCode,
|
|
_In_ ULONG32 errorCode) {
|
|
|
|
INTERRUPT_INFO info = { 0 };
|
|
info.Valid = TRUE;
|
|
info.InterruptType = interruptionType;
|
|
info.Vector = vector;
|
|
info.DeliverCode = deliverErrorCode;
|
|
__vmx_vmwrite(VM_ENTRY_INTR_INFO_FIELD, info.Flags);
|
|
|
|
if (deliverErrorCode)
|
|
__vmx_vmwrite(VM_ENTRY_EXCEPTION_ERROR_CODE, errorCode);
|
|
else
|
|
__vmx_vmwrite(VM_ENTRY_EXCEPTION_ERROR_CODE, 0);
|
|
|
|
if (!IsSoftwareEvent(interruptionType))
|
|
__vmx_vmwrite(VM_ENTRY_INSTRUCTION_LEN, 0);
|
|
}
|
|
|
|
/*
|
|
* Description:
|
|
* InjectBreakpoint is responsible for injecting a breakpoint exception to the guest.
|
|
*
|
|
* Parameters:
|
|
* There are no parameters.
|
|
*
|
|
* Returns:
|
|
* There is no return value.
|
|
*/
|
|
void InjectBreakpoint() {
|
|
InjectInterruption(INTERRUPT_TYPE_SOFTWARE_EXCEPTION, EXCEPTION_VECTOR_BREAKPOINT, false, 0);
|
|
SetupInstructionLength();
|
|
}
|
|
|
|
/*
|
|
* Description:
|
|
* InjectGeneralProtection is responsible for injecting a general protection fault exception to the guest.
|
|
*
|
|
* Parameters:
|
|
* There are no parameters.
|
|
*
|
|
* Returns:
|
|
* There is no return value.
|
|
*/
|
|
void InjectGeneralProtection() {
|
|
InjectInterruption(INTERRUPT_TYPE_HARDWARE_EXCEPTION, EXCEPTION_VECTOR_GENERAL_PROTECTION_FAULT, true, 0);
|
|
}
|
|
|
|
/*
|
|
* Description:
|
|
* InjectUndefinedOpcode is responsible for injecting an undefined opcode exception to the guest.
|
|
*
|
|
* Parameters:
|
|
* There are no parameters.
|
|
*
|
|
* Returns:
|
|
* There is no return value.
|
|
*/
|
|
void InjectUndefinedOpcode() {
|
|
InjectInterruption(INTERRUPT_TYPE_HARDWARE_EXCEPTION, EXCEPTION_VECTOR_UNDEFINED_OPCODE, false, 0);
|
|
}
|
|
|
|
/*
|
|
* Description:
|
|
* InjectPageFault is responsible for injecting a page fault exception to the guest with the provided faulting address and error code.
|
|
*
|
|
* Parameters:
|
|
* There are no parameters.
|
|
*
|
|
* Returns:
|
|
* There is no return value.
|
|
*/
|
|
void InjectPageFault(_In_ ULONG64 faultAddress, _In_ ULONG32 errorCode) {
|
|
__writecr2(faultAddress);
|
|
InjectInterruption(INTERRUPT_TYPE_HARDWARE_EXCEPTION, EXCEPTION_VECTOR_PAGE_FAULT, true, errorCode);
|
|
}
|
|
};
|