I ran into the following problem: When I initialized the kernel hypervisor, for me it is SVM and I exit from vmrun and get into my SvmExitHandler (this is the dispatcher that manages exit codes), then when I try to call any IRQL Passive level api (given that I am on it), I get a BSOD KERNEL_SECURIY_CHECK_FAILURE.
At the same time, when I call the same API with the same arguments, but before starting the SVM, then everything works for me. How can I organize communication with kernel functions when I am in SVM? For example, I need to process each instruction during tracing
extern "C" VMM_STATUS SvmVmexitHandler(PRIVATE_VM_DATA* Private, GUEST_CONTEXT* Context, GUEST_SSE_CONTEXT* SSeContext, GUEST_AVX_CONTEXT* AvxContext)
{
// Load the host state:
__svm_vmload(reinterpret_cast<size_t>(Private->VmmStack.Layout.InitialStack.HostVmcbPa));
// Restore the guest's RAX that was overwritten by host's RAX on #VMEXIT:
Context->Rax = Private->Guest.StateSaveArea.Rax;
VMM_STATUS Status = VMM_STATUS::VMM_CONTINUE;
switch (Private->Guest.ControlArea.ExitCode)
{
case VMEXIT_CPUID:
{
CPUID_REGS Regs = {};
int Function = static_cast<int>(Context->Rax);
int SubLeaf = static_cast<int>(Context->Rcx);
__cpuidex(Regs.Raw, Function, SubLeaf);
switch (Function) {
case CPUID_VMM_SHUTDOWN:
{
// Shutdown was triggered:
Status = VMM_STATUS::VMM_SHUTDOWN;
break;
}
case CPUID::Generic::CPUID_MAXIMUM_FUNCTION_NUMBER_AND_VENDOR_ID:
{
// Vendor = 'Hyper-Bridge' as RBX + RDX + RCX:
Context->Rax = Regs.Regs.Eax;
GetHvCpuName(Context->Rbx, Context->Rcx, Context->Rdx);
break;
}
default:
{
Context->Rax = Regs.Regs.Eax;
Context->Rbx = Regs.Regs.Ebx;
Context->Rcx = Regs.Regs.Ecx;
Context->Rdx = Regs.Regs.Edx;
break;
}
}
break;
}
case VMEXIT_MSR:
{
if ((Context->Rcx & MAXUINT32) == static_cast<unsigned int>(AMD_MSR::MSR_EFER) && Private->Guest.ControlArea.ExitInfo1)
{
EFER Efer = {};
Efer.Value = ((Context->Rdx & MAXUINT32) << 32) | (Context->Rax & MAXUINT32);
if (!Efer.Bitmap.SecureVirtualMachineEnable)
{
InjectEvent(&Private->Guest, INTERRUPT_VECTOR::GeneralProtection, EXCEPTION_VECTOR::FaultTrapException, 0); // #GP (Vector = 13, Type = Exception)
break;
}
Private->Guest.StateSaveArea.Efer = Efer.Value;
}
break;
}
case VMEXIT_VMRUN:
{
InjectEvent(&Private->Guest, INTERRUPT_VECTOR::GeneralProtection, EXCEPTION_VECTOR::FaultTrapException, 0); // #GP (Vector = 13, Type = Exception)
break;
}
case VMEXIT_EXCP_DB://TRACE EXCEPTION BY TF FLAG
{
KdPrint(("RIP %p\n", Private->Guest.StateSaveArea.Rip));
Private->Guest.StateSaveArea.Rax = Context->Rax;
return Status;
}
}
if (Status == VMM_STATUS::VMM_SHUTDOWN)
{
// We should to devirtualize this processor:
Context->Rax = reinterpret_cast<UINT64>(Private) & MAXUINT32; // Low part
Context->Rbx = Private->Guest.ControlArea.NextRip;
Context->Rcx = Private->Guest.StateSaveArea.Rsp;
Context->Rdx = reinterpret_cast<UINT64>(Private) >> 32; // High part
// Load the guest's state:
__svm_vmload(reinterpret_cast<size_t>(Private->VmmStack.Layout.InitialStack.GuestVmcbPa));
// Store the GIF - Global Interrupt Flag:
_disable();
__svm_stgi();
// Disable the SVM by resetting the EFER.SVME bit:
EFER Efer = {};
Efer.Value = __readmsr(static_cast<unsigned long>(AMD_MSR::MSR_EFER));
Efer.Bitmap.SecureVirtualMachineEnable = FALSE;
__writemsr(static_cast<unsigned long>(AMD_MSR::MSR_EFER), Efer.Value);
// Restoring the EFlags:
__writeeflags(Private->Guest.StateSaveArea.Rflags);
}
Private->Guest.StateSaveArea.Rax = Context->Rax;
// Go to the next instruction:
Private->Guest.StateSaveArea.Rip = Private->Guest.ControlArea.NextRip;
return Status;
}
So if I access the ZwWriteFIle API directly in order to write the RIP value to VMEXIT_EXCP_DB, then I will crash to the BSOD, since in fact all interrupts and other things are disabled when I am in SVM. How can I handle this?! I will be glad of any help!