Prototype PTE

本文深入探讨了操作系统中共享内存的工作原理,特别是在多进程环境中物理页的共享机制、Prototype PTE的作用及其如何帮助进程间共享数据。同时介绍了共享页在不同状态间的转换过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#define MM_DEFAULT_PAGED_POOL_START (0xE1000000)
 #define MiPteToProto(lpte) (DWORD)((DWORD)(((((lpte)) >> 11) << 9) +  \
                (((((lpte))) << 24) >> 23) + \
                MM_DEFAULT_PAGED_POOL_START))

int main(int argc, _TCHAR* argv[])
{
    DWORD PTE=0x00938c9c;
    DWORD BASE=MM_DEFAULT_PAGED_POOL_START;
    cout<<std::hex<<MiPteToProto(PTE)<<endl;
    cin.get();    
}
#define MiProtoAddressForPte(proto_va)  \
   ((((((ULONG)proto_va - MmProtopte_Base) >> 1) & (ULONG)0x000000FE)   | \
    (((((ULONG)proto_va - MmProtopte_Base) << 2) & (ULONG)0xfffff800))) | \
    MM_PTE_PROTOTYPE_MASK)// 依据ProtoAddress还原PTE


依据PTE计算出PPTE—ADDRESS

如上图:

DD  dd c01de478
0x00938c9c  依据PTE的标记位为0 无效

 

PPTE-ADDRESS=0xe124e338

kd> dd e124e338
e124e338  17cfa121 176bb121 17def121 17c70860
e124e348  17d71860 17fb2860 17bb3860 17cb4860
e124e358  17f75860 17d36860 11d43860 12f44860
e124e368  11245121 11a46121 14707121 17fbc121
e124e378  181fd860 18a7e860 16fff121 16f40860
e124e388  17d41860 17f42121 17183121 188a2860
e124e398  18ae3121 18964121 18765121 18926121
e124e3a8  18827121 18868860 18d29860 18cb88a0

 

经过PAGE异常后

 

kd> dd c01de478
c01de478  17cfa025 176bb025 17def025 00000000
c01de488  00000000 00000000 00000000 00000000
c01de498  00000000 00000000 00000000 00000000
c01de4a8  11245025 11a46025 14707025 17fbc025
c01de4b8  00000000 00000000 16fff025 00000000
c01de4c8  00000000 17f42025 17183025 00938cca
c01de4d8  18ae3025 18964025 18765025 18926025
c01de4e8  18827025 00938cd6 00938cd8 181ba867

进程1第一次将一些可以被共享的内容读入一个物理页。于是进程1相应的PTE有效,并指向这个物理页。被共享的物理页对应的 PFN DataBase Entry 状态为 Active(Valid) ,share count 值为1。

进程2需要共享这个物理页,于是进程2相应的PTE有效,并指向这个物理页。由于这个物理页现在被进程1和进程2共享,所以对应的 PFN DataBase Entry 的 share count 的值加1,变为2。

进程3需要共享这个物理页,于是进程3相应的PTE有效,并指向这个物理页。这个物理页对应的 PFN DataBase Entry 的 share count 的值加1,变为3。

进程2修整 Working Set (工作集),决定把该页从自己的 Working Set 中移出,于是相应的PTE无效。这个物理页对应的 PFN DataBase Entry 的 share count 的值减1,变为2。

进程1结束,这个物理页对应的 PFN DataBase Entry 的 share count 的值又减1,变为1。

进程2又需要访问这个共享页。于是PTE重新有效,并指向这个物理页。物理页的 share count 加1,又变为2。

进程2,进程3,修整 Working Set (工作集),都把这页从 Working Set 中移出,于是两个进程相应的PTE都无效。物理页的 share count 从 2 变成了 0。当变成0时,该物理页的状态从 Active(Valid) 变成了 Standby,链入了 Standby 链,不过该物理页中的内容不会被改变。

进程2又需要访问这个共享页。由于该物理页在 Standby 链上,内容没有被改变。于是直接取回该物理页,PTE重新有效并指向这个物理页。物理页状态从 Standby 变为 Active(Valid) , share count 变为1。

进程2又修整 Working Set (工作集),决定把该页从自己的 Working Set 中移出,于是相应的PTE无效。这个物理页的 share count 的值减1,变为0。当变成0时,该物理页的状态从 Active(Valid) 变成了 Standby,链入了 Standby 链,不过该物理页中的内容不会被改变。

系统需要内存,从 Standby 链上取走了该物理页。

进程2又需要访问这个共享页。没有物理页有原来的数据了,于是分配一个新的物理页,从文件中将数据读入。于是进程2相应的PTE有效,并指向这个新的物理页。这个物理页对应的 PFN DataBase Entry 状态为Active(Valid) ,share count 值为1。

    需要强调的一点是,只有被共享的物理页的 share count 减为 0 时,才能被移入 Standby 链,然后被用来做其他事。如果 share count 不为0,就说明还有进程在使用这个物理页,如果这时把这个物理页移入 Standby 链,可能会有非常严重的后果。比如放着被共享的dll的程序代码的一个物理页,被多个进程共享,而其中一个结束,share count 减1但不为0,这时如果把这个物理页移入 Standby 链,系统又把这个物理页给清零,放入 Zeroed 链中待用。而这时其他几个进程的相应的PTE仍然是有效的,并且指向这个本来该是程序代码的物理页。当这几个进程执行这里的代码的时候,将会彻底出错。如果 share count 为0 ,所有进程相应的 PTE 都已经无效了。

    共享机制还有一个问题。一个被共享的物理页 share count 为0 ,并且已经被用来做其他事,所有进程相应的 PTE 都已经无效了。当一个进程访问相应 PTE 对应的地址空间,系统会分配一个新的物理页,从文件中将数据读入新的物理页,相应的PTE有效,并指向这个新的物理页,这样这个进程就可以访问这个共享页。但是其他的进程无法知道这个新的物理页,他们相应的PTE仍然无效。他们如果也重新访问这个共享页,他们将如何得知新的物理页来填入PTE?Win2k 使用 Prototype PTE 来解决这个问题。

    对于一个载入内存的应用程序,载入内存的动态链接库,或者一个文件映射,他们都有可能被共享。比如一个可能被共享的东西,映射到地址空间,需要100页,那么每页都有一个相应的 Prototype PTE (4个字节)。一个进程把这个100页的共享的东西映射到地址空间,需要用100个PTE。这100个PTE中,有效的PTE指向共享的物理页,无效的PTE将指向相应的 Prototype PTE ,Prototype PTE 指向物理页。这样一来,当遇到前面的问题,一个进程重新访问一个共享页,而这个共享页原来映射的物理页已经做其他事,系统分配新的物理页,把进程相应的PTE指向新的物理页,并把PTE变为有效之后,也把 Prototype PTE 指向新的物理页。其他的进程重新访问这个共享页时,他们的PTE是无效的,并且指向 Prototype PTE ,而 Prototype PTE 这时就已经指向了新的物理页,于是他们就可以把相应的PTE指向新的物理页,并把PTE变为有效。

    载入内存的应用程序,载入内存的动态链接库,或者一个文件映射,他们都位于用户地址空间。为了描述方便我们把这些都叫做共享的东西。一个共享的东西都会有一个位于系统地址空间的 Segment 结构,这个共享的东西的 Prototype PTE 都顺序的放在这个 Segment 结构的 ProtoPtes数组中。比如一个共享的东西,映射到地址空间需要100页,那么它就有100个 Prototype PTE 放在它的 Segment 结构的 ProtoPtes数组中,并且它的第0页对应的 Prototype PTE 在数组的第0项,它的第1页对应的 Prototype PTE 在数组的第1项。Segment 结构0x38字节长,其中比较重要的是偏移+34处的 4个字节长的 ProtoPtes。ProtoPtes 中为 ProtoPtes数组 的首地址,不过通常情况下,ProtoPtes数组 就紧跟在 0x38字节长的 Segment 结构之后。Segment 结构偏移+8处4个字节长的 Total Ptes 指明了 ProtoPtes数组 中元素的个数。Segment 结构偏移+0处的4个字节长的 ControlArea,是一个指向 ControlArea 结构的指针,ControlArea 结构是一个很重要的结构,通过它我们可以找到相应的 File Object ,ControlArea 结构还有指回 Segment 结构 的指针

 

#include <ntifs.h> ULONG_PTR pPhyAddr[5] = { 0 }; ULONG IsPdeLager = 0; ULONG_PTR newPPEphy = 0; //ULONG_PTR pPhyAddr[5] = { 0 }; ULONG_PTR newPDEphy = 0; ULONG_PTR newPTEphy = 0; ULONG_PTR newphy = 0; typedef struct _HARDWARE_PTE { ULONG64 Valid : 1; ULONG64 Write : 1; ULONG64 Owner : 1; ULONG64 WriteThrough : 1; ULONG64 CacheDisable : 1; ULONG64 Accessed : 1; ULONG64 Dirty : 1; ULONG64 LargePage : 1; ULONG64 Global : 1; ULONG64 CopyOnWrite : 1; ULONG64 Prototype : 1; ULONG64 reserved0 : 1; ULONG64 PageFrameNumber : 36; ULONG64 reserved1 : 4; ULONG64 SoftwareWsIndex : 11; ULONG64 NoExecute : 1; } HARDWARE_PTE, * PHARDWARE_PTE; BOOLEAN InitHook(ULONG_PTR VirtualAddress_s, ULONG Pid, ULONG_PTR offset) { //1获取虚拟内存的PXE PDPTE pde,pte的索引 ULONG PxeIndex = (VirtualAddress_s >> 0x27) & 0x1FF; UINT32 PPEIndex = (VirtualAddress_s >> 0x1E) & 0x1FF; //PPEIndex UINT32 PDEIndex = (VirtualAddress_s >> 0x15) & 0x1FF; //PDEIndex UINT32 PTEIndex = (VirtualAddress_s >> 0xC) & 0x1FF; //DbgBreakPoint(); //2 获取要hook进程的CR3 PEPROCESS pEprocess = NULL; NTSTATUS status = PsLookupProcessByProcessId(Pid, &pEprocess); if (!NT_SUCCESS(status)) { return 0; } HANDLE hMemory = NULL; UNICODE_STRING unName = { 0 }; RtlInitUnicodeString(&unName, L"\\Device\\PhysicalMemory"); OBJECT_ATTRIBUTES obj; InitializeObjectAttributes(&obj, &unName, OBJ_CASE_INSENSITIVE, NULL, NULL); status = ZwOpenSection(&hMemory, SECTION_ALL_ACCESS, &obj); if (!NT_SUCCESS(status)) { return 0; } SIZE_T sizeView = PAGE_SIZE; PVOID sectionObj = NULL; status = ObReferenceObjectByHandle(hMemory, SECTION_ALL_ACCESS, NULL, KernelMode, &sectionObj, NULL); if (!NT_SUCCESS(status)) { return status; } ULONG_PTR Cr3PhyAddr = *(PULONG64)((ULONG64)pEprocess + KERNEL_CR3_OFFSET) & ~(0xf); PHYSICAL_ADDRESS Cr3 = { 0 }; Cr3.QuadPart = Cr3PhyAddr; ULONG_PTR VirtualAddresss = NULL; status = ZwMapViewOfSection(hMemory, NtCurrentProcess(), &VirtualAddresss, 0, PAGE_SIZE, &Cr3, &sizeView, ViewUnmap, MEM_TOP_DOWN, PAGE_READWRITE); //ULONG_PTR VirtualAddresss = MmMapIoSpace(Cr3, PAGE_SIZE, MmNonCached);//由于Cr3是物理地址我们需要映射到虚拟内存中去 if (!NT_SUCCESS(status)) { return 0; } //3 构建页表 //*(PULONG64)(VirtualAddresss + PxeIndex * 8) |= 70; PHYSICAL_ADDRESS Low = { 0 }; PHYSICAL_ADDRESS High = { MAXULONG64 }; //ppe do { pPhyAddr[0] = (ULONG_PTR)MmAllocateContiguousMemorySpecifyCache(PAGE_SIZE, Low, High, Low, MmCached); newPPEphy = MmGetPhysicalAddress(pPhyAddr[0]).QuadPart; ULONG_PTR PPEPhyAddr = (ULONG_PTR)(((PHARDWARE_PTE)(VirtualAddresss + PxeIndex * 8))->PageFrameNumber) * 0x1000; PHYSICAL_ADDRESS temp = { 0 }; temp.QuadPart = PPEPhyAddr; ULONG_PTR VirtualAddress_PPE = NULL; ZwMapViewOfSection(hMemory, NtCurrentProcess(), &VirtualAddress_PPE, 0, PAGE_SIZE, &temp, &sizeView, ViewUnmap, MEM_TOP_DOWN, PAGE_READWRITE); memcpy(pPhyAddr[0], VirtualAddress_PPE, PAGE_SIZE); //pde pPhyAddr[1] = (ULONG_PTR)MmAllocateContiguousMemorySpecifyCache(PAGE_SIZE, Low, High, Low, MmCached); newPDEphy = MmGetPhysicalAddress(pPhyAddr[1]).QuadPart; ULONG_PTR pdePhy = (ULONG_PTR)(((PHARDWARE_PTE)(VirtualAddress_PPE + PPEIndex * 8))->PageFrameNumber) * 0x1000; temp.QuadPart = pdePhy; ULONG_PTR VirtualAddress_PDE = NULL; ZwMapViewOfSection(hMemory, NtCurrentProcess(), &VirtualAddress_PDE, 0, PAGE_SIZE, &temp, &sizeView, ViewUnmap, MEM_TOP_DOWN, PAGE_READWRITE); memcpy(pPhyAddr[1], VirtualAddress_PDE, PAGE_SIZE); //pte ULONG_PTR ptePhy = (ULONG_PTR)(((PHARDWARE_PTE)(VirtualAddress_PDE + PDEIndex * 8))->PageFrameNumber) * 0x1000; temp.QuadPart = ptePhy; if (((PHARDWARE_PTE)(VirtualAddress_PDE + PDEIndex * 8))->LargePage == 1) { pPhyAddr[2] = (ULONG_PTR)MmAllocateContiguousMemorySpecifyCache(PAGE_SIZE * 1024, Low, High, Low, MmCached); memset(pPhyAddr[2], 0, PAGE_SIZE * 1024); ULONG_PTR Real = MmGetPhysicalAddress(pPhyAddr[2]).QuadPart; ULONG_PTR Real1 = Real; ULONG_PTR Realtemp = 0; if (Real == 0) { MmFreeContiguousMemory(pPhyAddr[0]); MmFreeContiguousMemory(pPhyAddr[1]); MmFreeContiguousMemory(pPhyAddr[2]); return FALSE; } ULONG i = 0; for (i = 0; i < 1024; i++) { Real += PAGE_SIZE; //Real &= 0x1fffff; Realtemp = Real & 0x1fffff; if (!Realtemp) break; } DbgBreakPoint(); pPhyAddr[2] += PAGE_SIZE * (i + 1); newPTEphy = MmGetPhysicalAddress(pPhyAddr[2]).QuadPart; ULONG_PTR VirtualAddress_PTE = NULL; sizeView = PAGE_SIZE * 0x200; ZwMapViewOfSection(hMemory, NtCurrentProcess(), &VirtualAddress_PTE, 0, PAGE_SIZE, &temp, &sizeView, ViewUnmap, MEM_TOP_DOWN, PAGE_READWRITE); memcpy(pPhyAddr[2], VirtualAddress_s & ~(0x1fffff), PAGE_SIZE * 0x200); ((PHARDWARE_PTE)(pPhyAddr[0] + PPEIndex * 8))->PageFrameNumber = newPDEphy >> 12; ((PHARDWARE_PTE)(pPhyAddr[1] + PDEIndex * 8))->PageFrameNumber = newPTEphy >> 12; //((PHARDWARE_PTE)(pPhyAddr[2] + PTEIndex * 8))->Write = 1; ULONG_PTR newOffset = (VirtualAddress_s & 0x1ff000) + offset; //((PHARDWARE_PTE)(pPhyAddr[1] + PTEIndex * 8))->Write = 1; *(PUCHAR)(pPhyAddr[2] + newOffset + 0x27) = 0x90; *(PUCHAR)(pPhyAddr[2] + newOffset + 0x28) = 0x90; *(PUCHAR)(pPhyAddr[2] + newOffset + 0x29) = 0xc3; ULONG_PTR ss = pPhyAddr[2]; ULONG_PTR ss2 = VirtualAddress_s & ~(0x1fffff); IsPdeLager = 1; break; } pPhyAddr[2] = (ULONG_PTR)MmAllocateContiguousMemorySpecifyCache(PAGE_SIZE, Low, High, Low, MmCached); newPTEphy = MmGetPhysicalAddress(pPhyAddr[2]).QuadPart; ULONG_PTR VirtualAddress_PTE = NULL; ZwMapViewOfSection(hMemory, NtCurrentProcess(), &VirtualAddress_PTE, 0, PAGE_SIZE, &temp, &sizeView, ViewUnmap, MEM_TOP_DOWN, PAGE_READWRITE); memcpy(pPhyAddr[2], VirtualAddress_PTE, PAGE_SIZE); //物理内存 pPhyAddr[3] = (ULONG_PTR)MmAllocateContiguousMemorySpecifyCache(PAGE_SIZE, Low, High, Low, MmCached); newphy = MmGetPhysicalAddress(pPhyAddr[3]).QuadPart; ULONG_PTR Phy = (ULONG_PTR)(((PHARDWARE_PTE)(VirtualAddress_PTE + PTEIndex * 8))->PageFrameNumber) * 0x1000; temp.QuadPart = Phy; ULONG_PTR VirtualAddress_PHY = NULL; ZwMapViewOfSection(hMemory, NtCurrentProcess(), &VirtualAddress_PHY, 0, PAGE_SIZE, &temp, &sizeView, ViewUnmap, MEM_TOP_DOWN, PAGE_READWRITE); memcpy(pPhyAddr[3], VirtualAddress_PHY, PAGE_SIZE); } while (0); //ULONG_PTR ss3 = pPhyAddr[3]; //ULONG_PTR ss1 = pPhyAddr[1]; //ULONG_PTR ss2 = pPhyAddr[2]; //DbgBreakPoint(); //4 修改PXE PPE PDE PTE从而改变 if (IsPdeLager) { ((PHARDWARE_PTE)(VirtualAddresss + PxeIndex * 8))->PageFrameNumber = newPPEphy >> 12; return TRUE; } ((PHARDWARE_PTE)(VirtualAddresss + PxeIndex * 8))->PageFrameNumber = newPPEphy >> 12; ((PHARDWARE_PTE)(pPhyAddr[0] + PPEIndex * 8))->PageFrameNumber = newPDEphy >> 12; ((PHARDWARE_PTE)(pPhyAddr[1] + PDEIndex * 8))->PageFrameNumber = newPTEphy >> 12; ((PHARDWARE_PTE)(pPhyAddr[2] + PTEIndex * 8))->PageFrameNumber = newphy >> 12; return TRUE; }; VOID unstallHook() { if (IsPdeLager) { MmFreeContiguousMemory(pPhyAddr[0]); MmFreeContiguousMemory(pPhyAddr[1]); MmFreeContiguousMemory(pPhyAddr[2]); return; } } VOID DriverUnload(PDRIVER_OBJECT pDriver) { unstallHook(); } NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING pRes) { pDriver->DriverUnload = DriverUnload; PKLDR_DATA_TABLE_ENTRY pKldr = (PKLDR_DATA_TABLE_ENTRY)pDriver->DriverSection; pKldr->Flags |= 0x20; //NTSTATUS status = PsSetCreateProcessNotifyRoutine(ProcessNotifyRoutine, FALSE); UNICODE_STRING ss = { 0 }; RtlInitUnicodeString(&ss, L"NtOpenProcess"); ULONG_PTR NtOpenAddr = MmGetSystemRoutineAddress(&ss); ULONG_PTR funcVir = NtOpenAddr & ~(0xfff); ULONG_PTR funcOffset = NtOpenAddr & 0xfff; InitHook(funcVir, 8568, funcOffset); //SetPTEHook(ssz); return STATUS_SUCCESS; }修改错误严重性 代码 说明 项目 文件 行 禁止显示状态 详细信息 错误(活动) E0020 未定义标识符 "(VirtualAddress_s" pte1 C:\Users\17116\source\repos\pte1\pte1\源.cpp 154 错误(活动) E0020 未定义标识符 "PKLDR_DATA_TABLE_ENTRY" pte1 C:\Users\17116\source\repos\pte1\pte1\源.cpp 219 错误(活动) E0020 未定义标识符 "PKLDR_DATA_TABLE_ENTRY" pte1 C:\Users\17116\source\repos\pte1\pte1\源.cpp 219 错误(活动) E0020 未定义标识符 "KERNEL_CR3_OFFSET" pte1 C:\Users\17116\source\repos\pte1\pte1\源.cpp 68 错误(活动) E2486 找不到用户定义的文本运算符 pte1 C:\Users\17116\source\repos\pte1\pte1\源.cpp 154 错误(活动) E0065 应输入“;” pte1 C:\Users\17116\source\repos\pte1\pte1\源.cpp 219 错误(活动) E0167 "unsigned long long" 类型的实参与 "const void *" 类型的形参不兼容 pte1 C:\Users\17116\source\repos\pte1\pte1\源.cpp 149 错误(活动) E0167 "ULONG_PTR" (aka "unsigned long long") 类型的实参与 "void *" 类型的形参不兼容 pte1 C:\Users\17116\source\repos\pte1\pte1\源.cpp 98 错误(活动) E0167 "ULONG_PTR" (aka "unsigned long long") 类型的实参与 "void *" 类型的形参不兼容 pte1 C:\Users\17116\source\repos\pte1\pte1\源.cpp 108 错误(活动) E0167 "ULONG_PTR" (aka "unsigned long long") 类型的实参与 "void *" 类型的形参不兼容 pte1 C:\Users\17116\source\repos\pte1\pte1\源.cpp 118 错误(活动) E0167 "ULONG_PTR" (aka "unsigned long long") 类型的实参与 "void *" 类型的形参不兼容 pte1 C:\Users\17116\source\repos\pte1\pte1\源.cpp 149 错误(活动) E0167 "ULONG_PTR" (aka "unsigned long long") 类型的实参与 "void *" 类型的形参不兼容 pte1 C:\Users\17116\source\repos\pte1\pte1\源.cpp 170 错误(活动) E0167 "ULONG_PTR" (aka "unsigned long long") 类型的实参与 "void *" 类型的形参不兼容 pte1 C:\Users\17116\source\repos\pte1\pte1\源.cpp 180 错误(活动) E0167 "ULONG_PTR" (aka "unsigned long long") 类型的实参与 "PVOID" (aka "void *") 类型的形参不兼容 pte1 C:\Users\17116\source\repos\pte1\pte1\源.cpp 90 错误(活动) E0167 "ULONG_PTR" (aka "unsigned long long") 类型的实参与 "PVOID" (aka "void *") 类型的形参不兼容 pte1 C:\Users\17116\source\repos\pte1\pte1\源.cpp 101 错误(活动) E0167 "ULONG_PTR" (aka "unsigned long long") 类型的实参与 "PVOID" (aka "void *") 类型的形参不兼容 pte1 C:\Users\17116\source\repos\pte1\pte1\源.cpp 119 错误(活动) E0167 "ULONG_PTR" (aka "unsigned long long") 类型的实参与 "PVOID" (aka "void *") 类型的形参不兼容 pte1 C:\Users\17116\source\repos\pte1\pte1\源.cpp 124 错误(活动) E0167 "ULONG_PTR" (aka "unsigned long long") 类型的实参与 "PVOID" (aka "void *") 类型的形参不兼容 pte1 C:\Users\17116\source\repos\pte1\pte1\源.cpp 125 错误(活动) E0167 "ULONG_PTR" (aka "unsigned long long") 类型的实参与 "PVOID" (aka "void *") 类型的形参不兼容 pte1 C:\Users\17116\source\repos\pte1\pte1\源.cpp 126 错误(活动) E0167 "ULONG_PTR" (aka "unsigned long long") 类型的实参与 "PVOID" (aka "void *") 类型的形参不兼容 pte1 C:\Users\17116\source\repos\pte1\pte1\源.cpp 142 错误(活动) E0167 "ULONG_PTR" (aka "unsigned long long") 类型的实参与 "PVOID" (aka "void *") 类型的形参不兼容 pte1 C:\Users\17116\source\repos\pte1\pte1\源.cpp 165 错误(活动) E0167 "ULONG_PTR" (aka "unsigned long long") 类型的实参与 "PVOID" (aka "void *") 类型的形参不兼容 pte1 C:\Users\17116\source\repos\pte1\pte1\源.cpp 173 错误(活动) E0167 "ULONG_PTR" (aka "unsigned long long") 类型的实参与 "PVOID" (aka "void *") 类型的形参不兼容 pte1 C:\Users\17116\source\repos\pte1\pte1\源.cpp 205 错误(活动) E0167 "ULONG_PTR" (aka "unsigned long long") 类型的实参与 "PVOID" (aka "void *") 类型的形参不兼容 pte1 C:\Users\17116\source\repos\pte1\pte1\源.cpp 206 错误(活动) E0167 "ULONG_PTR" (aka "unsigned long long") 类型的实参与 "PVOID" (aka "void *") 类型的形参不兼容 pte1 C:\Users\17116\source\repos\pte1\pte1\源.cpp 207 错误(活动) E0167 "ULONG_PTR" (aka "unsigned long long") 类型的实参与 "const void *" 类型的形参不兼容 pte1 C:\Users\17116\source\repos\pte1\pte1\源.cpp 98 错误(活动) E0167 "ULONG_PTR" (aka "unsigned long long") 类型的实参与 "const void *" 类型的形参不兼容 pte1 C:\Users\17116\source\repos\pte1\pte1\源.cpp 108 错误(活动) E0167 "ULONG_PTR" (aka "unsigned long long") 类型的实参与 "const void *" 类型的形参不兼容 pte1 C:\Users\17116\source\repos\pte1\pte1\源.cpp 170 错误(活动) E0167 "ULONG_PTR" (aka "unsigned long long") 类型的实参与 "const void *" 类型的形参不兼容 pte1 C:\Users\17116\source\repos\pte1\pte1\源.cpp 180 错误(活动) E0167 "ULONG_PTR *" (aka "unsigned long long *") 类型的实参与 "PVOID *" (aka "void **") 类型的形参不兼容 pte1 C:\Users\17116\source\repos\pte1\pte1\源.cpp 74 错误(活动) E0167 "ULONG_PTR *" (aka "unsigned long long *") 类型的实参与 "PVOID *" (aka "void **") 类型的形参不兼容 pte1 C:\Users\17116\source\repos\pte1\pte1\源.cpp 96 错误(活动) E0167 "ULONG_PTR *" (aka "unsigned long long *") 类型的实参与 "PVOID *" (aka "void **") 类型的形参不兼容 pte1 C:\Users\17116\source\repos\pte1\pte1\源.cpp 106 错误(活动) E0167 "ULONG_PTR *" (aka "unsigned long long *") 类型的实参与 "PVOID *" (aka "void **") 类型的形参不兼容 pte1 C:\Users\17116\source\repos\pte1\pte1\源.cpp 147 错误(活动) E0167 "ULONG_PTR *" (aka "unsigned long long *") 类型的实参与 "PVOID *" (aka "void **") 类型的形参不兼容 pte1 C:\Users\17116\source\repos\pte1\pte1\源.cpp 168 错误(活动) E0167 "ULONG_PTR *" (aka "unsigned long long *") 类型的实参与 "PVOID *" (aka "void **") 类型的形参不兼容 pte1 C:\Users\17116\source\repos\pte1\pte1\源.cpp 178 错误(活动) E0167 "ULONG" (aka "unsigned long") 类型的实参与 "HANDLE" (aka "void *") 类型的形参不兼容 pte1 C:\Users\17116\source\repos\pte1\pte1\源.cpp 43 错误(活动) E0144 "PVOID" (aka "void *") 类型的值不能用于初始化 "ULONG_PTR" (aka "unsigned long long") 类型的实体 pte1 C:\Users\17116\source\repos\pte1\pte1\源.cpp 224
07-16
#include <ntifs.h> // 页表项结构 typedef struct _HARDWARE_PTE { ULONG64 Valid : 1; ULONG64 Write : 1; // ... 其他位域与Win10兼容 ULONG64 PageFrameNumber : 36; ULONG64 NoExecute : 1; } HARDWARE_PTE, * PHARDWARE_PTE; // 全局资源记录 typedef struct _HOOK_CONTEXT { ULONG_PTR NewPages[4]; // [0]PPE [1]PDE [2]PTE [3]Data ULONG_PTR OriginalPTE; BOOLEAN IsLargePage; } HOOK_CONTEXT, * PHOOK_CONTEXT; NTSTATUS MapPhysicalMemory(IN PHYSICAL_ADDRESS PhysicalAddress, OUT PVOID* MappedVa) { static HANDLE hSection = NULL; SIZE_T size = PAGE_SIZE; if (!hSection) { UNICODE_STRING physName = RTL_CONSTANT_STRING(L"\\Device\\PhysicalMemory"); OBJECT_ATTRIBUTES oa; InitializeObjectAttributes(&oa, &physName, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL); if (!NT_SUCCESS(ZwOpenSection(&hSection, SECTION_ALL_ACCESS, &oa))) return STATUS_UNSUCCESSFUL; } return ZwMapViewOfSection(hSection, NtCurrentProcess(), MappedVa, 0, size, &PhysicalAddress, &size, ViewUnmap, 0, PAGE_READWRITE); } NTSTATUS InitHookWin10(IN ULONG_PTR TargetVa, IN HANDLE Pid, IN ULONG_PTR Offset) { PEPROCESS Process = NULL; PHYSICAL_ADDRESS Cr3Pa = { 0 }; PVOID Cr3Va = NULL; HOOK_CONTEXT ctx = { 0 }; // 1. 获取目标进程CR3 NTSTATUS status = PsLookupProcessByProcessId(Pid, &Process); if (!NT_SUCCESS(status)) return status; Cr3Pa.QuadPart = *(ULONG_PTR*)((PUCHAR)Process + 0x28) & ~0xF; // Win10 CR3偏移 ObDereferenceObject(Process); // 2. 映射CR3 status = MapPhysicalMemory(Cr3Pa, &Cr3Va); if (!NT_SUCCESS(status)) return status; // 3. 计算页表索引 (x64四级页表) ULONG Pml4Index = (TargetVa >> 39) & 0x1FF; ULONG PdptIndex = (TargetVa >> 30) & 0x1FF; ULONG PdIndex = (TargetVa >> 21) & 0x1FF; ULONG PtIndex = (TargetVa >> 12) & 0x1FF; // 4. 复制并修改PML4E PHYSICAL_ADDRESS LowAddr = { 0 }, HighAddr = { .QuadPart = ~0ULL }; ctx.NewPages[0] = (ULONG_PTR)MmAllocateContiguousMemorySpecifyCache( PAGE_SIZE, LowAddr, HighAddr, LowAddr, MmCached); PHARDWARE_PTE OrigPml4e = (PHARDWARE_PTE)((PUCHAR)Cr3Va + Pml4Index * 8); PHYSICAL_ADDRESS PdptPa = { .QuadPart = OrigPml4e->PageFrameNumber << 12 }; PVOID PdptVa = NULL; MapPhysicalMemory(PdptPa, &PdptVa); memcpy((PVOID)ctx.NewPages[0], PdptVa, PAGE_SIZE); // 复制原始PDPT // 5. 处理PDPTE ctx.NewPages[1] = (ULONG_PTR)MmAllocateContiguousMemorySpecifyCache( PAGE_SIZE, LowAddr, HighAddr, LowAddr, MmCached); PHARDWARE_PTE OrigPdpte = (PHARDWARE_PTE)((PUCHAR)PdptVa + PdptIndex * 8); PHYSICAL_ADDRESS PdPa = { .QuadPart = OrigPdpte->PageFrameNumber << 12 }; PVOID PdVa = NULL; MapPhysicalMemory(PdPa, &PdVa); memcpy((PVOID)ctx.NewPages[1], PdVa, PAGE_SIZE); // 复制原始PD // 6. 检查大页 PHARDWARE_PTE OrigPde = (PHARDWARE_PTE)((PUCHAR)PdVa + PdIndex * 8); ctx.IsLargePage = OrigPde->LargePage; if (ctx.IsLargePage) { // 处理2MB大页 ULONG_PTR LargePageBase = TargetVa & ~0x1FFFFF; PHYSICAL_ADDRESS DataPa = { .QuadPart = OrigPde->PageFrameNumber << 12 }; // 分配2MB对齐内存 PVOID LargePageBuf = MmAllocateContiguousMemorySpecifyCache( 0x200000, LowAddr, HighAddr, LowAddr, MmCached); PHYSICAL_ADDRESS NewDataPa = MmGetPhysicalAddress(LargePageBuf); // 复制原始数据 PVOID OrigDataVa = NULL; MapPhysicalMemory(DataPa, &OrigDataVa); memcpy(LargePageBuf, OrigDataVa, 0x200000); // 修改新页面指令 PUCHAR HookLoc = (PUCHAR)LargePageBuf + (TargetVa & 0x1FFFFF) + Offset; HookLoc[0] = 0x90; HookLoc[1] = 0x90; HookLoc[2] = 0xC3; // NOP; NOP; RET // 更新PDE PHARDWARE_PTE NewPde = (PHARDWARE_PTE)(ctx.NewPages[1] + PdIndex * 8); NewPde->PageFrameNumber = NewDataPa.QuadPart >> 12; ctx.NewPages[3] = (ULONG_PTR)LargePageBuf; } else { // 处理4KB页 ctx.NewPages[2] = (ULONG_PTR)MmAllocateContiguousMemorySpecifyCache( PAGE_SIZE, LowAddr, HighAddr, LowAddr, MmCached); PHYSICAL_ADDRESS PtPa = { .QuadPart = OrigPde->PageFrameNumber << 12 }; PVOID PtVa = NULL; MapPhysicalMemory(PtPa, &PtVa); memcpy((PVOID)ctx.NewPages[2], PtVa, PAGE_SIZE); // 复制原始PT // 处理PTE PHARDWARE_PTE OrigPte = (PHARDWARE_PTE)((PUCHAR)PtVa + PtIndex * 8); ctx.OriginalPTE = OrigPte->Value; PHYSICAL_ADDRESS DataPa = { .QuadPart = OrigPte->PageFrameNumber << 12 }; // 分配新数据页 PVOID NewData = MmAllocateContiguousMemorySpecifyCache( PAGE_SIZE, LowAddr, HighAddr, LowAddr, MmCached); PHYSICAL_ADDRESS NewDataPa = MmGetPhysicalAddress(NewData); // 复制原始数据 PVOID OrigDataVa = NULL; MapPhysicalMemory(DataPa, &OrigDataVa); memcpy(NewData, OrigDataVa, PAGE_SIZE); // 修改新页面指令 PUCHAR HookLoc = (PUCHAR)NewData + (TargetVa & 0xFFF) + Offset; HookLoc[0] = 0x90; HookLoc[1] = 0x90; HookLoc[2] = 0xC3; // 更新PTE PHARDWARE_PTE NewPte = (PHARDWARE_PTE)(ctx.NewPages[2] + PtIndex * 8); NewPte->PageFrameNumber = NewDataPa.QuadPart >> 12; ctx.NewPages[3] = (ULONG_PTR)NewData; } // 7. 更新页表链 PHARDWARE_PTE NewPdpte = (PHARDWARE_PTE)(ctx.NewPages[0] + PdptIndex * 8); NewPdpte->PageFrameNumber = MmGetPhysicalAddress((PVOID)ctx.NewPages[1]).QuadPart >> 12; PHARDWARE_PTE NewPml4e = (PHARDWARE_PTE)((PUCHAR)Cr3Va + Pml4Index * 8); NewPml4e->PageFrameNumber = MmGetPhysicalAddress((PVOID)ctx.NewPages[0]).QuadPart >> 12; // 8. 清理映射 ZwUnmapViewOfSection(NtCurrentProcess(), Cr3Va); // ... 清理其他映射 return STATUS_SUCCESS; } // 驱动卸载时释放资源 VOID UninstallHook(PHOOK_CONTEXT ctx) { for (int i = 0; i < 4; i++) { if (ctx->NewPages[i]) MmFreeContiguousMemory((PVOID)ctx->NewPages[i]); } } // 驱动入口示例 NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) { DriverObject->DriverUnload = [](PDRIVER_OBJECT drv) { // 实际使用中需保存ctx HOOK_CONTEXT dummy = { 0 }; UninstallHook(&dummy); }; // 获取NtOpenProcess地址 UNICODE_STRING funcName = RTL_CONSTANT_STRING(L"NtOpenProcess"); ULONG_PTR funcAddr = (ULONG_PTR)MmGetSystemRoutineAddress(&funcName); ULONG_PTR pageBase = funcAddr & ~0xFFF; ULONG_PTR offset = funcAddr & 0xFFF; return InitHookWin10(pageBase, (HANDLE)1234, offset); // 1234为目标PID } 严重性 代码 说明 项目 文件 行 禁止显示状态 详细信息 错误(活动) E0029 应输入表达式 pte1 C:\Users\17116\source\repos\pte1\pte1\源.cpp 61 错误(活动) E0029 应输入表达式 pte1 C:\Users\17116\source\repos\pte1\pte1\源.cpp 66 错误(活动) E0029 应输入表达式 pte1 C:\Users\17116\source\repos\pte1\pte1\源.cpp 77 错误(活动) E0135 类 "_HARDWARE_PTE" 没有成员 "LargePage" pte1 C:\Users\17116\source\repos\pte1\pte1\源.cpp 85 错误(活动) E0029 应输入表达式 pte1 C:\Users\17116\source\repos\pte1\pte1\源.cpp 90 错误(活动) E0029 应输入表达式 pte1 C:\Users\17116\source\repos\pte1\pte1\源.cpp 116 错误(活动) E0135 类 "_HARDWARE_PTE" 没有成员 "Value" pte1 C:\Users\17116\source\repos\pte1\pte1\源.cpp 123 错误(活动) E0029 应输入表达式 pte1 C:\Users\17116\source\repos\pte1\pte1\源.cpp 124
07-16
[讨论][转帖][讨论][原创]windows Hook内核api,能过win10 22H2的pg 发表于: 2023-12-6 17:35 12258 举报 最近一直在思考如何hook内核函数而不触发pg,于是我在看雪找到一篇文章讲解如何hook内核函数不触发pg,链接:https://bbs.kanxue.com/thread-266781.htm。 文章并没有讲解思路,直接贴上代码,在看完他的代码后,我理解了其思路,发现代码有点冗长,存在一些多余的操作,不过这也给了我过pg的思路。 windows64位系统内核中内核函数线性地址对应的物理地址是pte里面的物理地址,是不是可以修改pte里面物理地址从而改变线性地址对应的物理地址,但是内核中的函数的pte里面的物理地址是全局的,只要一修改,其他进程也会受到影响。好在我们通过进程的Cr3找到进程的内核函数地址对应的PXE,这个PXE不是全局的,如果修改了PXE里面的值,该进程内核函数对应的物理地址也就变了,但是不会影响的其他进程。于是我们可以重构页表,通过修改PXE,PDPTE,PDE,PTE来修改该进程内核函数对应的物理地址,从而可以对该内核函数进行hook而不触发pg。大致做法如下图: 图片描述 图片描述 图片描述 我们可以通过映射物理内存到虚拟内存的方法来修改PXE,PDPTE,PDE,PTE。 这里一共两份源码,一份win7,一份win10,win10的源码针对2Mb大页的。 下面是源码: 支持win7 #include<ntifs.h> ULONG_PTR pPhyAddr[5] = { 0 }; typedef struct _HARDWARE_PTE { ULONG64 Valid : 1; ULONG64 Write : 1; ULONG64 Owner : 1; ULONG64 WriteThrough : 1; ULONG64 CacheDisable : 1; ULONG64 Accessed : 1; ULONG64 Dirty : 1; ULONG64 LargePage : 1; ULONG64 Global : 1; ULONG64 CopyOnWrite : 1; ULONG64 Prototype : 1; ULONG64 reserved0 : 1; ULONG64 PageFrameNumber : 36; ULONG64 reserved1 : 4; ULONG64 SoftwareWsIndex : 11; ULONG64 NoExecute : 1; } HARDWARE_PTE, *PHARDWARE_PTE; BOOLEAN InitHook(ULONG_PTR VirtualAddress_s, ULONG Pid, ULONG_PTR offset) { //1获取虚拟内存的PXE PDPTE pde,pte的索引 ULONG PxeIndex = (VirtualAddress_s >> 0x27) & 0x1FF; UINT32 PPEIndex = (VirtualAddress_s >> 0x1E) & 0x1FF; //PPEIndex UINT32 PDEIndex = (VirtualAddress_s >> 0x15) & 0x1FF; //PDEIndex UINT32 PTEIndex = (VirtualAddress_s >> 0xC) & 0x1FF; 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 //DbgBreakPoint(); //2 获取要hook进程的CR3 PEPROCESS pEprocess = NULL; NTSTATUS status = PsLookupProcessByProcessId(Pid, &pEprocess); if (!NT_SUCCESS(status)) { return 0; } ULONG_PTR Cr3PhyAddr = *(PULONG64)((ULONG64)pEprocess + KERNEL_CR3_OFFSET); PHYSICAL_ADDRESS Cr3 = { 0 }; Cr3.QuadPart = Cr3PhyAddr; ULONG_PTR VirtualAddresss = MmMapIoSpace(Cr3, PAGE_SIZE, MmNonCached);//由于Cr3是物理地址我们需要映射到虚拟内存中去 if (!VirtualAddresss) { return 0; } //3 构建页表 //*(PULONG64)(VirtualAddresss + PxeIndex * 8) |= 70; PHYSICAL_ADDRESS Low = { 0 }; PHYSICAL_ADDRESS High = { MAXULONG64 }; //ppe pPhyAddr[0] = (ULONG_PTR)MmAllocateContiguousMemorySpecifyCache(PAGE_SIZE, Low, High, Low, MmCached); ULONG_PTR newPPEphy = MmGetPhysicalAddress(pPhyAddr[0]).QuadPart; ULONG_PTR PPEPhyAddr = (ULONG_PTR)(((PHARDWARE_PTE)(VirtualAddresss + PxeIndex * 8))->PageFrameNumber) * 0x1000; PHYSICAL_ADDRESS temp = { 0 }; temp.QuadPart = PPEPhyAddr; ULONG_PTR VirtualAddress_PPE= MmMapIoSpace(temp, PAGE_SIZE, MmNonCached); memcpy(pPhyAddr[0], VirtualAddress_PPE, PAGE_SIZE); //pde pPhyAddr[1] = (ULONG_PTR)MmAllocateContiguousMemorySpecifyCache(PAGE_SIZE, Low, High, Low, MmCached); ULONG_PTR newPDEphy= MmGetPhysicalAddress(pPhyAddr[1]).QuadPart; ULONG_PTR pdePhy= (ULONG_PTR)(((PHARDWARE_PTE)(VirtualAddress_PPE + PPEIndex * 8))->PageFrameNumber) * 0x1000; temp.QuadPart = pdePhy; ULONG_PTR VirtualAddress_PDE = MmMapIoSpace(temp,PAGE_SIZE, MmNonCached); memcpy(pPhyAddr[1], VirtualAddress_PDE, PAGE_SIZE); //pte pPhyAddr[2] = (ULONG_PTR)MmAllocateContiguousMemorySpecifyCache(PAGE_SIZE, Low, High, Low, MmCached); ULONG_PTR newPTEphy = MmGetPhysicalAddress(pPhyAddr[2]).QuadPart; ULONG_PTR ptePhy = (ULONG_PTR)(((PHARDWARE_PTE)(VirtualAddress_PDE + PDEIndex * 8))->PageFrameNumber) * 0x1000; temp.QuadPart = ptePhy; ULONG_PTR VirtualAddress_PTE = MmMapIoSpace(temp, PAGE_SIZE, MmNonCached); memcpy(pPhyAddr[2], VirtualAddress_PTE, PAGE_SIZE); //物理内存 pPhyAddr[3] = (ULONG_PTR)MmAllocateContiguousMemorySpecifyCache(PAGE_SIZE, Low, High, Low, MmCached); ULONG_PTR newphy = MmGetPhysicalAddress(pPhyAddr[3]).QuadPart; ULONG_PTR Phy = (ULONG_PTR)(((PHARDWARE_PTE)(VirtualAddress_PTE + PTEIndex * 8))->PageFrameNumber) * 0x1000; temp.QuadPart = Phy; ULONG_PTR VirtualAddress_PHY = MmMapIoSpace(temp, PAGE_SIZE, MmNonCached); memcpy(pPhyAddr[3], VirtualAddress_PHY, PAGE_SIZE); //ULONG_PTR ss3 = pPhyAddr[3]; //ULONG_PTR ss1 = pPhyAddr[1]; //ULONG_PTR ss2 = pPhyAddr[2]; //DbgBreakPoint(); //4 修改PXE PPE PDE PTE从而改变 ((PHARDWARE_PTE)(VirtualAddresss + PxeIndex * 8))->PageFrameNumber = newPPEphy >> 12; ((PHARDWARE_PTE)(pPhyAddr[0] + PPEIndex * 8))->PageFrameNumber = newPDEphy >> 12; ((PHARDWARE_PTE)(pPhyAddr[1] + PDEIndex * 8))->PageFrameNumber = newPTEphy >> 12; ((PHARDWARE_PTE)(pPhyAddr[2] + PTEIndex * 8))->PageFrameNumber = newphy >> 12; ((PHARDWARE_PTE)(pPhyAddr[2] + PTEIndex * 8))->Write = 1; *(PUCHAR)(pPhyAddr[3] + offset + 0x27) = 0x90; *(PUCHAR)(pPhyAddr[3] + offset + 0x28) = 0x90; *(PUCHAR)(pPhyAddr[3] + offset + 0x29) = 0xc3; return TRUE; } VOID unstallHook() { 1 2 3 4 MmFreeContiguousMemory(pPhyAddr[0]); MmFreeContiguousMemory(pPhyAddr[1]); MmFreeContiguousMemory(pPhyAddr[2]); MmFreeContiguousMemory(pPhyAddr[3]); } VOID DriverUnload(PDRIVER_OBJECT pDriver) { unstallHook(); } NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING pRes) { pDriver->DriverUnload = DriverUnload; UNICODE_STRING ss = { 0 }; RtlInitUnicodeString(&ss, L"NtOpenProcess"); ULONG_PTR NtOpenAddr = MmGetSystemRoutineAddress(&ss); ULONG_PTR funcVir = NtOpenAddr & ~(0xfff); ULONG_PTR funcOffset = NtOpenAddr & 0xfff; InitHook(funcVir, 2280, funcOffset); //SetPTEHook(ssz); return STATUS_SUCCESS; } 当我附加到被我下钩子的进程,NtOpenProcess的结果在内存中是这样的: 图片描述 附加到我们没有HOOK的其他进程: 图片描述 在win7 64位系统中存在了5小时未发生pg。 我的这份源码纯粹是为了实验,封装的不太好,请谅解。 由于我刚学习64位系统内核没多久,可能文章会有一些错误,希望各位大佬能够指正。 对于win10,由于不能像win7用同样的方法映射页表的物理内存,我换了一种方式,且这次是2Mb的大页,细节有很多发生了变化,但思路还是一样的,我没有完善卸载函数,卸载的时候会蓝屏。 下面是源码: ULONG_PTR pPhyAddr[5] = { 0 }; ULONG IsPdeLager = 0; ULONG_PTR newPPEphy = 0; //ULONG_PTR pPhyAddr[5] = { 0 }; ULONG_PTR newPDEphy = 0; ULONG_PTR newPTEphy = 0; ULONG_PTR newphy = 0; typedef struct _HARDWARE_PTE { ULONG64 Valid : 1; ULONG64 Write : 1; ULONG64 Owner : 1; ULONG64 WriteThrough : 1; ULONG64 CacheDisable : 1; ULONG64 Accessed : 1; ULONG64 Dirty : 1; ULONG64 LargePage : 1; ULONG64 Global : 1; ULONG64 CopyOnWrite : 1; ULONG64 Prototype : 1; ULONG64 reserved0 : 1; ULONG64 PageFrameNumber : 36; ULONG64 reserved1 : 4; ULONG64 SoftwareWsIndex : 11; ULONG64 NoExecute : 1; } HARDWARE_PTE, *PHARDWARE_PTE; BOOLEAN InitHook(ULONG_PTR VirtualAddress_s, ULONG Pid, ULONG_PTR offset) { 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 //1获取虚拟内存的PXE PDPTE pde,pte的索引 ULONG PxeIndex = (VirtualAddress_s >> 0x27) & 0x1FF; UINT32 PPEIndex = (VirtualAddress_s >> 0x1E) & 0x1FF; //PPEIndex UINT32 PDEIndex = (VirtualAddress_s >> 0x15) & 0x1FF; //PDEIndex UINT32 PTEIndex = (VirtualAddress_s >> 0xC) & 0x1FF; //DbgBreakPoint(); //2 获取要hook进程的CR3 PEPROCESS pEprocess = NULL; NTSTATUS status = PsLookupProcessByProcessId(Pid, &pEprocess); if (!NT_SUCCESS(status)) { return 0; } HANDLE hMemory = NULL; UNICODE_STRING unName = { 0 }; RtlInitUnicodeString(&unName, L"\\Device\\PhysicalMemory"); OBJECT_ATTRIBUTES obj; InitializeObjectAttributes(&obj, &unName, OBJ_CASE_INSENSITIVE, NULL, NULL); status = ZwOpenSection(&hMemory, SECTION_ALL_ACCESS, &obj); if (!NT_SUCCESS(status)) { return 0; } SIZE_T sizeView = PAGE_SIZE; PVOID sectionObj = NULL; status = ObReferenceObjectByHandle(hMemory, SECTION_ALL_ACCESS, NULL, KernelMode, &sectionObj, NULL); if (!NT_SUCCESS(status)) { return status; } ULONG_PTR Cr3PhyAddr = *(PULONG64)((ULONG64)pEprocess + KERNEL_CR3_OFFSET)&~(0xf); PHYSICAL_ADDRESS Cr3 = { 0 }; Cr3.QuadPart = Cr3PhyAddr; ULONG_PTR VirtualAddresss = NULL; status = ZwMapViewOfSection(hMemory, NtCurrentProcess(), &VirtualAddresss, 0, PAGE_SIZE, &Cr3, &sizeView, ViewUnmap, MEM_TOP_DOWN, PAGE_READWRITE); //ULONG_PTR VirtualAddresss = MmMapIoSpace(Cr3, PAGE_SIZE, MmNonCached);//由于Cr3是物理地址我们需要映射到虚拟内存中去 if (!NT_SUCCESS(status)) { return 0; } //3 构建页表 //*(PULONG64)(VirtualAddresss + PxeIndex * 8) |= 70; PHYSICAL_ADDRESS Low = { 0 }; PHYSICAL_ADDRESS High = { MAXULONG64 }; //ppe do { pPhyAddr[0] = (ULONG_PTR)MmAllocateContiguousMemorySpecifyCache(PAGE_SIZE, Low, High, Low, MmCached); newPPEphy = MmGetPhysicalAddress(pPhyAddr[0]).QuadPart; ULONG_PTR PPEPhyAddr = (ULONG_PTR)(((PHARDWARE_PTE)(VirtualAddresss + PxeIndex * 8))->PageFrameNumber) * 0x1000; PHYSICAL_ADDRESS temp = { 0 }; temp.QuadPart = PPEPhyAddr; ULONG_PTR VirtualAddress_PPE = NULL; ZwMapViewOfSection(hMemory, NtCurrentProcess(), &VirtualAddress_PPE, 0, PAGE_SIZE, &temp, &sizeView, ViewUnmap, MEM_TOP_DOWN, PAGE_READWRITE); memcpy(pPhyAddr[0], VirtualAddress_PPE, PAGE_SIZE); //pde pPhyAddr[1] = (ULONG_PTR)MmAllocateContiguousMemorySpecifyCache(PAGE_SIZE, Low, High, Low, MmCached); newPDEphy = MmGetPhysicalAddress(pPhyAddr[1]).QuadPart; ULONG_PTR pdePhy = (ULONG_PTR)(((PHARDWARE_PTE)(VirtualAddress_PPE + PPEIndex * 8))->PageFrameNumber) * 0x1000; temp.QuadPart = pdePhy; ULONG_PTR VirtualAddress_PDE = NULL; ZwMapViewOfSection(hMemory, NtCurrentProcess(), &VirtualAddress_PDE, 0, PAGE_SIZE, &temp, &sizeView, ViewUnmap, MEM_TOP_DOWN, PAGE_READWRITE); memcpy(pPhyAddr[1], VirtualAddress_PDE, PAGE_SIZE); //pte ULONG_PTR ptePhy = (ULONG_PTR)(((PHARDWARE_PTE)(VirtualAddress_PDE + PDEIndex * 8))->PageFrameNumber) * 0x1000; temp.QuadPart = ptePhy; if (((PHARDWARE_PTE)(VirtualAddress_PDE + PDEIndex * 8))->LargePage == 1) { pPhyAddr[2] = (ULONG_PTR)MmAllocateContiguousMemorySpecifyCache(PAGE_SIZE* 1024, Low, High, Low, MmCached); memset(pPhyAddr[2], 0, PAGE_SIZE * 1024); ULONG_PTR Real = MmGetPhysicalAddress(pPhyAddr[2]).QuadPart; ULONG_PTR Real1 = Real; ULONG_PTR Realtemp = 0; if (Real == 0) { MmFreeContiguousMemory(pPhyAddr[0]); MmFreeContiguousMemory(pPhyAddr[1]); MmFreeContiguousMemory(pPhyAddr[2]); return FALSE; } ULONG i = 0; for (i = 0; i < 1024; i++) { Real += PAGE_SIZE; //Real &= 0x1fffff; Realtemp = Real & 0x1fffff; if (!Realtemp) break; } DbgBreakPoint(); pPhyAddr[2] += PAGE_SIZE * (i+1); newPTEphy = MmGetPhysicalAddress(pPhyAddr[2]).QuadPart; ULONG_PTR VirtualAddress_PTE = NULL; sizeView = PAGE_SIZE * 0x200; ZwMapViewOfSection(hMemory, NtCurrentProcess(), &VirtualAddress_PTE, 0, PAGE_SIZE, &temp, &sizeView, ViewUnmap, MEM_TOP_DOWN, PAGE_READWRITE); memcpy(pPhyAddr[2], VirtualAddress_s &~(0x1fffff), PAGE_SIZE*0x200); ((PHARDWARE_PTE)(pPhyAddr[0] + PPEIndex * 8))->PageFrameNumber = newPDEphy >> 12; ((PHARDWARE_PTE)(pPhyAddr[1] + PDEIndex * 8))->PageFrameNumber = newPTEphy >> 12; //((PHARDWARE_PTE)(pPhyAddr[2] + PTEIndex * 8))->Write = 1; ULONG_PTR newOffset = (VirtualAddress_s & 0x1ff000) + offset; //((PHARDWARE_PTE)(pPhyAddr[1] + PTEIndex * 8))->Write = 1; *(PUCHAR)(pPhyAddr[2] + newOffset + 0x27) = 0x90; *(PUCHAR)(pPhyAddr[2] + newOffset + 0x28) = 0x90; *(PUCHAR)(pPhyAddr[2] + newOffset + 0x29) = 0xc3; ULONG_PTR ss = pPhyAddr[2]; ULONG_PTR ss2 = VirtualAddress_s & ~(0x1fffff); IsPdeLager = 1; break; } pPhyAddr[2] = (ULONG_PTR)MmAllocateContiguousMemorySpecifyCache(PAGE_SIZE, Low, High, Low, MmCached); newPTEphy = MmGetPhysicalAddress(pPhyAddr[2]).QuadPart; ULONG_PTR VirtualAddress_PTE = NULL; ZwMapViewOfSection(hMemory, NtCurrentProcess(), &VirtualAddress_PTE, 0, PAGE_SIZE, &temp, &sizeView, ViewUnmap, MEM_TOP_DOWN, PAGE_READWRITE); memcpy(pPhyAddr[2], VirtualAddress_PTE, PAGE_SIZE); //物理内存 pPhyAddr[3] = (ULONG_PTR)MmAllocateContiguousMemorySpecifyCache(PAGE_SIZE, Low, High, Low, MmCached); newphy = MmGetPhysicalAddress(pPhyAddr[3]).QuadPart; ULONG_PTR Phy = (ULONG_PTR)(((PHARDWARE_PTE)(VirtualAddress_PTE + PTEIndex * 8))->PageFrameNumber) * 0x1000; temp.QuadPart = Phy; ULONG_PTR VirtualAddress_PHY = NULL; ZwMapViewOfSection(hMemory, NtCurrentProcess(), &VirtualAddress_PHY, 0, PAGE_SIZE, &temp, &sizeView, ViewUnmap, MEM_TOP_DOWN, PAGE_READWRITE); memcpy(pPhyAddr[3], VirtualAddress_PHY, PAGE_SIZE); } while (0); //ULONG_PTR ss3 = pPhyAddr[3]; //ULONG_PTR ss1 = pPhyAddr[1]; //ULONG_PTR ss2 = pPhyAddr[2]; //DbgBreakPoint(); //4 修改PXE PPE PDE PTE从而改变 if (IsPdeLager) { ((PHARDWARE_PTE)(VirtualAddresss + PxeIndex * 8))->PageFrameNumber = newPPEphy >> 12; return TRUE; } ((PHARDWARE_PTE)(VirtualAddresss + PxeIndex * 8))->PageFrameNumber = newPPEphy >> 12; ((PHARDWARE_PTE)(pPhyAddr[0] + PPEIndex * 8))->PageFrameNumber = newPDEphy >> 12; ((PHARDWARE_PTE)(pPhyAddr[1] + PDEIndex * 8))->PageFrameNumber = newPTEphy >> 12; ((PHARDWARE_PTE)(pPhyAddr[2] + PTEIndex * 8))->PageFrameNumber = newphy >> 12; return TRUE; }; VOID unstallHook() { if (IsPdeLager) { MmFreeContiguousMemory(pPhyAddr[0]); MmFreeContiguousMemory(pPhyAddr[1]); MmFreeContiguousMemory(pPhyAddr[2]); return; } 1 2 3 4 //MmFreeContiguousMemory(pPhyAddr[0]); //MmFreeContiguousMemory(pPhyAddr[1]); //MmFreeContiguousMemory(pPhyAddr[2]); //MmFreeContiguousMemory(pPhyAddr[3]); } VOID DriverUnload(PDRIVER_OBJECT pDriver) { unstallHook(); } NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING pRes) { pDriver->DriverUnload = DriverUnload; PKLDR_DATA_TABLE_ENTRY pKldr = (PKLDR_DATA_TABLE_ENTRY)pDriver->DriverSection; pKldr->Flags |= 0x20; //NTSTATUS status = PsSetCreateProcessNotifyRoutine(ProcessNotifyRoutine, FALSE); UNICODE_STRING ss = { 0 }; RtlInitUnicodeString(&ss, L"NtOpenProcess"); ULONG_PTR NtOpenAddr = MmGetSystemRoutineAddress(&ss); ULONG_PTR funcVir = NtOpenAddr & ~(0xfff); ULONG_PTR funcOffset = NtOpenAddr & 0xfff; InitHook(funcVir, 8568, funcOffset); //SetPTEHook(ssz); return STATUS_SUCCESS; } 附加到我们hook的进程: 图片描述 附加到其他进程: 图片描述 实验结果和win7是一样的,同样也没有出发PG。 根据上面的帖子,总结一个适用于win10 10240的页表hook
07-16
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值