如何在SVM根(执行)模式下使用内核函数?

问题描述 投票:0回答:1

我遇到了以下问题:当我初始化内核管理程序时,对我来说它是SVM,我从vmrun退出并进入我的SvmExitHandler(这是管理退出代码的调度程序),然后当我尝试调用任何IRQL Passive时level api(假设我正在使用它),我得到一个 BSOD KERNEL_SECURIY_CHECK_FAILURE。

同时,当我使用相同的参数调用相同的 API 时,但在启动 SVM 之前,一切都对我有用。当我使用 SVM 时,如何组织与内核函数的通信?比如我需要在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;
    }

因此,如果我直接访问 ZwWriteFIle API 以便将 RIP 值写入 VMEXIT_EXCP_DB,那么我将崩溃并出现 BSOD,因为实际上当我处于 SVM 中时,所有中断和其他功能都被禁用。我该怎么办?我会很高兴得到任何帮助!

c++ driver svm hardware amd-processor
1个回答
0
投票

这个问题的完整答案是:不,因为为了进入中断,我的 IRQL 级别会上升,然后在进入 SvmVmexitHandler 后下降,因此我不能在中使用任何依赖于 IRQL 的本机 API它

© www.soinside.com 2019 - 2024. All rights reserved.