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

如何合并不连续内存?驱动内存映射及探测问题咨询

驱动内存映射问题解答

核心问题:是否需要探测未使用未分配的内存?

是的,必须探测。要将不连续内存映射到指定虚拟地址,必须确保目标地址范围完全未被占用、未分配——不管是内核态还是用户态虚拟地址空间,一旦目标地址已被其他内存块(如池内存、驱动镜像、系统数据)占用,强行映射会触发内存冲突,导致系统崩溃或内存访问错误。

内核态虚拟地址空间有明确分区(系统镜像区、驱动加载区、分页/非分页池、会话空间等),你需要确认目标地址段属于空闲区域,且满足页对齐、大小匹配的要求。

你的代码问题分析

从WinDbg输出看,g_pMaped和你期望的g_p地址不一致,原因是代码逻辑存在两处关键错误:

  1. 目标地址已被占用
    你用ExAllocatePool分配了g_p,这个地址已经被非分页池占用,系统不可能再将其他内存映射到这里——MmMapLockedPagesSpecifyCache会自动忽略被占用的BaseAddress参数,重新分配一个空闲地址。

  2. MDL初始化逻辑错误
    MmBuildMdlForNonPagedPool用于关联你自己分配的非分页池内存和MDL,但你的MDL是针对系统分配的pDriverObject创建的,调用这个函数属于画蛇添足,反而可能破坏MDL的正确状态。

修正方案

步骤1:实现空闲虚拟地址探测

你需要先找到一个页对齐、大小足够的空闲内核态虚拟地址。以Windows 10+为例,可以用MmQueryVirtualMemory查询地址状态,判断是否为MEM_FREE。示例探测逻辑框架:

PVOID FindFreeKernelAddress(SIZE_T size) {
    // 内核态虚拟地址起始范围(避开系统关键区域)
    PVOID addr = (PVOID)0xFFFF800000000000;
    SIZE_T pageSize = PAGE_SIZE;
    SIZE_T alignedSize = PAGE_ALIGN(size);

    while ((ULONG_PTR)addr < 0xFFFFF80000000000) { // 避开系统镜像核心区
        MEMORY_BASIC_INFORMATION mbi;
        NTSTATUS status = MmQueryVirtualMemory(
            NtCurrentProcess(),
            addr,
            MemoryBasicInformation,
            &mbi,
            sizeof(mbi),
            NULL
        );

        if (!NT_SUCCESS(status)) {
            addr = (PVOID)((ULONG_PTR)addr + pageSize);
            continue;
        }

        if (mbi.State == MEM_FREE && mbi.RegionSize >= alignedSize) {
            return addr;
        }

        addr = (PVOID)((ULONG_PTR)addr + mbi.RegionSize);
    }

    return NULL;
}

步骤2:修正映射代码

去掉错误的ExAllocatePool和MmBuildMdlForNonPagedPool调用,使用探测到的空闲地址作为映射目标:

SIZE_T mapSize = sizeof(DRIVER_OBJECT);
PVOID targetAddr = FindFreeKernelAddress(mapSize);
if (!targetAddr) {
    DbgPrint("Failed to find free address\n");
    return;
}

// 创建MDL描述目标内存
g_pMdl = IoAllocateMdl(pDriverObject, mapSize, FALSE, FALSE, NULL);
if (!g_pMdl) {
    DbgPrint("IoAllocateMdl failed\n");
    return;
}

// 锁定内存页
__try {
    MmProbeAndLockPages(g_pMdl, KernelMode, IoModifyAccess);
} __except(EXCEPTION_EXECUTE_HANDLER) {
    DbgPrint("MmProbeAndLockPages failed\n");
    IoFreeMdl(g_pMdl);
    g_pMdl = NULL;
    return;
}

// 映射到指定地址
g_pMaped = MmMapLockedPagesSpecifyCache(
    g_pMdl,
    KernelMode,
    MmCached,
    targetAddr,
    FALSE,
    NormalPagePriority
);

if (g_pMaped != targetAddr) {
    DbgPrint("Failed to map to specified address\n");
    MmUnlockPages(g_pMdl);
    IoFreeMdl(g_pMdl);
    g_pMdl = NULL;
    return;
}

// 输出验证
DbgPrint("DriverObject: 0x%p\n", pDriverObject);
DbgPrint("targetAddr: 0x%p\n", targetAddr);
DbgPrint("g_pMdl: 0x%p\n", g_pMdl);
DbgPrint("g_pMaped: 0x%p\n", g_pMaped);

注意事项

  • 目标地址必须页对齐,否则MmMapLockedPagesSpecifyCache会忽略指定地址。
  • 不要映射到系统关键地址区域(如0xFFFFF80000000000以上的系统镜像区),否则会触发系统崩溃。
  • 映射完成后,在驱动卸载时要记得调用MmUnmapLockedPages、MmUnlockPages和IoFreeMdl释放资源。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 22:17:54