Sfilter过滤驱动框架

来源:互联网 发布:经济数据库都有什么 编辑:程序博客网 时间:2024/05/29 11:28

原理

Sfilter框架是基于NT驱动框架之上通过设备栈绑定的形式绑定的,驱动自己生成一个设备(过滤设备对象),调用系统提供的绑定API,绑定到目标设备上。并返回一个在未绑定之前目标设备所在设备栈的最顶层设备。这样发往下层的IRP或者发往上层的数据都会被过滤设备截获。

移动设备链接到系统中时系统会为其生成一个文件系统设备,然后系统会向文件系统设备发送mount IRP,文件系统设备接收到IRP后会动态生成卷设备对象【盘符】

如果要监控移动设备卷设备对象,首先要先生成过滤设备对象绑定到移动设备的文件系统设备对象上拦截mount IRP请求,之后在该IRP内生成过滤设备对象绑定到卷设备对象上【两次绑定操作】

IoRegisterFsRegistrationChange函数可注册一个动态监控移动设备对象插入时生成文件系统设备对象的回调函数

关于固定的卷设备对象可直接通过函数一一枚举出来,然后依次生成过滤设备对象绑定上去即可。

实现

函数主流程

首先创建控制设备和符号链接用于与R3客户端通信。然后注册过滤分发函数【内部对客户端IRP和其他进程IRP分开处理】

分配一个Fastio结构体大小的内存,然后对其内部初始化Fastio的操作函数【内部全部返回False,不添加会有问题,只需要简单的禁用处理即可】之后将该结构体注册到DriverObject->FastIoDispatch中。

接下来通过IoRegisterFsRegistrationChange注册监控文件系统设备创建的回调函数。函数内判断设备插入时,生成过滤设备对象绑定到对应的文件系统设备对象上【通过判断系统版本使用绑定函数】用来监控mount IRP【回调函数参1为监控到到文件系统设备对象,参2为bool值表示文件系统是插入还是拔掉。函数内创建的过滤设备对象会和文件系统设备对象通讯方式一样(通过依次判断的方式实现)】

当监控到发往文件系统设备上的mount IRP时就会调用Sfilter中指定的分发函数【IRP分发函数中的IRP_MJ_FILE_SYSTEM_CONTROL】函数内部会生成过滤设备对象绑定到对应的卷设备对象上【IRP->MinorFunction(次功能号)为IRP_MN_MOUNT_VOLUME(mount)时就调用定义的附加函数。函数内部生成了过滤设备对象,由于卷设备对象要等mount下发到文件设备对象后才能创建,所以要用IoSetCompletionRoutine为mount设置一个完成例程然后用IoCallDriver下发。之后等待例程完成然后从文件设备对象设备扩展中拿到卷设备对象之后作为绑定参数绑定(xp前的版本使用工作者线程绑定,原因是mount会提升IRQL)】

FileMon函数中通过枚举26个盘符,打开文件获取FileObject->DeviceObject,通过驱动生成过滤设备绑定到DeviceObjec上【无法监控动态加载的移动设备】

fastio时Cache manager【缓存管理】的一部分,必须为DriverObject撰写一组函数,函数指针在driver->FastIoDispatch里,函数内部不作处理简单的返回False即可。

分发函数处理细节
函数中共有两个过滤驱动设备,根据R3客户设备和卷设备的过滤设备分别编写处理流程。IS_MY_CONTROL_DEVICE_OBJECT宏可判定是否为控制设备,IS_MY_DEVICE_OBJECT宏可判定是否为过滤设备

然后通过sfDebug的标志判断过滤过程中所需要抓取的信息【保存在注册表中,DriverEntry中有从注册表获取的操作】不需要抓取则会直接IoSkipCurrentIrpStackLocation放行IRP并用IoCallDriver下发。否则分配内存空间调用NLGetFullPathName获取文件名称,然后调用IoCopyCurrentIrpStackLocationToNext将当前IRP栈拷到下一层IRP栈上,创建事件后IoSetCompletionRoutine设置完成例程,并用IoCallDriver下发。等待完成例程修改事件后将文件名称打印出来。

最后通过IRP下发结果继续处理并完成。一般IoCallDriver下发之后就不能对IRP进行操作了【不再关心,否则蓝屏】,但通过设置完成例程并让完成例程返回STATUS_MORE_PROCESSING_REQUIRED可以通知IO管理器在底层处理完IRP后不去销毁。而上层【即本层】调用IoCopyCurrentIrpStackLocationToNext拷贝栈并通过IoCallDriver下发后等待完成例程更改的事件状态继续执行,最后在本层结束IRP。通过该方法可在下发IRP后继续对IRP进行处理

注意
文件名称只有在创建文件时是可靠的,所以获取文件名称操作只能在Create分发函数中做。

过滤驱动IRP处理方式有三种:
1.通过IoCopyCurrentIrpStackLocationToNext+完成例程+IoCallDriver等待处理完成
2.通过IoSkipCurrentirpStackLocation+IoCallDriver忽略直接下发。下层设备拿到的栈和当前栈一样【该函数会将栈指针++操作,IoCallDriver会对栈指针–操作】
3.通过IoGetCurrentirpStackLocation获取当前栈然后设置irp的IoStatus中的Status【成功STATUS_SUCCESS或失败STATUS_ACCESS_DENIED】和Information【操作字节数】最后通过IoCompleteRequest结束IRP停止下发

绑定API:
IoAttachDevice()
IoAttachDeviceToDeviceStackSafe(2000 SP4以及XP以上)
IoAttachDeviceToDeviceStack()

PDEVICE_OBJECT //返回该函数绑定前最顶层的设备对象IoAttachDeviceToDeviceStack(IN PDEVICE_OBJECT  SourceDevice,//指定设备对象IN PDEVICE_OBJECT  TargetDevice //目标设备对象);//该函数将指定设备对象绑定到目标设备对象上,使用时注意保存原顶层设备对象用于处理后下发

基于Sfilter的HIPS放行规则

IRP过滤函数规则
FilterCreate:该函数内拦截文件的创建和打开,而且要在该文件内获取文件的全路径
FilterRead:主防中不拦截,加解密时需要拦截
FilterWrite:函数内拦截修改,加解密时需要拦截
FileterSetInfo:函数内拦截删除和重命名
FilterClose:读关闭一般不拦截
FilterClean:函数内拦截写关闭【重新扫描文件防止多次写入,Sfilter无法判断读关闭或写关闭】

其他规则
放行内核请求:通过Irp->RequestorMode==KernelMode识别
放行本进程请求:通过FilterDeviceloctrl中使用PsGetCurrentProcessId获取PID识别
放行系统进程请求:通过DriverEntry中使用PsGetCurrentProcessId获取PID识别【DriverEntry运行于系统上下文】
IRQL大于APC级别:KeGetCurrentIrql()>APC_LEVEL

放行使用IoSkipXXX+IoCallDriver方式即可

其他

Deubug调试过滤驱动时可使用以下命令:
!devobj 查看设备对象信息
!drvobj 查看驱动对象信息
!devstack 查看设备栈
!devnode 0 1 系统设备树

代码

//
0 0
原创粉丝点击