当前位置:文档之家› 《Windows内核编程》基本数据结构

《Windows内核编程》基本数据结构

《Windows内核编程》基本数据结构学习各种高级外挂制作技术,马上去百度搜索(魔鬼作坊),点击第一个站进入,快速成为做挂达人。

驱动对象:每个驱动程序都会有唯一的驱动对象与之对应,并且这个驱动对象是在驱动加载时被内核中的对象管理程序所创建的。

驱动对象用DRIVER_OBJECT数据结构表示,它作为驱动的一个实例被内核加载,并且内核对一个驱动只加载一个实例。

确切地说,是由内核中的I/O管理器负责加载的,驱动程序需要在DriverEntry中初始化。

驱动对象的结构定义如下(wd m.h):typedef struct_DRIVER_OBJECT{//结构的类型和大小CSHORT Type;CSHORT Size;//每个驱动程序会有一个或多个设备对象,其中,每个设备对象都有一个指针指向下一个驱动对象//最后一个设备对象指向空。

DeviceObject指向驱动对象的第一个设备对象。

通过Devic eObject,就//可以遍历驱动对象中的所有设备对象了。

PDEVICE_OBJECT DeviceObject;ULONG Flags;//The following section describes where the driver is loaded.The count //field is used to count the number of times the driver has had its//registered reinitialization routine invoked.PVOID DriverStart;ULONG DriverSize;PVOID DriverSection;PDRIVER_EXTENSION DriverExtension;//记录驱动设备的名字,用UNICODE字符串记录,该字符串一般/Driver/[驱动程序名称]UNICODE_STRING DriverName;//设备的硬件数据库键名,也是UNICODE字符串记录。

一般为///REGISTRY/MACHINE/HADRWARE/DESCRIPTION/SYSTEMPUNICODE_STRING HardwareDatabase;//文件驱动中用到的派遣函数PFAST_IO_DISPATCH FastIoDispatch;//The following section describes the entry points to this particular//driver.Note that the major function dispatch table must be the last //field in the object so that it remains extensible.PDRIVER_INITIALIZE DriverInit;//记录StartIO例程的函数地址,用于串行化操作PDRIVER_STARTIO DriverStartIo;//指定驱动卸载时所用的回调函数地址PDRIVER_UNLOAD DriverUnload;//MajorFunction域记录的是一个函数指针数组,也就是MajorFunction是一个数组,数组中的每个//成员记录着一个指针,每一个指针指向的是一个函数。

这个函数是处理IRP的派遣函数PDRIVER_DISPATCH MajorFunction[IRP_MJ_MAXIMUM_FUNCTION+1];}DRIVER_OBJECT;typedef struct_DRIVER_OBJECT*PDRIVER_OBJECT;实际上如果写一个驱动程序,或者说编写一个内核模块,要在Windows中加载,就必须填写上面的结构,来告诉Windows程序提供的功能。

注意内核模块并不生成一个进程,它只是写一组回调函数让Windows调用,且这组回调函数必须符合Windows内核规定的格式。

上面代码中的“快速IO分发函数”FastIoDispatch和“普通分发函数”MajorFunction就是这样一种回调函数。

这些函数用来处理发送给这个内核模块的请求。

Windows中很多组件都拥有自己的DRIVER_OBJECT,例如:所有的硬件驱动程序、所有的类驱动(Disk、Cdrom…)、文件系统(NTFS和FastFat,有各自的DRIVER_OBJECT),以及许多其他的内核组件。

我们可以使用一个软件WinObj来查看所有的内核对象。

设备对象:每个驱动程序会创建一个或多个设备对象,用DEVICE_OBJECT数据结构表示。

每个设备对象都会有一个指针指向下一个设备对象,因此就形成一个设备链。

设备链的第一个设备是由DRIVER_OBJECT结构体中指明的。

设备对象是内核中的重要对象,其重要性不亚于Windows GUI编程中的窗口。

窗口是唯一可以接收消息的对象,任何消息都是发送到一个窗口中的;而在内核编程中,大部分“消息”是以请求IRP的方式传递的。

而设备对象(DEVICE_OBJECT)是唯一可以接收请求的实体,任何一个请求IRP都是发送给某个设备对象的。

设备对象的结构是DEVICE_OBJECT,常常被简称为DO。

一个DO可以代表很多不同的东西,例如一个实际的硬盘、或实现一个类似管道的功能等等。

我们总是在内核程序中生成一个DO,而一个内核程序是用一个驱动对象表示的,因此,一个设备对象总是属于一个驱动对象。

在WDK的wdm.h文件中DO的定义如下:typedef struct DECLSPEC_ALIGN(MEMORY_ALLOCATION_ALIGNMENT)_DEVICE_OBJECT{//结构的类型和大小CSHORT Type;USHORT Size;//引用计数LONG ReferenceCount;//指向驱动程序中的驱动对象,同属于一个驱动程序的驱动对象指向的是同一驱动对象struct_DRIVER_OBJECT*DriverObject;//下一个设备对象。

//这里指的下一个设备对象是同属于一个驱动对象的设备,也就是同一个驱动程序创建的若干设备//对象,每个设备对象根据NextDevice域形成链表,从而可以枚举每个设备对象struct_DEVICE_OBJECT*NextDevice;//指向下一个设备对象,这里指的是,如果有更高一层的驱动附加到这个驱动的时候//AttachedDevice指向的就是那个更高一层的驱动struct_DEVICE_OBJECT*AttachedDevice;//在使用StartIO例程的时候,此域指向的是当前IRP结构struct_IRP*CurrentIrp;PIO_TIMER Timer;//此域是一个32位的无符号整型,每一位有具体的含义//DO_BUFFERED_IO---读写操作使用缓冲方式(系统复制缓冲区)访问用户模式数据//DO_EXCLUSIVE---一次只允许一个线程打开设备句柄//DO_DIRECT_IO---读写操作使用直接方式(内存描述符表)访问用户模式数据//DO_DEVICE_INITIALIZING---设备对象正在初始化//DO_POWER_PAGABLE---必须在PASSIVE_LEVEL级上处理IRP_MJ_PNP请求//DO_POWER_INRUSH---设备上电期间需要大电流ULONG Flags;ULONG Characteristics;__volatile PVPB Vpb;//指向设备扩展对象,每个设备都会指定一个设备扩展对象,设备扩展对象记录的是设备自己//特殊定义的结构体,即程序员自己定义的结构体。

另外,在驱动开发中,应该尽量避免全局变量的//使用,因为全局变量涉及不容易同步问题。

解决的方法是:将全局变量存在设备扩展中PVOID DeviceExtension;//设备类型,当制作虚拟设备时,应选择FILE_DEVICE_UNKNOWN类型的设备DEVICE_TYPE DeviceType;//IRP栈大小。

在多层驱动情况下,驱动与驱动之间会形成类似堆栈的结构,IRP会依次从//最高层传递到最底层CCHAR StackSize;union{LIST_ENTRY ListEntry;WAIT_CONTEXT_BLOCK Wcb;}Queue;//设备在大容量传输时,需要内存对齐,以保证传输速度ULONG AlignmentRequirement;KDEVICE_QUEUE DeviceQueue;KDPC Dpc;//The following field is for exclusive use by the filesystem to keep //track of the number of Fsp threads currently using the device 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;一个驱动对象可以生成多个设备对象,而Windows向设备对象发送请求时,这些请求是被驱动对象的分发函数所捕获的,即当Windows内核向一个设备发送一个请求时,驱动对象的分发函数中的某一个会被调用,分发函数原型如下://参数device是请求的目标设备;参数irp是请求的指针NTSTATUE ASCEDispatch(PDEVICE_OBJECT device,PIRP irp);附:设备扩展:设备对象记录“通用”设备的信息,而另外一些“特殊”信息记录在设备扩展里。

各个设备扩展由程序员自己定义,每个设备的设备扩展不尽相同。

设备扩展是由程序员指定内容和大小,由I/O管理器创建的,并保存在非分页内存中。

在驱动程序中,尽量避免使用全局函数,因为全局函数往往导致函数的不可重入性。

重入性指的是在多线程程序中,多个函数并行运行,函数的运行结果不会根据函数的调用先后顺序而导致不同。

解决的办法是,将全局变量以设备扩展的形式存储,并加以适当的同步保护措施。

除此之外,在设备扩展中还会记录下列一些内容:设备对象的反向指针;设备状态或驱动环境变量;中断对象指针;控制器对象指针。

由于设备扩展是驱动程序专用的,它的结构必须在驱动程序的头文件中定义。

相关主题