如题,我PTEHook,但是我的虚拟机是大页的,所以我就是用大页的Hook
一开始我是用的4kb小页PTE顺序排列,假装一个PDE大页的。但是会蓝屏,我就准备大页换大页
一开始我连替换都不行,后面看了白皮书和经过指导才知道替换2MB的大页物理地址也得是2MB对齐的。
后来大页能替换了,但是我挂了半小时 发现虚拟机直接死了
求大佬解决,这是替换之后的
这是死了之后
代码贴一下 申请内存我用的是申请的非分页内存池的:
ULONG_PTR PTEHOOK::PteHook::fn_init_isolation(HANDLE ProcessId, ULONG_PTR LineAddress)
{
//直接修改这个
//PULONG_PTR pPmle4e, pPdpte, pPde, pPte;
//这个函数的功能是修改pmle4e pdpte pde pte 因此实现隔离物理页
//这个时候就可以随便修改内存 而不改变其他地方的物理内存了
PageAttrHide::PteTable table = { 0 };
table.pLineAddr = LineAddress;
KAPC_STATE Apc = { 0 };
PEPROCESS Process = 0;
//申请的内存 一般来说 申请3页即可 大页2MB 无需申请pde那一页来替换
PVOID Pml4e = 0;
PVOID Pdpte = 0;
PVOID Pde = 0;
ULONG_PTR FlagTemp = 0;
//要替换的 新的 旧的物理地址
PHYSICAL_ADDRESS NewPml4e = { 0 };
PHYSICAL_ADDRESS OldPml4e = { 0 };
PHYSICAL_ADDRESS NewPdpte = { 0 };
PHYSICAL_ADDRESS OldPdpte = { 0 };
PHYSICAL_ADDRESS NewPde = { 0 };
PHYSICAL_ADDRESS OldPde = { 0 };
PHYSICAL_ADDRESS NewPte = { 0 };
PHYSICAL_ADDRESS OldPte = { 0 };
PHYSICAL_ADDRESS _Cr3 = { 0 };
//物理地址映射线性地址 用于修改页表的内容
PULONG_PTR Cr3Page=0,Pml4ePage=0,PdptePage=0,PdePage=0,PtePage = 0;
enum PageSize
{
small, //4kb
medium, //2mb
big//1gb
};
int nPageSize = small;
//get ptes
PageAttrHide::GetLineAddrPteTable(&table);
if (!NT_SUCCESS(PsLookupProcessByProcessId(ProcessId, &Process))){
DbgPrintEx(77, 0, "[OxygenDriver]err process id\r\n");
return (ULONG_PTR)0;
}
KeStackAttachProcess(Process, &Apc);
//alloc a page size mem for pml4e
Pml4e = ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE, 'PML4');
Pdpte = ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE, 'Pdpt');
Pde = ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE, 'Pde');
//isolate pml4e
//get alloc mem physical addr
//获取老的页表
OldPml4e = *(PPHYSICAL_ADDRESS)(table.Pml4e);
OldPdpte = *(PPHYSICAL_ADDRESS)(table.PdPte);
OldPde = *(PPHYSICAL_ADDRESS)(table.Pde);
OldPte = *(PPHYSICAL_ADDRESS)(table.Pte);
//获取老页表指针
//获取新的页表
table.pLineAddr = (ULONG_PTR)Pml4e;
PageAttrHide::GetLineAddrPteTable(&table);
NewPml4e = *(PPHYSICAL_ADDRESS)(table.Pte);
table.pLineAddr = (ULONG_PTR)Pdpte;
PageAttrHide::GetLineAddrPteTable(&table);
NewPdpte = *(PPHYSICAL_ADDRESS)(table.Pte);
table.pLineAddr = (ULONG_PTR)Pde;
PageAttrHide::GetLineAddrPteTable(&table);
NewPde = *(PPHYSICAL_ADDRESS)(table.Pte);
//save pml4e-pde attributes
NewPml4e.QuadPart &= 0x000ffffffffff000;
FlagTemp = OldPml4e.QuadPart & 0xfff0000000000FFF;
NewPml4e.QuadPart |= FlagTemp;
NewPdpte.QuadPart &= 0x000ffffffffff000;
FlagTemp = OldPdpte.QuadPart & 0xfff0000000000FFF;
NewPdpte.QuadPart |= FlagTemp;
NewPde.QuadPart &= 0x000ffffffffff000;
FlagTemp = OldPde.QuadPart & 0xfff0000000000FFF;
NewPde.QuadPart |= FlagTemp;
//get cr3
_Cr3.QuadPart = __readcr3();
Cr3Page =(PULONG_PTR)MmGetVirtualForPhysical(_Cr3);
//判断页面大小
if (BitTest((PLONG)&OldPdpte.QuadPart, 7)) {
//1Gb
nPageSize = big;
}
else {
nPageSize = BitTest((PLONG)&OldPde.QuadPart, 7) ? medium : small;
}
if (nPageSize == big) {
//1GB太离谱 申请太多非分页直接寄
DbgPrintEx(77, 0, "[OxygenDriver]:can not support 1GB page isolate!!\r\n");
KeUnstackDetachProcess(&Apc);
return 0;
}
else if (nPageSize == medium) {
//记得移位
DbgBreakPoint();
int pml4eindex = (LineAddress & 0x0000FF8000000000)>>39;
int pdpteindex = (LineAddress & 0x0000007FC0000000)>>30;
int pdeindex = (LineAddress & 0x000000003FE00000)>>21;
//不需要pte的索引了 因为是2MB
//把原先的2MB内存 复制到申请是2MB里面去
PHYSICAL_ADDRESS low = { 0 };
PHYSICAL_ADDRESS high;
high.QuadPart = MAXULONG64;
//申请一块连续的物理内存 就可以假装大页
//物理页也要对齐!!!!21位为0 坑死了
PVOID p2MbMemory_ = MmAllocateContiguousMemorySpecifyCache(1024 * PAGE_SIZE, low, high, low, MmCached);
int i = 0;
for (;i<1024;i++) {
//找到2MB对齐的位置
table.pLineAddr = (UINT64)p2MbMemory_ + PAGE_SIZE * i;
PageAttrHide::GetLineAddrPteTable(&table);
UINT64 uPte = *(PULONG_PTR)table.Pte;
//去掉属性位
uPte &= 0x000ffffffffff000;
//看下是否是21位对齐
uPte &= 0x1fffff;
if (!uPte) break;
}
PVOID p2MbMemory= (PVOID)((UINT64)p2MbMemory_ + PAGE_SIZE * i);
memcpy(p2MbMemory, (PVOID)(LineAddress & 0xffffffffffe00000), 512 * PAGE_SIZE);
//把这2MB内存的pte复制到假的pde里面 这样 假的pde做好了
UINT64 uPdetmp;
table.pLineAddr = (UINT64)p2MbMemory;
PageAttrHide::GetLineAddrPteTable(&table);
uPdetmp = *(PULONG_PTR)table.Pte;
uPdetmp &= 0x000ffffffffff000;
//去掉物理地址
NewPde.QuadPart &= 0xfff0000000000fff;
NewPde.QuadPart |= uPdetmp;
NewPde.QuadPart |= 0x80;
//做假的pdpte
PHYSICAL_ADDRESS PhyPdpte = { 0 };
//去掉属性位
PhyPdpte.QuadPart = OldPdpte.QuadPart & 0x000ffffffffff000;
PdptePage = (PULONG_PTR)MmGetVirtualForPhysical(PhyPdpte);
//复制
memcpy(Pdpte, PdptePage, PAGE_SIZE);
//找到索引并替换
//((PULONG_PTR)Pdpte)[pdeindex] = NewPde.QuadPart;
((PULONG_PTR)Pdpte)[pdeindex] = NewPde.QuadPart;
//去做假的Pml4e
PHYSICAL_ADDRESS PhyPml4e = { 0 };
PhyPml4e.QuadPart=OldPml4e.QuadPart & 0x000ffffffffff000;
Pml4ePage = (PULONG_PTR)MmGetVirtualForPhysical(PhyPml4e);
//复制
memcpy(Pml4e, Pml4ePage, PAGE_SIZE);
//找到pdpte的索引 替换物理地址
((PULONG_PTR)Pml4e)[pdpteindex] = NewPdpte.QuadPart;
//去做cr3指向的pml4e的替换 自此页表隔离完毕
LARGE_INTEGER __cr3;
__cr3.QuadPart = __readcr3();
KeUnstackDetachProcess(&Apc);
HANDLE hSection = nullptr;
OBJECT_ATTRIBUTES objattr = { 0 };
UNICODE_STRING usPhysicalMemory = { 0 };
RtlInitUnicodeString(&usPhysicalMemory, L"\\Device\\PhysicalMemory");
InitializeObjectAttributes(&objattr, &usPhysicalMemory, 0, 0, 0);
UINT64 nSize = PAGE_SIZE;
PVOID cr3tmp = 0;
if (!NT_SUCCESS(ZwOpenSection(&hSection, SECTION_ALL_ACCESS, &objattr))) {
//err
DbgPrintEx(77, 0, "[+]failed to open physec\r\n");
return false;
}
if (!NT_SUCCESS(ZwMapViewOfSection(hSection,
NtCurrentProcess(),
&cr3tmp, 0, PAGE_SIZE,
&__cr3, &nSize, ViewUnmap, MEM_TOP_DOWN, PAGE_READWRITE
))) {
DbgPrintEx(77, 0, "[+]unable to map cr3\r\n");
return 0;
}
((PULONG_PTR)cr3tmp)[pml4eindex] = NewPml4e.QuadPart;
//2MB的页表隔离完毕
KdPrint(("[+]Big page hook! bsod is coming\r\n"));
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!