You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

内核模式下物理地址有效性验证的Kernel API查询

内核模式下物理地址有效性验证方案

首先纠正你的代码误区:不能直接将物理地址作为指针传入memcpy,内核虚拟地址空间中无法直接访问物理地址,必须先通过MmMapIoSpace或MmGetVirtualForPhysical将其映射为虚拟地址后才能访问,否则必然触发蓝屏。

回到你的核心需求:在访问物理地址前验证其有效性,以下是几种无需依赖MmCopyMemory的可行方案:

方案一:通过系统物理内存范围列表验证

使用MmGetPhysicalMemoryRanges函数获取系统中所有已分配的物理内存块,遍历这些块检查目标物理地址是否落在有效范围内。这个方法适合批量地址验证,或者需要快速判断地址是否属于系统可用物理内存的场景。

代码示例

BOOL IsPhysicalAddressValid(PHYSICAL_ADDRESS targetPa, SIZE_T size)
{
    PPHYSICAL_MEMORY_RANGE ranges = MmGetPhysicalMemoryRanges();
    if (!ranges)
        return FALSE;

    PPHYSICAL_MEMORY_RANGE current = ranges;
    while (current->BaseAddress.QuadPart != 0 || current->NumberOfBytes.QuadPart != 0)
    {
        // 检查目标地址范围是否完全落在当前物理内存块内
        if (targetPa.QuadPart >= current->BaseAddress.QuadPart &&
            (targetPa.QuadPart + size) <= (current->BaseAddress.QuadPart + current->NumberOfBytes.QuadPart))
        {
            ExFreePool(ranges);
            return TRUE;
        }
        current++;
    }

    ExFreePool(ranges);
    return FALSE;
}

// 修正后的ReadPhysicalAddress函数
BOOL ReadPhysicalAddress(PHYSICAL_ADDRESS TargetPhysicalAddress, PVOID Buffer, SIZE_T Size)
{
    if (!IsPhysicalAddressValid(TargetPhysicalAddress, Size))
        return FALSE;

    // 映射物理地址到虚拟地址
    PVOID virtualAddr = MmMapIoSpace(TargetPhysicalAddress, Size, MmNonCached);
    if (!virtualAddr)
        return FALSE;

    memcpy(Buffer, virtualAddr, Size);
    MmUnmapIoSpace(virtualAddr, Size);
    return TRUE;
}

方案二:通过页表查询验证(精准单地址验证)

如果只需要验证单个物理地址的有效性,可以通过遍历页表来判断该地址是否存在对应的有效页表项。这种方法更精准,但实现相对复杂,需要处理不同CPU架构(x86/x64)的页表结构差异。

x64架构下的简化示例

#include <ntddk.h>
#include <intrin.h>

BOOL IsPhysicalPageValid(PHYSICAL_ADDRESS pa)
{
    // 获取当前进程的页目录基址(CR3)
    ULONG64 cr3 = __readcr3();
    // 页目录项(PML4)索引
    ULONG64 pml4Index = (pa.QuadPart >> 39) & 0x1FF;
    // 页目录指针项(PDPT)索引
    ULONG64 pdptIndex = (pa.QuadPart >> 30) & 0x1FF;
    // 页目录项(PD)索引
    ULONG64 pdIndex = (pa.QuadPart >> 21) & 0x1FF;
    // 页表项(PT)索引
    ULONG64 ptIndex = (pa.QuadPart >> 12) & 0x1FF;

    // 映射PML4表到虚拟地址
    PULONG64 pml4 = (PULONG64)MmMapIoSpace({cr3}, PAGE_SIZE, MmNonCached);
    if (!pml4)
        return FALSE;

    ULONG64 pml4Entry = pml4[pml4Index];
    MmUnmapIoSpace(pml4, PAGE_SIZE);

    // 检查PML4项是否有效(存在且可访问)
    if (!(pml4Entry & 0x1)) // Present位
        return FALSE;

    // 映射PDPT表
    PHYSICAL_ADDRESS pdptPa = {pml4Entry & ~0xFFF};
    PULONG64 pdpt = (PULONG64)MmMapIoSpace(pdptPa, PAGE_SIZE, MmNonCached);
    if (!pdpt)
        return FALSE;

    ULONG64 pdptEntry = pdpt[pdptIndex];
    MmUnmapIoSpace(pdpt, PAGE_SIZE);

    if (!(pdptEntry & 0x1))
        return FALSE;

    // 映射PD表
    PHYSICAL_ADDRESS pdPa = {pdptEntry & ~0xFFF};
    PULONG64 pd = (PULONG64)MmMapIoSpace(pdPa, PAGE_SIZE, MmNonCached);
    if (!pd)
        return FALSE;

    ULONG64 pdEntry = pd[pdIndex];
    MmUnmapIoSpace(pd, PAGE_SIZE);

    // 检查是否是大页(2MB)
    if (pdEntry & 0x80) // PS位
        return TRUE;

    // 映射PT表
    PHYSICAL_ADDRESS ptPa = {pdEntry & ~0xFFF};
    PULONG64 pt = (PULONG64)MmMapIoSpace(ptPa, PAGE_SIZE, MmNonCached);
    if (!pt)
        return FALSE;

    ULONG64 ptEntry = pt[ptIndex];
    MmUnmapIoSpace(pt, PAGE_SIZE);

    return (ptEntry & 0x1) != 0;
}

关于你尝试的MmIsIoSpaceActive的说明

这个函数仅用于验证IO端口空间的地址有效性,而系统模块的物理地址属于系统物理内存空间,不属于IO空间,所以调用该函数必然返回0,这是预期行为,不能用于物理内存地址的验证。

另外,不存在类似MmIsAddressValid的导出API直接验证物理地址,MmIsAddressValid仅针对虚拟地址生效。

内容的提问来源于stack exchange,提问作者YoAvrageBiTz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 16:48:18