windows内核原理与实现读书笔记之驱动程序对象和设备对象
I/O管理器加载设备驱动程序时,会创建一个驱动程序对象,该对象在对象管理器目录中的路径为:\Driver\<DriverName> 或\FileSystem\<DriverName>。如果时文件系统类型的驱动程序则放在”\FileSystem”目录下,否则放在“\Driver”目录下。
与驱动程序相关的时设备对象,有两种途径创建设备对象:即插即用在检测到设备时,通过AddDevice 创建设备对象;非即插即用设备在初始化例程中创建设备对象。设备对象是通过IoCreateDevice 来完成的,原型如下:
NTKERNELAPI NTSTATUS IoCreateDevice(
IN PDRIVER_OBJECT DriverObject,
IN ULONG DeviceExtensionSize,
IN PUNICODE_STRING DeviceName OPTIONAL,
IN DEVICE_TYPE DeviceType,
IN ULONG DeviceCharacteristics,
IN BOOLEAN Exclusive,
OUT PDEVICE_OBJECT *DeviceObject
);
DriverObject:为指针调用驱动程序对象。每个驱动程序接收一个参数的指针。
DeviceExtensionSize:给_DEVICE_OBJECT.DeviceExtension指定内存空间大小,具体看自己定义结构的大小
DeviceName:设备名字
DeviceType: 设备类型 这里我们用FILE_DEVICE_UNKNOWN
DeviceCharacteristics:设备特征信息 一般为0
Exclusive: 是否指定设备为独占 是为TRUE,否为FALSE
DeviceObject:指针变量接收一个指向新创建的DEVICE_OBJECT结构。用来回传数据
IoCreateDevice 函数的基本流程:
- 根据参数,构造出设备的名称,并且创建一个安全描述符,用于对该设备的访问控制。
- 调用ObCreateObject 创建一个IoDeviceObjectType 的内核对象。
- 如果ObCreateObject失败,则重试。
- IoCreateDevice初始化新建的设备对象中的成员,并调用ObInsertObject,将设备对象插入到进程的句柄表中。
- 设定该设备对象中的驱动程序对象,并将设备对象插入到驱动程序对象的设备链表中,因而将设备对象与驱动程序对象关联起来。
驱动程序对象的数据结构:
typedef struct _DRIVER_OBJECT {
CSHORT Type;
CSHORT Size;
PDEVICE_OBJECT DeviceObject;//指向设备对象,所有的设备对象构成一个链表
ULONG Flags; //驱动程序标志
PVOID DriverStart; //驱动程序映像起始地址
ULONG DriverSize;//驱动程序映像大小
PVOID DriverSection;//指向驱动程序映像的内存区对象
PDRIVER_EXTENSION DriverExtension;//指向驱动程序对象的扩展部分
UNICODE_STRING DriverName;//驱动程序名称
PUNICODE_STRING HardwareDatabase;//指向注册表中保护硬件信息的路径
PFAST_IO_DISPATCH FastIoDispatch;//指向快速I/O的分发结构
PDRIVER_INITIALIZE DriverInit;//驱动程序的初始化例程
PDRIVER_STARTIO DriverStartIo;//驱动程序的启动I/O例程
PDRIVER_UNLOAD DriverUnload;//驱动程序的协助例程
PDRIVER_DISPATCH MajorFunction[IRP_MJ_MAXIMUM_FUNCTION + 1];
} DRIVER_OBJECT;
扩展部分的数据结构DRIVER_EXTENSION定义:
typedef struct _DRIVER_EXTENSION {
struct _DRIVER_OBJECT *DriverObject;//指向驱动程序
//AddDevice 是一个函数指针,当即插即用管理器检测到一个新的设备由该驱动程序
//负责时,调用该函数,以便通知该驱动程序
PDRIVER_ADD_DEVICE AddDevice;
ULONG Count;//记录了重新初始化调用的次数
UNICODE_STRING ServiceKeyName;//驱动程序的服务名称
PIO_CLIENT_EXTENSION ClientDriverExtension;//指向驱动程序的客户扩展部分
PFS_FILTER_CALLBACKS FsFilterCallbacks;//用于文件系统过滤驱动程序
} DRIVER_EXTENSION, *PDRIVER_EXTENSION;
驱动程序对象中的MajorFunction 数组包含了一组例程,当I/O管理器接收到一个I/O请求时,它将根据I/O请求有关信息,找到驱动程序对象,并调用相应的例程累处理该I/O请求。设备驱动程序初始化时会填充MajorFunction数组,未填充的将会将其填充为IopInvalidDeviceRequest 函数。
设备对象的数据结构为:
typedef struct _DEVICE_OBJECT {
CSHORT Type;
USHORT Size;
LONG ReferenceCount;//引用计数值
struct _DRIVER_OBJECT *DriverObject;//指向关联的驱动程序对象
struct _DEVICE_OBJECT *NextDevice;//指向关联同一驱动程序对象的下一个对象
struct _DEVICE_OBJECT *AttachedDevice;//附载的设备,与AttachedTo 构成双链表关系
struct _IRP *CurrentIrp;//当前正在处理的I/O请求包
PIO_TIMER Timer;//设备对象的定时器
ULONG Flags; //设备对象标志,以DO_作为前缀的一组常量
ULONG Characteristics; //设备的特征,以FILE_作为前缀的一组常量
PVPB Vpb;//指向设备的卷参数块(volum parameter Block)
PVOID DeviceExtension;//指向设备对象的扩展部分
DEVICE_TYPE DeviceType;//设备类型
CCHAR StackSize; //设备栈的大小
union {
LIST_ENTRY ListEntry;//用于文件系统的设备对象,形成一个链表
WAIT_CONTEXT_BLOCK Wcb;//等待环境块,用于控制器对象协作
} Queue;
ULONG AlignmentRequirement;//缓冲区的对齐要求,其值等于对齐边界减一
KDEVICE_QUEUE DeviceQueue;//设备队列,存放针对该设备的I/O请求
KDPC Dpc;
ULONG ActiveThreadCount;//用于文件系统:使用此设备对象的线程数
PSECURITY_DESCRIPTOR SecurityDescriptor;//设备的安全描述符
KEVENT DeviceLock;//设备锁
USHORT SectorSize;//扇区大小
USHORT Spare1;
struct _DEVOBJ_EXTENSION *DeviceObjectExtension;//指向扩展部分
PVOID Reserved;
} DEVICE_OBJECT;
typedef struct _DEVICE_OBJECT *PDEVICE_OBJECT;
设备对象扩展部分的定义:
typedef struct _DEVOBJ_EXTENSION {
CSHORT Type;
USHORT Size;
PDEVICE_OBJECT DeviceObject; //指向关联的设备对象
ULONG PowerFlags; //电源标志
struct _DEVICE_OBJECT_POWER_EXTENSION *Dope;//设备对象的电源扩展部分
ULONG ExtensionFlags;//设备对象扩展标志
PVOID DeviceNode;//设备节点域,由即插即用管理器使用
PDEVICE_OBJECT AttachedTo;//当前设备对象被附载到此设备对象
//以下三个域用于IoStart*函数
LONG StartIoCount;//已启动但未完成的I/O的数量
LONG StartIoKey;//下一个启动I/O的键
ULONG StartIoFlags;//启动I/O标志
PVPB Vpb; //已挂载卷的VPB,用于文件系统的设备对象
} DEVOBJ_EXTENSION, *PDEVOBJ_EXTENSION;
正如IoCreateDevice 那样,设备对象的DriverObject指向附载该设备的驱动程序,NextDevice构成了同属一个驱动程序的设备对象单链表。IoCreateDevice 调用IopInsertRemoveDevice ,将设备对象插入到此链表中。设备对象的AttachedDevice 和扩展部分的AttachTo 构成了一个双链表节点的前后指针。设备对象的StackSize 指定了最小需要的栈深度,AttachTo 将设备栈中的设备对象自栈顶向底层链接起来,而AttachedDevice则自底向上将这些设备对象链接起来。
设备栈示意图: