用户
搜索

该用户从未签到

版主

推荐组组员(最帅的那个)

Rank: 7Rank: 7Rank: 7

37

主题

50

帖子

406

魔法币
收听
0
粉丝
1
注册时间
2018-4-12

i春秋推荐小组

Arizona 版主 推荐组组员(最帅的那个) i春秋推荐小组 楼主
发表于 2018-11-15 10:22:57 25298

Paging和Virtualization-第二部分

放弃

本文基于广泛的研究,我不是这一领域的专家。我唯一的目的是“ 了解虚拟化如何工作并分享它 ”。请告诉我你发现的任何错误。我会尽快纠正它。

到目前为止,我们已经讨论过处理器部分的虚拟化问题。但记忆是什么?如果一个客人可以在记忆中做有趣的事情那么游戏就结束了,不是吗?原因在于,为了解释VMM如何控制内存,我们必须看看内存是如何组织的。

大多数解释都描述了线性内存管理。因此,你有可以存储字节的单元格,并且这些单元格从0x00000000-0xFFFFFFFF索引,这些索引是CPU使用的(32位)地址。

______________ 
| |> [0x00000000] 
| | 
| | 
    ........ 
| | 
| | 
| ______________ |> [0xFFFFFFFF]

但对于大多数计算机来说这已不再适用(小型嵌入式系统有时会为了节省资源而寻址内存)。

相反,我们有一个内存管理单元(MMU),它位于CPU中并转换虚拟地址而不是物理地址(虚拟并不是指虚拟化。它只是这样称呼)。
分页是一个非常简单的概念,虽然它需要一些时间,直到你得到正确的计算部分,它感觉有点熟悉。

我们的想法是,我们需要4KB的物理内存,并将这个4KB的物理基址存储在一个表项中。
4KB称为页面。我们存储它的表称为页表(PT)。

英特尔在其手册中告诉程序员,PT可以容纳512页。512页-4KB大约是我们可以解决的2MB内存。
但是我们想要处理超过2MB的内存,因此我们将512个PT的物理基址存储到一个页面目录条目(PDE)中。每个PDE一个PTà2MB* 512 = 1GB。

每个PDE 1GB仍然不够。所以我们再做一次,取512个PDE并将这些条目的物理基地址存储到页面目录指针表条目(PDPTE)中。
因为我们可以将512个PDPTE整合到一个Page Map Level 4条目(PML4E)中。


可以读取物理地址,例如“给我内存中的0xffec1230字节”。虚拟地址改为包含不同指针表的所有索引,这些索引将MMU引导到正确的字节:

虚拟64位地址:

FLAGS | PML4 | PDPTE | PDE | PT |偏移到页面
 0000000000000000 | 000000000 | 000000000 | 000000000 | 000000000 | 000000000000 
      [16bit] | [9bit] | [9bit] | [9bit] | [9bit] | [12bit] 

(9bit编码0-511)

不要害怕,这里有一个例子:

假设我们有这个虚拟地址:0x00000000007FC031。写下来看起来像:

                            | | PML4 | PDPTE | PDE | PT |偏移到页面
二进制:0000000000000000 | 000000000 | 000000000 | 000000011 | 111111100 | 000000110001 
十进制:0 0 3 508 49

基于虚拟地址,MMU查找PML4中的第一个条目(索引为0)。
这个包含一个指向PDPT的物理地址。
它再次跟随PD的第一个条目中的指针。
在该PD中,它选择第四个PT。
在PT中,它在第509个条目处查找指针。
最后,最后一个指针将MMU指向一个页面。在该页面中,读取或写入第50个字节。

请记住,每个表条目的实际物理地址由两部分组成。存储在表条目中的物理地址的前导位,以及来自虚拟地址的索引。附加这些部分以创建有效的物理地址。

也许你已经知道了,但64位计算机中的地址总线大多数时候只有48位宽。所以实际上处理器只使用48位来寻址内存而不是64位。这意味着指向下一个表项或位的指针不是64位长。

但是因为每个表长度为64位,所以指向下一个条目的指针不使用所有位。

实际上,表条目存储了最终指针的前36位。如果索引是9位,则它与3个额外位相连。这3个额外位是填充。如果附加索引标识一个字节,则不使用这3个位。

  表条目索引填充的指针
 | [36bits] | [9bits] | 
 | 0000000000000000000000000000000000000000 | 00000000 | 000
  来自表条目索引的指针
 | [36bits] | [12bits] 
 | 0000000000000000000000000000000000000000 | 00000000000

分页是一种权衡:MMU必须将虚拟地址转换为物理地址。这意味着处理器需要更多时间来访问内存。但另一方面,我们也可以做更有趣的事情。
因为指向下一个条目的指针不占用整个64位(但是36位),我们可以使用其余的来存储标志。
作为所有其他条目的示例,我们来看一下Page Table Entry:

每个页面及其先前的表条目都会获得一个特权级别(红色)。权限级别可以为0,这使得此页面及其存储的数据,代码或表条目只能由内核或OS访问。只有OS /内核可以访问,处理器必须在从内存请求数据时执行OS /内核代码。否则MMU将通过页面错误异常。
如果设置为1,则用户应用程序可以访问它。

读/写标志(蓝色)是不言自明的。

最后但显然并非最不重要的是,存在执行禁用位(绿色),这将阻止页面内容的任何执行。这是一种防止恶意软件执行代码的安全功能,代码写入进程的数据段。但不要担心,有办法解决这个问题

那么为什么我们要经历这一切呢?嗯,首先是它的基本计算机科学知识:P。其次,英特尔支持基于此概念的硬件智能内存虚拟化。

只是为了说清楚:MMU只将给定的虚拟地址转换为物理地址,然后将数据传回处理器。设置所有页表并将它们分配给正在运行的进程仍由内核完成。

因此,如果你在计算机上启动虚拟客户端,它将自然地设置页面表。虽然,主机已经建立了自己的分页结构。为了防止内存中的完全混乱,客户访问内存也需要进行操作。

在过去,这必须通过VMM来完成,VMM持有客户分页表的影子(也就是副本)并将客户页面翻译成物理页面,这是令人难以置信的慢。因此,英特尔在其处理器中添加了扩展页表(EPT)功能,可以在MMU中完成翻译过程,并且可以更快地完成。

如果处理器处于非VM根状态且guest虚拟机请求内存,则MMU将首先正常计算guest虚拟机物理地址。
此时,MMU查找一个称为扩展页表指针的特殊指针
这个指针只有36位长。在下一步中,MMU将客户物理地址的第47:39 加上3位。

| [36bits] | [9bits] | 
 | 0000000000000000000000000000000000000000 | 00000000 | 000

看起来很熟悉?它确实和往常一样翻译程序。虽然,这次MMU没有使用虚拟地址来读取索引,而是访客的物理地址。

这基本上就是这样。guest虚拟机内存被映射到主机内存而不会覆盖whings。主机有机会操纵guest虚拟机内存,而guest虚拟机甚至不知道它正在使用不同的分页结构。

如果分页对你来说是全新的,那么这可能是一个难以理解的内容。我试图让它可访问,并没有涵盖像缓存1 或使用GDT 2的 内存分段。
如果有任何不明确的陈述或错误,请告诉我。

在接下来的部分中,我最初计划撰写有关VT-d的文章,但我很擅长主演英特尔手册。因此,当我有空闲时间时,我将介绍使用虚拟化的Qubes OS。或者写一篇关于突破客户的漏洞利用的文章。或者甚至像rootkit一样编写PoC Bluepill 4

作者:Rot127

翻译:I春秋翻译小组-FWorldCodeZ

责任编辑:F0rmat

翻译来源:https://www.0x00sec.org/t/a-lot-about-paging-a-little-about-virtualization-part-2/8868

有第一部分吗?
使用道具 举报 回复
F0rmat i春秋作家 i春秋十五军装逼团团长 i春秋签约作者 春秋文阁 积极活跃奖 春秋游侠
板凳
发表于 2018-11-24 10:27:36
getpass.cn
使用道具 举报 回复
发新帖
您需要登录后才可以回帖 登录 | 立即注册