Windows内核采用的是面向对象的编程方式,但使用的确是C语言。Windows内核认为许多东西都是“对象”,
比如一个驱动一个文件一个设备,“对象”相当于一个基类。
一个驱动对象代表了一个驱动程序,或者说一个内核模块。驱动对象结构如下:
typedef struct _DRIVER_OBJECT{
//结构的类型和大小
CSHORT Type;
CSHORT Size;
......
//设备对象,该驱动创建的设备对象链表的开始
PDEVICE_OBJECT DeviceObject;
......
//该内核模块在内核空间中的开始地址和大小
PVOID DriverStart;
ULONG DriverSize;
......
//驱动的名字
UNICODE_STRING DriverName;
......
//FastIO例程
PFAST_IO_DISPATCH FastIoDispath;
......
//StartIO例程
PDRIVER_STARTIO DriverStartIo;
......
//卸载例程
PDRIVER_UNLOAD DriverUnload;
......
//普通分发函数,派遣例程
PDRIVER_DISPATH MajorFunction[IRP_MJ_MAXIMUM_FUNCTION+1];
}DRIVER_OBJECT;
在驱动对象中我们可以看到其中有一个设备对象成员
PDEVICE_OBJECT DeviceObject 它指向一个设备对象链表的第一个对象,因为每个驱动对象可以创建若干个设备对象,
这些设备对象正是用链表形式链接起来(最后一个设备对象指向NULL)。设备对象即DEVICE_OBJECT ,简称DO。
在内核中,信息主要以IRP(I/O请求包)方式传递,而设备对象是唯一可以接受请求的实体。
那么说到这里我们再来看看设备对象这个数据结构。
typedef struct _DEVICE_OBJECT{
......
//该设备对象所属的驱动对象
struct _DRIVER_OBJECT *DriverObject;
//水平层次上的下一个设备对象,即和该设备对象同属一个驱动对象
struct _DEVICE_OBJECT *NextDevice;
//垂直层次的上一个设备对象,和该设备对象不属于同一个驱动对象
struct _DEVICE_OBJECT *AttachedDevice;
//使用StartIO例程的时时候,此域指向的是当前IRP结构
struct _IRP *CurrentIrp;
ULONG Flags;
//设备扩展对象,又程序员自己定义的结构体记录一些设备信息,
//为避免使用全局变量,可以将全局变量存在设备扩展里面
struct _DEVOBJ_EXTENSION *DeviceObjectExtension;
}DEVICE_OBJECT;
从驱动对象和设备对象的结构定义来看,设备对象通过struct _DEVICE_OBJECT *NextDevice;
这个域将该驱动中的设备对象链接起来。
驱动对象可以找到它创建的设备链表头,而设备对象可以找到它所属的驱动对象。
我们看到设备对象中有一个struct _DEVICE_OBJECT *AttachedDevice成员,它是跟设备栈相关联的。
设备的创建顺序是,先创建底层PDO(物理设备对象),再创建FDO(功能设备对象),PDO和FDO之间可能还有一些过滤驱动
(称为FiDO Filter Device Object)。
每一层设备对象由不同的驱动对象创建,这些驱动对象共同完成一个物理设备的驱动任务。
这由下而上生长的设备便形成了设备栈。*AttachedDevice就指向上一层的设备对象,如果为NULL表示已经是最顶层。
从底层向高层可以通过*AttachedDevice来寻找,从高层到底层,设备对象没有提供相关子域。这里就可以通过设备扩展
这个成员来自定义,在_DEVOBJ_EXTENSION 结构中定义一个指向低一层设备的域。