06_基本框架_VMCS_GuestArea
阅读原文时间:2023年07月15日阅读:1

1 Guest-State Area

注释:

其实 内容很多 一般是不背 的;需要的时候来查就行;但是要大致知道是做啥的。

代码

》 设置 Guest Area

// 设置GUEST

// 当尝试执行 VM_Guest 出错的时候,会调用VM_Exit.
Vmx_VmWrite(GUEST_CR0, Asm_GetCr0());
Vmx_VmWrite(GUEST_CR3, Asm_GetCr3());
Vmx_VmWrite(GUEST_CR4, Asm_GetCr4());

Vmx_VmWrite(GUEST_DR7, 0x400);
Vmx_VmWrite(GUEST_RFLAGS, Asm_GetEflags() & ~0x200);//cli

Vmx_VmWrite(GUEST_ES_SELECTOR, Asm_GetEs() & 0xFFF8);
Vmx_VmWrite(GUEST_CS_SELECTOR, Asm_GetCs() & 0xFFF8);
Vmx_VmWrite(GUEST_DS_SELECTOR, Asm_GetDs() & 0xFFF8);
Vmx_VmWrite(GUEST_FS_SELECTOR, Asm_GetFs() & 0xFFF8);
Vmx_VmWrite(GUEST_GS_SELECTOR, Asm_GetGs() & 0xFFF8);
Vmx_VmWrite(GUEST_SS_SELECTOR, Asm_GetSs() & 0xFFF8);
Vmx_VmWrite(GUEST_TR_SELECTOR, Asm_GetTr() & 0xFFF8);

Vmx_VmWrite(GUEST_ES_AR_BYTES, 0x10000);// 设置成不可用;然后进入GuestEntry 刷新
Vmx_VmWrite(GUEST_FS_AR_BYTES, 0x10000);
Vmx_VmWrite(GUEST_DS_AR_BYTES, 0x10000);
Vmx_VmWrite(GUEST_SS_AR_BYTES, 0x10000);
Vmx_VmWrite(GUEST_GS_AR_BYTES, 0x10000);
Vmx_VmWrite(GUEST_LDTR_AR_BYTES, 0x10000);

Vmx_VmWrite(GUEST_CS_AR_BYTES, 0xc09b);// CS 和 TR 不能 像 前面一样设置成不可用,然后进入GuestEntry 刷新;因为GuestEntry以来CS和TR
Vmx_VmWrite(GUEST_CS_BASE, );// 所以需要手动设置。
Vmx_VmWrite(GUEST_CS_LIMIT, 0xffffffff);

Vmx_VmWrite(GUEST_TR_AR_BYTES, 0x008b);
Vmx_VmWrite(GUEST_TR_BASE, 0x80042000);
Vmx_VmWrite(GUEST_TR_LIMIT, 0x20ab);


Vmx_VmWrite(GUEST_GDTR_BASE, GdtBase);
Vmx_VmWrite(GUEST_GDTR_LIMIT, Asm_GetGdtLimit());
Vmx_VmWrite(GUEST_IDTR_BASE, IdtBase);
Vmx_VmWrite(GUEST_IDTR_LIMIT, Asm_GetIdtLimit());

Vmx_VmWrite(GUEST_IA32_DEBUGCTL, Asm_ReadMsr(MSR_IA32_DEBUGCTL)&0xFFFFFFFF);
Vmx_VmWrite(GUEST_IA32_DEBUGCTL_HIGH, Asm_ReadMsr(MSR_IA32_DEBUGCTL)>>);

Vmx_VmWrite(GUEST_SYSENTER_CS, Asm_ReadMsr(MSR_IA32_SYSENTER_CS)&0xFFFFFFFF);
Vmx_VmWrite(GUEST_SYSENTER_ESP, Asm_ReadMsr(MSR_IA32_SYSENTER_ESP)&0xFFFFFFFF);
Vmx_VmWrite(GUEST_SYSENTER_EIP, Asm_ReadMsr(MSR_IA32_SYSENTER_EIP)&0xFFFFFFFF); // KiFastCallEntry

Vmx_VmWrite(GUEST_RSP, ((ULONG)g_VMXCPU.pStack) + 0x1000); //Guest 临时栈
Vmx_VmWrite(GUEST_RIP, (ULONG)GuestEntry); // 客户机的入口点

Vmx_VmWrite(VMCS_LINK_POINTER, 0xffffffff);// referrence volume 3. 24.10

Vmx_VmWrite(VMCS_LINK_POINTER_HIGH, 0xffffffff);

》 设置 入口函数(例程)

void _declspec(naked) GuestEntry(void)

{
__asm{
  mov ax, es// 刷新VM 的selector 背后的数据
  mov es, ax

  mov ax, ds
  mov ds, ax

  mov ax, fs
12   mov fs, ax

14   mov ax, gs
  mov gs, ax

  mov ax, ss
  mov ss, ax

  //int 3; WARNING!!! HERE CAN'T USE INT3!!
  }
  Vmx_VmCall();
23 }

》修改 EXIT 函数以 便于查看 EXIT信息

static void VMMEntryPointEbd(void)

{
  ULONG ExitReason;
  ExitReason = Vmx_VmRead(VM_EXIT_REASON);
  g_GuestRegs.esp = Vmx_VmRead(GUEST_RSP);
  g_GuestRegs.eip = Vmx_VmRead(GUEST_RIP);
  Log("g_GuestRegs.eip:",g_GuestRegs.eip);
  __asm int ;// Interrupt Here;Give the chance to view the Info
}

void __declspec(naked) VMMEntryPoint(void)
// 注意: 1. 裸函数里面不要用局部变量;因为使用到ebp;而裸函数不维护,如果手动维护,那么和普通函数有什么却别;
//     2. 裸函数 是为了我们更好的控制进来那一刻 寄存器等的 获取、设置
//     3. 裸函数 最好不要太冗余;所以 有很多操作的话,最好 另外封装一个函数,在裸函数中调用即可。(这里封装了VMMEntryPointEbd()函数)
{
//     Refresh selector -- >underneath part-- gdtinfo;
//     do Exchange itself can refresh the VM TLB when selector right ;
__asm{
    mov ax,fs;
    mov fs,ax;

    mov ax,gs;
    mov gs,ax;

  }

// Call the Func to show the ExitReason and regs!
  VMMEntryPointEbd();

}

从开始 到现在所实现的阶段性代码 我放在了github 上面有需要的可以参考这里的代码:https://github.com/leibso/VT-learning/tree/05_Fields_Area(环境 vs 2010),

测试代码:

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器