这里感谢Satoshi大师,师承Satoshi。这里主要聊一下基于uefi模式下的Hypervisor层的VT-D对抗(TYPE1型Hypervisor或者说某些反作弊的预加载方案)。这里不讨论固伪装和绕过保护手法只讨论保护方向。黑灰勿扰。(全文无AI 古法)
这里讨论的是基于,PCILeech所开发的硬件。先说明一下:我个人完整阅读过PCILeech和LeechCore、MemProcFS 相关的库。对于PCILeech我是非常佩服的,提供的功能太强大了。ps:(2022年就通过老外接触到这个设备,当时对它提供的能力感到的惊讶的。后面也感受到这个东西将来要出大事,没想到这几年,祸事都从它而起。。。。劝大家向善吧)
正常的网卡、存储控制器需要向内存传输数据。DMA 允许设备直接读写为它准备的缓冲区,减少 CPU 搬运数据的工作。所以才诞生了PCILeech这类产品。

这个最开始是出现在2024年10月的EasyAnti-Cheat给的一个方案,卡死不少人hhh。这里简单说一下保护思路:
当我们启动了Hypervisor之后,我们是可以手动给Guest分配内存页。相当于我们有自己管理Guest的内存的能力。(这一块后续我单开一个板块慢慢说)
重点来了:
如图所示:

VT-d 防护的基本思路,是在设备访问内存的路径上增加硬件控制。我们自定义的 Hypervisor 组件负责建立转换表,规定设备请求的地址最终对应哪块物理内存,以及是否允许读取和写入。启用 DMA 重映射后,经过对应 VT-d 单元的请求都会受到这些规则约束。
具体实现分为三步:
VTD单元和DMA设备的关系是一对多。一个VTD下可以绑定多个DMA设备,从而进行分组管理。
这里需要注意的是这里一种说的VTD是一个物理硬件通常在CPU里面。而我们则需要针对这个物理硬件进行设置,VTD可以管理DMA的的行文。而VTD是由数量上限,这样推荐的上限是4。
VTD可以提供如下的能力:最直观的能力就是控制DMA与RAM的交互能力
全称是 Memory-Mapped I/O,中文叫“内存映射输入输出”。首先不是所有内存都是映射到RAM(内存条),会有硬件自己的内存,比如硬件的寄存器等。。。。
通过CPU角度去看:

白皮书解释;

所以从上面流程图可以看到, MMIO 会把一些寄存器映射到我们的内存中,这样我们可以方便操控硬件,也算是一个底层调用硬件的统一接口。这和我们VT-D有什么关系呢?看intel88白皮书

两段分别说明:
我们需要通过MMIO来控制我们的VTD物理硬件。
DmarTable是用来存储VTD信息的地方,每条 DRHD 记录描述一个 VT-d 单元。通过寄存器地址来访问和设置VTD

主板的 BIOS/UEFI启动过程中,它根据平台信息,在内存中准备 ACPI 表,包括描述 VT-d 硬件的 DMAR,并建立指向这些表的地址目录。EDK2库函数负责处理以下这些事情:
SystemTable:它就是固件交给程序的实际内存地址。
从这个已知指针,沿着内存里的地址逐级查找。
这一部分实际上EDK2已经帮我们是实现完了,我们只需要调用 Edk中的EfiLocateFirstAcpiTable()就可以拿到DMAR表
EDK2定义的表结构。
DmarTable解析代码:
DRHD就是用来存储VTD的结构体。
定义如下:
对应如上结构的白皮书解释:

通过RegisterBaseAddress地址就可以设置我们需要的功能了,功能对应的偏移标志位如下:



通过RTADDR设置我们就可以让硬件执行我们的转换表。转换表分几种模式这里只详细介绍Legacy模式(剩下自己探索吧):
有如下几种模式
根表,就是 VT-d 硬件开始查找规则时,读取的第一张目录表。流程如下:
上下文表对应的就映射的真正设备。
DMA 页表,就是告诉 VT-d:设备请求的地址,对应哪块真实物理内存,以及允许读、允许写。表结构:


这里说直白一点,就是传统的四级页表结构一模一样。这里的页表就是单纯的物理地址映射物理地址,只不过这个物理地址可以被重映射。如下:
循环映射代码:
首先我们设置好权限页表,再去设置权限即可
运行期间修改保护规则时,需要定位目标地址对应的表项,修改目标物理页或读写权限;随后确保更新对硬件可见,使相关转换缓存失效,并等待完成。
用EPT 限制 Guest 对 VT-d 寄存器的访问:读的时候给它看影子页,写的时候拦下来
如图:
感谢您看到这里如果觉得有用可以给我点个赞噢。如有其他问题或者讨论的可以在评论区讨论。如果有保护方面可以和我沟通我可以提供技术支持。
传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!!
最后于 17小时前
被BitWarden编辑
,原因: