注意下:我的这套过滤只能用在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
#include
#include
#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
#include
#include
#include
#include
#include
#include
#include
#include "../MiniFliter_Scaner/scanuk.h"
#include "User.h"
#include
#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(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(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);
}