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 函数的基本流程:

  1. 根据参数,构造出设备的名称,并且创建一个安全描述符,用于对该设备的访问控制。
  2. 调用ObCreateObject 创建一个IoDeviceObjectType 的内核对象。
  3. 如果ObCreateObject失败,则重试。
  4. IoCreateDevice初始化新建的设备对象中的成员,并调用ObInsertObject,将设备对象插入到进程的句柄表中。
  5. 设定该设备对象中的驱动程序对象,并将设备对象插入到驱动程序对象的设备链表中,因而将设备对象与驱动程序对象关联起来。

驱动程序对象的数据结构:

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则自底向上将这些设备对象链接起来。

设备栈示意图:

windows内核原理与实现读书笔记之驱动程序对象和设备对象