Intel VT学习笔记(七)—— EPT物理地址转换

Intel VT学习笔记(七)—— EPT物理地址转换

要点回顾

上一篇中,已经初步实现了最小VT框架,但实际上还有许多问题需要解决。

在最小VT框架中,我们仅处理了三个退出码:

#define EXIT_REASON_CPUID               10
#define EXIT_REASON_VMCALL              18
#define EXIT_REASON_CR_ACCESS           28

要是想开发一个成熟的VT框架,需要处理的退出码远要多得多。

本节,我们主要学习的内容是EPT物理地址转换。

EPT

描述:EPT全称为Extended Page Table,用于实现内存虚拟化。

之前,在学习保护模式的时候,我们了解了MMU(虚拟内存管理器)是如何将虚拟地址转换成物理地址的,那便是通过分页模式,在XP系统中,我们学习了10-10-12分页2-9-9-12分页两种分页模式,EPT的作用与此非常像,它能够将guest的物理地址(Guest Physical Address, GPA)转换成host的物理地址(Host Physical Address, HPA)。

开启EPT后,真正的物理内存就被隐藏起来了,Guest中的所有人都访问不到,只有Host能访问到。

关于EPT的详细资料可以参考Intel开发手册卷3第28节。

支持检测

步骤:检测IA32_VMX_PROCBASED_CTLS2 MSR(index 48BH)高32位的第2位,为1则表示支持。
在这里插入图片描述

9-9-9-9-12分页

描述:EPT提供的分页模式为9-9-9-9-12分页,即最多支持48位地址的转换,也就是256T内存 。

以之前学过的2-9-9-12分页模式为例,寻址流程大致如下:
PDPTE
关于2-9-9-12分页模式的具体内容可通过这篇文章复习,连笔者自己也有点忘了。

再来看看9-9-9-9-12分页模式的流程:
在这里插入图片描述
不难发现,这两者看上去差别不大,只是后者比前者多了一个目录项,但实际上大有不同。

其中,EPTP的作用相当于Cr3,GPA通过它逐步找到HPA。

思考:VT是如何完成物理地址到物理地址之间的转换的呢?

按照以往的经验,如果需要将虚拟地址转换成物理地址,首先要知道这个虚拟地址是属于谁的,也就是Cr3是多少,然后将虚拟地址按照分页模式进行拆分,逐级读取各个表项,最终找到相应的物理页。

但是在EPT模式下,Guest中的每个物理地址都经过了虚拟化,因此,每访问一个物理地址,就要经过一次从GPA到HPA的转换。

那也就是说,若系统使用的是2-9-9-12分页模式,那么如果从想要找到真正的物理页,一共要经过三次从物理地址到物理地址的转换,具体的过程由VMM实现,我们只要了解其寻址原理即可。

第一次:PDPTE(GPA) -> PDPTE(HPA)
第二次:PDE(GPA) -> PDE(HPA)
第三次:PTE(GPA) -> PTE(HPA)

总寻址次数 = 3*4 = 12次

实验:EPT物理地址转换

第一步:分配内存,使其整体结构成为9-9-9-9-12模式,并挂入相应的物理页。

//ept.c
#include <ntddk.h>
#define PAGE_SIZE 0x1000

ULONG64* ept_PML4T;

static PVOID *pagesToFree;
static int index = 0;

void InitEptPagesPool()
{
    pagesToFree = ExAllocatePoolWithTag(NonPagedPool, 12*1024*1024, 'ept');
    if(!pagesToFree)
        __asm int 3
    RtlZeroMemory(pagesToFree, 12*1024*1024);
}

static ULONG64* AllocateOnePage()
{
    PVOID page;
    page = ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE, 'ept');
    if(!page)
        __asm int 3
    RtlZeroMemory(page, PAGE_SIZE);
    pagesToFree[index] = page;
    index++;
    return (ULONG64 *)page;
}

ULONG64* MyEptInitialization()
{
    ULONG64 *ept_PDPT, *ept_PDT, *ept_PT;
    PHYSICAL_ADDRESS FirstPtePA, FirstPdePA, FirstPdptePA;
    int a, b, c;

    InitEptPagesPool();
    ept_PML4T = AllocateOnePage();
    ept_PDPT = AllocateOnePage();
    FirstPdptePA = MmGetPhysicalAddress(ept_PDPT);
    *ept_PML4T = (FirstPdptePA.QuadPart) + 7;
    for (a = 0; a < 4; a++)
    {
        ept_PDT = AllocateOnePage();
        FirstPdePA = MmGetPhysicalAddress(ept_PDT);
        *ept_PDPT = (FirstPdePA.QuadPart) + 7;
        ept_PDPT++;
        for (b = 0; b < 512; b++)
        {
            ept_PT = AllocateOnePage();
            FirstPtePA = MmGetPhysicalAddress(ept_PT);
            *ept_PDT = (FirstPtePA.QuadPart) + 7;
            ept_PDT++;
            for (c = 0; c < 512; c++)
            {
                *ept_PT  = ((a << 30) | (b << 21) | (c << 12) | 0x37) & 0xFFFFFFFF;
                ept_PT++;
            }
        }
    }

    return ept_PML4T;
}

void MyEptFree()
{
    int i;
    for (i = 0; i < index; i++) {
        ExFreePool(pagesToFree[i]);
    }
    ExFreePool(pagesToFree);
    index = 0;
}
//driver.c
#include <ntddk.h>
#include "vtasm.h"
#include "vtsystem.h"

VOID DriverUnload(PDRIVER_OBJECT pDriver)
{
	StopVirtualTechnology();
	DbgPrint("Driver unload. \r\n");
}

ULONG g_back_esp;
ULONG g_back_eip;

extern void InitEptPagesPool();
extern ULONG64* MyEptInitialization();

NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING reg_path)
{
	DbgPrint("Driver load. \r\n");

	pDriver->DriverUnload = DriverUnload;

	InitEptPagesPool();
	ULONG64* ept_PML4T = MyEptInitialization();
	Log("ept_PML4T", ept_PML4T);
	__asm int 3;

	__asm
	{
		pushad
		pushfd
		mov g_back_esp, esp
		mov g_back_eip, offset BACK
	}

	StartVirtualTechnology();	//开启VT

BACK:

	__asm
	{
		popfd
		popad
	}

	//Log("Return To DriverEntry", 0);

	return STATUS_SUCCESS;
}

第二步:运行驱动程序(注意,当Windbg获取中断时,此时并未开启VT以及EPT模式)
在这里插入图片描述
在这里插入图片描述
第三步:读取当前cr3和esp的值
在这里插入图片描述

在这里插入图片描述

第四步:获取当前esp的物理地址作为GPA,下面尝试将其转换成HPA
在这里插入图片描述
第五步:将esp的物理地址拆分为9-9-9-9-12模式
在这里插入图片描述

二进制:00011110 11010110 10011100 01101100
9-9-9-9-12:000000000 000000000 011110110 101101001 110001101100
十六进制:000_000_0f6_169_c6c

第六步:定位PLM4E(注意,此时EPTP即ept_PLM4T指针是虚拟地址,里面的值才是物理地址)
在这里插入图片描述
这里PLM4E只有1项,因为XP系统物理内存最大为4GB,因此一项就够了

第七步:定位PDPTE(这个时候开始就是物理地址了,记得去掉属性位)
在这里插入图片描述
第八步:定位PDE
在这里插入图片描述
第九步:定位PTE
在这里插入图片描述
第十步:定位物理内存
在这里插入图片描述在这里插入图片描述
物理页中的内容和ESP里的值相同,说明整个过程没有问题。

总结:不难发现,GPA经过转换后得到的HPA没有变化,但实际上,如果开启EPT模式,当Guest和Host访问同一个物理地址时,Guest只能对“虚拟的”物理内存进行读写,只有Host才能访问到真正的物理内存。

参考资料

参与评论 您还未登录,请先 登录 后发表或查看评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页

打赏作者

lzyddf

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值