• Intel VT入门


    前言
     
     
    传说中的VT貌似很神秘的样子,关于VT入门的资料又很少,于是研究了一番
    由于资源有限,自身水平亦有限,并且是闭门造车之作,如有错误的地方请指正,不胜感激!
    关于VT可以先参考海风月影写的关于VT调试器http://bbs.pediy.com/showthread.PHP?t=96122
     
    运行环境
    操作系统: windows XP 
    CPU : intel i3-390M 
    状态单核运行
     
    驱动没有卸载部分,测试前请先保存好文档. boot.ini 文件中添加 /numproc=1,重启
    VT简介
     
     
    Intel VIrtual Techonlogy , intel 硬件虚拟化技术 ,在硬件级别上完成计算机的虚拟化
     
    为实现硬件虚拟化 ,VT增加了 12新的 VMX指令
     
    [VMCS控制 5 ]
    VMPTRLD 
    VMPTRST 
    VMCLEAR 
    VMREAD 
    VMWRITE 
     
    [VMX命令 5]
    VMLAUNCH 
    VMCALL 
    VMXON 
    VMXOFF 
    VMRESUME 
     
    [Guest software 2]
    INVEPT 
    INVVPID 
     
     
    12条指令对应的机器码(xen-3.4.1xenincludeasm-x86hvmvmxvmx.h)
    代码中使用 _emit
     
    #define VMCALL_OPCODE ".byte 0x0f,0x01,0xc1 "
    #define VMCLEAR_OPCODE ".byte 0x66,0x0f,0xc7 " /* reg/opcode: /6 */
    #define VMLAUNCH_OPCODE ".byte 0x0f,0x01,0xc2 "
    #define VMPTRLD_OPCODE ".byte 0x0f,0xc7 " /* reg/opcode: /6 */
    #define VMPTRST_OPCODE ".byte 0x0f,0xc7 " /* reg/opcode: /7 */
    #define VMREAD_OPCODE ".byte 0x0f,0x78 "
    #define VMRESUME_OPCODE ".byte 0x0f,0x01,0xc3 "
    #define VMWRITE_OPCODE ".byte 0x0f,0x79 "
    #define INVEPT_OPCODE ".byte 0x66,0x0f,0x38,0x80 " /* m128,r64/32 */
    #define INVVPID_OPCODE ".byte 0x66,0x0f,0x38,0x81 " /* m128,r64/32 */
    #define VMXOFF_OPCODE ".byte 0x0f,0x01,0xc4 "
    #define VMXON_OPCODE ".byte 0xf3,0x0f,0xc7 "
     
     
    驱动初在始化一个VMCS (Virtual Machine Control Structures)内存区域后,启动VMM (Virtual Machine Monitor) , 
    得到最高权限从而管理硬件资源操作系统是运行于ring0
    VMM要监控管理整个系统的资源,因而VMM的权限是大于操作系统,它处于一个全新的级别ring -1
    用一个形象的比喻来讲就是:当前操作系统的的“政权”被VMM颠覆了
    下面这个图是: VMM Guest OS 的联系
     
    名称:  image001.jpg
查看次数: 1987
文件大小:  16.6 KB
     
     
    下面简单介绍一下VMM的建立过程,看看“政权”是如何被颠覆的
    首先通过CPUID检查CPU是否支持VT
     
    硬件环境的检测,通过指令CPUID检测CPU是否支持VT
    ECX的第5bit标志代表对 VT 的支持与否
    (更多检测可以看
    http://bbs.pediy.com/showthread.php?t=96122
    回贴部分)
    初始化主要的内存区域
    使用VMXON 进入 VMX (虚拟机指令扩展指令集)操作
     
    执行VMXON指令 , EFLAGS.CF 可判断执行是否成功
    __asm
    {
    PUSH 0
    PUSH PhysicalVMXONRegionPtr.LowPart
     
    _emit 0xF3 // VMXON [ESP]
    _emit 0x0F
    _emit 0xC7
    _emit 0x34
    _emit 0x24
     
    PUSHFD
    POP eFlags
     
    ADD ESP, 8
    }
     
    接下来开始初始化VMCS区域,(相当于部署军队,准备起义)
    这个结构只能够被VMCLEAR, VMPTRLD, VMREAD,VMWRITE操作。
    VMM运行后guest 执行这些指令时会引发#VMExit事件
     
    VMCS 结构如下图
     
     
     
    名称:  image002.jpg
查看次数: 1989
文件大小:  18.2 KB 
    VMCS 是一个4K的内存区域
    在逻辑上,虚拟机控制结构被划分为 6 部分:
    1) GUEST-STATE 域:虚拟机从根操作模式进入非根操作模式时,处理器所处的状态;
    2) HOST-STATE 域:虚拟机从非根操作模式退出到根操作模式时,处理器所处的状态;
    3) VM 执行控制域:虚拟机在非根操作模式运行的时候,控制处理器非根操作模式退出到根操作模式;
    4) VM 退出控制域:虚拟机从非根操作模式下退出时,需要保存的信息;
    5) VM 进入控制域:虚拟机从根操作模式进入非根操作模式时,需要读取的信息;
    6) VM 退出信息域:虚拟机从非根操作模式退出到根操作模式时,将退出的原因保存到该域中。
     
     
    在这里初始化的代码比较多,要初始化 host  guest  CR0CR3CR4IDTRGDTRLDTRRflagSYSENTER_CSSYSENTER_EIPSYSENTER_ESP
    初始化时使用VMWRITE 指令设置 , 设置时主要的宏是
    GUEST_ES_SELECTOR = 0x00000800,
    GUEST_CS_SELECTOR = 0x00000802,
    GUEST_SS_SELECTOR = 0x00000804,
    GUEST_DS_SELECTOR = 0x00000806,
    GUEST_FS_SELECTOR = 0x00000808,
    GUEST_GS_SELECTOR = 0x0000080a,
    GUEST_LDTR_SELECTOR = 0x0000080c,
    GUEST_TR_SELECTOR = 0x0000080e,
    HOST_ES_SELECTOR = 0x00000c00,
    HOST_CS_SELECTOR = 0x00000c02,
    HOST_SS_SELECTOR = 0x00000c04,
    HOST_DS_SELECTOR = 0x00000c06,
    HOST_FS_SELECTOR = 0x00000c08,
    HOST_GS_SELECTOR = 0x00000c0a,
    HOST_TR_SELECTOR = 0x00000c0c,

    使用 VMWRITE 指令集成的函数
    VOID WriteVMCS( ULONG encoding, ULONG value )
    {
    __asm
    {
    PUSHAD
    PUSH value
    MOV EAX, encoding 
     
    _emit 0x0F 
    _emit 0x79 
    _emit 0x04
    _emit 0x24
     
    POP EAX
    POPAD
    }
    }
    例如初始化 GDT , IDT 使用的是以下代码
    __asm
    {
    SGDT gdt_reg
    }
    temp32 = 0;
    temp32 = gdt_reg.BaseHi;
    temp32 <<= 16;
    temp32 |= gdt_reg.BaseLo;
    Log( "Setting Host GDTR Base" , temp32 );
    WriteVMCS( HOST_GDTR_BASE, temp32 ); 
     
     
    __asm
    {
    SIDT idt_reg
    }
    temp32 = 0;
    temp32 = idt_reg.BaseHi;
    temp32 <<= 16;
    temp32 |= idt_reg.BaseLo;
     
    Log( "Setting Host IDTR Base" , temp32 );
    WriteVMCS( HOST_IDTR_BASE, temp32 );
     
    比较重要的是设置 #VMExit 事件处理入口 HOST_RIP
    WriteVMCS( HOST_RIP, (ULONG)VMMEntryPoint ); //0x6C16
     
    最后执行 VMLAUNCH 指令 ,正式启动虚拟机(建立了新的政权)
    __asm
    {
    _emit 0x0F 
    _emit 0x01
    _emit 0xC2
    }
    至此,整个VMM的帝国已经运行起来,帝国将会管理整个系统资源
    接下来的就是#VMExit的事件循环处理(类似在调试器中下断点后,等待事件发生)
    运行过程中Guest OS 遇到要监控的指令,会发生 #VMExit 事件 (相当于被调试程序执行到中断事件)
    此时由VMM 处理,例如cpuid , 
    处理完后由 VMRESUME 继续执行 (相当于在 OD  F9 继续运行)
     
    #VMExit事件的类型
     
    #VMExit事件分为二种
    无条件事件CPUID GETSEC INVD XSETBV 所有 VMX指令
    有条件事件I/O访问,中断事件, MSR寄存器访问, HTL  (要设置VMCS相应部分触发)
     
     
     
    VMM使用VMREAD读取虚拟机状态,主要的一些变量有
    VM_EXIT_REASON = 0x00004402, //退出代码
    VM_EXIT_INTR_INFO = 0x00004404, //中断信息
    VM_EXIT_INTR_ERROR_CODE = 0x00004406,
    IDT_VECTORING_INFO = 0x00004408,
    IDT_VECTORING_ERROR_CODE = 0x0000440a,
    VM_EXIT_INSTRUCTION_LEN = 0x0000440c, //指令长度
    VMX_INSTRUCTION_INFO = 0x0000440e,
    GUEST_ES_LIMIT = 0x00004800,
    GUEST_CS_LIMIT = 0x00004802,
    GUEST_SS_LIMIT = 0x00004804,
    GUEST_DS_LIMIT = 0x00004806,

    其中最重要的就是VM_EXIT_REASON , 可以看作是消息类型
    主要的类型有
    #define EXIT_REASON_EXCEPTION_NMI 0
    #define EXIT_REASON_EXTERNAL_INTERRUPT 1
    #define EXIT_REASON_TRIPLE_FAULT 2
    #define EXIT_REASON_INIT 3
    #define EXIT_REASON_SIPI 4
    #define EXIT_REASON_IO_SMI 5
    #define EXIT_REASON_OTHER_SMI 6
    #define EXIT_REASON_PENDING_VIRT_INTR 7
    #define EXIT_REASON_PENDING_VIRT_NMI 8
    #define EXIT_REASON_TASK_SWITCH 9
    #define EXIT_REASON_CPUID 10
    #define EXIT_REASON_HLT 12
    #define EXIT_REASON_INVD 13
    #define EXIT_REASON_INVLPG 14
    #define EXIT_REASON_RDPMC 15
    #define EXIT_REASON_RDTSC 16
    #define EXIT_REASON_RSM 17
    #define EXIT_REASON_VMCALL 18
    #define EXIT_REASON_VMCLEAR 19
    #define EXIT_REASON_VMLAUNCH 20
    #define EXIT_REASON_VMPTRLD 21
    #define EXIT_REASON_VMPTRST 22
    #define EXIT_REASON_VMREAD 23
    #define EXIT_REASON_VMRESUME 24
    #define EXIT_REASON_VMWRITE 25
    #define EXIT_REASON_VMXOFF 26
    #define EXIT_REASON_VMXON 27

     
    DWORD VmxRead(DWORD in_code)
    {
    DWORD m_vmread = 0;
    __asm
    {
    PUSHAD
     
    MOV EAX, in_code 
    _emit 0x0F // VMREAD EBX, EAX
    _emit 0x78
    _emit 0xC3
     
    MOV m_vmread, EBX 
    POPAD
    }
    return m_vmread; 
    }
     
    VOID VMMReadGuestState( )
    {
    HandlerLogging = 0;
    ExitReason = VmxRead(VM_EXIT_REASON); //0x4402
    ExitInterruptionInformation = VmxRead( VM_EXIT_INTR_INFO); //0x4404
    ExitInstructionLength = VmxRead(VM_EXIT_INSTRUCTION_LEN); //0x440c
    ExitQualification = VmxRead(EXIT_QUALIFICATION) ; //0x6400
    ExitInterruptionInformation = VmxRead(VM_EXIT_INTR_INFO); //0x4404
    ExitInterruptionErrorCode = VmxRead(VM_EXIT_INTR_ERROR_CODE); //0x4406
     
    IDTVectoringInformationField = VmxRead(IDT_VECTORING_INFO); //0X00004408 // IDT-Vectoring Information Field
    IDTVectoringErrorCode = VmxRead(IDT_VECTORING_ERROR_CODE); //0X0000440A // IDT-Vectoring Error Code 
    ExitInstructionLength = VmxRead(VM_EXIT_INSTRUCTION_LEN); //0x0000440C // VM-Exit Instruction Length
    ExitInstructionInformation = VmxRead(VMX_INSTRUCTION_INFO) ; //0x0000440E //VM-Exit Instruction Information
    GuestEIP = VmxRead(GUEST_RIP); //0x0000681E; //GuestEIP
    GuestESP = VmxRead(GUEST_RSP); //0x0000681c //esp
    GuestCR3 = VmxRead(GUEST_CR3); //0X6802 GuestCR3
     
    }
     
    CPUID指令的拦截与修改
     
     
     guest OS 执行 cupid ,会得到这样一个错误号 10 (VMX_EXIT_CPUID )
    当执行到CPUID这条指令的时候,响应,然后就可以修改cpuid的返回值
     
    if( ExitReason == VMX_EXIT_CPUID ) 

    if( GuestEAX == 0 )
    {
    DbgPrint("CPUID EIP == %08X  " , GuestEIP );
    //0x34EC2B 
    __asm
    {
    POPAD
    MOV EAX, 0
    CPUID 
     
     
    //修改CPUID返回值
    MOV EBX, 0x80808080
    MOV ECX, 0x90909090
    MOV EDX, 0x10101010
    JMP Resume
    }
    }
    else
    {
    __asm
    {
    POPAD
    MOV EAX, GuestEAX
    CPUID
    JMP Resume


    }
     
     
    最后运行的效果
     
    运行VT cupid
    名称:  cpuid1.jpg
查看次数: 1976
文件大小:  8.1 KB
     
    运行VT cpuid
     
    名称:  cpuid2.jpg
查看次数: 1981
文件大小:  14.5 KB
     
    顺道打印了执行CPUID程序的 EIP,与输出的 00401009一致
    00401003 |. 53 push ebx
    00401004 |? B8 00000000 mov eax,0
    00401009 |. 0FA2 cpuid
    0040100B |. 894424 0C mov dword ptr ss:[esp+C],eax
    0040100F |? 894C24 08 mov dword ptr ss:[esp+8],ecx
    00401013 |? 895C24 04 mov dword ptr ss:[esp+4],ebx
    00401017 |? 68 10614000 push cpuid.00406110 ; ASCII "---------cpuid------",LF

    EXIT_REASON 的所有类型注释

    VirtualBoxsrcVBoxVMMVMMR3HWACCM.cpp

    EXIT_REASON(VMX_EXIT_EXCEPTION          ,  0, "Exception or non-maskable interrupt (NMI)."),
        EXIT_REASON(VMX_EXIT_EXTERNAL_IRQ       ,  1, "External interrupt."),
        EXIT_REASON(VMX_EXIT_TRIPLE_FAULT       ,  2, "Triple fault."),
        EXIT_REASON(VMX_EXIT_INIT_SIGNAL        ,  3, "INIT signal."),
        EXIT_REASON(VMX_EXIT_SIPI               ,  4, "Start-up IPI (SIPI)."),
        EXIT_REASON(VMX_EXIT_IO_SMI_IRQ         ,  5, "I/O system-management interrupt (SMI)."),
        EXIT_REASON(VMX_EXIT_SMI_IRQ            ,  6, "Other SMI."),
        EXIT_REASON(VMX_EXIT_IRQ_WINDOW         ,  7, "Interrupt window."),
        EXIT_REASON_NIL(),
        EXIT_REASON(VMX_EXIT_TASK_SWITCH        ,  9, "Task switch."),
        EXIT_REASON(VMX_EXIT_CPUID              , 10, "Guest software attempted to execute CPUID."),
        EXIT_REASON_NIL(),
        EXIT_REASON(VMX_EXIT_HLT                , 12, "Guest software attempted to execute HLT."),
        EXIT_REASON(VMX_EXIT_INVD               , 13, "Guest software attempted to execute INVD."),
        EXIT_REASON(VMX_EXIT_INVPG              , 14, "Guest software attempted to execute INVPG."),
        EXIT_REASON(VMX_EXIT_RDPMC              , 15, "Guest software attempted to execute RDPMC."),
        EXIT_REASON(VMX_EXIT_RDTSC              , 16, "Guest software attempted to execute RDTSC."),
        EXIT_REASON(VMX_EXIT_RSM                , 17, "Guest software attempted to execute RSM in SMM."),
        EXIT_REASON(VMX_EXIT_VMCALL             , 18, "Guest software executed VMCALL."),
        EXIT_REASON(VMX_EXIT_VMCLEAR            , 19, "Guest software executed VMCLEAR."),
        EXIT_REASON(VMX_EXIT_VMLAUNCH           , 20, "Guest software executed VMLAUNCH."),
        EXIT_REASON(VMX_EXIT_VMPTRLD            , 21, "Guest software executed VMPTRLD."),
        EXIT_REASON(VMX_EXIT_VMPTRST            , 22, "Guest software executed VMPTRST."),
        EXIT_REASON(VMX_EXIT_VMREAD             , 23, "Guest software executed VMREAD."),
        EXIT_REASON(VMX_EXIT_VMRESUME           , 24, "Guest software executed VMRESUME."),
        EXIT_REASON(VMX_EXIT_VMWRITE            , 25, "Guest software executed VMWRITE."),
        EXIT_REASON(VMX_EXIT_VMXOFF             , 26, "Guest software executed VMXOFF."),
        EXIT_REASON(VMX_EXIT_VMXON              , 27, "Guest software executed VMXON."),
        EXIT_REASON(VMX_EXIT_CRX_MOVE           , 28, "Control-register accesses."),
        EXIT_REASON(VMX_EXIT_DRX_MOVE           , 29, "Debug-register accesses."),
        EXIT_REASON(VMX_EXIT_PORT_IO            , 30, "I/O instruction."),
        EXIT_REASON(VMX_EXIT_RDMSR              , 31, "RDMSR. Guest software attempted to execute RDMSR."),
        EXIT_REASON(VMX_EXIT_WRMSR              , 32, "WRMSR. Guest software attempted to execute WRMSR."),
        EXIT_REASON(VMX_EXIT_ERR_INVALID_GUEST_STATE,  33, "VM-entry failure due to invalid guest state."),
        EXIT_REASON(VMX_EXIT_ERR_MSR_LOAD       , 34, "VM-entry failure due to MSR loading."),
        EXIT_REASON_NIL(),
        EXIT_REASON(VMX_EXIT_MWAIT              , 36, "Guest software executed MWAIT."),
        EXIT_REASON_NIL(),
        EXIT_REASON_NIL(),
        EXIT_REASON(VMX_EXIT_MONITOR            , 39, "Guest software attempted to execute MONITOR."),
        EXIT_REASON(VMX_EXIT_PAUSE              , 40, "Guest software attempted to execute PAUSE."),
        EXIT_REASON(VMX_EXIT_ERR_MACHINE_CHECK  , 41, "VM-entry failure due to machine-check."),
        EXIT_REASON_NIL(),
        EXIT_REASON(VMX_EXIT_TPR                , 43, "TPR below threshold. Guest software executed MOV to CR8."),
        EXIT_REASON(VMX_EXIT_APIC_ACCESS        , 44, "APIC access. Guest software attempted to access memory at a physical address on the APIC-access page."),
        EXIT_REASON_NIL(),
        EXIT_REASON(VMX_EXIT_XDTR_ACCESS        , 46, "Access to GDTR or IDTR. Guest software attempted to execute LGDT, LIDT, SGDT, or SIDT."),
        EXIT_REASON(VMX_EXIT_TR_ACCESS          , 47, "Access to LDTR or TR. Guest software attempted to execute LLDT, LTR, SLDT, or STR."),
        EXIT_REASON(VMX_EXIT_EPT_VIOLATION      , 48, "EPT violation. An attempt to access memory with a guest-physical address was disallowed by the configuration of the EPT paging structures."),
        EXIT_REASON(VMX_EXIT_EPT_MISCONFIG      , 49, "EPT misconfiguration. An attempt to access memory with a guest-physical address encountered a misconfigured EPT paging-structure entry."),
        EXIT_REASON(VMX_EXIT_INVEPT             , 50, "INVEPT. Guest software attempted to execute INVEPT."),
        EXIT_REASON_NIL(),
        EXIT_REASON(VMX_EXIT_PREEMPTION_TIMER   , 52, "VMX-preemption timer expired. The preemption timer counted down to zero."),
        EXIT_REASON(VMX_EXIT_INVVPID            , 53, "INVVPID. Guest software attempted to execute INVVPID."),
        EXIT_REASON(VMX_EXIT_WBINVD             , 54, "WBINVD. Guest software attempted to execute WBINVD."),
        EXIT_REASON(VMX_EXIT_XSETBV             , 55, "XSETBV. Guest software attempted to execute XSETBV."),
        EXIT_REASON_NIL()
      jpg改rar

  • 相关阅读:
    2月4日学习日志
    2月3日学习日志
    2月2日学习日志
    2月1日学习日志
    Result Maps collection already contains value for ***
    mapreduce入门程序之---wordcount
    利用Git上传项目到github以及遇到的问题
    看100篇架构设计的文章,不如重构一次代码
    面试中的微服务架构
    分布式架构中数据一致性常见的几个问题
  • 原文地址:https://www.cnblogs.com/kuangke/p/6155379.html
Copyright © 2020-2023  润新知