MmGetSystemRoutineAddress

本文详细介绍了MmGetSystemRoutineAddress函数在ReactOS项目中的实现细节,包括如何遍历加载的模块列表查找ntoskrnl.exe与hal.dll模块基址,并通过MiFindExportedRoutineByName函数在两个模块中查找特定函数地址。同时,展示了二分查找法在函数查找过程中的应用。

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

MmGetSystemRoutineAddress这个函数也是比较有用的,是得到系统导出函数的地址,不过网上都是写了一堆汇编代码在哪里,根本没有可读性,还不如用IDA看呢。

下面的函数是摘自ReactOS项目的代码:

[cpp]  view plain copy
  1. PVOID  
  2. NTAPI  
  3. MmGetSystemRoutineAddress(IN PUNICODE_STRING SystemRoutineName)  
  4. {  
  5.     PVOID ProcAddress = NULL;  
  6.     ANSI_STRING AnsiRoutineName;  
  7.     NTSTATUS Status;  
  8.     PLIST_ENTRY NextEntry;  
  9.     PLDR_DATA_TABLE_ENTRY LdrEntry;  
  10.     BOOLEAN Found = FALSE;  
  11.     UNICODE_STRING KernelName = RTL_CONSTANT_STRING(L"ntoskrnl.exe");  
  12.     UNICODE_STRING HalName = RTL_CONSTANT_STRING(L"hal.dll");  
  13.     ULONG Modules = 0;  
  14.   
  15.     /* Convert routine to ansi name */  
  16.     Status = RtlUnicodeStringToAnsiString(&AnsiRoutineName,  
  17.                                           SystemRoutineName,  
  18.                                           TRUE);  
  19.     if (!NT_SUCCESS(Status)) return NULL;  
  20.   
  21.     /* Lock the list */  
  22.     KeEnterCriticalRegion();  
  23.     ExAcquireResourceSharedLite(&PsLoadedModuleResource, TRUE);  
  24.   
  25.     /* Loop the loaded module list */  
  26.     NextEntry = PsLoadedModuleList.Flink;  
  27.     while (NextEntry != &PsLoadedModuleList)  
  28.     {  
  29.         /* Get the entry */  
  30.         LdrEntry = CONTAINING_RECORD(NextEntry,  
  31.                                      LDR_DATA_TABLE_ENTRY,  
  32.                                      InLoadOrderLinks);  
  33.   
  34.         /* Check if it's the kernel or HAL */  
  35.         if (RtlEqualUnicodeString(&KernelName, &LdrEntry->BaseDllName, TRUE))  
  36.         {  
  37.             /* Found it */  
  38.             Found = TRUE;  
  39.             Modules++;  
  40.         }  
  41.         else if (RtlEqualUnicodeString(&HalName, &LdrEntry->BaseDllName, TRUE))  
  42.         {  
  43.             /* Found it */  
  44.             Found = TRUE;  
  45.             Modules++;  
  46.         }  
  47.   
  48.         /* Check if we found a valid binary */  
  49.         if (Found)  
  50.         {  
  51.             /* Find the procedure name */  
  52.             ProcAddress = MiFindExportedRoutineByName(LdrEntry->DllBase,  
  53.                                                       &AnsiRoutineName);  
  54.   
  55.             /* Break out if we found it or if we already tried both modules */  
  56.             if (ProcAddress) break;  
  57.             if (Modules == 2) break;  
  58.         }  
  59.   
  60.         /* Keep looping */  
  61.         NextEntry = NextEntry->Flink;  
  62.     }  
  63.   
  64.     /* Release the lock */  
  65.     ExReleaseResourceLite(&PsLoadedModuleResource);  
  66.     KeLeaveCriticalRegion();  
  67.   
  68.     /* Free the string and return */  
  69.     RtlFreeAnsiString(&AnsiRoutineName);  
  70.     return ProcAddress;  
  71. }  

函数主要是遍历PsLoadedModuleList查找"ntoskrnl.exe"与"hal.dll"模块基址,然后调用MiFindExportedRoutineByName在两个模块中查找函数地址,查看下MiFindExportedRoutineByName实现

[cpp]  view plain copy
  1. PVOID  
  2. MiFindExportedRoutineByName (  
  3.     IN PVOID DllBase,  
  4.     IN PANSI_STRING AnsiImageRoutineName  
  5.     )  
  6. {  
  7.     USHORT OrdinalNumber;  
  8.     PULONG NameTableBase;  
  9.     PUSHORT NameOrdinalTableBase;  
  10.     PULONG Addr;  
  11.     LONG High;  
  12.     LONG Low;  
  13.     LONG Middle;  
  14.     LONG Result;  
  15.     ULONG ExportSize;   // 保存表项的大小  
  16.     PVOID FunctionAddress;  
  17.     PIMAGE_EXPORT_DIRECTORY ExportDirectory;  
  18.   
  19.     PAGED_CODE();  
  20.   
  21.     ExportDirectory = (PIMAGE_EXPORT_DIRECTORY) RtlImageDirectoryEntryToData (  
  22.                                 DllBase,  
  23.                                 TRUE,  
  24.                                 IMAGE_DIRECTORY_ENTRY_EXPORT,  
  25.                                 &ExportSize);  
  26.   
  27.     if (ExportDirectory == NULL) {  
  28.         return NULL;  
  29.     }  
  30.   
  31.     NameTableBase = (PULONG)((PCHAR)DllBase + (ULONG)ExportDirectory->AddressOfNames);  
  32.     NameOrdinalTableBase = (PUSHORT)((PCHAR)DllBase + (ULONG)ExportDirectory->AddressOfNameOrdinals);  
  33.   
  34.     //二分查找法  
  35.     Low = 0;  
  36.     Middle = 0;  
  37.     High = ExportDirectory->NumberOfNames - 1;  
  38.   
  39.     while (High >= Low) {  
  40.         Middle = (Low + High) >> 1;  
  41.   
  42.         Result = strcmp (AnsiImageRoutineName->Buffer,  
  43.                          (PCHAR)DllBase + NameTableBase[Middle]);  
  44.   
  45.         if (Result < 0) {  
  46.             High = Middle - 1;  
  47.         }  
  48.         else if (Result > 0) {  
  49.             Low = Middle + 1;  
  50.         }  
  51.         else {  
  52.             break;  
  53.         }  
  54.     }  
  55.   
  56.     // 如果High < Low,表明没有在EAT中找到这个函数;否则,返回此函数的索引  
  57.     if (High < Low) {  
  58.         return NULL;  
  59.     }  
  60.   
  61.     OrdinalNumber = NameOrdinalTableBase[Middle];  
  62.   
  63.     // 如果索引值大于EAT中已有的函数数量,则查找失败  
  64.     if ((ULONG)OrdinalNumber >= ExportDirectory->NumberOfFunctions) {  
  65.         return NULL;  
  66.     }  
  67.   
  68.     Addr = (PULONG)((PCHAR)DllBase + (ULONG)ExportDirectory->AddressOfFunctions);  
  69.   
  70.     FunctionAddress = (PVOID)((PCHAR)DllBase + Addr[OrdinalNumber]);  
  71.     ASSERT ((FunctionAddress <= (PVOID)ExportDirectory) ||  
  72.             (FunctionAddress >= (PVOID)((PCHAR)ExportDirectory + ExportSize)));  
  73.   
  74.     return FunctionAddress;  
  75. }  

在函数MiFindExportedRoutineByName中,利用RtlImageDirectoryEntryToData 函数得到模块的导出表地址,然后二分遍历导出表,查看是否有指定的字符串导出,还用了Ordinal值判断(PE解析的内容~)
[讨论][转帖][讨论][原创]windows Hook内核api,能过win10 22H2的pg 发表于: 2023-12-6 17:35 12257 最近一直在思考如何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; } 你看看这个代码,分析然后写一个win10 10240版本可行的页表hook代码
07-16
#include "ntddk.h" /* 获取指定地址的数值 base:要获取的地址 offset:偏移量 size:获取的大小 */ PVOID GetAddrValue(PVOID* base, INT offset, INT size) { PVOID Addr = *base; PVOID templong = 0; //复制内存,将指定位置的内存的值读取出来 RtlCopyMemory(&templong, (PUCHAR)Addr + offset, size); return templong; } VOID DriverUnload(IN PDRIVER_OBJECT DriverObject) { DbgPrint("卸载完成!\n"); } NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) { //通过MmGetSystemRoutineAddress直接获取PsTerminateSystemThread地址 UNICODE_STRING s; CHAR* string = L"PsTerminateSystemThread"; RtlInitUnicodeString(&s, string); PVOID address = MmGetSystemRoutineAddress(&s); DbgPrint("PsTerminateSystemThread Address:%p\n", address); //将PsTerminateSystemThread作为起始地址 ULONG beginAdress =(ULONG) address; //搜索范围限制为0x1000 ULONG endAdress = beginAdress + 0x1000; //刚开始匹配地址为0,表示尚未匹配到 PVOID matchAdress = 0; //开始循环比较 搜索特征码 for (ULONG i=beginAdress;i< endAdress;i+=1) { PVOID value = GetAddrValue(&i, 0, 4); PVOID value2 = GetAddrValue(&i, 0, 3); //特征码为8b ff 55 8b ec 5d e9 小端存储 if (value == 0x8b55ff8b && value2 == 0xe95dec) { //匹配特征码后 赋值,终止循环 matchAdress = i; break; } } DbgPrint("PsTerminateProcess Address:%p\n", address); DriverObject->DriverUnload = DriverUnload; return STATUS_SUCCESS; }分析代码的特征码搜索原理
最新发布
07-19
#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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值