Posted on 2010-02-19 14:32
S.l.e!ep.¢% 阅读(1000)
评论(0) 编辑 收藏 引用 所属分类:
Windows WDM
驱动的入口 DriverEntry() 函数
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
{
}
1. 驱动对象 DriverObject
DRIVER_OBJECT 对应 .sys 文件?
DRIVER_OBJECT 对象是操作系统在加载驱动时所分配的.
RegisteryPath 也是操作系统用于记录驱动相关参数的注册表路径.
DriverObject 重要之处,在于它有一组函数指针,称之为 dispatch functions
开发驱动的主要任务就是自己实现这些 dispatch functions, 当系统用到你的驱动时,就会向你的驱动发送 IRP, 可以在 dispatch functions 中处理这些 IRP, 可以让IRP 失败,也可以让它返回成功,甚至可以修改或自己发出IRP。(如何把驱动关联到系统中,让它可以通知到呢?)
2. 设备对象 DeviceObject 简称 DO
IRP 是由 DeviceObject 发出的,只有针对该驱动所生成的 DeviceObject 的 IRP,操作系统才会发给该驱动来处理。具体的 dispatch function 决定于 DeviceObject 下的 DriverObject 成员
3. 文件系统 File System 简称 FS
4. 控制设备 Control Device Object 简称 CDO
CDO主要任务是修改整个驱动的内部配置,因此一个驱动只对应一个 CDO
5. Symbolic Link 符号链接
可以通过 Symbolic links viewer 工具查看操作系统的所有符号链接
可以看到 C: 对应 \Device\HarddiskVolume1
这里可以看出,文件系统驱动是针对每个 Volume 来生成一个 DeviceObject ,则不是针对文件。实际上对某个 Volume 的文件读写,都发到这个 Volume 设备对象上面去了.
6. 可以使用 IoCreateDevice() 函数来创建 控制设备对象(控制设备对象的作用?)
7. 指定 DriverObject 的处理函数
for(i = 0; i<= IRP_MJ_MAXIMUM_FUNCTION; i++)
{
DriverObject->MajorFunction[i] = SfPassThrough;
}
处理函数里面最简单的处理就是什么都不做,传给操作系统的其它驱动处理,使用下面的代码
IoSkipCurrentIrpStackLocation(Irp);
return IoCallDriver( ((PSFILTER_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->AttachedToDeviceObject, Irp);
8. 文件系统的驱动,除了要处理正常的IRP之外,还要处理 FastIo
(a. FastIo 是操作系统的 Cache Manager 调用所触发的没有 IRP 的请求
b. FastIo 是独立于普通IRP分发函数之外的另一组接口,作用跟普通的IRP是一样的
c. 如果是一个文件过滤驱动,那么普通的IRP分发函数 和 FastIo 都有可能被调用,所以最好是同时过滤这两套接口
d. fastio 的分发函数直接返回 FALSE 不做任何事,这样这些请求都会通过IRP重新发送,有一定的效率损失,但不是很大。 )
FastIo 的函数可以通过 Driver->FastIoDispatch 来指定
9. 驱动中的内存分配
并不是简单的 new, 而是调用函数 ExAllocatePoolWithTag() 函数来分配
内存清零则使用 RtlZeroMemory() 函数
10. 操作系统 保存了 目前所有的驱动设备对象,并且用类似于“链表”的方式,这个“链表”称为设备栈
任何来自应用层(Ring3)的请求,都会被 Windows 系统的 IO管理器翻译成 IRP,然后发给设备栈中最顶端的那个设备
原始 IRP IRP IRP
--------------> -----------> --------->
最顶端的设备 排第二的设备 ....
<-------------- <----------- <---------
原始IRP返回 IRP返回 IRP返回
箭头表示IRP请求的发送过程
a. 只要我们在这个设备栈的顶端再绑定一个设备,那么发给这个设备的请求,自然就会先发给我们的设备来处理(可以通过 IoAttachDeviceToDeviceStack)
11. 某些 dispatch function 里开头有 PAGED_CODE(); 的作用是?
12. 先用 IoCreateDevice() 创建一个 Device Object , 然后调用 IoAttachDeviceToDeviceStack() 绑定到 \Device\HarddiskVolume1 这个设备,那么所有发给 C:\ 的IRP,都必然先发送给我们的驱动,这样一来就可以捕获所有对文件的操作了。
13. 当一个新的存储媒介被系统发现(如U盘)并生成一个Volume的过程称为 Mounting, 此时,文件系统的CDO会得到一个IRP, 这个IRP是 IRP_MJ_FILE_SYSTEM_CONTROL, MinorFunctionCode == IRP_MN_MOUNT
14. IoRegisterFsRegistrationChange() 注册一个回调函数,当操作系统中有任何文件系统被激活或者是被注销时,注册过的回调函数会被调用。
(注意,这里说的文件系统是指 NTFS, FAT32, CDFS 这些文件系统
win2k以前的系统,对已经激活的文件系统不会调用回调,但2K以后的系统会对已经存在的文件系统重新枚举一次, 所以在2K下需要自己枚举已经加载的文件系统)
(注册这个回调有什么作用?直接绑定 RawDisk 和处理 IRP_MN_MOUNT
不就得了?)
15. 当收到文件系统的 notify 时,绑定设备前,需要一个宏的判断是否是文件系统类型的设备
#define IS_DESIRED_DEVICE_TYPE(_type) \
(((_type) == FILE_DEVICE_DISK_FILE_SYSTEM) || \
((_type) == FILE_DEVICE_CD_ROM_FILE_SYSTEM) || \
((_type) == FILE_DEVICE_NETWORK_FILE_SYSTEM))
(难道阿猫阿狗的设备增加时,都会触发 fs system notify?)
15. 初始化完后,需要设置一个标志位
DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
作用?原因?