Minifilter文件系统过滤框架

原理

正常的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_STATUS
HOOK_PreNtCreateFile (
PFLT_CALLBACK_DATA Data,//IRP封装
PCFLT_RELATED_OBJECTS FltObjects,//相关对象,例如文件、卷设备、实例和设备对象
PVOID *CompletionContext//上下文对象,可用于让pre分配传给post操作 
//分配的一个context资源
)
{
    //sandbox?,主防?,杀毒引擎?,加解密?
    return XXX;
}

//______________________________post:
FLT_POSTOP_CALLBACK_STATUS
HOOK_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_SYNCHRONIZE

POST的返回值有:
FLT_POSTOP_FINISHED_PROCESSING//无更多处理
FLT_POSTOP_MORE_PROCESSING_REQUIRED//需要做更多的处理,例如需要等待线程结束

读写缓冲区

Data->lopb->Parameters.Read/Write.MdlAddress/ReadBuffer/Length;

由于Data不仅处理IRP还处理FASTIO和文件过滤驱动,可以使用三个宏分别判定:

FLT_IS_IRP_OPERATION
FLT_IS_FASTIO_OPERATION
FLT_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 Context
FltSet/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,//安全描述符,可传入&oa
fnConnectFromClient, //获得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)//关联到oa
FltFreeSecurityDescriptor(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主动

//发送消息给R3
timeout.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等待函数中

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
软件名称:SEFS透明加密内核 V 2.0.0.1软件版本:2.0.0.1建议分类:系统安全/文件加密软件大小:371K安装平台:Win2000 sp4+urp / xp sp2 / 2003 sp1 / vista软件语言:简体中文/繁体中文/英文软件授权:共享软件软件主页:http://www.sefs.net支持邮箱:admin@sefs.net软件下载:http://www.sefs.net/setup.rar国内首家采用MS全新 MiniFilter架构的SEFS透明加密内核 V 2.0.0.1发布1、简述 SEFS透明加密开发内核是基于MS最新的IFS文件过滤驱动(MiniFilter)开发的透明加密平台。加密标识内置于文件本身、可支持PKCS7电子 信封、加密算法可在内核态。也可在应用层,支持MS CSP 标准,可实现对加密硬件如USBKEY的支持。加、解密操作均受保护 的内存区域完成,高效安全。不会产生临时文件,同时配套保护驱动可防止进程注入、内存Dump、和截屏操作,全程保护您的 机密资料。2、特点   1、强制加密:客户端指定规则或匹配规则产生的任意文件均强制加密。所有的“文件另存”均为加密。不管是 怎么样的文件名称。SEFS是智能识别应用程序的行为.  2、文件加密标记识别采用指纹智能识别技术,加密标记植于文件本身,支持电子信封模式(PKCS7)和支持   身份/身份组机制.方便交流和传输。  3、SEFS平台工作于文件系统驱动层面,可以支持内存映射文件的方式.而非一些基于API Hook方式的加密系   统绝对无法支持内存映射文件。例如最常见的notepad(记事本)/另外可执行文件的加载执行均是通过内存   映射文件的方式.  4、进程识别基于特征值,而非简单的基于进程名称判断。可防止进程改名、加壳等形式的攻击。  5、非授权进程无法读取密文。网络间受控文件的传输为密文。FoxMail、OutLook或Ftp客户端等网络软件无法发送 明文。(假设其为非授权进程的话) 6、完美解决明文缓存问题,即便是密文正在被打开,也不能非法夺取明文 7、使用全新的MiniFilter架构,同杀毒软件有较好的兼容性,同时在性能和稳定性方面,较老的IFS过滤驱动 有着明显的提升。 8、支持应用层的加、解密算法和引擎。可兼容MS CSP 、PKCS11 等标准,从而实现硬件的加解密。满足不同的安全级别的要求。3、安装环境 客户端:Win2000 sp4 + URP /XP sp2/2003 sp1 / Vista Win2000需要Update Rollup Pack (URP) 下载:http://www.microsoft.com/downloads/details.aspx?displaylang=zh-cn&FamilyID=B54730CF-8850-4531-B52B-BF28B324C6624、支持的软件: 1. 办公类: Microsoft Office 2000/XP/2003 、 Adobe acrobat7 、NotePad、 WordPad。 2. 图像类: Photoshop 、 CorelDraw12 、 Mspaint画图等 3. 设计类: AutoCAD 2004 、圆方BtoCAD、等 4. ...................SEFS--透明加密内核=============================================商业授权:sales@sefs.netBug 报告:bug@sefs.net

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值