Minifilter文件系统过滤框架
来源:互联网 发布:pinyinime 源码 编辑:程序博客网 时间:2024/06/16 13:46
原理
正常的IRP流程是R3 API调用时,会将请求封装成一个IRP经过IO管理器到达文件系统,然后在发往磁盘存储系统,最后到达硬件。
使用MiniFilter后会在IO栈中添加MiniFilter管理器。当IRP到达文件系统之前时,首先会被该管理器拦截。管理器会将IRP封装成CALLBACK_DATA,由管理器中存在的多个minifilter驱动依次处理。这些驱动位置是固定的,位置由altitude属性决定。处理结束后把结果返回给管理器,管理器根据结果决定是否把IRP继续下发。
MiniFilter可以有多个祯【多个管理器,每个管理器有多个minifilter驱动】IRP发给帧1,帧1处理后继续下发到Legacy Filter驱动【例如Sfilter】然后继续下发到帧0,最后下发到文件系统、磁盘存储系统最后到达硬件。
Minifilter管理器处理CALLBACK_DATA时会依次获取高altitude值的minifilter驱动的处理结果然后根据结果决定是否继续下发到低altitude值的minifilter驱动。
每一个minifilter驱动必须有Altitude这个唯一标识符。在加载时值越小相对于其他minifilter驱动在I/O栈中的位置越低。Altitude值取值范围在20000到429999。在320000到329999组中包含了在文件I/O期间探测杀毒的过滤驱动,140000到149999组中包含了在文件I/O期间加解密的过滤驱动。
使用
将Minfilter驱动往Minfilter框架中注册前需要先对驱动的结构体fileMonitorRegistration初始化,结构体类型为FLT_REGISTRATION。成员描述的有结构体大小、版本号、Flags值、各种函数等,其中ContextRegistration指向上下文管理的函数,fileMonitorCallbacks指向回调函数结构体数组【存放关于每个IRP处理的组函数】fileMonUnload指向用于卸载驱动的函数,fileMonInstanceSetup指向的函数在驱动绑定到卷设备时会被调用【驱动在启动时会遍历卷设备并为每个卷设备绑定自身的实例】,fileMonInstanceTeardownStart指向的函数在驱动从卷设备卸载时会被调用。
在fileMonitorCallbacks中根据每个IRP可注册一组【pre(处理前)post(处理后)】回调函数,不注册的由Minfilter管理器处理。结构体如下:
const FLT_OPERATION_REGISTRATION fileMonitorCallbacks[] ={ { IRP_MJ_CREATE, FLTFL_OPERATION_REGISTRATION_SKIP_PAGING_IO, HOOK_PreNtCreateFile, HOOK_PostNtCreateFile }, { IRP_MJ_CLEANUP, 0, HOOK_PreNtCleanup, NULL }, { IRP_MJ_WRITE, 0, HOOK_PreNtWriteFile, HOOK_PostNtWriteFile }, { IRP_MJ_SET_INFORMATION, 0, HOOK_PreNtSetInformationFile, HOOK_PostNtSetInformationFile }, { IRP_MJ_OPERATION_END } ... ...};
注册的函数参数基本类似,关于CreateFile的一组函数如下:
//______________________________pre:FLT_PREOP_CALLBACK_STATUSHOOK_PreNtCreateFile (PFLT_CALLBACK_DATA Data,//IRP封装PCFLT_RELATED_OBJECTS FltObjects,//相关对象,例如文件、卷设备、实例和设备对象PVOID *CompletionContext//上下文对象,可用于让pre分配传给post操作 //分配的一个context资源){ //sandbox?,主防?,杀毒引擎?,加解密? return XXX;}//______________________________post:FLT_POSTOP_CALLBACK_STATUSHOOK_PostNtCreateFile (PFLT_CALLBACK_DATA Data,PCFLT_RELATED_OBJECTS FltObjects,PVOID CompletionContext, //在PRE-OP里返回 //FLT_PREOP_SUCCESS_WITH_CALLBACK //时获取里面的上下文,并最后释放FLT_POST_OPERATION_FLAGS Flags){ return XXX;}//_______________________________end函数返回值用于返回给MiniFilter管理器控制其操作PRE的返回值有:FLT_PREOP_SUCCESS_WITH_CALLBACK//继续下发,而且调用对应的post函数FLT_PREOP_SUCCESS_NO_CALLBACK//继续下发,不需要调用post函数FLT_PREOP_COMPLETE//终止下发,具体执行成功还是失败在CALLBACK_DATA中设置。例如成功处理://Data->IoStatus.Status=STATUS_ACCESS_DENIED;//Data->IoStatus.Information=0;//return FLT_PREOP_COMPLETE;PRE其他的返回值还有:FLT_PREOP_PENDING,FLT_PREOP_DISALLOW_FASTIO,FLT_PREOP_SYNCHRONIZEPOST的返回值有:FLT_POSTOP_FINISHED_PROCESSING//无更多处理FLT_POSTOP_MORE_PROCESSING_REQUIRED//需要做更多的处理,例如需要等待线程结束
读写缓冲区
Data->lopb->Parameters.Read/Write.MdlAddress/ReadBuffer/Length;
由于Data不仅处理IRP还处理FASTIO和文件过滤驱动,可以使用三个宏分别判定:
FLT_IS_IRP_OPERATIONFLT_IS_FASTIO_OPERATIONFLT_IS_FS_FILTER_OPERATION
安装与卸载
安装Minifilter过滤驱动有两种方式,.inf文件安装和代码动态加载
.inf文件安装需要准备一个与MiniFilter驱动关联的.inf文件,然后通过右键安装或SetupCopyOEMinf安装。之后系统会将驱动sys文件拷贝到C:\WINDOWS\SYSTEM32\Dirver目录下并在注册表中创建驱动服务(不会触发DirverEntry)这时需要在CMD中使用”net start/stop 驱动名称”启动或卸载驱动服务。
另一种就是通过动态代码安装。这种方式与NT驱动的驱动安装大同小异,不同在于CreateService设置Group为”FSFilter Acticity Moniter”,DependOnService值为”Fltmgr”,还要在SYSTEM\CurrentControlSet\Services\DriverName\Instances子健并在其下面建立驱动名称子健,再在新建的子健下设置Altitude的值。
初始化fileMonitorRegistration结构体后在DriverEntry中调用FltRegisterFilter注册并获取Minfilter的句柄然后使用FltStartFiltering启动即可:
FltRegisterFilter( DriverObject,&fileMonitorRegistration,&g_pFilter );FltStartFiltering( g_pFilter );FltUnregisterFilter( g_pFilter );//DirverUnload中使用该函数注销过滤设备
框架提供的操作方法
路径获取
//在postCreate中使用PFLT_FILE_NAME_INFORMATION pNameInfo=NULL;//定义一个文件信息指针FltGetFileNameInformation(Data,FLT_FILE_NAME_NORMALIZEDI|FLT_FILE_NAME_QUERY_DEFAULT,&pNameInfo);//函数内部申请了内存并设置了引用计数,将文件信息保存到文件信息指针中。FltParseFileNameInformation(pNameInfo);//解析文件信息,解析后文件地址依然为盘符。需要进一步转换pNameInfo->Name;pNameInfo->Volume;FltReleaseFileNameInformation(pNameInfo);//引用计数减一,最后释放内存//IRP_MJ_SETINFO中重命名获取:PFLT_FILE_NAME_INFORMATION pNameInfo=(PFLT_FILE_NAME_INFORMATION)Data->lopb->Parameters.SetFileInformation.InfoBuffer;//或使用:FltGetDestinationFileNameInformation//重命名获取Parameters.SetFile.FileInformationClass == FileRenameInformation//判断setInformation为修改名称操作
监控进程创建
IRP_MJ_ACQUIRE_FOR_SECTION_SYNCHRONIZATION//该IRP会在进程创建时调用Data->Iopb->Parameters.AcquireForSectionSynchronization.PageProtection == PAGE_EXECUTE//创建进程
文件操作
//与Zw系列函数对应,例如:FltCreateFile、FltReadFile、FltWriteFile、FltClose、FltQueryXxx、FltSetXxx、FltGetXxx、FltPerformXxx//该系列函数比Zw系列多了头两个参数:参1、参2为实例【MiniFilter实例或在FltObject->XXX实例,看情况选择】
在MiniFilter中不能使用Zw函数,否则可能的导致重入【再次调用zw函数,无限循环】
MiniFilter上下文
FltAllocateContext//申请FltReleaseContext//释放【内部使用了引用计数】//分配的类别FltGet/Stream/StreamHandle/Instance/Volume/File ContextFltSet/Stream/StreamHandle/Instance/Volume/File Context//分别为流【FCB】、流句柄【FO】、实例、卷、文件【vista以上】上下文。Get获取,Set设置。
Instance上下文例子:
typedef struct _INSTANCE_CONTEXT {…//自己定义结构体内容} INSTANCE_CONTEXT, *PINSTANCE_CONTEXT;PINSTANCE_CONTEXT pContext = NULL;//分配与设置ntStatus = FltGetInstanceContext(FltObjects->Instance, & pContext);if(NT_SUCCESS(Status) == FALSE)//如果还未分配上下文就申请一个{ ntStatus = FltAllocateContext(g_pFilter,FLT_INSTANCE_CONTEXT, sizeof(INSTANCE_CONTEXT), PagedPool,& pContext); if(NT_SUCCESS(Status) == FALSE) { return ntStatus ; } RtlZeroMemory(pContext, sizeof(INSTANCE_CONTEXT));}pContext->xxx = xxx;;//给自定义的结构成员赋值FltSetInstanceContext(FltObjects->Instance,FLT_SET_CONTEXT_REPLACE_IF_EXISTS,pContext,NULL);//将内存设置到上下文中if (pContext){ FltReleaseContext(pContext);//这里不使用了,所以直接减引用}//获取访问PINSTANCE_CONTEXT pContext = NULL;Status = FltGetInstanceContext(FltObjects->Instance,&pContext);pContext->xxx = xxx;
注册卸载上下文的函数在驱动注册结构体fileMonitorRegistration的ContextRegistration成员中。内部保存了每个类型的上下文的清理函数数组。
R3R0端口通信
R3主动:
//首先R0创建端口,R3通过端口名称与R0通信。FltCreateCommunicationPort( g_pFilter,&g_pServerPort,&oa,//设置PORT的名字NULL,//安全描述符,可传入&oafnConnectFromClient, //获得R3端口g_pClientPort等【R3请求链接时调用,函数内可获取R3端口以及R3进程信息】fnDisconnectFromClient,//【断开链接时调用】fnMessageFromClient, //处理从R3 FilterSendMessage的请求【R3发送数据后处理数据时调用】1 );//R0创建端口FltBuildDefaultSecurityDescriptor(&sd,FLT_PORT_ALL_ACCESS);//建立只允许管理员和系统访问的安全描述符InitializeObjectAttributes(&oa,&portName,OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE,NULL,sd)//关联到oaFltFreeSecurityDescriptor(sd);//使用后释放描述符FltCloseClientPort//R0关闭R3端口//R0处理函数NTSTATUS fnMessageFromClient(IN PVOID PortCookie,IN PVOID InputBuffer OPTIONAL,IN ULONG InputBufferLength,OUT PVOID OutputBuffer OPTIONAL,IN ULONG OutputBufferLength,OUT PULONG ReturnOutputBufferLength){ __try { ProbeForRead(InputBuffer, InputBufferLength, sizeof(ULONG));//验证地址为R3地址 //获取InputBuffer //Do something ProbeForWrite(OutputBuffer, OutputBufferLength, sizeof(ULONG));//验证地址为R3地址 //将返回的值拷贝到Outputbuffer } __except(EXCEPTION_EXECUTE_HANDLER) { return STATUS_NOT_IMPLEMENTED; } return STATUS_SUCCESS;}
R3发送
//获取R0端口,参1为端口名称,参6接收端口FilterConnectCommunicationPort( ScannerPortName,0,NULL,0,NULL,&Port );FilterSendMessage(Port,//R0端口&request,//R3发给R0数据sizeof(REQUEST),//R3发给R0数据长度&reply,//R0返回给R3的结果sizeof(REPLY),//R0返回给R3的结果的长度&dwRtn//实际传输的字节数);
R0主动
//发送消息给R3timeout.QuadPart = (LONGLONG)40 * -10000000i64; // 40 秒Status = FltSendMessage( g_pFilter,//MiniFilter全局句柄 &g_pClientPort,//R3端口 &request,//发送的数据 sizeof(SCANNER_NOTIFICATION),//数据的大小 &reply,//R3函数FilterReplyMessage返回的结果 &replySize,//返回值的长度 &timeout );//等待时间FltCloseCommunicationPort( g_pServerPort ); //R0关闭端口
R3接收
completion = CreateIoCompletionPort( port,NULL,0,1);//创建完成端口//函数是异步的,需要完成端口判断端口是否完成【数据是否收到】FilterGetMessage( Port,//拿数据的端口&message->MessageHeader,//message为R0传上来的数据结构FIELD_OFFSET( SANDBOX_MESSAGE, Ovlp ),&message->Ovlp );GetQueuedCompletionStatus(completion, &outSize, &key, &pOvlp, INFINITE );//永久等待FilterReplyMessage(Port,(PFILTER_REPLY_HEADER) &replyMessage,sizeof( replyMessage ) );//R3返回消息到R0的FltSendMassage等待函数中
- Minifilter文件系统过滤框架
- Windows驱动_文件系统微小过滤驱动之一初识MiniFilter
- 文件系统Minifilter驱动(一)
- 文件系统Minifilter驱动(二)
- 文件系统Minifilter驱动(三)
- 文件系统Minifilter驱动(四)
- 文件系统Minifilter驱动(五)
- 文件系统Minifilter驱动(六)
- 文件系统Minifilter驱动(七)
- 文件系统Minifilter驱动(八)
- 文件系统Minifilter驱动(九)
- 文件系统Minifilter驱动(十)
- 文件系统Minifilter驱动
- 文件系统Minifilter驱动
- 文件系统Minifilter驱动(一)
- 文件系统Minifilter驱动(二)
- 文件系统Minifilter驱动(三)
- 文件系统Minifilter驱动(四)
- java验证码
- HTML`CSS_网站页面不同浏览器兼容性问题解决
- SpringBoot 通过属性文件外置配置
- 5.11
- ios 延迟的几种方法
- Minifilter文件系统过滤框架
- uva 437 DAG上的动态规划
- el表达式和JSTL标签
- 转载:在Vue中通过自定义指令获取元素
- dbms_spm绑定执行计划
- Archive Data DSO Demo 1
- LinkedList,ArrayList和Vector
- java文件流处理jd-gui反编译后文件中每行的注释符
- 查找(1)---顺序查找