内存监控器(Memory Monitor)的功能是截获内核程序对内核数据的访问。由于客户虚拟机中并没有监控模块,因此底层的VMM无法感知内核程序对内核数据的访问。传统的解决方法一般采用轮询[47]或者定期将虚拟机内存倾卸(dump)[50]出来的方法,以分析特定内核数据是否被恶意篡改。然而,这种方法存在两个问题:检测攻击的实时性不强;性能开销比较明显。为了解决以上两个问题,VMhuko充分利用了虚拟化环境下页故障处理机制及操作系统的内部知识。
在硬件辅助的全虚拟化环境中(未启用硬件辅助的页表机制),虚拟机监控器采用了影子页表机制(Shadow Paging)管理客户机内存。该机制使每个虚拟机拥有两套不同的页表:客户机页表(Guest Page Table,GPT)和影子页表(Shadow Page Table,SPT)。客户机页表属于客户机操作系统,而影子页表则由虚拟机监控器控制。为了提高系统的效率,影子页表被直接加载到内存管理单元(Memory Management Unit,MMU)中。另外,为保证内存映射的正确性,虚拟机监控器必须尽可能保证GPT和SPT之间的数据同步。当发生内存页故障时,程序的执行将陷入VMM中。(https://www.xing528.com)
为了使VMhuko能实时截获内核程序对某些重要内核数据的访问,可以通过修改影子页表将这些内核数据所在的内存页置为写保护或者不存在。首先,VMhuko必须获得这些内核数据的虚拟地址,以定位SPT中的页表项。对于全局内核数据,其虚拟地址可以从目标操作系统的符号表中获得。然而对于动态内核数据结构,其虚拟地址无法事先得到。针对这个问题,VMhuko采用了一种动态定位的方法。该方法基于这样一个事实:如果把所有内核数据看作一棵树,那么根节点则是全局内核数据结构,叶子节点则是动态内核数据结构。换句话说,从全局内核数据结构出发可以遍历动态内核数据结构。以Linux系统为例,init_task是全局内核数据结构,指向进程链表的表头。通过该数据结构,操作系统就能遍历所有的进程描述符。为了截获内核程序对动态数据结构的访问,VMhuko必须将全局内核数据结构中的指针设置为受保护的内存区域。当内核程序通过这些指针访问动态内核数据时,VMhuko将截获这些操作并验证该访问是否合法。内存监控器的具体实现过程将在3.5.1节中进行讨论。
免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。
