注意下:我的这套过滤只能用在nt6系统上
原因是使用一个nt6上才有的函数
见函数
PsGetProcessFullName
其实没必要自己来写获取全路径
因为minifilter已经给我们提供了获取全路径的函数
FltGetFileNameInformation
我就不改了,哈哈
说说遇到的问题吧
在监控创建的时候,我是在post中监控,我拒绝后,会弹窗,2-3次吧,也就是会请求2-3次,我的解决方法是记录上一次拒绝的文件全路径,然后下一次来的时候来比对
这里可以将处理过的文件加入链表或者hash,我偷懒了,就直接用这种方法来解决多重求情的问题,
这里注意下,出现多次请求的原因是你第一次放行了,那么我们第二次的时候就知道比对的时候就直接放行了
考虑过在pre中监控
但根据MF周老师的意见 说在这里拿到的信息是不准确的,
可以用下面一句话总结:
在pre中是对请求本身就行拦截,在post中是对请求完成结果的拦截.
遵循周老师的意见,我还是在post中监控
在拦截创建的时候,还有一个问题,就是如果创建的时候我拒绝了,那么返回给用户的会出现一个替换的框(文件已存在,但大小是0)
针对这个情况,我直接对这个data设置文件属性 有点像前面学习的IRP下发强删文件
//就算拒绝了 也会创建一个空文件 这里我们删除
fdi.DeleteFile = TRUE;
FltSetInformationFile(FltObjects->Instance, FltObjects->FileObject, &fdi, sizeof(FILE_DISPOSITION_INFORMATION), FileDispositionInformation);
在post中 我们可以使用FltCancelFileOpen 或者FltCancelFileIrp(未测试)来取消前面的操作
还有一点是,刚开始写的时候我直接对Create的回调函数进行过滤,没有判断文件打开的属性,或是文件还是文件夹
然后一直弹窗,然后 你懂得....
然后就修复了 对文件夹的判断和打开的判断
这里其实是有BUG的 为什么这么说呢,在CreateFile的函数中 我们可以用FILE_OPEN_IF创建文件 这里没有过滤
这里不应该在内核中过滤 原因是如果这里填写了对FILE_OPEN_IF的过滤,会不断弹窗,而且这个时候在这里已经不能判断文件是否存在了 已经完成了
已经生成了一个文件 一个为空的文件
那么怎么办呢,思路是得到此时文件的大小,如果是0则是新建,否则就是打开操作
获取大小的方法我知道的是通过FltReadFile去读文件 然后BytesRead就是文件的大小
还有一个思路就是在pre中过滤,此时文件还没有创建,我们得到文件的全路径,然后打开,如果返回NO_FOUND就说明是新建操作
下面是对文件夹的判断
if (!NT_SUCCESS( Data->IoStatus.Status ) ||
(STATUS_REPARSE == Data->IoStatus.Status)) {
return FLT_POSTOP_FINISHED_PROCESSING;
}
Options = Data->Iopb->Parameters.Create.Options;
if (FlagOn(Options, FILE_DIRECTORY_FILE) ||
FlagOn(FltObjects->FileObject->Flags, FO_VOLUME_OPEN) ||
FlagOn(Data->Flags, SL_OPEN_PAGING_FILE))
{
return FLT_POSTOP_FINISHED_PROCESSING;
}
ulDisposition = (Data->Iopb->Parameters.Create.Options >> 24) & 0xFF;
if (ulDisposition == FILE_CREATE || ulDisposition == FILE_OVERWRITE || ulDisposition == FILE_OVERWRITE_IF)
{
PopWindow = TRUE;
}
另外遇到的问题是删除
删除分两种
一种是直接删除 也就是shift+Del的方式
这种没什么问题
另外一种普通的删除,右键文件-删除-或者直接按Del
这其实一个发现 + 更名的操作
这个发现具体我也不知道怎么说,因为你普通删除文件的时候,不是有一个正在发现文件吗,就是统计文件的大小操作
然后就是更名的操作
这是我第一次实验时出现的情况
我的操作是 普通删除->放行->然后就出现了这个框
有了这个后 就简单了,在PreSetInforMation中获得文件全路径,匹配如果中间有Recycle.Bin的字符串
但这不是准确的,我也偷懒啦
至于重命名 无非就是拿到重命名后的路径
两种方法
1.直接在buffer中拿
2.FltGetDestinationFileNameInformation获得
不懂的是:重命名的路径能直接在buffer中拿到 为什么还要使用FltGetDestinationFileNameInformation呢,知道的人可以回复下
pRenameInfo = (PFILE_RENAME_INFORMATION)Data->Iopb->Parameters.SetFileInformation.InfoBuffer;
/*
//这也是可行的
wstrTest = ExAllocatePool(NonPagedPool,pRenameInfo->FileNameLength + 1);
if(wstrTest == NULL)
leave;
memset(wstrTest,'\0',pRenameInfo->FileNameLength + 1);
wcsncpy(wstrTest,pRenameInfo->FileName,pRenameInfo->FileNameLength);
DbgPrint("%ws\n",wstrTest);*/
status = FltGetDestinationFileNameInformation(Instance,Data->Iopb->TargetFileObject,pRenameInfo->RootDirectory,pRenameInfo->FileName,pRenameInfo->FileNameLength,FLT_FILE_NAME_NORMALIZED,&pOutReNameinfo);
if(!NT_SUCCESS(status))
{
DbgPrint("FltGetDestinationFileNameInformation is faild! 0x%x",status);
leave;
}
wcsncpy(¬ification->RePathName,pOutReNameinfo->Name.Buffer,pOutReNameinfo->Name.MaximumLength);
DbgPrint("重命名:%wZ\n",&pOutReNameinfo->Name);
FltReleaseFileNameInformation(pOutReNameinfo);
其他没什么了 就是R3的处理了,我对创建多次请求的判断是放在R3的
核心文件:R0
#include <fltKernel.h>
#include <dontuse.h>
#include <suppress.h>
#include "scanuk.h"
#include "scanner.h"
#pragma prefast(disable:__WARNING_ENCODE_MEMBER_FUNCTION_POINTER, "Not valid for kernel mode drivers")
NTSTATUS
PsReferenceProcessFilePointer (
IN PEPROCESS Process,
OUT PVOID *OutFileObject
);
SCANNER_DATA ScannerData;
UNICODE_STRING g_LastDelFileName = {0};
//
// This is a static list of file name extensions files we are interested in scanning
//
const UNICODE_STRING ScannerExtensionsToScan[] =
{ RTL_CONSTANT_STRING( L"doc"),
RTL_CONSTANT_STRING( L"txt"),
RTL_CONSTANT_STRING( L"bat"),
RTL_CONSTANT_STRING( L"cmd"),
RTL_CONSTANT_STRING( L"inf"),
/*RTL_CONSTANT_STRING( L"ini"), Removed, to much usage*/
{0, 0, NULL}
};
//
// Function prototypes
//
NTSTATUS
ScannerPortConnect (
__in PFLT_PORT ClientPort,
__in_opt PVOID ServerPortCookie,
__in_bcount_opt(SizeOfContext) PVOID ConnectionContext,
__in ULONG SizeOfContext,
__deref_out_opt PVOID *ConnectionCookie
);
VOID
ScannerPortDisconnect (
__in_opt PVOID ConnectionCookie
);
NTSTATUS
ScannerpScanFileInUserMode (
__in PFLT_INSTANCE Instance,
__in PFILE_OBJECT FileObject,
__out PBOOLEAN SafeToOpen
);
BOOLEAN
ScannerpCheckExtension (
__in PUNICODE_STRING Extension
);
NTSTATUS
MyScannerpScanFileInUserMode (
__in PFLT_INSTANCE Instance,
__in PFILE_OBJECT FileObject,
__in PFLT_CALLBACK_DATA Data,
__in ULONG Operation,
__out PBOOLEAN SafeToOpen
);
//
// Assign text sections for each routine.
//
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT, DriverEntry)
#pragma alloc_text(PAGE, ScannerInstanceSetup)
#pragma alloc_text(PAGE, ScannerPreCreate)
#pragma alloc_text(PAGE, ScannerPostCreate)
#pragma alloc_text(PAGE, ScannerPortConnect)
#pragma alloc_text(PAGE, ScannerPortDisconnect)
#pragma alloc_text(PAGE, ScannerPostSetInforMation)
#pragma alloc_text(PAGE, ScannerPreSetInforMation )
//IsPatternMatch
//PsGetProcessFullName
#endif
//
// Constant FLT_REGISTRATION structure for our filter. This
// initializes the callback routines our filter wants to register
// for. This is only used to register with the filter manager
//
const FLT_OPERATION_REGISTRATION Callbacks[] = {
{ IRP_MJ_CREATE,
0,
ScannerPreCreate,
ScannerPostCreate},
{ IRP_MJ_CLEANUP,
0,
ScannerPreCleanup,
NULL},
{ IRP_MJ_WRITE,
0,
ScannerPreWrite,
NULL},
{ IRP_MJ_SET_INFORMATION,
0,
ScannerPreSetInforMation,
ScannerPostSetInforMation},
{ IRP_MJ_OPERATION_END }
};
const FLT_CONTEXT_REGISTRATION ContextRegistration[] = {
{ FLT_STREAMHANDLE_CONTEXT,
0,
NULL,
sizeof(SCANNER_STREAM_HANDLE_CONTEXT),
'chBS' },
{ FLT_CONTEXT_END }
};
const FLT_REGISTRATION FilterRegistration = {
sizeof( FLT_REGISTRATION ), // Size
FLT_REGISTRATION_VERSION, // Version
0, // Flags
ContextRegistration, // Context Registration.
Callbacks, // Operation callbacks
ScannerUnload, // FilterUnload
ScannerInstanceSetup, // InstanceSetup
ScannerQueryTeardown, // InstanceQueryTeardown
NULL, // InstanceTeardownStart
NULL, // InstanceTeardownComplete
NULL, // GenerateFile