这篇博客说说一个安全防护系统完备性上所需的一个小原则:防护系统与被防护对象所用资源的完全隔离,包括防护系统自身工作所依赖的资源不能依赖被防护对象。听起来是原理很简单的一个点,实现中往往很复杂。例如操作系统隔离应用程序、虚拟机监视器隔离客户机,需要考虑方方面面、还需要处理器/芯片组硬件的大量支持。分析、设计系统时遵循许多这类小原则是必要的。

记得好像是06年的时候吧,Joanna团队在Blackhat上推出了一个基于硬件虚拟化的rootkit样本,取名Blue Pill,07年又出了改进的新版New Blue Pill。这个样本并没有任何实质的恶意行为,仅仅是一个最有名气的利用硬件虚拟化支持的原型系统。这回的话题就拿它来做例子说说,从相反的方向介绍这个原则的必要性。

New Blue Pill作为一个驱动程序加载后,沉淀下去,利用硬件虚拟化支持将原本的操作系统置入客户机中运行,其自身则以虚拟机监视器的形态存在。它的目的是展示一个利用硬件虚拟化技术的rootkit,和一些利用了硬件虚拟化支持的程序(如某些调试器)一样,它是不完备的,我们可以较为简单的检测它、脱离它的控制。阅读过new blue pill源代码的同学们很容易回忆起来,这个虚拟机监视器工作所需的不少资源都没有有效保护、客户机软件可随意访问修改,其中一个很重要的就是物理内存资源。BluePill的内存保护仅仅是虚拟内存隐藏,原理见Joanna所绘图示(图1)。其虚拟机监视器有自己的私有页表,同时将客户机操作系统所用页表中对自己的映射处理掉,因此客户机中的软件想直接访问虚拟机监视器的虚存页面自然不行。

这样的虚拟内存保护有多大作用呢,因为客户机和虚拟机监视器的物理内存资源并没有有效隔离,不符合原则,所以效果只能说是聊胜于无。客户机内的软件可以轻松访问虚拟机监视器的物理内存,篡改虚拟机监视器代码数据乃至完全突破使客户机原操作系统重回Host环境(如VMX Root)运行。下面的内容阅读前需要预先熟悉一些Intel64体系结构、Windows内核上的一些知识。

先设计一个非常简单的物理内存访问库(工作于Win7 X64系统),原理为修改事先分配的NonPagedPool页所对应的PTE,使该线性地址可以用来依次映射我们指定的物理内存页面。注意x64系统如此分配一般获得一个在大页面中的线性地址,所以需要重新映射一下,以便得到可供修改的4K页对应的PTE;另外要注意的是这个映射方案是演示用的、很粗糙的,不应随意用该PTE去映射已被以NonCached等类型映射的物理空间,如外设的IO映射地址空间。

001 typedef struct _MAP_STRUCT {
002     PVOID OrigPage;
003     PVOID MapPage;
004     PMDL Mdl;
005     PHYSICAL_ADDRESS MapPagePhys;
006 } MAP_STRUCT, *PMAP_STRUCT;
007  
008 #define VIRTUAL_ADDRESS_BITS 48
009 #define VIRTUAL_ADDRESS_MASK ((((ULONG_PTR)1) << VIRTUAL_ADDRESS_BITS) - 1)
010  
011 #define PTE_BASE          0xFFFFF68000000000UI64
012  
013 #define PTI_SHIFT 12
014 #define PDI_SHIFT 21
015 #define PPI_SHIFT 30
016 #define PXI_SHIFT 39
017  
018 #define PTE_SHIFT 3
019  
020 #define _HARDWARE_PTE_WORKING_SET_BITS  11
021  
022 typedef struct _MMPTE {
023     ULONGLONG Valid : 1;
024     ULONGLONG Writable : 1;        // changed for MP version
025     ULONGLONG Owner : 1;
026     ULONGLONG WriteThrough : 1;
027     ULONGLONG CacheDisable : 1;
028     ULONGLONG Accessed : 1;
029     ULONGLONG Dirty : 1;
030     ULONGLONG LargePage : 1;
031     ULONGLONG Global : 1;
032     ULONGLONG CopyOnWrite : 1; // software field
033     ULONGLONG Prototype : 1;   // software field
034     ULONGLONG Write : 1;       // software field - MP change
035     ULONGLONG PageFrameNumber : 28;
036     ULONG64 reserved1 : 24 - (_HARDWARE_PTE_WORKING_SET_BITS+1);
037     ULONGLONG SoftwareWsIndex : _HARDWARE_PTE_WORKING_SET_BITS;
038     ULONG64 NoExecute : 1;
039 } MMPTE, *PMMPTE;
040  
041 #define MiGetPteAddress(va) \
042     ((PMMPTE)(((((ULONG_PTR)(va) & VIRTUAL_ADDRESS_MASK) >> PTI_SHIFT) << PTE_SHIFT) + PTE_BASE))
043  
044 NTSTATUS
045 InitMapPage(
046     OUT PMAP_STRUCT MapHandle
047     )
048 {
049     NTSTATUS Status = STATUS_SUCCESS;
050     PMMPTE pte;
051  
052     RtlZeroMemory(MapHandle, sizeof(*MapHandle));
053  
054     try {
055  
056         MapHandle->OrigPage = ExAllocatePool(NonPagedPool,
057                                              PAGE_SIZE);
058  
059         if (MapHandle->OrigPage == NULL)
060         {
061             Status = STATUS_INSUFFICIENT_RESOURCES;
062             leave;
063         }
064  
065         MapHandle->Mdl = IoAllocateMdl(MapHandle->OrigPage,
066                                        PAGE_SIZE,
067                                        FALSE,
068                                        FALSE,
069                                        NULL);
070  
071         if (MapHandle->Mdl == NULL)
072         {
073             Status = STATUS_INSUFFICIENT_RESOURCES;
074             leave;
075         }
076  
077         //
078         // Remap
079         //
080  
081         MapHandle->MapPage = MmMapLockedPagesSpecifyCache(MapHandle->Mdl,
082                                                           KernelMode,
083                                                           MmCached,
084                                                           NULL,
085                                                           FALSE,
086                                                           HighPagePriority);
087  
088         if (MapHandle->MapPage == NULL)
089         {
090             Status = STATUS_INSUFFICIENT_RESOURCES;
091             leave;
092         }
093  
094         pte = MiGetPteAddress(MapHandle->MapPage);
095  
096         MapHandle->MapPagePhys.QuadPart = *(PULONGLONG)pte;
097  
098     } finally {
099  
100         if (!NT_SUCCESS(Status))
101         {
102             if (MapHandle->Mdl != NULL)
103             {
104                 IoFreeMdl(MapHandle->Mdl);
105             }
106  
107             if (MapHandle->OrigPage != NULL)
108             {
109                 ExFreePool(MapHandle->OrigPage);
110             }
111         }
112     }
113  
114     return Status;
115 }
116  
117 PVOID
118 MapSpecifiedPage(
119     IN PMAP_STRUCT MapHandle,
120     IN PHYSICAL_ADDRESS PhysicalAddress
121     )
122 {
123     PMMPTE pte = MiGetPteAddress(MapHandle->MapPage);
124  
125     pte->PageFrameNumber = PhysicalAddress.QuadPart >> 12;
126  
127     _ReadWriteBarrier();
128  
129     __invlpg(MapHandle->MapPage);
130  
131     return MapHandle->MapPage;
132 }
133  
134 VOID
135 FiniMapPage(
136     IN PMAP_STRUCT MapHandle
137     )
138 {
139     PMMPTE pte = MiGetPteAddress(MapHandle->MapPage);
140  
141     pte->PageFrameNumber = MapHandle->MapPagePhys.QuadPart >> 12;
142  
143     MmUnmapLockedPages(MapHandle->MapPage, MapHandle->Mdl);
144  
145     IoFreeMdl(MapHandle->Mdl);
146  
147     ExFreePool(MapHandle->OrigPage);
148 }

然后下面的程序片段基于这个访问库,搜索当前Intel Core i3 CPU所关联的VMCS,顺便打印了其中的一些由New Blue Pill事先填充的数据:

01 {
02     ……
03  
04     PhysicalMemoryBlock = MmGetPhysicalMemoryRanges();
05  
06     if (PhysicalMemoryBlock == NULL)
07     {
08         return STATUS_INSUFFICIENT_RESOURCES;
09     }
10  
11     Status = InitMapPage(&MapHandle);
12  
13     if (!NT_SUCCESS(Status))
14     {
15         ExFreePool(PhysicalMemoryBlock);
16  
17         return Status;
18     }
19  
20     i = 0;
21  
22     while (PhysicalMemoryBlock[i].NumberOfBytes.QuadPart != 0)
23     {
24         PHYSICAL_ADDRESS BaseAddress = PhysicalMemoryBlock[i].BaseAddress;
25         LARGE_INTEGER NumberOfBytes = PhysicalMemoryBlock[i].NumberOfBytes;
26  
27         DbgPrint("BaseAddress: %I64x\n", BaseAddress.QuadPart);
28         DbgPrint("NumberOfBytes: %I64x\n", NumberOfBytes.QuadPart);
29  
30         while (NumberOfBytes.QuadPart > 0)
31         {
32             MapAddress = (PUCHAR)MapSpecifiedPage(&MapHandle, BaseAddress);
33  
34             if (MapAddress != NULL)
35             {
36                 //
37                 // 偏移依赖处理器实现,这里是Intel Core i3.
38                 // 部分硬编码依赖nbp
39                 //
40  
41                 if (*(PULONG)MapAddress == 0x10 &&                 // VMCS revision identifier
42                     *(PULONG)(MapAddress + 0x2D0) == 0x7F &&      // Guest GDTR limit
43                     *(PULONG)(MapAddress + 0x2D4) == 0xFFF &&     // Guest IDTR limit
44                     *(PULONGLONG)(MapAddress + 0x358) == __readmsr(0xc0000101)) // Host GS base
45                 {
46                     //
47                     // Vmcs for current cpu.
48                     //
49  
50                     DbgPrint("VMCS: %I64x\n", MapAddress);
51                     DbgPrint("VMCS Host RIP: %I64x\n",
52                              *(PULONGLONG)(MapAddress + 0x390));
53                     DbgPrint("VMCS Host GDTR Base: %I64x\n",
54                              *(PULONGLONG)(MapAddress + 0x368));
55                     DbgPrint("VMCS Host IDTR Base: %I64x\n",
56                              *(PULONGLONG)(MapAddress + 0x370));
57                 }
58             }
59  
60             BaseAddress.QuadPart += PAGE_SIZE;
61             NumberOfBytes.QuadPart -= PAGE_SIZE;
62         }
63  
64         i ++;
65     }
66  
67     FiniMapPage(&MapHandle);
68  
69     ExFreePool(PhysicalMemoryBlock);
70  
71 ……
72 }

程序debug输出如图2。

拿到这些信息,怎么制作“Red Pill”跳出被硬件虚拟化监控的状态就非常简单了,举个例子——比如首先可以通过Host CR3查找、修改Host页表映射加入我们的代码物理页(当然也可以直接利用Host中已经被映射的物理页面);随后通过修改VmxVmexitHandler(图中VMCS Host RIP所指)代码或者直接替换每个VMCS的Host RIP,在合适的VM Exit时获得Host上的运行权;最后利用获得的信息修改CPU各寄存器并转移到正确位置执行。具体代码就不贴了,有兴趣的同学可以试试。完成了这些,也就突破了nbp的限制。故以nbp的需求而言,它至少要管理完整的客户页表结构(构建Shadow Page Table或使用EPT/NPT)。

反过来,我们设计虚拟化系统或是其它安防系统,就要认真思考完备性的一些原则,才有做到滴水不漏的可能。当然了这类原则也不需要无限制扩大,例如为安全卫士设计硬件虚拟化辅助的需求,其主要是以扩充X64系统安全防护能力为目标,例如使得64位windows上的卫士软件不受PatchGuard限制,获得类似32位一样的拦截、防护能力。因此不仅无需提供物理内存防护,还要从保障性能方面考虑尽量减少不必要的#VMEXIT。

从Blue Pill、硬件虚拟化谈安全防护完备性上的一个小原则相关推荐

  1. 度娘计算机cpu,CPU硬件虚拟化技术和360“核晶防护引擎”(进一步强化电脑性能)...

    关于CPU的硬件虚拟化技术(VT) CPU硬件虚拟化技(VT)术在两家CPU厂商的叫法不同,英特尔方面叫作 Intel-VT,AMD方面叫作 AMD-VT 简单讲,硬件虚拟化技术(以下简称VT)可以让 ...

  2. ARMv8架构下修改Linux内核并打开kvm硬件虚拟化支持(平台Firefly-rk3568)

    前言 在做的一个项目需要使用ARMv8的硬件虚拟化支持,而购买的Firefly-3568默认的操作系统内核没有打开kvm虚拟化支持,所以尝试重新编译了一下内核开启虚拟化支持,并将遇到的问题和一些解决方 ...

  3. blue pill Flash 128KB的传言

    有传言说,部分F103C8的Flash容量是128KB.用ST-Link Utility检查了一下,此言非虚.一款黑色的小板,Flash为官方标称的64KB:blue pill则显示确为128KB.意 ...

  4. virtualbox禁用硬件虚拟化_Mac版Virtualbox6.1开启嵌套虚拟化

    Virtualbox从6.0版本后,支持起了Intel cpu的嵌套虚拟化.很多用Virtualbox的朋友开始陷入了茫然,为何在BIOS或EFI中开启了CPU硬件虚拟化后,Virtualbox中的v ...

  5. 虚拟机如何支持硬件虚拟化

    虚拟机如何支持硬件虚拟化        配置:联想T440P,i7CPU,支持VT-x(硬件虚拟化技术),BIOS中已经打开虚拟化选项     系统:64位Win8     软件:VirtualBox ...

  6. 23. 硬件虚拟化技术分享

    前段时间在梳理一些概念时,突然对虚拟化有一种新的认识,之后再去了解相关的概念或技术,能够推测某个技术是为了解决什么问题和如何实现的. 本文将对硬件虚拟化及其相关逻辑进行罗列,可能会对理解虚拟化有一些帮 ...

  7. 虚拟机安装kvm,bios已经开启硬件虚拟化功能,仍显示不支持硬件虚拟化

    在Linux虚拟机上安装kvm,要检查硬件是否支持硬件虚拟化功能. 首先在BIOS中启动硬件虚拟化功能,发现仍然不支持 网上找了很久之后发现虚拟机设置的时候要开虚拟化引擎

  8. virtualbox 硬件加速配置页中已启用硬件虚拟化,但主机并不支持。需要禁用硬件虚拟化才能启动虚拟机

    错误:virtualbox 硬件加速配置页中已启用硬件虚拟化,但主机并不支持.需要禁用硬件虚拟化才能启动虚拟机 解决办法: 选择[系统] 硬件加速 去掉勾选 保存 即可

  9. mac如何启用cpu虚拟化_如何查看自己的电脑 CPU 是否支持硬件虚拟化 - Binge-和时间做朋友...

    引言 在你安装各种虚拟机之前,应该先测试一下自己的电脑 CPU 是否支持硬件虚拟化. 如果你的电脑比较老旧,可能不支持硬件虚拟化,那么将无法安装虚拟机软件. 如何查看自己 CPU 是否支持硬件虚拟化 ...

最新文章

  1. Failed to register Grid Infrastructure type ora.mdns.type
  2. numpy permutation排列组合方法
  3. Centos下Yum安装PHP5.5,5.6
  4. cli3暴露api地址 vue_手把手教你开发 Vue 组件库
  5. vlfeat 特征检测
  6. 力扣刷题心得(设计类题目)
  7. 焊接空间臂_焊接烟尘净化器设备哪种好
  8. 【论文翻译】HeteSim:异构网络中相关性度量的通用框架
  9. Java学习笔记--导航
  10. DataTable的Merge方法和添加datatable到dataset
  11. svn导出项目到myeclipse,运行报ClassNotFoundException
  12. python百分号字符串_python--003--百分号字符串拼接、format
  13. 【Redis 开发与运维】初识 Redis
  14. 启用计算机并口,电脑并口被禁用怎么办
  15. jsp网页视频播放器
  16. 目标检测中PR曲线和mAP
  17. Alpaca 凭什么成为 BSC 第三大协议?
  18. 三种代码生成炫酷代码雨(推荐)
  19. php货币符号怎么打,Magento修改货币符号和货币符号的位置
  20. 全网首发!老大众奥迪碟盒通信协议破解,可以模拟数码碟盒,外接AUX蓝牙U盘等音频设备

热门文章

  1. jquery---基本标签
  2. 树莓派学习笔记(6):让Raspbian支持中文、禁用休眠
  3. PostgreSQL学习手册(四) 常用数据类型
  4. 使用Axis开发Web Service程序
  5. VMware View是如何帮助企业省钱的
  6. u-boot-1.3.4移植到mini2440+128M nand boot(3)
  7. CentOS系统更换软件安装源yum
  8. Windows系统安装改磁盘格式
  9. python中的reduce、lambda函数
  10. 《Imperfect C++中文版》——第2章 对象生命期