Windows内核中把驱动,设备,文件等都称为"对象",在系统启动后,这些对象都在内存中.
一个驱动对象(DRIVER_OBJECT)代表了一个驱动程序,或者是内核模块.
设备对象(DEVICE_OBJECT)是在内核中唯一接收请求的实体.大部分消息都是以请求(IRP)方式传递的,而任何一个请求都是发送被某个设备对象的.设备对象是驱动对象结构的第三个参数对象.
内核程序是以一个驱动对象表示的,所以一个设备对象总是属于一个驱动对象.
驱动对象结构:
typedef struct _DRIVER_OBJECT{
CSHORT Type;
CSHORT Size;
//设备对象,是一个设备对象链表的开始.
PDEVICE_OBJECT DeviceObject;
ULONG Flags;
//驱动在内核空间的开始地址和大小
PVOID DriverStart;
ULONG DriverSize;
PVOID DriverSection;
PDRIVER_EXTENSION DriverExtension;
//驱动的名字,确定一个I/O请求被绑定的驱动程序的名称
UNICODE_STRING DriverName;
//指向注册表中的硬件信息的路径
PUNICODE_STRING HardwareDatabase;
//快速IO分发函数的入口,数组的可选指针,通过参数单独调用驱动程序执行,而不是使用IRP(操作系统内核的一个数据结构,应用程序与驱动程序进行通信需要通过IRP包)调用机制,这些功能只能被用户同步IO或者文件缓存
PFAST_IO_DISPATCH FastIoDispatch;
//驱动程序初始化
PDRIVER_INITIALIZE DriverInit;
//特定入口,
PDRIVER_STARTIO DriverStartIo;
//驱动卸载函数
PDRIVER_UNLOAD DriverUnload;
//普通分发函数(IRP)
PDRIVER_DISPATCH MajorFunction[IRP_MJ_MAXIMUM_FUNCTION + 1];
} DRIVER_OBJECT;
设备对象结构:
typedef struct DECLSPEC_ALIGN(MEMORY_ALLOCATION_ALIGNMENT) _DEVICE_OBJECT {
CSHORT Type;
USHORT Size;
//引用计数
LONG ReferenceCount;
//设备所属驱动对象
struct _DRIVER_OBJECT *DriverObject;
//下一个设备对象,一个驱动对象中可能有许多个设备,这些设备用指针连接,作为单向链表
struct _DEVICE_OBJECT *NextDevice;
struct _DEVICE_OBJECT *AttachedDevice;
struct _IRP *CurrentIrp;
PIO_TIMER Timer;
ULONG Flags;
ULONG Characteristics;
__volatile PVPB Vpb;
PVOID DeviceExtension;
//设备类型
DEVICE_TYPE DeviceType;
//IRP栈的大小
CCHAR StackSize;
union {
LIST_ENTRY ListEntry;
WAIT_CONTEXT_BLOCK Wcb;
} Queue;
ULONG AlignmentRequirement;
KDEVICE_QUEUE DeviceQueue;
KDPC Dpc;
ULONG ActiveThreadCount;
PSECURITY_DESCRIPTOR SecurityDescriptor;
KEVENT DeviceLock;
USHORT SectorSize;
USHORT Spare1;
struct _DEVOBJ_EXTENSION *DeviceObjectExtension;
PVOID Reserved;
} DEVICE_OBJECT;
IRP向设备对象发送请求时会被驱动对象的分发函数捕获,被其中一个调用
分发函数原型
NTSTATUS MyDispatch(PDEVICE_OBJECT device, PIRP irp);
参数1是请求的目标设备,参数2是IRP请求的指针
IRP的结构
IRP是一个内核数据结构,结构非常复杂,因为要表示无数中实际请求.
typedef struct DECLSPEC_ALIGN(MEMORY_ALLOCATION_ALIGNMENT) _IRP 共300多行代码,位于 wdm.h 24795行
其中
PMDL MdlAddress; 内存描述符表链表指针,是一个缓冲区,内核请求都需要一个缓冲区,用来保存数据
union {
struct _IRP *MasterIrp;
__volatile LONG IrpCount;
PVOID SystemBuffer;
} AssociatedIrp; 该共用体也是一个系统缓冲,比 MdlAddress 稍简单表示缓冲的方式,IRP会根据IO的请求方式选择其中的某一个.
IO_STATUS_BLOCK IoStatus; IO状态,请求完成之后的返回情况放在这里.
CHAR StackCount; IRP栈空间大小
CHAR CurrentLocation; IRP当前栈空间
__volatile PDRIVER_CANCEL CancelRoutine; 用来取消一个未决(没有执行完成?)请求的函数
PVOID UserBuffer; 与上面两个一样可以表示缓冲区,但特性稍有不同
union {
struct {
union {
KDEVICE_QUEUE_ENTRY DeviceQueueEntry;
struct {
PVOID DriverContext[4];
} ;
} ;
//发出这个请求的线程
PETHREAD Thread;
PCHAR AuxiliaryBuffer;
struct {
LIST_ENTRY ListEntry;
union {
//IRP栈空间元素
struct _IO_STACK_LOCATION *CurrentStackLocation;
ULONG PacketType;
};
};
PFILE_OBJECT OriginalFileObject;
} Overlay;
KAPC Apc;
PVOID CompletionKey;
} Tail;
因为IRP请求会传递许多个设备才能完成,所以每次中转都会留一个栈空间,用于保存中间参数.