x64/vista/2003 sp1下使用ZwOpenSection直接读写物理内存

本文介绍在x64/vista/2003sp1系统中,用户模式程序无法通过DevicePhysicalMemory访问物理内存的问题,并提供了一种在驱动级别实现该功能的方法。

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

习惯于在应用程序用ZwOpenSection打开"Device"PhysicalMemory访问物理内存的朋友可能要郁闷了,微软出于安全考 虑的原因,在x64/vista/2003 sp1系统中所有用户模式的程序将不能访问"Device"PhysicalMemory对象。

   经过测试,原来应用程序在2k/xp中使用ZwOpenSection,ZwMapViewOfSection可以正常访问物理内存,而同样的代码在 x64上却在ZwOpenSection时返回"拒绝访问"(C0000022 STATUS_ACCESS_DENIED)。

   幸运的是在驱动中,仍然能通过这个方法访问物理内存。所以在x64/vista/2003 sp1下使用ZwOpenSection直接读写物理内存,必须在驱动中进行。

 相关代码如下:

NTSTATUS MapPhysicalMemoryToLinearSpace(PVOID pPhysAddress,
                                        ULONG PhysMemSizeInBytes,
                                        PVOID *ppPhysMemLin,
                                        HANDLE *pPhysicalMemoryHandle)
{
  UNICODE_STRING     PhysicalMemoryUnicodeString;
  PVOID              PhysicalMemorySection = NULL;
  OBJECT_ATTRIBUTES  ObjectAttributes;
  PHYSICAL_ADDRESS   ViewBase;
  NTSTATUS           ntStatus;
  PHYSICAL_ADDRESS   pStartPhysAddress;
  PHYSICAL_ADDRESS   pEndPhysAddress;
  PHYSICAL_ADDRESS   MappingLength;
  BOOLEAN            Result1, Result2;
  ULONG              IsIOSpace;
  unsigned char     *pbPhysMemLin = NULL;

  OutputDebugString ("Entering MapPhysicalMemoryToLinearSpace");

  RtlInitUnicodeString (&PhysicalMemoryUnicodeString,
                        L"""Device""PhysicalMemory ");

  InitializeObjectAttributes (&ObjectAttributes,
                              &PhysicalMemoryUnicodeString,
                              OBJ_CASE_INSENSITIVE,
                              (HANDLE) NULL,
                              (PSECURITY_DESCRIPTOR) NULL);

  *pPhysicalMemoryHandle = NULL;

  ntStatus = ZwOpenSection (pPhysicalMemoryHandle,
                            SECTION_ALL_ACCESS,
                            &ObjectAttributes);

  if (NT_SUCCESS(ntStatus))
  {

    ntStatus = ObReferenceObjectByHandle (*pPhysicalMemoryHandle,
                                          SECTION_ALL_ACCESS,
                                          (POBJECT_TYPE) NULL,
                                          KernelMode,
                                          &PhysicalMemorySection,
                                          (POBJECT_HANDLE_INFORMATION) NULL);

    if (NT_SUCCESS(ntStatus))
    {

      pStartPhysAddress.QuadPart = (ULONGLONG)pPhysAddress;

      pEndPhysAddress = RtlLargeIntegerAdd (pStartPhysAddress,
                                            RtlConvertUlongToLargeInteger(PhysMemSizeInBytes));

      IsIOSpace = 0;

      Result1 = HalTranslateBusAddress (1, 0, pStartPhysAddress, &IsIOSpace, &pStartPhysAddress);

      IsIOSpace = 0;

      Result2 = HalTranslateBusAddress (1, 0, pEndPhysAddress, &IsIOSpace, &pEndPhysAddress);

      if (Result1 && Result2)
      {

        MappingLength = RtlLargeIntegerSubtract (pEndPhysAddress, pStartPhysAddress);

        if (MappingLength.LowPart)
        {
       
          // Let ZwMapViewOfSection pick a linear address

          PhysMemSizeInBytes = MappingLength.LowPart;

          ViewBase = pStartPhysAddress;

          ntStatus = ZwMapViewOfSection (*pPhysicalMemoryHandle,
                                         (HANDLE) -1,
                                         &pbPhysMemLin,
                                         0L,
                                         PhysMemSizeInBytes,
                                         &ViewBase,
                                         (PSIZE_T)&PhysMemSizeInBytes,
                                         ViewShare,
                                         0,
                                         PAGE_READWRITE | PAGE_NOCACHE);

          if (!NT_SUCCESS(ntStatus))
            OutputDebugString ("ERROR: ZwMapViewOfSection failed");
          else
          {
            pbPhysMemLin += (ULONG)pStartPhysAddress.LowPart - (ULONG)ViewBase.LowPart;
            *ppPhysMemLin = pbPhysMemLin;
          } 
        }
        else
          OutputDebugString ("ERROR: RtlLargeIntegerSubtract failed");
      }
      else
        OutputDebugString ("ERROR: MappingLength = 0");
    }
    else
      OutputDebugString ("ERROR: ObReferenceObjectByHandle failed");
  }
  else
    OutputDebugString ("ERROR: ZwOpenSection failed");
   
  if (!NT_SUCCESS(ntStatus))
    ZwClose(*pPhysicalMemoryHandle);
 
  OutputDebugString ("Leaving MapPhysicalMemoryToLinearSpace");

 

return ntStatus;
}

#include <ntifs.h> #include <ntddk.h> // 全局物理内存区段句柄 HANDLE g_phys_mem_handle = NULL; // 页表索引宏定义 #define PML4_INDEX(va) ((va >> 39) & 0x1FF) #define PDPT_INDEX(va) ((va >> 30) & 0x1FF) #define PD_INDEX(va) ((va >> 21) & 0x1FF) #define PT_INDEX(va) ((va >> 12) & 0x1FF) #define PAGE_OFFSET(va) (va & 0xFFF) // 初始化物理内存区段 NTSTATUS init_physical_memory_section() { OBJECT_ATTRIBUTES objAttr; UNICODE_STRING physMemName; RtlInitUnicodeString(&physMemName, L"\\Device\\PhysicalMemory"); InitializeObjectAttributes(&objAttr, &physMemName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL); return ZwOpenSection(&g_phys_mem_handle, SECTION_MAP_READ | SECTION_MAP_WRITE, &objAttr); } // 映射物理页到虚拟地址 PVOID map_physical_page(ULONG64 physical_address) { if (!g_phys_mem_handle) return NULL; LARGE_INTEGER sectionOffset; sectionOffset.QuadPart = physical_address; PVOID baseAddress = NULL; SIZE_T viewSize = PAGE_SIZE; NTSTATUS status = ZwMapViewOfSection( g_phys_mem_handle, NtCurrentProcess(), &baseAddress, 0L, PAGE_SIZE, &sectionOffset, &viewSize, ViewShare, 0, PAGE_READWRITE ); return NT_SUCCESS(status) ? baseAddress : NULL; } // 取消映射 void unmap_physical_page(PVOID base_address) { if (base_address) { ZwUnmapViewOfSection(NtCurrentProcess(), base_address); } } // 获取进程的CR3值 ULONG64 get_process_cr3(HANDLE pid) { PEPROCESS process; if (NT_SUCCESS(PsLookupProcessByProcessId(pid, &process))) { // Windows 10 10240 EPROCESS中CR3的偏移为0x28 ULONG64 cr3 = *(ULONG64*)((PUCHAR)process + 0x28); ObDereferenceObject(process); return cr3; } return 0; } // 主函数:映射线性地址到物理空间 PVOID get_pyse_map_space(HANDLE pid, ULONG64 linear_address) { // 1. 获取目标进程CR3 ULONG64 cr3 = get_process_cr3(pid); if (!cr3) return NULL; // 2. 计算页表索引 ULONG64 pml4_index = PML4_INDEX(linear_address); ULONG64 pdpt_index = PDPT_INDEX(linear_address); ULONG64 pd_index = PD_INDEX(linear_address); ULONG64 pt_index = PT_INDEX(linear_address); ULONG64 offset = PAGE_OFFSET(linear_address); // 3. 递归查询页表 ULONG64 current_phys = cr3 & ~0xFFF; // 清除低12位标志 // PML4 -> PDPT PVOID mapped_page = map_physical_page(current_phys); if (!mapped_page) return NULL; ULONG64* pml4_entry = (ULONG64*)mapped_page + pml4_index; if (!(*pml4_entry & 1)) { // 检查有效位 unmap_physical_page(mapped_page); return NULL; } current_phys = *pml4_entry & 0x000FFFFFFFFFF000; unmap_physical_page(mapped_page); // PDPT -> PD mapped_page = map_physical_page(current_phys); if (!mapped_page) return NULL; ULONG64* pdpt_entry = (ULONG64*)mapped_page + pdpt_index; if (!(*pdpt_entry & 1)) { unmap_physical_page(mapped_page); return NULL; } // 检查2MB大页 if (*pdpt_entry & 0x80) { ULONG64 large_page_base = *pdpt_entry & 0x000FFFFFFFFFF000; unmap_physical_page(mapped_page); return (PVOID)((ULONG64)map_physical_page(large_page_base) + offset); } current_phys = *pdpt_entry & 0x000FFFFFFFFFF000; unmap_physical_page(mapped_page); // PD -> PT mapped_page = map_physical_page(current_phys); if (!mapped_page) return NULL; ULONG64* pd_entry = (ULONG64*)mapped_page + pd_index; if (!(*pd_entry & 1)) { unmap_physical_page(mapped_page); return NULL; } // 检查1GB大页 if (*pd_entry & 0x80) { ULONG64 large_page_base = *pd_entry & 0x000FFFFFFFFFF000; unmap_physical_page(mapped_page); return (PVOID)((ULONG64)map_physical_page(large_page_base) + offset); } current_phys = *pd_entry & 0x000FFFFFFFFFF000; unmap_physical_page(mapped_page); // PT -> 物理页 mapped_page = map_physical_page(current_phys); if (!mapped_page) return NULL; ULONG64* pt_entry = (ULONG64*)mapped_page + pt_index; if (!(*pt_entry & 1)) { unmap_physical_page(mapped_page); return NULL; } ULONG64 target_phys = *pt_entry & 0x000FFFFFFFFFF000; unmap_physical_page(mapped_page); // 4. 映射目标物理页 PVOID result = map_physical_page(target_phys); return result ? (PVOID)((ULONG64)result + offset) : NULL; } // 驱动卸载清理 VOID DriverUnload(PDRIVER_OBJECT DriverObject) { if (g_phys_mem_handle) { ZwClose(g_phys_mem_handle); g_phys_mem_handle = NULL; } } // 驱动入口 extern "C" NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) { DriverObject->DriverUnload = DriverUnload; NTSTATUS status = init_physical_memory_section(); if (!NT_SUCCESS(status)) { KdPrint(("Failed to open physical memory section: 0x%X\n", status)); return status; } HANDLE pid = 0; ULONG64 linear_addr = 0; PVOID mapped_addr = get_pyse_map_space(pid, linear_addr); return STATUS_SUCCESS; } 这代码映射物理地址到虚拟地址?什么流程?是获取到物理地址然后给自己的进程空间的虚拟地址替换物理页?指定了哪个虚拟地址吗?
最新发布
07-22
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值