关于开发驱动重要的内核数据结构,方便自己理解:
DRIVER_OBJECT:
typedef struct _DRIVER_OBJECT
{
CSHORT Type;
CSHORT Size;
//一个链表,记录了该驱动创建的所有设备对象
PDEVICE_OBJECT DeiceObject;
ULONG Flags;
PVOID DriverStart;
ULONG DriverSize;
PVOID DriverSection;
PDRIVER_EXTENSION DriverExtension;
UNICODE_STRING DriverName;
PUNICODE_STRING HardwareDataBase;
PFAST_IO_DISPATCH FastIoDispatch;
PDRIVER_INITIALIZE DriverInit;
PDRIVER_STARTIO DriverStartIo;
PDRIVER_UNLOAD DriverUnload;
PDRIVER_DISPATCH MajorFunction[IRP_MJ_MAXIMUM_FUNCTION];
}DRIVER_OBJECT,*PDRIVER_OBJECT;
I/O管理器在装载驱动时,首先调用IopLoadDriver()函数,该函数执行一下功能
1. 确定要装载的驱动名称,查询该驱动是否已经被装载。系统中包含一个已经装载的驱动链表,I/O管理器是通过查询这个链表确定驱动是否被装载的,如果已经被装载,则返回成功;另外注册表中也必须配置相关的信息
2. 如果驱动没有被装载,I/O管理器请求虚拟存储管理器(VMM)将驱动可执行文件映射到内存中,VMM在映射时检查该文件是否为可用的PE格式,如果不是,VMM使请求失败,驱动装载失败
3. I/O管理器通过对象管理器创建驱动对象,该驱动对象存储在非分页内存池中,因此任意IRQL都可以访问
4. I/O管理器将驱动对象结构清零,MajorFunction中的每一个元素被设置为IopInvalidDeiviceRequest()。该函数仅仅返回STATUS_INVALID_DEVICE_REQUEST状态码
5. I/O管理器将DriverInit字段设置为驱动的入口程序(DriverEntry),DriverSection被初始化为驱动的Section对象指针,该section对象指向驱动的可执行文件;DriverStart设置为驱动映像的基址;DriverSize被设置为驱动映像的尺寸。
6. I/O管理器将该驱动对象插到 NT Object Manager维护的驱动列表中
7. HardwareDatabase字段初始化为Configuration Manager的硬件配置信息。底层驱动可以使用这个字段决定驱动启动顺序的配置;DriverName也被初始化,这样错误记录服务可以记录相关的信息
8. I/O 管理器调用驱动初始化程序。该初始化程序总是在系统进程中IRQL_PASSIVE_LEVEL级别被调用。
DEVICE_OBJECT :
typedef struct _DEVICE_OBJECT {
CSHORT Type;
USHORT Size;
LONG ReferenceCount;
PDRIVER_OBJECT DriverObject; // 这个设备所属的驱动对象
PDEVICE_OBJECT NextDevice; // 下一个设备对象。在一个驱动对象中有n个设备,这些设备用这个指针
// 连接起来作为一个单向的链表。
PDEVICE_OBJECT AttachedDevice; //指向上层绑定的设备,若是该设备即为顶层绑定设备,则为NULL
PIRP CurrentIrp;
PIO_TIMER Timer;
ULONG Flags;
ULONG Characteristics;
__volatile PVPB Vpb;
PVOID DeviceExtension; //指向自定义的设备扩展结构,DEVICE_EXTENSION
DEVICE_TYPE DeviceType;
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;
PDEVOBJ_EXTENSION DeviceObjectExtension;
PVOID Reserved;
} DEVICE_OBJECT, *PDEVICE_OBJECT;
FILE_OBJECT:
typedef struct _FILE_OBJECT {
CSHORT Type;
CSHORT Size;
PDEVICE_OBJECT DeviceObject; //
PVPB Vpb;
PVOID FsContext;
PVOID FsContext2;
PSECTION_OBJECT_POINTERS SectionObjectPointer;
PVOID PrivateCacheMap;
NTSTATUS FinalStatus;
struct _FILE_OBJECT *RelatedFileObject;
BOOLEAN LockOperation;
BOOLEAN DeletePending;
BOOLEAN ReadAccess;
BOOLEAN WriteAccess;
BOOLEAN DeleteAccess;
BOOLEAN SharedRead;
BOOLEAN SharedWrite;
BOOLEAN SharedDelete;
ULONG Flags;
UNICODE_STRING FileName; ///
LARGE_INTEGER CurrentByteOffset;
ULONG Waiters;
ULONG Busy;
PVOID LastLock;
KEVENT Lock;
KEVENT Event;
PIO_COMPLETION_CONTEXT CompletionContext;
} FILE_OBJECT, *PFILE_OBJECT; // ntndis
成员详解:
Type:一个只读成员,被系统用于标识这是一个文件对象,如果对象是一个文件对象,那么它的值就是5.
Size:一个只读成员,标识文件对象的大小(比特),如果扩展部分存在的话,这个大小不包括文件对象的扩展部分。
DeviceObject:指向设备对象,文件在该设备对象上打开。
Vpb:指向同文件对象关联的卷参数块,如果Vpb成员非空,便标识文件存在一个被挂载的卷上。
FsContext:指向任何驱动程序维护的文件对象可选状态的指针,否则为空。对文件系统驱动程序,这个成员必须指向一个叫做FSRTL_ADVANCED_FCB_HEADER的头结构,它包含一个文件系统特殊结构,否则可能会导致系统不稳定,通常,这个头结构包含在FCB中。然而,在一些支持多数据流的文件系统,例如NTFS,这个头结构是流控制块(SCB)。
注意:在WDM设备栈中,只有功能设备对象能用两个上下文指针,文件系统驱动程序通过打开多个相同的数据流共享这个成员。
FsContext2:一个指向驱动程序维护的文件对象的任何其他状态,否则为空。
注意:这个成员对文件系统栈的驱动程序是不透明的,因为底层文件系统使用此成员。
SectionObjectPointer:指向文件对象的只读区域对象。这个成员被设置成只能被文件系统用作与缓存管理器交互。
PrivateCacheMap:一个不透明成员,只能被文件系统设置。它指向处理特殊信息,被用作与缓存管理器的交互。
FinalStatus:一个只读成员,被用作某些特定的同步事件中,标识文件对象IO请求的最终状态
RelatedFileObject:一个指向FILE_OBJECT结构的指针,用作标识当前文件对象已经打开相对于一个已经打开的文件对象。这个文件对象通常通过这个成员指向一个目录(表示当前文件已经被打开相对于这个目录)。然而,一个文件能够重新打开相对于它本身,一个文件的分支数据流能够被打开相对于已经打开的同一文件的主数据流。RelatedFileObject成员只在IRP_MJ_CREATE请求例程有效。
LockOperation:一个只读成员。如果为FALSE,一个锁操作(NtLockFile)从来没有执行在文件对象上。如果是真,至少有一个锁操作执行在文件对象上。一旦设置成TRUE,这个成员总是保持TRUE(例如,释放文件对象上文件锁不会将这个成员设置成FALSE)。
DeletePending:一个只读成员。如果是TRUE,一个文件的删除操作同文件对象的存在关联。如果是FALSE,当前没有待删除的文件对象操作。
ReadAccess:一个只读成员,如果是TRUE,与文件相关联的文件对象已经被用作读操作打开,如果是FALSE,文件没有被用作读操作打开,这个信息被用作核查或者设置文件的共享操作。
WriteAccess:一个只读成员,如果是TRUE,与文件相关联的文件对象已经被用作写操作打开,如果是FALSE,文件没有被用作写操作打开,这个信息被用作核查或者设置文件的共享操作。
DeleteAccess:一个只读成员。如果是TRUE,与文件相关联的文件对象已经被用作删除操作打开,如果是FALSE,文件没有被用作删除操作打开,这个信息被用作核查或者设置文件的共享操作。
LARGE_INTEGER
typedef struct _LARGE_INTEGER
{
LONGLONG QuadPart;
} LARGE_INTEGER;
初始化:
LARGE_INTEGER lenth = {0}