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

Windows 11内核模式驱动无法获取全部硬盘信息求助

Windows内核模式获取磁盘信息:符号链接处理错误分析与修复

我是内核编程新手,在Windows 11内核模式下尝试获取硬盘名称、序列号等信息时遇到问题。目前用IoGetDeviceInterfaces获取磁盘符号链接的代码能正常运行,但在循环内调用自定义的SymbolicLinkTarget函数解析符号链接时,出现名称为空、调用ZwOpenSymbolicLinkObject导致BSOD的问题。

当前可用的符号链接获取代码

static VOID DeviceInterfaceTest_Func() {
NTSTATUS Status;
PWSTR SymbolicLinkList;
PWSTR SymbolicLinkListPtr;
GUID Guid = {
    0x53F5630D,
    0xB6BF,
    0x11D0,
    {
        0x94,
        0xF2,
        0x00,
        0xA0,
        0xC9,
        0x1E,
        0xFB,
        0x8B
    }
}; //Defined in mountmgr.h
Status = IoGetDeviceInterfaces( &
    Guid,
    NULL,
    0, &
    SymbolicLinkList);

if (!NT_SUCCESS(Status)) {
    return;
}

KdPrint(("IoGetDeviceInterfaces results:\n"));
for (SymbolicLinkListPtr = SymbolicLinkList; SymbolicLinkListPtr[0] != 0 && SymbolicLinkListPtr[1] != 0; SymbolicLinkListPtr += wcslen(SymbolicLinkListPtr) + 1) {
    KdPrint(("Symbolic Link: %S\n", SymbolicLinkListPtr));

    PUNICODE_STRING PTarget {};
    UNICODE_STRING Input;
    NTSTATUS s = 0;
    Input.Length = sizeof((PWSTR) & SymbolicLinkListPtr);
    Input.MaximumLength = 200 * sizeof(WCHAR);
    Input.Buffer = (PWSTR) ExAllocatePool2(PagedPool, Input.MaximumLength, 0);
    s = SymbolicLinkTarget( & Input, PTarget);
    if (s == STATUS_SUCCESS) {
        //KdPrint(("%S\n", PTarget->Buffer));
        KdPrint(("Finished!\n"));
    }
}

ExFreePool(SymbolicLinkList);
}

出现问题的SymbolicLinkTarget函数代码

NTSTATUS SymbolicLinkTarget(_In_ PUNICODE_STRING SymbolicLinkStr, _Out_ PUNICODE_STRING PTarget) {
OBJECT_ATTRIBUTES ObjectAtiribute {};
NTSTATUS Status = 0;
HANDLE Handle = nullptr;
InitializeObjectAttributes( & ObjectAtiribute, SymbolicLinkStr, OBJ_CASE_INSENSITIVE, 0, 0);
KdPrint(("Object length:%u \n", ObjectAtiribute.Length));
KdPrint(("Object name:%s \n", ObjectAtiribute.ObjectName -> Buffer));
Status = ZwOpenSymbolicLinkObject(&Handle, GENERIC_READ, &ObjectAtiribute);
if (Status != STATUS_SUCCESS)
{
    KdPrint(("ZwOpenSymbolicLinkObject failed (0x%08X)\n", Status));
    return Status;
}
UNREFERENCED_PARAMETER(PTarget);
ULONG Tag1 = 'Tag1';
PTarget->MaximumLength = 200 * sizeof(WCHAR);
PTarget->Length = 0;
PTarget->Buffer = (PWCH)ExAllocatePool2(PagedPool, PTarget->MaximumLength, Tag1);
if (!PTarget->Buffer)
{
    ZwClose(Handle);
    return STATUS_INSUFFICIENT_RESOURCES;
}
Status = ZwQuerySymbolicLinkObject(Handle, PTarget, NULL);
ZwClose(Handle);
if (Status != STATUS_SUCCESS)
{
    KdPrint(("ZwQuerySymbolicLinkObject failed (0x%08X)\n", Status));
    ExFreePool(PTarget->Buffer);
    return Status;
}
return STATUS_SUCCESS;
}

核心错误点分析

  1. Input UnicodeString初始化错误
    循环中仅分配了Input.Buffer,但未将符号链接字符串复制到其中,且Input.Length计算错误(取了指针大小而非字符串字节长度),导致传入SymbolicLinkTarget的是空的Unicode字符串。

  2. 未初始化的PTarget指针
    PUNICODE_STRING PTarget {};定义了一个空指针,直接在SymbolicLinkTarget中访问PTarget->MaximumLength会触发内存访问违规,直接导致BSOD。

  3. KdPrint格式化符错误
    ObjectAtiribute.ObjectName->Buffer是宽字符类型,需用%S格式化符,用%s会打印乱码或空值。

  4. 多余的UNREFERENCED_PARAMETER(PTarget)
    该语句会屏蔽编译器对空指针的警告,但后续直接使用空指针的操作依然存在,属于严重逻辑错误。


修正后的代码示例

修正后的DeviceInterfaceTest_Func循环部分

for (SymbolicLinkListPtr = SymbolicLinkList; SymbolicLinkListPtr[0] != 0 && SymbolicLinkListPtr[1] != 0; SymbolicLinkListPtr += wcslen(SymbolicLinkListPtr) + 1) {
    KdPrint(("Symbolic Link: %S\n", SymbolicLinkListPtr));

    UNICODE_STRING Target = {0}; // 在栈上分配合法的UNICODE_STRING结构体
    UNICODE_STRING Input;
    NTSTATUS s = 0;
    Input.MaximumLength = 200 * sizeof(WCHAR);
    Input.Buffer = (PWSTR)ExAllocatePool2(PagedPool, Input.MaximumLength, 'DevL'); // 使用有意义的池标签
    if (!Input.Buffer) {
        continue;
    }
    // 复制符号链接字符串到Input并设置正确长度
    wcscpy_s(Input.Buffer, Input.MaximumLength / sizeof(WCHAR), SymbolicLinkListPtr);
    Input.Length = wcslen(SymbolicLinkListPtr) * sizeof(WCHAR);

    s = SymbolicLinkTarget(&Input, &Target);
    if (s == STATUS_SUCCESS) {
        KdPrint(("Target Path: %S\n", Target.Buffer));
        ExFreePool(Target.Buffer); // 释放Target的缓冲区
        KdPrint(("Finished!\n"));
    }
    ExFreePool(Input.Buffer); // 释放Input的缓冲区
}

修正后的SymbolicLinkTarget函数

NTSTATUS SymbolicLinkTarget(_In_ PUNICODE_STRING SymbolicLinkStr, _Out_ PUNICODE_STRING PTarget) {
    OBJECT_ATTRIBUTES ObjectAttributes = {0};
    NTSTATUS Status = STATUS_SUCCESS;
    HANDLE Handle = nullptr;

    // 先校验输入参数合法性
    if (!SymbolicLinkStr || !SymbolicLinkStr->Buffer || !PTarget) {
        return STATUS_INVALID_PARAMETER;
    }

    InitializeObjectAttributes(&ObjectAttributes, SymbolicLinkStr, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
    KdPrint(("Object length:%u \n", ObjectAttributes.Length));
    KdPrint(("Object name:%S \n", ObjectAttributes.ObjectName->Buffer));

    Status = ZwOpenSymbolicLinkObject(&Handle, GENERIC_READ, &ObjectAttributes);
    if (!NT_SUCCESS(Status)) {
        KdPrint(("ZwOpenSymbolicLinkObject failed (0x%08X)\n", Status));
        return Status;
    }

    ULONG Tag1 = 'Tag1';
    PTarget->MaximumLength = 200 * sizeof(WCHAR);
    PTarget->Length = 0;
    PTarget->Buffer = (PWCH)ExAllocatePool2(PagedPool, PTarget->MaximumLength, Tag1);
    if (!PTarget->Buffer) {
        ZwClose(Handle);
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    ULONG ReturnedLength = 0;
    Status = ZwQuerySymbolicLinkObject(Handle, PTarget, &ReturnedLength);
    ZwClose(Handle);

    if (!NT_SUCCESS(Status)) {
        KdPrint(("ZwQuerySymbolicLinkObject failed (0x%08X)\n", Status));
        ExFreePool(PTarget->Buffer);
        PTarget->Buffer = nullptr;
        PTarget->Length = PTarget->MaximumLength = 0;
        return Status;
    }

    return STATUS_SUCCESS;
}

替代方案:直接获取磁盘属性

如果目标是获取硬盘名称、序列号等信息,解析符号链接并非最优路径,更可靠的方式是:

  • 通过IoGetDeviceInterfaces获取设备接口路径后,直接用ZwCreateFile打开设备
  • 发送IOCTL_STORAGE_QUERY_PROPERTY控制码查询存储设备属性(含序列号、友好名称)
  • 发送IOCTL_DISK_GET_DRIVE_GEOMETRY_EX获取磁盘几何信息

这种方式无需解析符号链接,直接与磁盘设备通信,逻辑更简洁可靠。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 11:54:20