注意下:我的这套过滤只能用在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, // GenerateFileName NULL, // GenerateDestinationFileName NULL // NormalizeNameComponent }; BOOLEAN IsPatternMatch(PUNICODE_STRING Expression, PUNICODE_STRING Name, BOOLEAN IgnoreCase) { return FsRtlIsNameInExpression( Expression, Name, IgnoreCase,//如果这里设置为TRUE,那么Expression必须是大写的 NULL ); } PUNICODE_STRING PsGetProcessFullName(PEPROCESS pTargetProcess) { PFILE_OBJECT pFileObject=NULL; POBJECT_NAME_INFORMATION pObjectNameInfo=NULL; if(!NT_SUCCESS(PsReferenceProcessFilePointer(pTargetProcess,&pFileObject))) return NULL; if(!NT_SUCCESS(IoQueryFileDosDeviceName(pFileObject,&pObjectNameInfo))) return NULL; ObDereferenceObject(pFileObject); return &(pObjectNameInfo->Name);//尚未释放内存 以及 ObDereferenceObject } ULONG g_Count = 0; NTSTATUS DriverEntry ( __in PDRIVER_OBJECT DriverObject, __in PUNICODE_STRING RegistryPath ) { OBJECT_ATTRIBUTES oa; UNICODE_STRING uniString; PSECURITY_DESCRIPTOR sd; NTSTATUS status; UNREFERENCED_PARAMETER( RegistryPath ); g_LastDelFileName.Buffer = ExAllocatePool(NonPagedPool,MAX_PATH*2); g_LastDelFileName.Length = g_LastDelFileName.MaximumLength = MAX_PATH*2; memset(g_LastDelFileName.Buffer,'\0',MAX_PATH*2); //注册回调 status = FltRegisterFilter( DriverObject, &FilterRegistration, &ScannerData.Filter ); if (!NT_SUCCESS( status )) { return status; } //创建端口 RtlInitUnicodeString( &uniString, ScannerPortName ); //设置通信端口权限 ,只有管理员和系统进程才能操作 status = FltBuildDefaultSecurityDescriptor( &sd, FLT_PORT_ALL_ACCESS ); if (NT_SUCCESS( status )) { InitializeObjectAttributes( &oa, &uniString, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, sd ); //创建通信端口,并设置对应的回调函数 status = FltCreateCommunicationPort( ScannerData.Filter, &ScannerData.ServerPort, &oa,//设置的名字 NULL, ScannerPortConnect,//当R3连接时回调 主要是记录R3的进程ID或EPROCESS以便放过本进程 还有记录R3的通信端口,给后面主动通信的时候用 ScannerPortDisconnect,//当R3离线时回调 主要是关闭R3端口和设置R3的进程信息为NULL NULL,//处理R3主动函数 比如R3下新的规则, 1 );//最后一个常为1 //设置好后需要释放权限的设置 FltFreeSecurityDescriptor( sd ); if (NT_SUCCESS( status )) { // // Start filtering I/O. // //开始过滤 status = FltStartFiltering( ScannerData.Filter ); if (NT_SUCCESS( status )) { return STATUS_SUCCESS; } //失败就滚吧 FltCloseCommunicationPort( ScannerData.ServerPort ); } } //失败就滚吧 FltUnregisterFilter( ScannerData.Filter ); return status; } NTSTATUS ScannerPortConnect ( __in PFLT_PORT ClientPort, __in_opt PVOID ServerPortCookie, __in_bcount_opt(SizeOfContext) PVOID ConnectionContext, __in ULONG SizeOfContext, __deref_out_opt PVOID *ConnectionCookie ) { PAGED_CODE(); UNREFERENCED_PARAMETER( ServerPortCookie ); UNREFERENCED_PARAMETER( ConnectionContext ); UNREFERENCED_PARAMETER( SizeOfContext); UNREFERENCED_PARAMETER( ConnectionCookie ); ASSERT( ScannerData.ClientPort == NULL ); ASSERT( ScannerData.UserProcess == NULL ); //设置本身进程 和 R3的的通信端口 给后面判断和通信时使用 ScannerData.UserProcess = PsGetCurrentProcess(); ScannerData.ClientPort = ClientPort; DbgPrint( "!!! scanner.sys --- connected, port=0x%p\n", ClientPort ); return STATUS_SUCCESS; } VOID ScannerPortDisconnect( __in_opt PVOID ConnectionCookie ) { UNREFERENCED_PARAMETER( ConnectionCookie ); PAGED_CODE(); DbgPrint( "!!! scanner.sys --- disconnected, port=0x%p\n", ScannerData.ClientPort ); //关闭R3通信端口 FltCloseClientPort( ScannerData.Filter, &ScannerData.ClientPort ); //设置R3进程为0 ScannerData.UserProcess = NULL; } NTSTATUS ScannerUnload ( __in FLT_FILTER_UNLOAD_FLAGS Flags ) { UNREFERENCED_PARAMETER( Flags ); // // Close the server port. // if(g_LastDelFileName.Buffer) ExFreePool(g_LastDelFileName.Buffer); FltCloseCommunicationPort( ScannerData.ServerPort ); // // Unregister the filter // FltUnregisterFilter( ScannerData.Filter ); return STATUS_SUCCESS; } NTSTATUS ScannerInstanceSetup ( __in PCFLT_RELATED_OBJECTS FltObjects, __in FLT_INSTANCE_SETUP_FLAGS Flags, __in DEVICE_TYPE VolumeDeviceType, __in FLT_FILESYSTEM_TYPE VolumeFilesystemType ) { UNREFERENCED_PARAMETER( FltObjects ); UNREFERENCED_PARAMETER( Flags ); UNREFERENCED_PARAMETER( VolumeFilesystemType ); PAGED_CODE(); ASSERT( FltObjects->Filter == ScannerData.Filter ); // // Don't attach to network volumes. // if (VolumeDeviceType == FILE_DEVICE_NETWORK_FILE_SYSTEM) { return STATUS_FLT_DO_NOT_ATTACH; } return STATUS_SUCCESS; } NTSTATUS ScannerQueryTeardown ( __in PCFLT_RELATED_OBJECTS FltObjects, __in FLT_INSTANCE_QUERY_TEARDOWN_FLAGS Flags ) { UNREFERENCED_PARAMETER( FltObjects ); UNREFERENCED_PARAMETER( Flags ); return STATUS_SUCCESS; } FLT_PREOP_CALLBACK_STATUS ScannerPreCreate ( __inout PFLT_CALLBACK_DATA Data, __in PCFLT_RELATED_OBJECTS FltObjects, __deref_out_opt PVOID *CompletionContext ) { UNREFERENCED_PARAMETER( FltObjects ); UNREFERENCED_PARAMETER( CompletionContext ); PAGED_CODE(); // // See if this create is being done by our user process. // //DbgPrint("Pre Creta!\n"); if (IoThreadToProcess( Data->Thread ) == ScannerData.UserProcess) { DbgPrint( "!!! scanner.sys -- allowing create for trusted process \n" ); return FLT_PREOP_SUCCESS_NO_CALLBACK; } return FLT_PREOP_SUCCESS_WITH_CALLBACK; } BOOLEAN ScannerpCheckExtension ( __in PUNICODE_STRING Extension ) { const UNICODE_STRING *ext; if (Extension->Length == 0) { return FALSE; } // // Check if it matches any one of our static extension list // ext = ScannerExtensionsToScan; while (ext->Buffer != NULL) { if (RtlCompareUnicodeString( Extension, ext, TRUE ) == 0) { // // A match. We are interested in this file // return TRUE; } ext++; } return FALSE; } //处理打开,创建时(一般这个时候提示的话就是已经被感染了) FLT_POSTOP_CALLBACK_STATUS ScannerPostCreate ( __inout PFLT_CALLBACK_DATA Data, __in PCFLT_RELATED_OBJECTS FltObjects, __in_opt PVOID CompletionContext, __in FLT_POST_OPERATION_FLAGS Flags ) { FLT_POSTOP_CALLBACK_STATUS returnStatus = FLT_POSTOP_FINISHED_PROCESSING; PFLT_FILE_NAME_INFORMATION nameInfo; NTSTATUS status; BOOLEAN safeToOpen, scanFile; UNICODE_STRING ustrRule = {0}; ULONG Options; ULONG ulDisposition; BOOLEAN PopWindow = FALSE; FILE_DISPOSITION_INFORMATION fdi; UNREFERENCED_PARAMETER( CompletionContext ); UNREFERENCED_PARAMETER( Flags ); //UNREFERENCED_PARAMETER( Flags ); // // If this create was failing anyway, don't bother scanning now. // //DbgPrint("Pos Creta!\n"); 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; } status = FltGetFileNameInformation( Data, FLT_FILE_NAME_NORMALIZED | FLT_FILE_NAME_QUERY_DEFAULT, &nameInfo ); if (!NT_SUCCESS( status )) { return FLT_POSTOP_FINISHED_PROCESSING; } FltParseFileNameInformation( nameInfo ); // // Check if the extension matches the list of extensions we are interested in // RtlInitUnicodeString(&ustrRule, L"\\*\\*\\WINDOWS\\SYSTEM32\\*\\*.SYS"); scanFile = IsPatternMatch(&ustrRule,&nameInfo->Name,TRUE); //DbgPrint("%wZ\n",&nameInfo->Name); //scanFile = ScannerpCheckExtension( &nameInfo->Extension ); // // Release file name info, we're done with it // FltReleaseFileNameInformation( nameInfo ); if (!scanFile) { // // Not an extension we are interested in // return FLT_POSTOP_FINISHED_PROCESSING; } if(PopWindow) { MyScannerpScanFileInUserMode( FltObjects->Instance, FltObjects->FileObject, Data, 1, &safeToOpen ); if (!safeToOpen) { // // Ask the filter manager to undo the create. // DbgPrint( "!!! scanner.sys -- foul language detected in postcreate !!!\n" ); DbgPrint( "!!! scanner.sys -- undoing create \n" ); //就算拒绝了 也会创建一个空文件 这里我们删除 fdi.DeleteFile = TRUE; FltSetInformationFile(FltObjects->Instance, FltObjects->FileObject, &fdi, sizeof(FILE_DISPOSITION_INFORMATION), FileDispositionInformation); FltCancelFileOpen( FltObjects->Instance, FltObjects->FileObject ); Data->IoStatus.Status = STATUS_ACCESS_DENIED; Data->IoStatus.Information = 0; returnStatus = FLT_POSTOP_FINISHED_PROCESSING; } } return returnStatus; } //处理打开时 有写权限但 打开成功时是安全的,等它关闭的时候的我们来扫描它 //触发这个回调的条件是文件引用技术为0,这个包括内核+R3的计数,一般是在上层使用了ZwClose或者CloseHandle时调用 FLT_PREOP_CALLBACK_STATUS ScannerPreCleanup ( __inout PFLT_CALLBACK_DATA Data, __in PCFLT_RELATED_OBJECTS FltObjects, __deref_out_opt PVOID *CompletionContext ) { UNREFERENCED_PARAMETER( Data ); UNREFERENCED_PARAMETER( FltObjects ); UNREFERENCED_PARAMETER( CompletionContext ); return FLT_PREOP_SUCCESS_NO_CALLBACK; } //处理写关闭 FLT_PREOP_CALLBACK_STATUS ScannerPreWrite ( __inout PFLT_CALLBACK_DATA Data, __in PCFLT_RELATED_OBJECTS FltObjects, __deref_out_opt PVOID *CompletionContext ) { FLT_PREOP_CALLBACK_STATUS returnStatus = FLT_PREOP_SUCCESS_NO_CALLBACK; UNREFERENCED_PARAMETER( CompletionContext ); UNREFERENCED_PARAMETER( FltObjects ); UNREFERENCED_PARAMETER( Data ); // // If not client port just ignore this write. // //如果R3进程退出了 if (ScannerData.ClientPort == NULL) { return FLT_PREOP_SUCCESS_NO_CALLBACK; } return returnStatus; } BOOLEAN isNeedWatchFile(PFLT_CALLBACK_DATA Data) { BOOLEAN Ret = FALSE; UNICODE_STRING ustrRule = {0}; PFLT_FILE_NAME_INFORMATION nameInfo = {0}; NTSTATUS status = STATUS_SUCCESS; status = FltGetFileNameInformation( Data, FLT_FILE_NAME_NORMALIZED | FLT_FILE_NAME_QUERY_DEFAULT, &nameInfo ); if (!NT_SUCCESS( status )) { return FALSE; } FltParseFileNameInformation( nameInfo ); RtlInitUnicodeString(&ustrRule, L"\\*\\*\\WINDOWS\\SYSTEM32\\*\\*.SYS"); Ret = IsPatternMatch(&ustrRule,&nameInfo->Name,TRUE); FltReleaseFileNameInformation( nameInfo ); return Ret; } VOID UnicodeToChar(PUNICODE_STRING src, char *dst) { ANSI_STRING string; RtlUnicodeStringToAnsiString(&string,src,TRUE); strcpy(dst,string.Buffer); RtlFreeAnsiString(&string); } BOOLEAN isRecycle(PFLT_CALLBACK_DATA Data ,PCFLT_RELATED_OBJECTS FltObje) { BOOLEAN Ret = FALSE; PFLT_FILE_NAME_INFORMATION nameInfo = {0}; PFILE_RENAME_INFORMATION pRenameInfo = {0}; NTSTATUS status = STATUS_SUCCESS; char *temp = (char*)ExAllocatePool(NonPagedPool,MAX_PATH*2); if(temp == NULL) return TRUE; memset(temp,'\0',MAX_PATH*2); //特殊情况,当字符串中包含$Recycle.Bin时是普通删除,实际上删除只是更名而已 pRenameInfo = (PFILE_RENAME_INFORMATION)Data->Iopb->Parameters.SetFileInformation.InfoBuffer; status = FltGetDestinationFileNameInformation(FltObje->Instance,Data->Iopb->TargetFileObject,pRenameInfo->RootDirectory,pRenameInfo->FileName,pRenameInfo->FileNameLength,FLT_FILE_NAME_NORMALIZED,&nameInfo); if(!NT_SUCCESS(status)) { DbgPrint("FltGetDestinationFileNameInformation is faild! 0x%x",status); return TRUE; } UnicodeToChar(&nameInfo->Name,temp); if(strstr(temp,"Recycle.Bin")) Ret = TRUE; else Ret = FALSE; FltReleaseFileNameInformation(nameInfo); ExFreePool(temp); return Ret; } FLT_PREOP_CALLBACK_STATUS ScannerPreSetInforMation( __inout PFLT_CALLBACK_DATA Data, __in PCFLT_RELATED_OBJECTS FltObjects, __deref_out_opt PVOID *CompletionContext ) { FLT_PREOP_CALLBACK_STATUS status = FLT_PREOP_SUCCESS_NO_CALLBACK; ULONG Options = 0;//记录操作类型 1创建,2重命名,3删除 BOOLEAN isAllow = TRUE;//是否放行 UNREFERENCED_PARAMETER(Data); UNREFERENCED_PARAMETER(FltObjects); UNREFERENCED_PARAMETER(CompletionContext); //UNREFERENCED_PARAMETER(FltObjects); if(ScannerData.ClientPort == NULL) { return FLT_PREOP_SUCCESS_NO_CALLBACK; } if(ScannerData.UserProcess == PsGetCurrentProcess()) { return FLT_PREOP_SUCCESS_NO_CALLBACK; } /* lpIrpStack->Parameters.SetFile.FileInformationClass == FileRenameInformation ||//重命名 lpIrpStack->Parameters.SetFile.FileInformationClass == FileBasicInformation || //设置基础信息 lpIrpStack->Parameters.SetFile.FileInformationClass == FileAllocationInformation || lpIrpStack->Parameters.SetFile.FileInformationClass == FileEndOfFileInformation ||//设置大小 lpIrpStack->Parameters.SetFile.FileInformationClass == FileDispositionInformation)//删除 */ if(Data->Iopb->Parameters.SetFileInformation.FileInformationClass == FileRenameInformation || Data->Iopb->Parameters.SetFileInformation.FileInformationClass == FileDispositionInformation ) { switch (Data->Iopb->Parameters.SetFileInformation.FileInformationClass) { case FileRenameInformation: Options = 2; break; case FileDispositionInformation: Options = 3; break; default: Options = 0;//爆炸啦 break; } //判断是不是我们要监控的 if(!isNeedWatchFile(Data)) { return FLT_PREOP_SUCCESS_NO_CALLBACK; } if(Options == 2) { if(isRecycle(Data,FltObjects)) { return FLT_PREOP_SUCCESS_NO_CALLBACK; } } //进程路径,操作类型,原路径,重命名后路径 MyScannerpScanFileInUserMode(FltObjects->Instance,FltObjects->FileObject,Data,Options,&isAllow); if(!isAllow) { DbgPrint("ReName in PreSetInforMation !\n"); Data->IoStatus.Status = STATUS_ACCESS_DENIED; Data->IoStatus.Information = 0; status = FLT_PREOP_COMPLETE; }else { status = FLT_PREOP_SUCCESS_NO_CALLBACK; } } return status; } FLT_POSTOP_CALLBACK_STATUS ScannerPostSetInforMation ( __inout PFLT_CALLBACK_DATA Data, __in PCFLT_RELATED_OBJECTS FltObjects, __in_opt PVOID CompletionContext, __in FLT_POST_OPERATION_FLAGS Flags ) { //FLT_POSTOP_CALLBACK_STATUS status = FLT_POSTOP_FINISHED_PROCESSING; //ULONG Options = 0;//记录操作类型 1创建,2重命名,3删除 //BOOLEAN isAllow = TRUE;//是否放行 UNREFERENCED_PARAMETER(Flags); UNREFERENCED_PARAMETER(Data); UNREFERENCED_PARAMETER(FltObjects); UNREFERENCED_PARAMETER(CompletionContext); /* lpIrpStack->Parameters.SetFile.FileInformationClass == FileRenameInformation ||//重命名 lpIrpStack->Parameters.SetFile.FileInformationClass == FileBasicInformation || //设置基础信息 lpIrpStack->Parameters.SetFile.FileInformationClass == FileAllocationInformation || lpIrpStack->Parameters.SetFile.FileInformationClass == FileEndOfFileInformation ||//设置大小 lpIrpStack->Parameters.SetFile.FileInformationClass == FileDispositionInformation)//删除 */ //if(Data->Iopb->Parameters.SetFileInformation.FileInformationClass == FileRenameInformation || // Data->Iopb->Parameters.SetFileInformation.FileInformationClass == FileDispositionInformation ) //{ // switch (Data->Iopb->Parameters.SetFileInformation.FileInformationClass) // { // case FileRenameInformation: // Options = 2; // break; // case FileDispositionInformation: // Options = 3; // break; // default: // Options = 0;//爆炸啦 // break; // } // //判断是不是我们要监控的 // if(!isNeedWatchFile(Data)) // { // return FLT_POSTOP_FINISHED_PROCESSING; // } // if(Options == 2) // { // if(isRecycle(Data,FltObjects)) // { // return FLT_POSTOP_FINISHED_PROCESSING; // } // } // //进程路径,操作类型,原路径,重命名后路径 // MyScannerpScanFileInUserMode(FltObjects->Instance,FltObjects->FileObject,Data,Options,&isAllow); // if(!isAllow) // { // DbgPrint("ReName in PostSetInforMation !\n"); // // FltCancelFileOpen( FltObjects->Instance, FltObjects->FileObject ); // Data->IoStatus.Status = STATUS_ACCESS_DENIED; // Data->IoStatus.Information = 0; // // status = FLT_POSTOP_FINISHED_PROCESSING; // }else // { // status = FLT_POSTOP_FINISHED_PROCESSING; // } //} //return status; return FLT_POSTOP_FINISHED_PROCESSING; } //操作类型 1创建 2重命名 3 删除 NTSTATUS MyScannerpScanFileInUserMode ( __in PFLT_INSTANCE Instance, __in PFILE_OBJECT FileObject, __in PFLT_CALLBACK_DATA Data, __in ULONG Operation, __out PBOOLEAN SafeToOpen ) { NTSTATUS status = STATUS_SUCCESS; PSCANNER_NOTIFICATION notification = NULL; ULONG replyLength = 0; PEPROCESS pEprocess = 0; PUNICODE_STRING uSProcessPath = NULL; PFLT_FILE_NAME_INFORMATION nameInfo; PFLT_FILE_NAME_INFORMATION pOutReNameinfo; PFILE_RENAME_INFORMATION pRenameInfo; UNREFERENCED_PARAMETER( FileObject ); UNREFERENCED_PARAMETER( Instance ); *SafeToOpen = TRUE; // // If not client port just return. // if (ScannerData.ClientPort == NULL) { return STATUS_SUCCESS; } try { notification = ExAllocatePoolWithTag( NonPagedPool, sizeof( SCANNER_NOTIFICATION ), 'nacS' ); if(NULL == notification) { status = STATUS_INSUFFICIENT_RESOURCES; leave; } //在这里获取进程路径,操作类型,目标路径 //拷贝操作类型 notification->Operation = Operation; pEprocess = Data->Thread ? IoThreadToProcess(Data->Thread) : PsGetCurrentProcess(); if(pEprocess == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; leave; } uSProcessPath = PsGetProcessFullName(pEprocess);//这里需要释放UNICODESTRING 的内存 if(uSProcessPath == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; leave; } //拷贝进程路径 wcsncpy(¬ification->ProcessPath,uSProcessPath->Buffer,uSProcessPath->Length); //wcsncpy(¬ification->ProcessPath,L"test",wcslen(L"test")); status = FltGetFileNameInformation( Data, FLT_FILE_NAME_NORMALIZED | FLT_FILE_NAME_QUERY_DEFAULT, &nameInfo ); //FltGetDestinationFileNameInformation( if (!NT_SUCCESS( status )) { status = STATUS_INSUFFICIENT_RESOURCES; leave; } //拷贝目标路径 FltParseFileNameInformation( nameInfo ); //这里应该注意下多线程的 if(Operation == 3) { //DbgPrint("[DjWow]%wZ\n",&g_LastDelFileName); //DbgPrint("[DjWow]%wZ\n",&nameInfo->Name); if(wcsncmp(g_LastDelFileName.Buffer,nameInfo->Name.Buffer,nameInfo->Name.MaximumLength) == 0) { FltReleaseFileNameInformation( nameInfo ); memset(g_LastDelFileName.Buffer,'\0',MAX_PATH*2); *SafeToOpen = TRUE; leave; } } if(Operation == 3) { wcsncpy(g_LastDelFileName.Buffer,nameInfo->Name.Buffer,nameInfo->Name.MaximumLength); } wcsncpy(¬ification->TargetPath,nameInfo->Name.Buffer,nameInfo->Name.MaximumLength); FltReleaseFileNameInformation( nameInfo ); if(Operation == 2)//重命名 { 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); } replyLength = sizeof( SCANNER_REPLY ); status = FltSendMessage( ScannerData.Filter, &ScannerData.ClientPort, notification, sizeof(SCANNER_NOTIFICATION), notification, &replyLength, NULL ); if (STATUS_SUCCESS == status) { *SafeToOpen = ((PSCANNER_REPLY) notification)->SafeToOpen; } else { // // Couldn't send message // DbgPrint( "!!! scanner.sys --- couldn't send message to user-mode to scan file, status 0x%X\n", status ); } } finally { if (NULL != notification) { ExFreePoolWithTag( notification, 'nacS' ); } if(NULL != pEprocess) { //ObfDereferenceObject(pEprocess); } if(NULL != uSProcessPath) { ExFreePool(uSProcessPath); } } return status; }
// MiniFliter_MFCDlg.cpp : 实现文件 // #include "stdafx.h" #include "MiniFliter_MFC.h" #include "MiniFliter_MFCDlg.h" #include "afxdialogex.h" #include "resource.h" #include <windows.h> #include <stdlib.h> #include <stdio.h> #include <winioctl.h> #include <string.h> #include <crtdbg.h> #include <assert.h> #include <fltuser.h> #include "../MiniFliter_Scaner/scanuk.h" #include "User.h" #include <dontuse.h> #include "PopupDlg.h" #pragma comment(lib,"fltlib.lib") #define SCANNER_DEFAULT_REQUEST_COUNT 5 #define SCANNER_DEFAULT_THREAD_COUNT 2 #define SCANNER_MAX_THREAD_COUNT 64 typedef struct _SCANNER_THREAD_CONTEXT { HANDLE Port; HANDLE Completion; } SCANNER_THREAD_CONTEXT, *PSCANNER_THREAD_CONTEXT; HANDLE g_port = 0; #ifdef _DEBUG #define new DEBUG_NEW #endif // 用于应用程序“关于”菜单项的 CAboutDlg 对话框 class CAboutDlg : public CDialogEx { public: CAboutDlg(); // 对话框数据 enum { IDD = IDD_ABOUTBOX }; protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 // 实现 protected: DECLARE_MESSAGE_MAP() public: //virtual INT_PTR DoModal(); }; CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD) { } void CAboutDlg::DoDataExchange(CDataExchange* pDX) { CDialogEx::DoDataExchange(pDX); } BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx) END_MESSAGE_MAP() // CMiniFliter_MFCDlg 对话框 CMiniFliter_MFCDlg::CMiniFliter_MFCDlg(CWnd* pParent /*=NULL*/) : CDialogEx(CMiniFliter_MFCDlg::IDD, pParent) { m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); } void CMiniFliter_MFCDlg::DoDataExchange(CDataExchange* pDX) { CDialogEx::DoDataExchange(pDX); } BEGIN_MESSAGE_MAP(CMiniFliter_MFCDlg, CDialogEx) ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_WM_QUERYDRAGICON() ON_BN_CLICKED(IDC_START, &CMiniFliter_MFCDlg::OnBnClickedStart) END_MESSAGE_MAP() // CMiniFliter_MFCDlg 消息处理程序 BOOL CMiniFliter_MFCDlg::OnInitDialog() { CDialogEx::OnInitDialog(); // 将“关于...”菜单项添加到系统菜单中。 // IDM_ABOUTBOX 必须在系统命令范围内。 ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); ASSERT(IDM_ABOUTBOX < 0xF000); CMenu* pSysMenu = GetSystemMenu(FALSE); if (pSysMenu != NULL) { BOOL bNameValid; CString strAboutMenu; bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX); ASSERT(bNameValid); if (!strAboutMenu.IsEmpty()) { pSysMenu->AppendMenu(MF_SEPARATOR); pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); } } // 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动 // 执行此操作 SetIcon(m_hIcon, TRUE); // 设置大图标 SetIcon(m_hIcon, FALSE); // 设置小图标 return TRUE; // 除非将焦点设置到控件,否则返回 TRUE } void CMiniFliter_MFCDlg::OnSysCommand(UINT nID, LPARAM lParam) { if ((nID & 0xFFF0) == IDM_ABOUTBOX) { CAboutDlg dlgAbout; //dlgAbout.DoModal(); } else { CDialogEx::OnSysCommand(nID, lParam); } } // 如果向对话框添加最小化按钮,则需要下面的代码 // 来绘制该图标。对于使用文档/视图模型的 MFC 应用程序, // 这将由框架自动完成。 void CMiniFliter_MFCDlg::OnPaint() { if (IsIconic()) { CPaintDC dc(this); // 用于绘制的设备上下文 SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0); // 使图标在工作区矩形中居中 int cxIcon = GetSystemMetrics(SM_CXICON); int cyIcon = GetSystemMetrics(SM_CYICON); CRect rect; GetClientRect(&rect); int x = (rect.Width() - cxIcon + 1) / 2; int y = (rect.Height() - cyIcon + 1) / 2; // 绘制图标 dc.DrawIcon(x, y, m_hIcon); } else { CDialogEx::OnPaint(); } } //当用户拖动最小化窗口时系统调用此函数取得光标 //显示。 HCURSOR CMiniFliter_MFCDlg::OnQueryDragIcon() { return static_cast<HCURSOR>(m_hIcon); } DWORD HandData(LPCTSTR str) { CPopupDlg dlg; dlg.SetText(str); dlg.DoModal(); if(dlg.m_Allow == TRUE) return 1; else return 0; } DWORD ScannerWorker( __in PSCANNER_THREAD_CONTEXT Context ) { DWORD dwRet = 0; DWORD outSize = 0; HRESULT hr = 0; ULONG_PTR key = 0; BOOL result = TRUE; //CHAR strPop[MAX_PATH*2] = {0}; WCHAR strOptions[50*2] = {0};//操作类型字符串 WCHAR LastPath[MAX_PATH*2] = {0}; BOOL LastResult = TRUE; LPOVERLAPPED pOvlp; PSCANNER_NOTIFICATION notification; SCANNER_REPLY_MESSAGE replyMessage; PSCANNER_MESSAGE message; //DWORD dwRet = 0; CString tip = NULL; memset(LastPath,'\0',MAX_PATH*2); #pragma warning(push) #pragma warning(disable:4127) // conditional expression is constant while (TRUE) { #pragma warning(pop) // // Poll for messages from the filter component to scan. // result = GetQueuedCompletionStatus( Context->Completion, &outSize, &key, &pOvlp, INFINITE ); // // Obtain the message: note that the message we sent down via FltGetMessage() may NOT be // the one dequeued off the completion queue: this is solely because there are multiple // threads per single port handle. Any of the FilterGetMessage() issued messages can be // completed in random order - and we will just dequeue a random one. // message = CONTAINING_RECORD( pOvlp, SCANNER_MESSAGE, Ovlp ); if (!result) { hr = HRESULT_FROM_WIN32( GetLastError() ); break; } //printf( "Received message, size %d\n", pOvlp->InternalHigh ); //tip.Format(L"Received message, size %d\n", pOvlp->InternalHigh ); notification = &message->Notification; if(notification->Operation == 1) { if(wcsncmp(LastPath,notification->TargetPath,wcslen(notification->TargetPath))==0) { memset(LastPath,'\0',MAX_PATH*2); result = LastResult; goto EX; } } memset(strOptions,'\0',50); switch (notification->Operation) { case 1: wcscpy_s(strOptions,50,L"创建"); break; case 2: wcscpy_s(strOptions,50,L"重命名"); break; case 3: wcscpy_s(strOptions,50,L"删除"); break; default: wcscpy_s(strOptions,50,L"爆炸"); break; } //memset(strPop,'\0',MAX_PATH*2); if(notification->Operation == 2) { //sprintf(strPop,"进程:%S\r\n操作:%s\r\n目标:%S\r\n重名为:%S\r\n是否放行?",notification->ProcessPath,strOptions,notification->TargetPath,notification->RePathName); tip.Format(L"进程:%s\r\n操作:%s\r\n目标:%s\r\n重名为:%s\r\n是否放行?",notification->ProcessPath,strOptions,notification->TargetPath,notification->RePathName); }else { //sprintf(strPop,"进程:%S\r\n操作:%s\r\n目标:%S\r\n是否放行?",notification->ProcessPath,strOptions,notification->TargetPath); tip.Format(L"进程:%s\r\n操作:%s\r\n目标:%s\r\n是否放行?",notification->ProcessPath,strOptions,notification->TargetPath); } Sleep(1000); //dwRet = MessageBoxA(NULL,strPop,"监控到攻击行为",MB_YESNO); dwRet = HandData(tip); if(dwRet == 1) result = FALSE; else result = TRUE; LastResult = result; EX: wcsncpy_s(LastPath,MAX_PATH*2,notification->TargetPath,MAX_PATH*2); replyMessage.ReplyHeader.Status = 0; replyMessage.ReplyHeader.MessageId = message->MessageHeader.MessageId; replyMessage.Reply.SafeToOpen = !result; printf( "Replying message, ResultCode: %d\n", replyMessage.Reply.SafeToOpen ); hr = FilterReplyMessage( Context->Port, (PFILTER_REPLY_HEADER) &replyMessage, sizeof( replyMessage ) ); if (SUCCEEDED( hr )) { printf( "Replied message\n" ); } else { printf( "Scanner: Error replying message. Error = 0x%X\n", hr ); break; } memset( &message->Ovlp, 0, sizeof( OVERLAPPED ) ); hr = FilterGetMessage( Context->Port, &message->MessageHeader, FIELD_OFFSET( SCANNER_MESSAGE, Ovlp ), &message->Ovlp ); if (hr != HRESULT_FROM_WIN32( ERROR_IO_PENDING )) { break; } } if (!SUCCEEDED( hr )) { if (hr == HRESULT_FROM_WIN32( ERROR_INVALID_HANDLE )) { // // Scanner port disconncted. // printf( "Scanner: Port is disconnected, probably due to scanner filter unloading.\n" ); } else { printf( "Scanner: Unknown error occured. Error = 0x%X\n", hr ); } } free( message ); return hr; } //此函数需放到线程中执行 int InitFltUser() { DWORD dwDefRequestCount = SCANNER_DEFAULT_REQUEST_COUNT; DWORD dwDefThreadCount = SCANNER_DEFAULT_THREAD_COUNT; DWORD dwMaxThreadCount = SCANNER_MAX_THREAD_COUNT; SCANNER_THREAD_CONTEXT context; PSCANNER_MESSAGE msg; HANDLE threads[SCANNER_MAX_THREAD_COUNT]; CString tip = NULL; DWORD threadId; DWORD i = 0; //连接到端口 HRESULT hr = FilterConnectCommunicationPort(ScannerPortName,0,NULL,0,NULL,&g_port); if(IS_ERROR(hr)) { AfxMessageBox(L"hr is null\n"); return 0; } //为这个句柄创建一个Comption HANDLE completion = CreateIoCompletionPort( g_port, NULL, 0, dwDefThreadCount ); if (completion == NULL) { tip.Format(L"ERROR: Creating completion port: %d\n", GetLastError()); AfxMessageBox(tip); CloseHandle( g_port ); return 0; } //tip.Format(L"Scanner: Port = 0x%p Completion = 0x%p\n", g_port, completion ); //this->SetWindowTextW(tip); context.Port = g_port; context.Completion = completion; //创建规定的线程 for (i = 0; i < dwDefThreadCount; i++) { //创建线程 threads[i] = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)ScannerWorker, &context, 0, &threadId ); if (threads[i] == NULL) { hr = GetLastError(); tip.Format(L"ERROR: Couldn't create thread: %d\n", hr ); //this->SetWindowTextW(tip); goto main_cleanup; } for (DWORD j = 0; j < dwDefRequestCount; j++) { // // Allocate the message. // #pragma prefast(suppress:__WARNING_MEMORY_LEAK, "msg will not be leaked because it is freed in ScannerWorker") msg = (PSCANNER_MESSAGE)malloc( sizeof( SCANNER_MESSAGE )); if (msg == NULL) { hr = ERROR_NOT_ENOUGH_MEMORY; goto main_cleanup; } memset( &msg->Ovlp, 0, sizeof( OVERLAPPED ) ); // // Request messages from the filter driver. // hr = FilterGetMessage( g_port, &msg->MessageHeader, FIELD_OFFSET( SCANNER_MESSAGE, Ovlp ), &msg->Ovlp ); if (hr != HRESULT_FROM_WIN32( ERROR_IO_PENDING )) { free( msg ); goto main_cleanup; } } } hr = S_OK; WaitForMultipleObjectsEx( i, threads, TRUE, INFINITE, FALSE ); //返回线程数组和 数组个数 main_cleanup: tip.Format(L"Scanner: All done. Result = 0x%08x\n", hr ); //this->SetWindowTextW(tip); CloseHandle(g_port); CloseHandle(completion); return hr+1; } void CMiniFliter_MFCDlg::OnBnClickedStart() { CreateThread(NULL,0, (LPTHREAD_START_ROUTINE)InitFltUser,NULL,0,NULL); }