内存虚拟化
内存虚拟化+无痕HOOK。
BOOLEAN SetupEptPaingStructure()
{
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[+] ept init...\n");
/*
1. 分配内存
*/
PVOID64 ept = (__int64)ExAllocatePoolWithTag(NonPagedPool, (2 + HardWarePhysicsAddressRange + HardWarePhysicsAddressRange * 512) * PAGE_SIZE, 'ept');
if (!ept)
{
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[-] ept paing structure 内存分配失败!\n");
return FALSE;
}
else
{
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[+] ept base: %p\n", ept);
memset(ept, 0, (2 + HardWarePhysicsAddressRange + HardWarePhysicsAddressRange * 512) * PAGE_SIZE);
g_vmx_config.EPT.ept_address = ept;
}
/*
2. 配置eptp属性
*/
EptPointer eptp = { 0 };
BOOLEAN bRet = SetupExtendedPageTablePointerRights(&eptp);
if (!bRet)
{
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[+] ept开启失败!\n");
return FALSE;
}
/*
3. 分配内存
空间分布状态: PT, PDT, PPE(1GB), PXE
*/
PVOID64 pa = 0; // 物理地址
PEptPtEntry pt = (PEptPtEntry)ept;
PEptPdEntry pdt = (PEptPdEntry)((__int64)ept + (HardWarePhysicsAddressRange << (30 - 12 + 3)));
PEptPdptEntry pdpt = (PEptPdptEntry)((__int64)pdt + (HardWarePhysicsAddressRange << (30 - 12 - 9 + 3)));
PEptPml4Entry pml4t = (PEptPml4Entry)((__int64)pdpt + PAGE_SIZE);
// eptp属性
eptp.Bits.physial_address = MmGetPhysicalAddress((PVOID64)pml4t).QuadPart >> 12;
g_vmx_config.EPT.eptp = eptp.all;
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[+] eptp pa: %p\n", MmGetPhysicalAddress((PVOID64)pml4t).QuadPart);
// pml4t属性
pml4t->Bits.physial_address = MmGetPhysicalAddress((PVOID64)pdpt).QuadPart >> 12;
//DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[+] pml4t pa: %p\n", pml4t->Bits.physial_address);
pml4t->Bits.execute_access = TRUE;
pml4t->Bits.read_access = TRUE;
pml4t->Bits.write_access = TRUE;
for (__int64 pdpt_index = 0; pdpt_index < HardWarePhysicsAddressRange; pdpt_index++, pdpt++)
{
//pdpt属性配置
pdpt->Bits.physial_address = MmGetPhysicalAddress((PVOID64)pdt).QuadPart >> 12;
//DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[+] pdpt pa: %p\n", pdpt->Bits.physial_address);
pdpt->Bits.execute_access = TRUE;
pdpt->Bits.read_access = TRUE;
pdpt->Bits.write_access = TRUE;
for (__int64 pdt_index = 0; pdt_index < 512; pdt_index++, pdt++)
{
// pde属性设置
pdt->Bits.physial_address = MmGetPhysicalAddress((PVOID64)pt).QuadPart >> 12;
pdt->Bits.execute_access = TRUE;
pdt->Bits.read_access = TRUE;
pdt->Bits.write_access = TRUE;
for (__int64 pt_index = 0; pt_index < 512; pt_index++, pt++)
{
// pte属性设置
pt->Bits.physial_address = (__int64)pa;
pt->Bits.execute_access = TRUE;
pt->Bits.read_access = TRUE;
pt->Bits.write_access = TRUE;
pt->Bits.memory_type = 6; //writeback
pa = (PVOID64)((__int64)pa + 1);
}
}
}
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[ok] ept初始化成功!\n");
return FALSE;
}
/* 检查eptp属性并进行设置 */
BOOLEAN SetupExtendedPageTablePointerRights(PEptPointer eptp)
{
CPUID cpuid = { 0 }; // 用于存储rdmsr的返回值
asm_rdmsr(IA32_VMX_EPT_VPID_CAP, &cpuid);
if (cpuid.eax & 0x100) // uncacheable, bit 8
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[+] CPU支持UC(uncacheable)!\n");
else
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[+] CPU不支持UC(uncacheable)!\n");
if (cpuid.eax & 0x4000) // writeback, bit 14, 支持则优先设置
{
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[+] CPU支持WB(writeback)!\n");
eptp->Bits.memory_type = 6;
}
else
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[+] CPU不支持WB(writeback)!\n");
if (cpuid.eax & 0x40) // page walk length, bit 6
{
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[+] CPU支持4级分页!\n");
eptp->Bits.page_walk_length = 3;
}
else
{
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[+] CPU支持4级分页!\n[-] CPU无法开启ept!\n");
return FALSE;
}
if (cpuid.eax & 0x200000) // dirty&accessed, bit 21
{
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[+] CPU支持dirty、accessed!\n");
eptp->Bits.enable_accessed_and_dirty_flags = TRUE;
}
else
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[+] CPU不支持dirty、accessed!\n");
}
/* 开启内存虚拟化 */
void StartVirtualizeMemory()
{
SetupEptPaingStructure();
HookEptPage(0xfffff80578a01800); // 0x0e page-fault
}
void InsertEptHookList(PEptHookItem pEptHookItem)
{
PEptHookItem hook_item = &g_vmx_config.EPT.ept_hook_list_header;
if (!hook_item->next)
{
hook_item->next = pEptHookItem;
}
else
{
pEptHookItem->next = hook_item->next;
hook_item->next = pEptHookItem;
}
}
BOOLEAN HookEptPage(PVOID64 pTargetLinerAddress)
{
/* guest线性地址转为ept.pte(线性地址)*/
PEptPtEntry pte = (PEptPtEntry)GetEptPtEntryLinerAddress(pTargetLinerAddress);
/* 设置hook-item属性 */
PEptHookItem hook_item = kmalloc(sizeof(EptHookItem));
hook_item->next = NULL;
hook_item->target_liner_address = pTargetLinerAddress;
hook_item->target_physical_address = MmGetPhysicalAddress(pTargetLinerAddress).QuadPart;
hook_item->pte_liner_address = (__int64*)pte;
hook_item->fake_page_liner_address = AllocateFakePage(pTargetLinerAddress);
/* 将被hook的物理页线性地址挂入ept-hook链 */
InsertEptHookList(hook_item);
/* 设置物理页新的属性位 */
pte->Bits.read_access = FALSE;
pte->Bits.write_access = FALSE;
pte->Bits.execute_access = TRUE;
return TRUE;
}
__int64* GetEptPtEntryLinerAddress(__int64* pTargetLinerAddress)
{
PVOID64 gpa = MmGetPhysicalAddress(pTargetLinerAddress).QuadPart;
return (__int64)g_vmx_config.EPT.ept_address + (((__int64)gpa >> 12) << 3);
}
void HandleOfEptViolation()
{
ULONG64 ExitQualification; // 详细的退出信息
PHYSICAL_ADDRESS TargetAddress_pa; // 目标物理地址
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[+] HandleOfEptViolation.\n");
asm_vmread(&ExitQualification, EXIT_QUALIFICATION);
asm_vmread(&TargetAddress_pa, GUEST_PHYSICAL_ADDRESS);
// 检测当前线性地址是否在目标页面范围内
PEptHookItem hook_item = { 0 };
BOOLEAN bRet = CheckCurrectEptViolationAddressIsTargetRange((__int64*)TargetAddress_pa.QuadPart, &hook_item);
if (bRet)
{
//DbgBreakPoint();
PEptPtEntry target_item = (PEptPtEntry)hook_item->pte_liner_address;
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[+] 检测到当前线性地址处于目标页面范围内! 内存修复...\n");
if (ExitQualification & 3) // 页面读写出错
{
target_item->Bits.read_access = TRUE;
target_item->Bits.write_access = TRUE;
target_item->Bits.execute_access = FALSE;
target_item->Bits.physial_address = MmGetPhysicalAddress(hook_item->fake_page_liner_address).QuadPart >> 12;
}
else // 页面无法执行
{
target_item->Bits.read_access = FALSE;
target_item->Bits.write_access = FALSE;
target_item->Bits.execute_access = TRUE;
target_item->Bits.physial_address = (__int64)hook_item->target_physical_address >> 12;
}
}
else
{
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[error] noknwon ept error!\n");
}
// 刷新 TLB ==> 作用没有体现出来???
//DbgBreakPoint();
//asm_invept(2, &g_vmx_config.EPT.eptp);
}
BOOLEAN CheckCurrectEptViolationAddressIsTargetRange(__int64* target_address_pa, __int64** hook_item_ret)
{
PEptHookItem hook_item = &g_vmx_config.EPT.ept_hook_list_header;
//__int64* pte_address_pa = GetEptPtEntryLinerAddress(target_address_pa);
while (hook_item)
{
hook_item = hook_item->next;
if (((__int64)hook_item->target_physical_address >> 12) == ((__int64)target_address_pa >> 12))
{
*hook_item_ret = hook_item;
return TRUE;
}
else
hook_item = hook_item->next;
}
return FALSE;
}
__int64* AllocateFakePage(__int64* real_page)
{
/* 无痕hook, 需要将原页面的数据复制至fake-page */
__int64* fake_page = kmalloc(PAGE_SIZE);
memcpy(fake_page, real_page, PAGE_SIZE);
return fake_page;
}
BOOLEAN UninstallEptPageHook(PVOID pTargetLinerAddress)
{
PEptHookItem hook_item = &g_vmx_config.EPT.ept_hook_list_header;
// 卸载指定 ept page hook
if (pTargetLinerAddress)
{
PEptHookItem front = hook_item;
hook_item = hook_item->next;
while (hook_item->next)
{
if (pTargetLinerAddress == hook_item->target_liner_address)
{
front->next = hook_item->next; // 删除hook_item节点
*hook_item->pte_liner_address |= 0x07; // 修复pte的权限属性
MmFreeContiguousMemory(hook_item->fake_page_liner_address); // 释放fake-page
MmFreeContiguousMemory(hook_item); // 释放hook_item
return TRUE;
}
}
return FALSE;
}
// 卸载所有 ept page hook
else
{
__int64* next = hook_item->next;
while (next)
{
hook_item = next;
next = hook_item->next;
MmFreeContiguousMemory(hook_item->fake_page_liner_address);
MmFreeContiguousMemory(hook_item);
}
return TRUE;
}
}