强大的硬件虚拟化

一、vt核心vmcs

前几篇介绍了vt强大的无察觉劫持页表hook的能力,kvm的大致原理,但vt的能力远远不止于此。因为实现vt托管的操作系统,将可以做到指令级的管控。甚至直接基于vt形成调试器,如果用来调试内核,将会大大提高稳定性。整个vt核心全部位于vmcs的 状态域。根据intel 开发手册第三卷,控制域的核心部分分为1.guest field ,.2 host field , 3.vm-excution control field, 4.vm-Exit control field, 5.vm Entry control field, 6.vm-exit information fields, 7.VMCS types
这几部分我做简要介绍,有兴趣的自行查看intel 开发手册的详细介绍。

  1. guest field
    这一部分用来设置虚拟机状态,包括中断页表寄存器栈等信息,是vt运行的虚拟状态机,也就是虚拟机状态都在这个域中设置。
  2. host field
    这一部分是托管虚拟状态机的vmm(virtual machine manager),可以称为虚拟机管理器也要设置中断页表寄存器栈等信息,因为虚拟机在退出的时候将会由VMM来处理vm-exit的各种信息,实现对虚拟机的管控。
  3. vm-excution control field
    此域掌控non-root 模式下的操作,外部中断,NMI, 内部中断,cr3 cr8寄存器的读取和写入,无条件IO退出,MSR bitmaps,激活secondary control(虚拟APIC 访问, 是能EPT), exception Bitmap, VMCS指针, EPTP(Extended-Page-Table Pointer), VM-Funtion 控制(这个用来直接非根模式触发根模式定义的行为)
  4. vm-Exit control field
    这部分设置非根模式下的guest 触发定义行为后,进入根模式的VMM处理。
  5. vm Entry control field
    这部分设置根模式下的VMM 触发定义行为后,进入非根模式的guest。
  6. vm-exit information fields
    这部分自动记录vm-exit发生的原因,用来后续处理
  7. VMCS types
    区别原始VMCS和镜像VMCS的标识

二、虚拟机启动

基于开源ksm介绍。
在这里插入图片描述
启动部分,主要是vmcs的设置,位于ksm_init。必须每个cpu分别设置VMCS,以实现每个cpu的虚拟执行。这里在用户态注册了/dev/ksm用来操作vt. 代码实现了epage hook 页表劫持的hook, 用户态沙箱, 内视引擎,idt劫持等功能。
我介绍先前三个。有个很复杂的结构体ksm vcpu,发个缩略图吧。
ksm核心结构体

三、epage hook

首先普及下EPT, 为了更高效的实现GPA到HPA的转换,intel 设计了EPT机制,当然我自己理解这个转换其实不是必须的,因为单纯的GPA足够找到物理地址,这样设计的目的还是虚拟机管控的完整性,因为经我测试,取消ept的虚拟机照样可以运行。
在这里插入图片描述
总之这个过程其实和普通的页表查询很类似,但是实现从guest 物理地址到host物理地址的转换。

EPT页表的建立流程

  1. 初始情况下:Guest CR3指向的Guest物理页面为空页面;
  2. Guest页表缺页异常,KVM采用不处理Guest页表缺页的机制,不会导致VM Exit,由Guest的缺页异常处理函数负责分配一个Guest物理页面(GPA),将该页面物理地址回填,建立Guest页表结构;
  3. 完成该映射的过程需要将GPA翻译到HPA,此时该进程相应的EPT页表为空,产生EPT_VIOLATION,虚拟机退出到根模式下执行,由KVM捕获该异常,建立该GPA到HOST物理地址HPA的映射,完成一套EPT页表的建立,中断返回,切换到非根模式继续运行。
  4. VCPU的mmu查询下一级Guest页表,根据GVA的偏移产生一条新的GPA,Guest寻址该GPA对应页面,产生Guest缺页,不发生VM_Exit,由Guest系统的缺页处理函数捕获该异常,从Guest物理内存中选择一个空闲页,将该Guest物理地址GPA回填给Guest页表;
  5. 此时该GPA对应的EPT页表项不存在,发生EPT_VIOLATION,切换到根模式下,由KVM负责建立该GPA->HPA映射,再切换回非根模式;
  6. 如此往复,直到非根模式下GVA最后的偏移建立最后一级Guest页表,分配GPA,缺页异常退出到根模式建立最后一套EPT页表。
  7. 至此,一条GVA对应在真实物理内存单元中的内容,便可通过这一套二维页表结构获得。

有了ept的概念,我们知道,GPA到HPA有ept的一重映射,那么如果我们需要无察觉的hook内存,只需要GPA 映射到新的HPA,那么页表就可实现替换,并做一定的内存检查绕过。
ksm的实现架构如下:
epage hook
ept_alloc_page就是对ept映射的改变,也是hook的核心。作者定义了一些列eptp的指针,通过以下宏进行切换。

#define EPTP_EXHOOK			0			/* hook eptp index, executable hooks only  */
#define EPTP_RWHOOK			1			/* hook eptp index, readwrite hooks, no exec  */
#define EPTP_NORMAL			2			/* sane eptp index, no hooks  */
#define EPTP_DEFAULT			EPTP_EXHOOK

原函数调用方式:

  • vcpu_vmfunc(EPTP_NORMAL, 0);
  • void *ret = MmMapIoSpace(x, y, z);
  • vcpu_vmfunc(EPTP_EXHOOK, 0);
  • return ret;

通过vmfunc实现根模式下的映射切换,便捷的实现页表切换。

四、用户态沙箱

图4.1

  1. 根据pid建立需要被隔离程序,struct sa_task。可以看到task->eptp有个初始化的过程,这个就是关键。
  2. 劫持cr vm->exit退出消息。
    图4.2
    vm_exit直接的可以获取的guest退出的类型,但是具体的退出信息还需要相应的状态域中读取。如图,vmcs_read(EXIT_QUALITICATION)获取到exit information后,通过解析域信息,获取到发生vm_exit的事件为mov to cr。然后获取寄存器号和寄存器值。这里的cr3值会被记录,如下图:
    图4.3
    之后就是访问控制,当发生特定进程的空间写操作的时候,触发ept violation:
    图4.4
    如上图4.4,沙箱会对写入的页表进行复制,写入独立的空间,也就是原来的内存会被保护起来,当操作恢复是,写入的内存可以直接丢弃恢复到原来的状态。

五、Introspect engine

这个引擎还是和ept相关,效果就是监控地址的访问。一旦发生特定地址的访问或执行,将会触发vm_exit,受到VMM的监控。
introspect engine架构
核心原理在于kms_instropct_add_watch, 通过addr->access设置访问属性,和addr->gpa访问地址。触发VMM
epte = ept_alloc_page(EPT4(ept, EPTP_DEFAULT), addr->access ^ EPT_ACCESS_ALL, mt, addr->gpa, addr->gpa);
那么ept的映射效果将是一旦在此地址发生访问或执行,VMM就可以接受到信息。从而监控特定地址的访问。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值