3. 设备对象创建

设备对象创建 学习卡片

任务说明

本案例目标是在内核驱动入口 DriverEntry 中创建一个设备对象,设置必要的设备标志,并通过设备管理器或内核调试器验证设备对象已成功创建。设备对象是驱动与 I/O 管理器交互的基础,后续所有 IRP 处理、符号链接创建都依赖该对象存在。

设备对象创建实现

以下代码展示了一个最小完整的内核驱动,在 DriverEntry 中调用 IoCreateDevice 创建设备对象,设置 DO_DIRECT_IO 标志,并在驱动卸载时删除该设备对象。代码包含必要的头文件、驱动入口、卸载例程和创建设备的核心逻辑。


#include <ntddk.h>

#define DEVICE_NAME  L"\\Device\\MyDemoDevice"
#define DEVICE_TYPE  FILE_DEVICE_UNKNOWN

// 驱动卸载例程:删除设备对象
VOID DriverUnload(PDRIVER_OBJECT DriverObject)
{
    PDEVICE_OBJECT deviceObject = DriverObject->DeviceObject;
    if (deviceObject != NULL)
    {
        IoDeleteDevice(deviceObject);
        DbgPrint("[MyDemo] Device object deleted.\n");
    }
}

// 驱动入口:创建设备对象并设置标志
NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
{
    UNREFERENCED_PARAMETER(RegistryPath);

    PDEVICE_OBJECT deviceObject = NULL;
    UNICODE_STRING deviceName;

    // 初始化设备名称
    RtlInitUnicodeString(&deviceName, DEVICE_NAME);

    // 创建设备对象
    NTSTATUS status = IoCreateDevice(
        DriverObject,          // 驱动对象
        0,                     // 设备扩展大小(本案例不需要)
        &deviceName,           // 设备名称
        DEVICE_TYPE,           // 设备类型
        0,                     // 设备特征
        FALSE,                 // 不独占
        &deviceObject          // 返回的设备对象指针
    );

    if (!NT_SUCCESS(status))
    {
        DbgPrint("[MyDemo] IoCreateDevice failed: 0x%X\n", status);
        return status;
    }

    // 清除 DO_DEVICE_INITIALIZING 标志(IoCreateDevice 已自动清除,此处显式确认)
    // 设置直接 I/O 标志,后续读写 IRP 将使用 METHOD_IN_DIRECT / METHOD_OUT_DIRECT
    deviceObject->Flags |= DO_DIRECT_IO;

    // 设置卸载例程
    DriverObject->DriverUnload = DriverUnload;

    DbgPrint("[MyDemo] Device object created successfully.\n");
    return STATUS_SUCCESS;
}

代码说明

上述代码中,IoCreateDevice 的第一个参数传入驱动对象指针,使设备对象与当前驱动关联;设备名称使用 \Device\MyDemoDevice 命名空间下的名称。设备类型选择 FILE_DEVICE_UNKNOWN,适用于通用设备。创建成功后,代码设置 DO_DIRECT_IO 标志,表示后续 I/O 操作使用直接内存访问方式。卸载例程中调用 IoDeleteDevice 释放设备对象,避免内存泄漏。

验证方法

编译生成 MyDemo.sys 后,可通过以下两种方式验证设备对象是否成功创建:

  1. 设备管理器验证:使用 devmgmt.msc 打开设备管理器,在菜单栏选择“查看 → 显示隐藏的设备”,在“非即插即用驱动程序”分类下查找名为“MyDemoDevice”的设备节点。若存在该节点且无黄色感叹号,说明设备对象创建成功。
  2. 内核调试器验证:使用 WinDbg 连接目标系统,执行 !devobj \Device\MyDemoDevice 命令。若返回设备对象详细信息(包括设备类型、标志位、驱动对象地址等),说明设备对象存在且参数正确。

判定标准

满足以下条件即可判定案例通过:

  • 驱动加载后,DbgPrint 输出“Device object created successfully”日志(可通过 DebugView 或 WinDbg 观察);
  • 设备管理器中能看到“MyDemoDevice”设备节点,且状态为“此设备工作正常”;
  • 使用 !devobj 命令查询时,返回的设备对象标志中包含 DO_DIRECT_IO(值为 0x00000002)。

设备对象结构示意

设备对象创建与关联结构 DRIVER_OBJECT DriverUnload DeviceObject DriverEntry ... FastIoDispatch 指向 DEVICE_OBJECT DeviceName: \Device\MyDemoDevice DeviceType: FILE_DEVICE_UNKNOWN Flags: DO_DIRECT_IO Driver: 指向 DriverObject NextDevice: NULL 回指 验证方式 1. !devobj \Device\MyDemoDevice 2. 设备管理器 查看隐藏设备 3. DbgPrint 日志 IoCreateDevice 建立 DriverObject 与 DeviceObject 的双向关联,验证时通过设备名称查询对象

编译与加载

使用 Visual Studio 的驱动程序开发环境(WDK)创建“内核模式驱动程序空项目”,将上述代码保存为 main.c 并编译。加载驱动前需创建服务,以管理员身份打开命令提示符执行:


sc create MyDemo type= kernel binPath= C:\Path\To\MyDemo.sys
sc start MyDemo

停止并删除驱动服务:


sc stop MyDemo
sc delete MyDemo

注意:binPath 需替换为实际编译输出的 .sys 文件路径。加载驱动需要管理员权限,且目标系统需开启测试签名模式(bcdedit /set testsigning on)或使用签名驱动。