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 后,可通过以下两种方式验证设备对象是否成功创建:
- 设备管理器验证:使用
devmgmt.msc打开设备管理器,在菜单栏选择“查看 → 显示隐藏的设备”,在“非即插即用驱动程序”分类下查找名为“MyDemoDevice”的设备节点。若存在该节点且无黄色感叹号,说明设备对象创建成功。 - 内核调试器验证:使用 WinDbg 连接目标系统,执行
!devobj \Device\MyDemoDevice命令。若返回设备对象详细信息(包括设备类型、标志位、驱动对象地址等),说明设备对象存在且参数正确。
判定标准
满足以下条件即可判定案例通过:
- 驱动加载后,
DbgPrint输出“Device object created successfully”日志(可通过 DebugView 或 WinDbg 观察); - 设备管理器中能看到“MyDemoDevice”设备节点,且状态为“此设备工作正常”;
- 使用
!devobj命令查询时,返回的设备对象标志中包含DO_DIRECT_IO(值为 0x00000002)。
设备对象结构示意
编译与加载
使用 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)或使用签名驱动。