看流星社区

 找回密码
 注册账号
查看: 1793|回复: 0

VT系列:退出事件系统构建(VMMEntryPoint)

[复制链接]

该用户从未签到

发表于 2017-6-1 12:17:36 | 显示全部楼层 |阅读模式


VT执行流程:
产生退出事件 -> 根据退出事件指定特定的处理函数–> 决定自己处理还是交给CPU处理–> 完成了调用VmResume将控制权交给虚拟机.





而当发生退出事件时要调用的函数就是本章要讲的
VMCS位置:
HOST_RIP-->VMMEntryPoint(VM-Exit处理程序)



VM-Exit事件表:
#define EXIT_REASON_EXCEPTION_NMI 0 (EXCEPTION_BITMAP)//异常信息可以拦截int3等异常
#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_INTERRUPT 7
#define EXIT_REASON_TASK_SWITCH 9
#defineEXIT_REASON_CPUID 10 //必须处理的
#define EXIT_REASON_HLT 12
#defineEXIT_REASON_INVD 13 //必须处理的
#define EXIT_REASON_INVLPG 14
#define EXIT_REASON_RDPMC 15
#define EXIT_REASON_RDTSC 16
#define EXIT_REASON_RSM 17
#defineEXIT_REASON_VMCALL 18 //必须处理的因为可能存在多个VT
#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
#defineEXIT_REASON_CR_ACCESS 28 //必须处理的只要处理cr3寄存器
#defineEXIT_REASON_DR_ACCESS 29 //可以监控硬件断点
#defineEXIT_REASON_IO_INSTRUCTION 30 //可以监控键盘鼠标输入输出
#defineEXIT_REASON_MSR_READ 31 //必须处理的
#defineEXIT_REASON_MSR_WRITE 32 //必须处理的
#define EXIT_REASON_INVALID_GUEST_STATE 33
#define EXIT_REASON_MSR_LOADING 34
#define EXIT_REASON_MWAIT_INSTRUCTION 36
#define EXIT_REASON_MONITOR_INSTRUCTION 39
#define EXIT_REASON_PAUSE_INSTRUCTION 40
#define EXIT_REASON_MACHINE_CHECK 41
#define EXIT_REASON_TPR_BELOW_THRESHOLD 43

必须交由我们自己处理的VM-EXIT事件(即不在CPU_BASED_VM_EXEC_CONTROL或EXCEPTION_BITMAP控制内的):




事件


代号


对应汇编指令




Model Specific Register Read (MSR寄存器读操作)


EXIT_REASON_MSR_READ(0x1F)


rdmsr




Model Specific Register Read (MSR寄存器写操作)


EXIT_REASON_MSR_WRITE(0x20)


wrmsr




Control Register Access
(CR寄存器读/写操作)


EXIT_REASON_CR_ACCESS(0x1C)


mov crX,XXX
mov XXX,crX




Invd(高速缓存控制)


EXIT_REASON_INVD(0xD)


invd




CPUID


EXIT_REASON_CPUID(0xA)


cpuid




VmCall


EXIT_REASON_VMCALL(0x12)


vmcall




注:代号参考自Newbluepill



需要注意的是处理CR控制寄存器和MSR时的一些细节

l CR Access:
退出事件条件:
ExitQualification=
Vmx_VmRead(EXIT_QUALIFICATION);
控制寄存器,我们只要处理CR3就可以了:
movcrControlRegister= (
ExitQualification & 0x0000000F );
操作类型,0为写入 1为读取
movcrAccessType= ( (
ExitQualification & 0x00000030 )>> 4 );
操作数类型,一般为0:
movcrOperandType= ( (
ExitQualification & 0x00000040 )>> 6 );
目的寄存器:
movcrGeneralPurposeRegister= ( (
ExitQualification & 0x00000F00 )>> 8 );

movcrControlRegister= 3 且movcrAccessType =0时为写入到CR3
movcrControlRegister= 3 且movcrAccessType =1时为从CR3读出到寄存器

movcrGeneralPurposeRegister
0=eax 1=ecx 2=edx 3=edx 4=esp 5=ebp6=esi 7=edi

l MSRAccess:
Read:ECX为MSR寄存器代号,EAX为返回值的低32位,EDX为返回值的高32位.
Write:ECX为MSR寄存器代号,EAX为写入值的低32位,EDX为写入值的高32位.
部分需要用VmRead和VmWrite来处理。


在产生退出事件的时需要保存虚拟机的寄存器信息
使用的数据结构如下:
  1. typedef struct _GUEST_REGS
  2. {
  3.         ULONG eax;
  4.         ULONG ecx;
  5.         ULONG edx;
  6.         ULONG ebx;
  7.         ULONG esp;
  8.         ULONG ebp;
  9.         ULONG esi;
  10.         ULONG edi;
  11.         ULONG eip;
  12.         ULONG cr3;
  13. }GUEST_REGS,*PGUEST_REGS;
复制代码
在处理函数中需要用到的一些定义
  1. /* VMCS Encordings */
  2. enum
  3. {
  4.         VIRTUAL_PROCESSOR_ID = 0x00000000,
  5.         POSTED_INTR_NV = 0x00000002,
  6.         GUEST_ES_SELECTOR = 0x00000800,
  7.         GUEST_CS_SELECTOR = 0x00000802,
  8.         GUEST_SS_SELECTOR = 0x00000804,
  9.         GUEST_DS_SELECTOR = 0x00000806,
  10.         GUEST_FS_SELECTOR = 0x00000808,
  11.         GUEST_GS_SELECTOR = 0x0000080a,
  12.         GUEST_LDTR_SELECTOR = 0x0000080c,
  13.         GUEST_TR_SELECTOR = 0x0000080e,
  14.         GUEST_INTR_STATUS = 0x00000810,
  15.         HOST_ES_SELECTOR = 0x00000c00,
  16.         HOST_CS_SELECTOR = 0x00000c02,
  17.         HOST_SS_SELECTOR = 0x00000c04,
  18.         HOST_DS_SELECTOR = 0x00000c06,
  19.         HOST_FS_SELECTOR = 0x00000c08,
  20.         HOST_GS_SELECTOR = 0x00000c0a,
  21.         HOST_TR_SELECTOR = 0x00000c0c,
  22.         IO_BITMAP_A = 0x00002000,
  23.         IO_BITMAP_A_HIGH = 0x00002001,
  24.         IO_BITMAP_B = 0x00002002,
  25.         IO_BITMAP_B_HIGH = 0x00002003,
  26.         MSR_BITMAP = 0x00002004,
  27.         MSR_BITMAP_HIGH = 0x00002005,
  28.         VM_EXIT_MSR_STORE_ADDR = 0x00002006,
  29.         VM_EXIT_MSR_STORE_ADDR_HIGH = 0x00002007,
  30.         VM_EXIT_MSR_LOAD_ADDR = 0x00002008,
  31.         VM_EXIT_MSR_LOAD_ADDR_HIGH = 0x00002009,
  32.         VM_ENTRY_MSR_LOAD_ADDR = 0x0000200a,
  33.         VM_ENTRY_MSR_LOAD_ADDR_HIGH = 0x0000200b,
  34.         TSC_OFFSET = 0x00002010,
  35.         TSC_OFFSET_HIGH = 0x00002011,
  36.         VIRTUAL_APIC_PAGE_ADDR = 0x00002012,
  37.         VIRTUAL_APIC_PAGE_ADDR_HIGH = 0x00002013,
  38.         APIC_ACCESS_ADDR = 0x00002014,
  39.         APIC_ACCESS_ADDR_HIGH = 0x00002015,
  40.         POSTED_INTR_DESC_ADDR = 0x00002016,
  41.         POSTED_INTR_DESC_ADDR_HIGH = 0x00002017,
  42.         EPT_POINTER = 0x0000201a,
  43.         EPT_POINTER_HIGH = 0x0000201b,
  44.         EOI_EXIT_BITMAP0 = 0x0000201c,
  45.         EOI_EXIT_BITMAP0_HIGH = 0x0000201d,
  46.         EOI_EXIT_BITMAP1 = 0x0000201e,
  47.         EOI_EXIT_BITMAP1_HIGH = 0x0000201f,
  48.         EOI_EXIT_BITMAP2 = 0x00002020,
  49.         EOI_EXIT_BITMAP2_HIGH = 0x00002021,
  50.         EOI_EXIT_BITMAP3 = 0x00002022,
  51.         EOI_EXIT_BITMAP3_HIGH = 0x00002023,
  52.         VMREAD_BITMAP = 0x00002026,
  53.         VMWRITE_BITMAP = 0x00002028,
  54.         XSS_EXIT_BITMAP = 0x0000202C,
  55.         XSS_EXIT_BITMAP_HIGH = 0x0000202D,
  56.         GUEST_PHYSICAL_ADDRESS = 0x00002400,
  57.         GUEST_PHYSICAL_ADDRESS_HIGH = 0x00002401,
  58.         VMCS_LINK_POINTER = 0x00002800,
  59.         VMCS_LINK_POINTER_HIGH = 0x00002801,
  60.         GUEST_IA32_DEBUGCTL = 0x00002802,
  61.         GUEST_IA32_DEBUGCTL_HIGH = 0x00002803,
  62.         GUEST_IA32_PAT = 0x00002804,
  63.         GUEST_IA32_PAT_HIGH = 0x00002805,
  64.         GUEST_IA32_EFER = 0x00002806,
  65.         GUEST_IA32_EFER_HIGH = 0x00002807,
  66.         GUEST_IA32_PERF_GLOBAL_CTRL = 0x00002808,
  67.         GUEST_IA32_PERF_GLOBAL_CTRL_HIGH = 0x00002809,
  68.         GUEST_PDPTR0 = 0x0000280a,
  69.         GUEST_PDPTR0_HIGH = 0x0000280b,
  70.         GUEST_PDPTR1 = 0x0000280c,
  71.         GUEST_PDPTR1_HIGH = 0x0000280d,
  72.         GUEST_PDPTR2 = 0x0000280e,
  73.         GUEST_PDPTR2_HIGH = 0x0000280f,
  74.         GUEST_PDPTR3 = 0x00002810,
  75.         GUEST_PDPTR3_HIGH = 0x00002811,
  76.         GUEST_BNDCFGS = 0x00002812,
  77.         GUEST_BNDCFGS_HIGH = 0x00002813,
  78.         HOST_IA32_PAT = 0x00002c00,
  79.         HOST_IA32_PAT_HIGH = 0x00002c01,
  80.         HOST_IA32_EFER = 0x00002c02,
  81.         HOST_IA32_EFER_HIGH = 0x00002c03,
  82.         HOST_IA32_PERF_GLOBAL_CTRL = 0x00002c04,
  83.         HOST_IA32_PERF_GLOBAL_CTRL_HIGH = 0x00002c05,
  84.         PIN_BASED_VM_EXEC_CONTROL = 0x00004000,
  85.         CPU_BASED_VM_EXEC_CONTROL = 0x00004002,
  86.         EXCEPTION_BITMAP = 0x00004004,
  87.         PAGE_FAULT_ERROR_CODE_MASK = 0x00004006,
  88.         PAGE_FAULT_ERROR_CODE_MATCH = 0x00004008,
  89.         CR3_TARGET_COUNT = 0x0000400a,
  90.         VM_EXIT_CONTROLS = 0x0000400c,
  91.         VM_EXIT_MSR_STORE_COUNT = 0x0000400e,
  92.         VM_EXIT_MSR_LOAD_COUNT = 0x00004010,
  93.         VM_ENTRY_CONTROLS = 0x00004012,
  94.         VM_ENTRY_MSR_LOAD_COUNT = 0x00004014,
  95.         VM_ENTRY_INTR_INFO_FIELD = 0x00004016,
  96.         VM_ENTRY_EXCEPTION_ERROR_CODE = 0x00004018,
  97.         VM_ENTRY_INSTRUCTION_LEN = 0x0000401a,
  98.         TPR_THRESHOLD = 0x0000401c,
  99.         SECONDARY_VM_EXEC_CONTROL = 0x0000401e,
  100.         PLE_GAP = 0x00004020,
  101.         PLE_WINDOW = 0x00004022,
  102.         VM_INSTRUCTION_ERROR = 0x00004400,
  103.         VM_EXIT_REASON = 0x00004402,
  104.         VM_EXIT_INTR_INFO = 0x00004404,
  105.         VM_EXIT_INTR_ERROR_CODE = 0x00004406,
  106.         IDT_VECTORING_INFO_FIELD = 0x00004408,
  107.         IDT_VECTORING_ERROR_CODE = 0x0000440a,
  108.         VM_EXIT_INSTRUCTION_LEN = 0x0000440c,
  109.         VMX_INSTRUCTION_INFO = 0x0000440e,
  110.         GUEST_ES_LIMIT = 0x00004800,
  111.         GUEST_CS_LIMIT = 0x00004802,
  112.         GUEST_SS_LIMIT = 0x00004804,
  113.         GUEST_DS_LIMIT = 0x00004806,
  114.         GUEST_FS_LIMIT = 0x00004808,
  115.         GUEST_GS_LIMIT = 0x0000480a,
  116.         GUEST_LDTR_LIMIT = 0x0000480c,
  117.         GUEST_TR_LIMIT = 0x0000480e,
  118.         GUEST_GDTR_LIMIT = 0x00004810,
  119.         GUEST_IDTR_LIMIT = 0x00004812,
  120.         GUEST_ES_AR_BYTES = 0x00004814,
  121.         GUEST_CS_AR_BYTES = 0x00004816,
  122.         GUEST_SS_AR_BYTES = 0x00004818,
  123.         GUEST_DS_AR_BYTES = 0x0000481a,
  124.         GUEST_FS_AR_BYTES = 0x0000481c,
  125.         GUEST_GS_AR_BYTES = 0x0000481e,
  126.         GUEST_LDTR_AR_BYTES = 0x00004820,
  127.         GUEST_TR_AR_BYTES = 0x00004822,
  128.         GUEST_INTERRUPTIBILITY_INFO = 0x00004824,
  129.         GUEST_ACTIVITY_STATE = 0X00004826,
  130.         GUEST_SYSENTER_CS = 0x0000482A,
  131.         VMX_PREEMPTION_TIMER_VALUE = 0x0000482E,
  132.         HOST_IA32_SYSENTER_CS = 0x00004c00,
  133.         CR0_GUEST_HOST_MASK = 0x00006000,
  134.         CR4_GUEST_HOST_MASK = 0x00006002,
  135.         CR0_READ_SHADOW = 0x00006004,
  136.         CR4_READ_SHADOW = 0x00006006,
  137.         CR3_TARGET_VALUE0 = 0x00006008,
  138.         CR3_TARGET_VALUE1 = 0x0000600a,
  139.         CR3_TARGET_VALUE2 = 0x0000600c,
  140.         CR3_TARGET_VALUE3 = 0x0000600e,
  141.         EXIT_QUALIFICATION = 0x00006400,
  142.         GUEST_LINEAR_ADDRESS = 0x0000640a,
  143.         GUEST_CR0 = 0x00006800,
  144.         GUEST_CR3 = 0x00006802,
  145.         GUEST_CR4 = 0x00006804,
  146.         GUEST_ES_BASE = 0x00006806,
  147.         GUEST_CS_BASE = 0x00006808,
  148.         GUEST_SS_BASE = 0x0000680a,
  149.         GUEST_DS_BASE = 0x0000680c,
  150.         GUEST_FS_BASE = 0x0000680e,
  151.         GUEST_GS_BASE = 0x00006810,
  152.         GUEST_LDTR_BASE = 0x00006812,
  153.         GUEST_TR_BASE = 0x00006814,
  154.         GUEST_GDTR_BASE = 0x00006816,
  155.         GUEST_IDTR_BASE = 0x00006818,
  156.         GUEST_DR7 = 0x0000681a,
  157.         GUEST_RSP = 0x0000681c,
  158.         GUEST_RIP = 0x0000681e,
  159.         GUEST_RFLAGS = 0x00006820,
  160.         GUEST_PENDING_DBG_EXCEPTIONS = 0x00006822,
  161.         GUEST_SYSENTER_ESP = 0x00006824,
  162.         GUEST_SYSENTER_EIP = 0x00006826,
  163.         HOST_CR0 = 0x00006c00,
  164.         HOST_CR3 = 0x00006c02,
  165.         HOST_CR4 = 0x00006c04,
  166.         HOST_FS_BASE = 0x00006c06,
  167.         HOST_GS_BASE = 0x00006c08,
  168.         HOST_TR_BASE = 0x00006c0a,
  169.         HOST_GDTR_BASE = 0x00006c0c,
  170.         HOST_IDTR_BASE = 0x00006c0e,
  171.         HOST_IA32_SYSENTER_ESP = 0x00006c10,
  172.         HOST_IA32_SYSENTER_EIP = 0x00006c12,
  173.         HOST_RSP = 0x00006c14,
  174.         HOST_RIP = 0x00006c16,
  175. };
复制代码
由于汇编里面不能直接引用cpp全局变量
这里需要一个函数得到保存虚拟机退出时的寄存器信息的地址
定义的保存寄存器信息的变量为GUEST_REGS g_GuestRegs;
在cpp代码中添加:
  1. extern "C" ULONG GetGuestRegsAddress()
  2. {
  3.          return(ULONG)&g_GuestRegs;
  4. }
复制代码

然后在asm文件中添加

GetGuestRegsAddress Proto

例子:
  1. .686p
  2. .model flat, stdcall
  3. option casemap:none
  4. GetGuestRegsAddress Proto :在这里添加
  5. VMMEntryPoint Proto
  6. .data
  7. .code
  8. …..
复制代码


这里我们要实现一个汇编函数 功能是
1.push 原始寄存器
2.保存寄存器信息到全局变量g_GuestRegs;中
3.call cpp代码中的退出事件分发函数
4.pop 原始寄存器
5.恢复原始寄存器


代码如下:
其中需要注意的是这里esp不是虚拟机的esp,是HOST机的这里需要在cpp(VMMEntryPoint的cpp)代码中重新获取
最后不是写ret 而是vmresume
  1. Asm_VMMEntryPoint Proc
  2.         cli
  3.         push eax
  4.         push ecx
  5.         push edx
  6.         push ebx
  7.         push esp     ;HOST_RSP
  8.         push ebp
  9.         push edi
  10.         push esi
  11.        
  12.         mov [esp-1280h],eax
  13.         mov [esp-1284h],ebx
  14.         call GetGuestRegsAddress
  15.         mov [eax+4h],ecx
  16.         mov [eax+8h],edx
  17.         mov [eax+0Ch],ebx
  18.         mov [eax+10h],esp
  19.         mov [eax+14h],ebp
  20.         mov [eax+18h],esi
  21.         mov [eax+1Ch],edi
  22.         mov ebx,[esp-1280h]
  23.         mov [eax],ebx
  24.         mov eax,[esp-1280h]
  25.         mov ebx,[esp-1284h]
  26.        
  27.         call VMMEntryPoint
  28.        
  29.         pop esi
  30.         pop edi
  31.         pop ebp
  32.         pop esp
  33.         pop ebx
  34.         pop edx
  35.         pop ecx
  36.         pop eax
  37.        
  38.         call GetGuestRegsAddress
  39.         mov ecx,[eax+4h]
  40.         mov edx,[eax+8h]
  41.         mov ebx,[eax+0Ch]
  42.         mov esp,[eax+10h]
  43.         mov ebp,[eax+14h]
  44.         mov esi,[eax+18h]
  45.         mov edi,[eax+1Ch]
  46.         mov eax,[eax]
  47.         sti
  48.         vmresume
  49. Asm_VMMEntryPoint Endp
复制代码
VMMEntryPoint 的Cpp代码实现(也就是汇编代码里call的那个):
  1. extern "C" void VMMEntryPoint()
  2. {
  3.         ULONG ExitReason;                                        //退出事件类型
  4.         ULONG ExitInstructionLength;                //退出事件时的代码的长度 用于后面恢复时跳过
  5.         ULONG GuestResumeEIP;                        //虚拟机恢复时的EIP
  6.         ExitReason = Vmx_VmRead(VM_EXIT_REASON);  //通过Vmx_VmRead(VM_EXIT_REASON)得到退出事件类型
  7.         ExitInstructionLength = Vmx_VmRead(VM_EXIT_INSTRUCTION_LEN); //得到产生退出事件时代码的长度 用于恢复
  8.         g_GuestRegs.esp = Vmx_VmRead(GUEST_RSP); //前面说过esp要重新获取
  9.         g_GuestRegs.eip = Vmx_VmRead(GUEST_RIP); //得到产生退出事件时的EIP
  10.         g_GuestRegs.cr3 = Vmx_VmRead(GUEST_CR3); //得到产生退出事件时的CR3 用于处理CR ACCESS(必须处理的)
  11.         switch(ExitReason)
  12.         {
  13.         case EXIT_REASON_CPUID: //如果是调用了CPUID
  14.                 {
  15.                         HandleCPUID();
  16.                         break;
  17.                 }
  18.         case EXIT_REASON_INVD://如果是INVD 不知道干什么的 但必须处理
  19.                 {
  20.                         HandleInvd();
  21.                         break;
  22.                 }
  23.         case EXIT_REASON_VMCALL: //处理VMCALL 可能存在多个VT 关闭虚拟机
  24.                 {
  25.                         HandleVmCall();
  26.                         break;
  27.                 }
  28.         case EXIT_REASON_MSR_READ: //MSR READ
  29.                 {
  30.                         HandleMsrRead();
  31.                         break;
  32.                 }
  33.         case EXIT_REASON_MSR_WRITE: // MSR WRITR
  34.                 {
  35.                         HandleMsrWrite();
  36.                         break;
  37.                 }
  38.         case EXIT_REASON_CR_ACCESS: //CR_ACCESS
  39.                 {
  40.                         HandleCrAccess();
  41.                         break;
  42.                 }
  43.         default:
  44.                 break;
  45.         }
  46. //如果不是上面的就恢复
  47. Resume:
  48.         GuestResumeEIP = g_GuestRegs.eip+ExitInstructionLength;
  49.         Vmx_VmWrite(GUEST_RIP,GuestResumeEIP);
  50.         Vmx_VmWrite(GUEST_RSP,g_GuestRegs.esp);
  51. }
复制代码
各个处理函数的实现 :这里只实现必须要处理的 其它请自己研究
  1. //CPUID的处理函数
  2. void HandleCPUID()
  3. {
  4. //如果是我们的
  5.         if (g_GuestRegs.eax == 'Mini')
  6.         {
  7.                 g_GuestRegs.ebx = 0x88888888;
  8.                 g_GuestRegs.ecx = 0x11111111;
  9.                 g_GuestRegs.edx = 0x12345678;
  10.         }//不是我们的就让CPU模拟执行后返回 x86下 nfn保存在eax中
  11.         else Asm_CPUID(g_GuestRegs.eax,&g_GuestRegs.eax,&g_GuestRegs.ebx,&g_GuestRegs.ecx,&g_GuestRegs.edx);
  12. }
  13. // Invd处理函数
  14. void HandleInvd()
  15. {
  16.         Asm_Invd();
  17. }
  18. //VMCall处理函数 未写完待续
  19. void HandleVmCall()
  20. {
  21.         if (g_GuestRegs.eax == 'SVT')
  22.         {
  23.                 Vmx_VmxOff();
  24.                
  25.                 // ......
  26.         }
  27. }
  28. //MSR Read 必须处理三个 MSR_IA32_SYSENTER_CS: MSR_IA32_SYSENTER_ESP: MSR_IA32_SYSENTER_EIP;
  29. 其中有意思的是MSR_IA32_SYSENTER_EIP 这个就是x86下KiFastCallEntry 看雪开学的一份OD插件中就是修改了此处
  30. void HandleMsrRead()
  31. {
  32.         switch(g_GuestRegs.ecx)
  33.         {
  34.         case MSR_IA32_SYSENTER_CS:
  35.                 {
  36.                         g_GuestRegs.eax = Vmx_VmRead(GUEST_SYSENTER_CS);
  37.                         break;
  38.                 }
  39.         case MSR_IA32_SYSENTER_ESP:
  40.                 {
  41.                         g_GuestRegs.eax = Vmx_VmRead(GUEST_SYSENTER_ESP);
  42.                         break;
  43.                 }
  44.         case MSR_IA32_SYSENTER_EIP:        // KiFastCallEntry
  45.                 {
  46.                         g_GuestRegs.eax = Vmx_VmRead(GUEST_SYSENTER_EIP);
  47.                         break;
  48.                 }
  49.         default:
  50.                 g_GuestRegs.eax = Asm_ReadMsr(g_GuestRegs.ecx);
  51.         }
  52. }
  53. //Msr Write 也必须处理三个 可能有误
  54. void HandleMsrWrite()
  55. {
  56.         switch(g_GuestRegs.ecx)
  57.         {
  58.         case MSR_IA32_SYSENTER_CS:
  59.                 {
  60.                         Vmx_VmWrite(GUEST_SYSENTER_CS,g_GuestRegs.eax);
  61.                         break;
  62.                 }
  63.         case MSR_IA32_SYSENTER_ESP:
  64.                 {
  65.                         Vmx_VmWrite(GUEST_SYSENTER_ESP,g_GuestRegs.eax);
  66.                         break;
  67.                 }
  68.         case MSR_IA32_SYSENTER_EIP:        // KiFastCallEntry
  69.                 {
  70.                         Vmx_VmWrite(GUEST_SYSENTER_EIP,g_GuestRegs.eax);
  71.                         break;
  72.                 }
  73.         default:
  74.                 Asm_WriteMsr(g_GuestRegs.ecx,g_GuestRegs.eax,g_GuestRegs.edx);
  75.         }
  76. }
  77. /*
  78. ?        CR Access:
  79.         退出事件条件:
  80.         ExitQualification = Vmx_VmRead(EXIT_QUALIFICATION) ;
  81.         控制寄存器,我们只要处理CR3就可以了:
  82.         movcrControlRegister = ( ExitQualification & 0x0000000F );
  83.         操作类型,0为写入 1为读取
  84.         movcrAccessType = ( ( ExitQualification & 0x00000030 ) >> 4 );
  85.         操作数类型,一般为0:
  86.         movcrOperandType = ( ( ExitQualification & 0x00000040 ) >> 6 );
  87.         目的寄存器:
  88.         movcrGeneralPurposeRegister = ( ( ExitQualification & 0x00000F00 ) >> 8 );
  89.         movcrControlRegister= 3 且movcrAccessType = 0时为写入到CR3
  90.         movcrControlRegister= 3 且movcrAccessType = 1时为从CR3读出到寄存器
  91.         movcrGeneralPurposeRegister
  92.         0=eax 1=ecx 2=edx 3=edx 4=esp 5=ebp 6=esi 7=edi
  93. */
  94. void HandleCrAccess()
  95. {
  96.         ULONG                movcrControlRegister;
  97.         ULONG                movcrAccessType;
  98.         ULONG                movcrOperandType;
  99.         ULONG                movcrGeneralPurposeRegister;
  100.         ULONG                movcrLMSWSourceData;
  101.         ULONG                ExitQualification;
  102.         ExitQualification = Vmx_VmRead(EXIT_QUALIFICATION) ;
  103.         movcrControlRegister = ( ExitQualification & 0x0000000F );
  104.         movcrAccessType = ( ( ExitQualification & 0x00000030 ) >> 4 );
  105.         movcrOperandType = ( ( ExitQualification & 0x00000040 ) >> 6 );
  106.         movcrGeneralPurposeRegister = ( ( ExitQualification & 0x00000F00 ) >> 8 );
  107.         //        Control Register Access (CR3 <-- reg32)
  108.         //
  109.         if( movcrControlRegister == 3 && movcrAccessType == 0 && movcrOperandType == 0 && movcrGeneralPurposeRegister == 0 )
  110.         {
  111.                 Vmx_VmWrite( GUEST_CR3, g_GuestRegs.eax );
  112.         }
  113.         if( movcrControlRegister == 3 && movcrAccessType == 0 && movcrOperandType == 0 && movcrGeneralPurposeRegister == 1 )
  114.         {
  115.                 Vmx_VmWrite( GUEST_CR3, g_GuestRegs.ecx );
  116.         }
  117.         if( movcrControlRegister == 3 && movcrAccessType == 0 && movcrOperandType == 0 && movcrGeneralPurposeRegister == 2 )
  118.         {
  119.                 Vmx_VmWrite( GUEST_CR3, g_GuestRegs.edx );
  120.         }
  121.         if( movcrControlRegister == 3 && movcrAccessType == 0 && movcrOperandType == 0 && movcrGeneralPurposeRegister == 3 )
  122.         {
  123.                 Vmx_VmWrite( GUEST_CR3, g_GuestRegs.ebx );
  124.         }
  125.         if( movcrControlRegister == 3 && movcrAccessType == 0 && movcrOperandType == 0 && movcrGeneralPurposeRegister == 4 )
  126.         {
  127.                 Vmx_VmWrite( GUEST_CR3, g_GuestRegs.esp );
  128.         }
  129.         if( movcrControlRegister == 3 && movcrAccessType == 0 && movcrOperandType == 0 && movcrGeneralPurposeRegister == 5 )
  130.         {
  131.                 Vmx_VmWrite( GUEST_CR3, g_GuestRegs.ebp );
  132.         }
  133.         if( movcrControlRegister == 3 && movcrAccessType == 0 && movcrOperandType == 0 && movcrGeneralPurposeRegister == 6 )
  134.         {
  135.                 Vmx_VmWrite( GUEST_CR3, g_GuestRegs.esi );
  136.         }
  137.         if( movcrControlRegister == 3 && movcrAccessType == 0 && movcrOperandType == 0 && movcrGeneralPurposeRegister == 7 )
  138.         {
  139.                 Vmx_VmWrite( GUEST_CR3, g_GuestRegs.edi );
  140.         }
  141.         //        Control Register Access (reg32 <-- CR3)
  142.         //
  143.         if( movcrControlRegister == 3 && movcrAccessType == 1 && movcrOperandType == 0 && movcrGeneralPurposeRegister == 0 )
  144.         {
  145.                 g_GuestRegs.eax = g_GuestRegs.cr3;
  146.         }
  147.         if( movcrControlRegister == 3 && movcrAccessType == 1 && movcrOperandType == 0 && movcrGeneralPurposeRegister == 1 )
  148.         {
  149.                 g_GuestRegs.ecx = g_GuestRegs.cr3;
  150.         }
  151.         if( movcrControlRegister == 3 && movcrAccessType == 1 && movcrOperandType == 0 && movcrGeneralPurposeRegister == 2 )
  152.         {
  153.                 g_GuestRegs.edx = g_GuestRegs.cr3;
  154.         }
  155.         if( movcrControlRegister == 3 && movcrAccessType == 1 && movcrOperandType == 0 && movcrGeneralPurposeRegister == 3 )
  156.         {
  157.                 g_GuestRegs.ebx = g_GuestRegs.cr3;
  158.         }
  159.         if( movcrControlRegister == 3 && movcrAccessType == 1 && movcrOperandType == 0 && movcrGeneralPurposeRegister == 4 )
  160.         {
  161.                 g_GuestRegs.esp = g_GuestRegs.cr3;
  162.         }
  163.         if( movcrControlRegister == 3 && movcrAccessType == 1 && movcrOperandType == 0 && movcrGeneralPurposeRegister == 5 )
  164.         {
  165.                 g_GuestRegs.ebp = g_GuestRegs.cr3;
  166.         }
  167.         if( movcrControlRegister == 3 && movcrAccessType == 1 && movcrOperandType == 0 && movcrGeneralPurposeRegister == 6 )
  168.         {
  169.                 g_GuestRegs.esi = g_GuestRegs.cr3;
  170.         }
  171.         if( movcrControlRegister == 3 && movcrAccessType == 1 && movcrOperandType == 0 && movcrGeneralPurposeRegister == 7 )
  172.         {
  173.                 g_GuestRegs.edi = g_GuestRegs.cr3;
  174.         }  
  175. }
复制代码
下一章将讲VMCS表填写


   





点击按钮快速添加回复内容: 支持 高兴 激动 给力 加油 苦寻 生气 回帖 路过 感恩
您需要登录后才可以回帖 登录 | 注册账号

本版积分规则

小黑屋|手机版|Archiver|看流星社区 |网站地图

GMT+8, 2024-4-23 18:03

Powered by Kanliuxing X3.4

© 2010-2019 kanliuxing.com

快速回复 返回顶部 返回列表