You need to enable JavaScript to run this app. Windows内核驱动与DLL通信时模块遍历因Name成员触发蓝屏的问题排查
优惠活动
大模型
产品
解决方案
定价
更多

Windows内核驱动与DLL通信时模块遍历因Name成员触发蓝屏的问题排查

Windows内核驱动模块通信蓝屏问题记录

开发场景

正在开发Windows内核驱动,实现内核驱动与用户态DLL的双向通信,同时编写了模块快照snapshot、模块遍历walk两个功能模块函数,联调过程中出现随机蓝屏问题。

核心数据结构

通信交互使用的结构体定义如下:

struct SM_MSI {
  wchar_t* Name;
  SIZE_T Size;
  uintptr_t Address;
};

功能函数实现

模块快照函数

快照函数核心执行逻辑:

  • 根据预估的模块数量,申请PagedPool内存作为模块列表的连续存储区
  • 遍历进程PEB的加载顺序模块链表,逐一解析模块项
  • 对符合长度要求的模块名,单独申请256宽字符长度的PagedPool内存存储模块名称
  • 填充模块大小、模块基地址字段后,将整条模块信息拷贝到连续存储区

对应代码片段:

ModulesList = ExAllocatePool(PagedPool, sizeof(SM_MSI) * index);
if (ModulesList == NULL) // 校验内存分配是否成功
{
    return STATUS_UNSUCCESSFUL;
}
index = 0;
for (PLIST_ENTRY pListEntry = (PLIST_ENTRY)((PPEB_LDR_DATA)pPeb->Ldr)->InLoadOrderModuleList.Flink;
    pListEntry != &((PPEB_LDR_DATA)pPeb->Ldr)->InLoadOrderModuleList; pListEntry = (PLIST_ENTRY)pListEntry->Flink)
{
    PLDR_DATA_TABLE_ENTRY pEntry = CONTAINING_RECORD(pListEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
    if (pEntry->BaseDllName.Buffer > 0 && pEntry->BaseDllName.Length < 256) {
        ModulesListCount = ModulesListCount + 1;

        SM_MSI temp = { 0 };
        temp.Name = (wchar_t*)ExAllocatePool(PagedPool, sizeof(wchar_t) * 256);
        if (temp.Name != NULL)
            wcscpy_s(temp.Name, 256, pEntry->BaseDllName.Buffer);

        temp.Size = pEntry->SizeOfImage;
        temp.Address = (uintptr_t)pEntry->DllBase;

        memcpy((PVOID)((ULONG_PTR)ModulesList + ((index++) * sizeof(SM_MSI))), &temp, sizeof(SM_MSI));
    }
}

模块遍历函数

遍历函数核心执行逻辑:

  • 校验模块列表计数为0时,直接返回拒绝访问状态
  • 按当前遍历索引,从连续存储区拷贝单条模块信息到用户态传出缓冲区
  • 当索引遍历到列表末尾时,重置计数、索引值,释放连续存储区内存

对应代码片段:

NTSTATUS ProcModulesWalk(OUT SM_MSI* module_sys_info) {
  if (ModulesListCount == 0)
      return STATUS_ACCESS_DENIED;

  memcpy(module_sys_info, (SM_MSI*)((ULONG_PTR)ModulesList) + ModulesListIndex++, sizeof(SM_MSI));

  if (ModulesListIndex >= ModulesListCount) {
      ModulesListCount = 0;
      ModulesListIndex = 0;

      ExFreePool(ModulesList); // 释放内存 
      DbgPrintEx(0, 0, "free memory\n");
  }
  return STATUS_SUCCESS;
}

问题表现

  • 在驱动加载阶段的DriverEntry中直接调用这组函数,运行完全正常,无蓝屏
  • 改为响应用户态DLL的调用请求时,仅能正常运行2秒左右就触发蓝屏
  • 临时将SM_MSI结构体中的Name成员移除后,程序可完全正常运行,无蓝屏
  • 初步将问题范围锁定在结构体中wchar_t* Name成员的处理逻辑上

问题根因

经自行排查定位,触发蓝屏的核心原因是内核与用户态交互传递结构体时,遗漏了指针成员对应的内存空间分配与拷贝:

  • 快照函数存储的SM_MSI结构体中,Name是指向内核态内存的指针,当通过IO请求将结构体拷贝到用户态缓冲区时,内核地址会被直接传递到用户态,用户态尝试访问这个内核地址就会触发非法内存访问,直接导致蓝屏
  • 连续列表内存释放时,仅释放了结构体数组本身的内存,没有单独释放每个Name成员申请的内核内存,长期运行会造成内存池损坏,进一步触发蓝屏

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.29 22:06:03