zhouhe VT(七) 非PAE下的EPT开启

一、zhouhe老师上次留的问题

Intel 第三卷 27.5.2
0
当退出Host的时候,IDT表和GDT表的界限会被赋值为 0xFFFF
我们退出虚拟机的时候没有修改这界限,所以当xuetr遍历gdt表的时候就会遍历到不可访问的代码页,引发蓝屏异常

二、加载Host的RIP与RSP的时候,自动关中断

27.5.3上:
0
当HOST的RIP和RSP从RIP域与RSP域上加载的时候,EFLAGS寄存器保留第一位,剩下的清零
 

三、分配物理地址

为了实现GPA到HPA的转化,我们需要为虚拟机分配物理地址
 
 
 

四、开启ETP

Table 24-7上
 
0
 
0
在IA32_VMX_PROCBASED_CTLS2(index 48BH)寄存器下可以设置EPT的开启
但设置IA32_VMX_PROCBASED_CTLS2寄存器前我们要先把CPU_BASED_VM_EXEC_CONTROL寄存器的第31位设置为1,不然,无效
 
0

五、EPTP位的设置

24.6.11
 
0
一些基础的设置要查看 MSR IA32_VMX_EPT_VPID_CAP(48C)寄存器
A.10
0
 
0

六、实验

代码:
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); //12Mb// } 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; } //extern PULONG test_data; //PHYSICAL_ADDRESS hook_pa; //ULONG64 *hook_ept_pt; ULONG64* MyEptInitialization() { ULONG64 *ept_PDPT, *ept_PDT, *ept_PT; PHYSICAL_ADDRESS FirstPtePA, FirstPdePA, FirstPdptePA; int a, b, c; initEptPagesPool(); ept_PML4T = AllocateOnePage(); //PML4E// ept_PDPT = AllocateOnePage(); //PDPTE// FirstPdptePA = MmGetPhysicalAddress(ept_PDPT); *ept_PML4T = (FirstPdptePA.QuadPart) + 7; //加权限//分页的后12位的属性//可读可写可执行// for (a = 0; a < 4; a++) { ept_PDT = AllocateOnePage(); FirstPdePA = MmGetPhysicalAddress(ept_PDT); *ept_PDPT = (FirstPdePA.QuadPart) + 7; ept_PDPT++; for (b = 0; b < 128; 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; //PTE是加的0x37// ept_PT++; } } } return ept_PML4T; } void MyEptFree() //由于直接通过物理地址转虚拟地址不好转,使用全局数组的方式,记录虚拟地址// { int i; for (i = 0; i < index; i++) { ExFreePool(pagesToFree[i]); } ExFreePool(pagesToFree); index = 0; }

 

 
0
0
实验时,直接产生了三重错误
停在了GuestEntry中,有些字段可能没有处理完成,但在非PAE模式下不会产生这种中断,下面我们开启非PAE模式,也就是10-10-12分页模式
 

七、完善内存大小

我们遇到了高地址的读写问题,产生了退出号48,这在Intel手册对应是EPT属性错误
 
0
试图用guest物理地址访问内存被EPT分页结构的配置所禁止。
 
 
0
可见是读取FFFE0080地址的时候发生了错误
它是一个名叫高级可编程中断控制器的东西,具体是什么我们暂且不研究
查看其物理地址
0
一个地址特别高的物理地址,我们明明只分配了1G物理内存,为什么会出现地址这么高的物理地址呢
因为它是Intel规定的,固定映射到fee00080这个地方的物理地址
 
依次类推,也有很多地址被Intel映射到了固定地址,我们只好在初始时分配足够的4Gb的内存

八、页属性+0x37(附)

这是加了一个可读可写可执行有缓存的属性
因为有些页需要缓存这个属性,方便起见,我们把所有物理页全设置成了有缓存...

 

 

设置完这些之后CPU能正常运行了

九、完善后的代码

#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); //12Mb// } 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; } //extern PULONG test_data; //PHYSICAL_ADDRESS hook_pa; //ULONG64 *hook_ept_pt; ULONG64* MyEptInitialization() { ULONG64 *ept_PDPT, *ept_PDT, *ept_PT; PHYSICAL_ADDRESS FirstPtePA, FirstPdePA, FirstPdptePA; int a, b, c; initEptPagesPool(); ept_PML4T = AllocateOnePage(); //PML4E// ept_PDPT = AllocateOnePage(); //PDPTE// FirstPdptePA = MmGetPhysicalAddress(ept_PDPT); *ept_PML4T = (FirstPdptePA.QuadPart) + 7; //加权限//分页的后12位的属性//可读可写可执行// 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; //PTE是加的0x37// 可读可写可执行,有缓存,由于有的地址要求有缓存,方便起见,这里全设置成了0x37,虽然这样会影响CPU的性能// ept_PT++; } } } return ept_PML4T; } void MyEptFree() //由于直接通过物理地址转虚拟地址不好转,使用全局数组的方式,记录虚拟地址// { int i; for (i = 0; i < index; i++) { ExFreePool(pagesToFree[i]); } ExFreePool(pagesToFree); index = 0; }

 

记一个Windbg命令

.hh + 命令
会弹出帮助文档
0
学到了!!!
 
该节代码链接
参考

__EOF__

本文作者_TLSN
本文链接https://www.cnblogs.com/lordtianqiyi/articles/16157707.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   TLSN  阅读(80)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 25岁的心里话
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示