0

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!

1 Answer 1

0

The full answer to this question will be: Nohow, because in order to get into the interrupt, my IRQL level rises, and then decreases after I got into my SvmVmexitHandler and for this reason I can't use any IRQL dependent native API in it

Sign up to request clarification or add additional context in comments.

1 Comment

As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.