windows内核开发笔记十二:DriverObject结构
学习好驱动开发,对于内核的结构的了解非常重要,只有熟悉了内核结构,才能更得心应手,每一个驱动对象代表着一个已经装载的内核模式下的驱动, 指向驱动对象的指针是驱动程序中以下例程的输入参数之一: DriverEntry, AddDevice, Reinitialize(可选例程),Unload(可选例程)。驱动对象是一个半透明对象,驱动编写者必须熟悉它的某些成员对象,以实现驱动的初始化功能和卸载功能(如果该驱动能够卸载)。
本节的学习驱动内核开发的一个重要的数据结构:驱动结构DriverObject的这个结构,这个数据结构,合计下来含有15个结构field,这些field有的是开发人员能够访问的,有的是被内核系统程序访问的,这就是所说的半透明的特性。
上图描述了在程序中的DriverObject的数据结构,采用C或C++语言开发的程序员,理解起来不会费劲。
虽然 DDK头中公开了整个结构,但我们仅能直接访问或修改结构中的某些域。在图中,我把驱动程序对象的不透明域用灰背景表示。这些不透明域类似于C++类中的私有成员或保护成员,而透明域类似于公共成员。
typedef struct _DRIVER_OBJECT {
// 结构的类型和大小。
CSHORT Type;
CSHORT Size;
// 设备对象,这里实际上是一个设备对象的链表的开始。因为 DeviceObject
// 中有相关链表信息。读下一小节“设备对象”会得到更多的信息。
PDEVICE_OBJECT DeviceObject;
……
// 驱动的名字
UNICODE_STRING DriverName;
……
// 快速 IO分发函数
PFAST_IO_DISPATCH FastIoDispatch;
……
// 驱动的卸载函数
PDRIVER_UNLOAD DriverUnload;
// 普通分发函数
PDRIVER_DISPATCH MajorFunction[IRP_MJ_MAXIMUM_FUNCTION + 1];
} DRIVER_OBJECT;
这个图是在内存中的数据存储结构,下图是DriverObject和例程的调用关系。
以下列出的是驱动对象中能被驱动访问的成员:
可访问成员
- PDEVICE_OBJECT DeviceObject
指向一个由驱动创建的设备对象,当驱动程序调用IoCreateDevice成功时,该成员会自动更新。驱动程序可以利用该成员以及DEVICE_OBJECT对象中的NextDevice成员来实现对由该驱动创建的所有设备列表中设备的遍历。
- PDRIVER_EXTENSION DriverExtension
驱动扩展对象指针,该对象唯一能访问的成员是DriverExtension-> AddDevice,对应的是驱动DriverEntry例程中的AddDevice例程。
- PUNICODE_STRING HardwareDatabase
指向\Registry\Machine\Hardware,该路径指向的是注册表中包含该硬件的配置信息。
- PFAST_IO_DISPATCH FastIoDispatch
指向快速I/O入口地址,该成员之用于FSD(文件系统驱动)已经网络传输驱动。
- PDRIVER_INITIALIZE DriverInit
DriverEntry例程的入口点,由I\O管理器设置。
- PDRIVER_STARTIO DriverStarIo
驱动程序中StartIo例程的入口地址(如果有的话),当驱动初始化时,DriverEntry例程负责设置它,如果驱动程序没有StartIo,该成员为NULL。
- PDRIVER_UNLOAD DriverUnload
驱动程序中Unload例程的入口地址(如果有的话),当驱动初始化时,DriverEntry例程负责设置它,如果驱动程序没有StartIo,该成员为NULL。
- PDRIVER_DISPATCHMajorFunction[IRP_MJ_MAXIMUM_FUNCTION + 1]
派遣例程表,该表包含了驱动中DispatchXxx routines等所有派遣例程的入口地址。该数组的索引值为IRP_MJ_Xxx,该值代表每一个IRP的主功能函数代码(IRP major function code), 任何驱动都必须为IRP_MJ_Xxx请求设置入口地址。每一个DispatchXxx例程的定义在上面的图中对应的函数,这里不再做赘述说明。
不可访问成员“
- Type :结构类型。
- Size; :结构大小。
- DriverName:驱动的名字。
-
DriverStart: 驱动在内核空间的开始地址
-
DriverSize: 驱动在内核空间的大小
-
DriverSection: 驱动在内核空间段
-
Flags:它的flags 有几个域在过滤程序中经常用到。。。
DO_BUFFERED_IO(缓冲读取)-------------DO_DIRECT_IO(直接读取)内存描述符表
DO_DEVICE_INITIALIZING(设备的初始化)--------DO_POWER_PAGED----(电源是否可以出于分页处)
DriverObeject的作用如下:
1. 在操作系统首次装载一个驱动程序之后,它会创建一个数据结构用来记录该驱动,该数据结构我们称为 驱 动对象 ( Driver Object )。
2. 驱动对象 记录与驱动程序本身相关的信息,它主要包含了除了DriverEntry之外的其它驱动程序入口函数的入口地址。( 驱动程序是一种具有多个入口函数的程 序 )
3. 驱动对象是由操作系统创建,然后作为DriverEntry的第一个参数传递给相应的驱动程序。
4. 在获得驱动对象的指针之后,所开发的程序需要对其中的一些字段进行初始化。