MiniFilter文件系统学习

原文地址: https://blog.csdn.net/zhuhuibeishadiao/article/details/51229122

Minfilter与legacy filter区别


比sfilter加载顺序更易控制. altitude被绑定到合适的位置。 
Minfilter在注册表服务项中有一项Altitude值
此值越高位置越靠前 (待考证
每一个minifilter驱动必须有一个叫做altitude的唯一标识符.一个minifilter驱动的altitude定义了它加载时在I/O栈中相对其他minifilter驱动的位置。值越小,栈中位置就越低
FSFilter Anti-Virus 320000-329999 此组包括在文件I/O期间探测并杀毒的过滤驱动. 
FSFilter Encryption 140000-149999此组包括在文件I/O期间加密和解密数据的过滤驱动. 
图片2


可卸载能力. 


Callback模型仅需处理必要操作的能力. 
不再需要给一个IRP配置一个完成例程,Minfilter每个过滤功能有2个回调函数,一个是“事前”回调(PreCallBack),一个是“事后”回调(PosCallBack)
相当于PosCallBack就是sfilter中的IRP完成例程
要调用PosCallBack只需要PreCallBack 返回 FLT_PREOP_SUCCESS_WITH_CALLBACK
而返回FLT_PREOP_SUCCESS_NO_CALLBACK则告诉系统,处理好这件事后不用调用PosCallBack了
一个相当于sfilter中的Cpy,一个是skip
阻止下发返回FLT_PREOP_COMPLETE


兼容性更好


名字处理更容易
FltGetFileNameInformation
只需要传入回调函数CALL_DATA data 和一个PFLT_FILE_NAME_INFORMATION指针就可以获得相关文件的信息 然后再调用
FltParseFileNameInformation就可以获得路径了
例子:(注意 获取路径需要在Pos中获取(即创建成功后才能获取到真实的数据))

[cpp]  view plain  copy
  1. //在postcreate里获得  
  2.   
  3.   
  4. PFLT_FILE_NAME_INFORMATION  pNameInfo = NULL;  
  5.   
  6.   
  7. ntStatus = FltGetFileNameInformation(Data,  
  8.         FLT_FILE_NAME_NORMALIZED|   
  9.         FLT_FILE_NAME_QUERY_DEFAULT,  
  10.         &pNameInfo);  
  11. FltParseFileNameInformation(pNameInfo);  
  12.   
  13.   
  14. pNameInfo->Name.Buffer  
  15. pNameInfo->Volume  
  16.   
  17.   
  18. FltReleaseFileNameInformation(pNameInfo);  




//重命名的获得:
[cpp]  view plain  copy
  1. PFILE_RENAME_INFORMATION   
  2.     pFileRenameInfomation = (PFILE_RENAME_INFORMATION)Data->Iopb->Parameters.SetFileInformation.InfoBuffer;  
  3.   
  4.   
  5. FltGetDestinationFileNameInformation //重命名获得  

安装方式(.inf/动态加载)


通信方式(port)
同样遵循IRQL,锁等内核开发通用机制
FltCreateFile


Minfilter架构


结构

在DriverEntry中只需要注册Fliter和Start
[cpp]  view plain  copy
  1. FltRegisterFilter( DriverObject,  
  2.         &fileMonitorRegistration,  
  3.         &g_pFilter );  
  4. FltStartFiltering( g_pFilter );  

fileMonitorRegistration是唯一我们需要做的

这是一个FLT_REGISTRATION 结构

[cpp]  view plain  copy
  1. const FLT_REGISTRATION fileMonitorRegistration =   
  2. {  
  3. sizeof( FLT_REGISTRATION ),                     //  Size  
  4. FLT_REGISTRATION_VERSION,               //  Version  
  5. 0,                                              //  Flags  
  6. ContextRegistration,                            //  ContextRegistration //上下文数组  
  7. fileMonitorCallbacks,                               //  Operation callbacks//最重要的  
  8. fileMonUnload,                                      //  FilterUnload  
  9. fileMonInstanceSetup,                           //  InstanceSetup  
  10. NULL,                                           //  InstanceQueryTeardown  
  11. fileMonInstanceTeardownStart,                   //  InstanceTeardownStart  
  12. NULL,                                       //  InstanceTeardownComplete  
  13. NULL,                                           //  GenerateFileName  
  14. NULL,                                           //  GenerateDestinationFileName  
  15. NULL                                            //  NormalizeNameComponent  
  16. };  



fileMonitorCallbacks 例子:
可以只需要一个回调如IRP_MJ_CLEANUP
[cpp]  view plain  copy
  1. const FLT_OPERATION_REGISTRATION   
  2. fileMonitorCallbacks[] =  
  3. {  
  4.     {   
  5.         IRP_MJ_CREATE,  
  6.         FLTFL_OPERATION_REGISTRATION_SKIP_PAGING_IO,//这个是可以忽略的IRP  
  7.         HOOK_PreNtCreateFile,  
  8.         HOOK_PostNtCreateFile  
  9.     },  
  10.     {   
  11.         IRP_MJ_CLEANUP,  
  12.         0,  
  13.         HOOK_PreNtCleanup,  
  14.         NULL  
  15.     },  
  16.     {  
  17.         IRP_MJ_WRITE,  
  18.         0,  
  19.         HOOK_PreNtWriteFile,  
  20.         HOOK_PostNtWriteFile  
  21.     },  
  22.     {    
  23.         IRP_MJ_SET_INFORMATION,  
  24.         0,  
  25.         HOOK_PreNtSetInformationFile,  
  26.         HOOK_PostNtSetInformationFile  
  27.     },  
  28.     {   
  29.         IRP_MJ_OPERATION_END//这个是必须要加的  
  30.     }  
  31. };  

//一个回调的例子:
[cpp]  view plain  copy
  1. FLT_PREOP_CALLBACK_STATUS  
  2. HOOK_PreNtCreateFile (  
  3. PFLT_CALLBACK_DATA Data,  
  4. PCFLT_RELATED_OBJECTS FltObjects,  
  5. PVOID *CompletionContext   
  6. //分配的一个context资源  
  7. )  
  8. {  
  9.     //sandbox?  
  10.     //主防??  
  11.     //杀毒引擎??  
  12.     //加解密??  
  13.     return XXX;  
  14. }  
  15. FLT_POSTOP_CALLBACK_STATUS  
  16. HOOK_PostNtCreateFile (  
  17. PFLT_CALLBACK_DATA Data,  
  18. PCFLT_RELATED_OBJECTS FltObjects,  
  19. PVOID CompletionContext,   
  20.     //在PRE-OP里返回          //FLT_PREOP_SUCCESS_WITH_CALLBACK  
  21.     //时获取里面的上下文,并最后释放  
  22. FLT_POST_OPERATION_FLAGS Flags  
  23. )  
  24. {  
  25.     return XXX;  
  26. }  

上下位数组 例子:
[cpp]  view plain  copy
  1. PFLT_FILTER g_pFilter = NULL;  
  2. const FLT_CONTEXT_REGISTRATION   
  3. ContextRegistration[] =   
  4. {//在释放context之前调用,可以在此释放context里的内存等  
  5.     {     
  6.         FLT_INSTANCE_CONTEXT,  
  7.         0,  
  8.         CtxContextCleanup,  
  9.         CTX_INSTANCE_CONTEXT_SIZE,  
  10.         CTX_INSTANCE_CONTEXT_TAG   
  11.     },  
  12.     {      
  13.         FLT_FILE_CONTEXT,  
  14.         0,  
  15.         CtxContextCleanup,  
  16.         CTX_FILE_CONTEXT_SIZE,  
  17.         CTX_FILE_CONTEXT_TAG   
  18.     },  
  19.     {     
  20.         FLT_STREAM_CONTEXT,  
  21.         0,  
  22.         CtxContextCleanup,  
  23.         CTX_STREAM_CONTEXT_SIZE,  
  24.         CTX_STREAM_CONTEXT_TAG  
  25.      },  
  26.     {     
  27.         FLT_STREAMHANDLE_CONTEXT,  
  28.         0,  
  29.         CtxContextCleanup,  
  30.         CTX_STREAMHANDLE_CONTEXT_SIZE,  
  31.         CTX_STREAMHANDLE_CONTEXT_TAG  
  32.      },  
  33.     { FLT_CONTEXT_END }  
  34. };  

Minifilter的启动
[cpp]  view plain  copy
  1. NTSTATUS initFileMonitor (PDRIVER_OBJECT DriverObject )  
  2. {  
  3. return FltRegisterFilter( DriverObject,  
  4.         &fileMonitorRegistration,  
  5.         &g_pFilter );  
  6. }  
  7.   
  8.   
  9.   
  10.   
  11. NTSTATUS startFileMonitor( )  
  12. {  
  13.     if(g_pFilter)  
  14.         return FltStartFiltering( g_pFilter );  
  15.     return STATUS_INSUFFICIENT_RESOURCES;  
  16. }  
  17.   
  18.   
  19. VOID stopFileMonitor( )  
  20. {  
  21.     if(g_pFilter)  
  22.     {  
  23.         FltUnregisterFilter( g_pFilter );  
  24.         g_pFilter = NULL;  
  25.     }  
  26. }  

.inf文件安装minifilter
这个就是抄啊改的 没什么介绍的,只需要注意里面的ClassGUID和Class必须对上
这是查询网址
http://msdn.microsoft.com/en-us/library/windows/hardware/ff540394(v=vs.85).aspx


如果需要用自己的加载器加载Minfilter 只需要在注册表服务对应的RegPath下创建REG_SZ类型的Instances子健
在这里键下创建键值项,项值为Altitude
[cpp]  view plain  copy
  1. SYSTEM\\CurrentControlSet\\Services\\DriverName\\Instances子健下的键值项   
  2. 例子:  
  3.   //-------------------------------------------------------------------------------------------------------  
  4.    // SYSTEM\\CurrentControlSet\\Services\\DriverName\\Instances子健下的键值项   
  5.    //-------------------------------------------------------------------------------------------------------  
  6.    strcpy(szTempStr,"SYSTEM\\CurrentControlSet\\Services\\");  
  7.    strcat(szTempStr,lpszDriverName);  
  8.    strcat(szTempStr,"\\Instances");  
  9.    if(RegCreateKeyEx(HKEY_LOCAL_MACHINE,szTempStr,0,"",REG_OPTION_NON_VOLATILE,KEY_ALL_ACCESS,NULL,&hKey,(LPDWORD)&dwData)!=ERROR_SUCCESS)  
  10.    {  
  11.        return FALSE;  
  12.    }  
  13.    // 注册表驱动程序的DefaultInstance 值   
  14.    strcpy(szTempStr,lpszDriverName);  
  15.    strcat(szTempStr," Instance");  
  16.    if(RegSetValueEx(hKey,"DefaultInstance",0,REG_SZ,(CONST BYTE*)szTempStr,(DWORD)strlen(szTempStr))!=ERROR_SUCCESS)  
  17.    {  
  18.        return FALSE;  
  19.    }  
  20.    RegFlushKey(hKey);//刷新注册表  
  21.    RegCloseKey(hKey);  
  22.   
  23.   
  24.   
  25.    //-------------------------------------------------------------------------------------------------------  
  26.    // SYSTEM\\CurrentControlSet\\Services\\DriverName\\Instances\\DriverName Instance子健下的键值项   
  27.    //-------------------------------------------------------------------------------------------------------  
  28.    strcpy(szTempStr,"SYSTEM\\CurrentControlSet\\Services\\");  
  29.    strcat(szTempStr,lpszDriverName);  
  30.    strcat(szTempStr,"\\Instances\\");  
  31.    strcat(szTempStr,lpszDriverName);  
  32.    strcat(szTempStr," Instance");  
  33.    if(RegCreateKeyEx(HKEY_LOCAL_MACHINE,szTempStr,0,"",REG_OPTION_NON_VOLATILE,KEY_ALL_ACCESS,NULL,&hKey,(LPDWORD)&dwData)!=ERROR_SUCCESS)  
  34.    {  
  35.        return FALSE;  
  36.    }  
  37.    // 注册表驱动程序的Altitude 值  
  38.    strcpy(szTempStr,lpszAltitude);  
  39.    if(RegSetValueEx(hKey,"Altitude",0,REG_SZ,(CONST BYTE*)szTempStr,(DWORD)strlen(szTempStr))!=ERROR_SUCCESS)  
  40.    {  
  41.        return FALSE;  
  42.    }  
  43.    // 注册表驱动程序的Flags 值  
  44.    dwData=0x0;  
  45.    if(RegSetValueEx(hKey,"Flags",0,REG_DWORD,(CONST BYTE*)&dwData,sizeof(DWORD))!=ERROR_SUCCESS)  
  46.    {  
  47.        return FALSE;  
  48.    }  
  49.    RegFlushKey(hKey);//刷新注册表  
  50.    RegCloseKey(hKey);  
  51.   
  52.   
  53.    return TRUE;  

下面说一说回调
[cpp]  view plain  copy
  1. FLT_PREOP_CALLBACK_STATUS  
  2. HOOK_PreNtCreateFile (  
  3. PFLT_CALLBACK_DATA Data,  
  4. PCFLT_RELATED_OBJECTS FltObjects,  
  5. PVOID *CompletionContext   
  6. //分配的一个context资源  
  7. )  
  8. {  
  9.     //sandbox?  
  10.     //主防??  
  11.     //杀毒引擎??  
  12.     //加解密??  
  13.     return XXX;  
  14. }  
  15. FLT_POSTOP_CALLBACK_STATUS  
  16. HOOK_PostNtCreateFile (  
  17. PFLT_CALLBACK_DATA Data,  
  18. PCFLT_RELATED_OBJECTS FltObjects,  
  19. PVOID CompletionContext,   
  20.     //在PRE-OP里返回          //FLT_PREOP_SUCCESS_WITH_CALLBACK  
  21.     //时获取里面的上下文,并最后释放  
  22. FLT_POST_OPERATION_FLAGS Flags  
  23. )  
  24. {  
  25.     return XXX;  
  26. }  


PRE-OP的返回值:
FLT_PREOP_SUCCESS_WITH_CALLBACK,//常用
FLT_PREOP_SUCCESS_NO_CALLBACK,//常用

FLT_PREOP_PENDING,//挂起IRP 不常用
FLT_PREOP_DISALLOW_FASTIO,//关闭FASTIO
FLT_PREOP_COMPLETE,//阻止
FLT_PREOP_SYNCHRONIZE//不常用


POST-OP的返回值:
FLT_POSTOP_FINISHED_PROCESSING,//常用
FLT_POSTOP_MORE_PROCESSING_REQUIRED


我们可以判断这个Data是什么请求
判断Data是什么操作的宏
[cpp]  view plain  copy
  1. FLT_IS_IRP_OPERATION  
  2. FLT_IS_FASTIO_OPERATION  
  3. FLT_IS_FS_FILTER_OPERATION  
  4.         if(FLT_IS_FASTIO_OPERATION(Data))  
  5.         {  
  6.             ntStatus = STATUS_FLT_DISALLOW_FAST_IO;  
  7.             Data->IoStatus.Status = ntStatus;  
  8.             Data->IoStatus.Information = 0;  
  9.             return FLT_PREOP_DISALLOW_FASTIO;  
  10.   
  11.   
  12.         }  

参数数据的获取:
[cpp]  view plain  copy
  1. PFLT_CALLBACK_DATA Data;  
  2. PEPROCESS processObject =   
  3.         Data->Thread ? IoThreadToProcess(Data->Thread) : PsGetCurrentProcess();//获取EPROCESS  
  4. HandleToUlong(PsGetProcessId(processObject));//获取PID  
  5.   
  6.   
  7. Data->IoStatus.Status = ntStatus;//返回给R3的  
  8. Data->IoStatus.Information = 0;//同上  
  9.   
  10.   
  11. FltObjects->Volume,//卷  
  12. FltObjects->Instance,//实例  
  13. FltObjects->FileObject,//文件对象  
  14. FltObjects->FileObject->DeviceObject//设备对象  
  15.   
  16.   
  17. Data->Iopb->Parameters.Create.SecurityContext->DesiredAccess //创建的权限   


比如这次是查询目录 (怎么判断是什么操作?每个对应的回调就告诉你了这是什么操作,不可以在Create的回调中收到写操作把)
[cpp]  view plain  copy
  1. PVOID   pQueryBuffer    =   
  2.         Data->Iopb->Parameters.DirectoryControl.QueryDirectory.DirectoryBuffer;  
  3. ULONG   uQueryBufferSize    =    
  4.         Data->Iopb->Parameters.DirectoryControl.QueryDirectory.Length  

//读, 读有可能是使用MDL可能使用其它buff 判断的方法是看这个有没有值,没有值则是另一种
[cpp]  view plain  copy
  1. PMDL pReadMdl       = Data->Iopb->Parameters.Read. MdlAddress;  
  2. PVOID pReadBuffer       = Data->Iopb->Parameters.Read. ReadBuffer;  
  3. ULONG uReadLength       = Data->Iopb->Parameters.Read.Length;  

写同上面


路径的获取:
[cpp]  view plain  copy
  1. //在postcreate里获得  
  2.   
  3.   
  4. PFLT_FILE_NAME_INFORMATION  pNameInfo = NULL;  
  5.   
  6.   
  7. ntStatus = FltGetFileNameInformation(Data,  
  8.         FLT_FILE_NAME_NORMALIZED|   
  9.         FLT_FILE_NAME_QUERY_DEFAULT,  
  10.         &pNameInfo);  
  11. FltParseFileNameInformation(pNameInfo);  
  12.   
  13.   
  14. pNameInfo->Name.Buffer  
  15. pNameInfo->Volume  
  16.   
  17.   
  18. FltReleaseFileNameInformation(pNameInfo);  


pNameInfo里面还有很多东西
WDK里面的例子:
[cpp]  view plain  copy
  1. //  look again at the first example string from above:  
  2.    //  
  3.    //    \Device\HarddiskVolume1\Documents and Settings\MyUser\My Documents\Test Results.txt:stream1  
  4.    //  
  5.    //  Extension = "txt"  
  6.    //  Stream = ":stream1"  
  7.    //  FinalComponent = "Test Results.txt:stream1"  
  8.    //  ParentDir = "\Documents and Settings\MyUser\My Documents\"  


//重命名的获得:

[cpp]  view plain  copy
  1. PFILE_RENAME_INFORMATION   
  2.     pFileRenameInfomation = (PFILE_RENAME_INFORMATION)Data->Iopb->Parameters.SetFileInformation.InfoBuffer;  
  3.   
  4.   
  5. FltGetDestinationFileNameInformation //重命名获得  


其实NtCreateSection对应着一个IRP
IRP_MJ_ACQUIRE_FOR_SECTION_SYNCHRONIZATION
Data->Iopb->Parameters.AcquireForSectionSynchronization.PageProtection == PAGE_EXECUTE
(等于这个就是创建进程)
在x64可以用这个监控进程 不过不需要


文件操作
在过滤驱动中,我们不能使用默认的文件操作,这会引起重入
Minfilter给我提供了专门的函数
FltCreateFile
FltReadFile
FltWriteFile
FltClose
FltQueryXxx
FltSetXxx
FltGetXxx
FltPerformXxx


其中的一个例子:
[cpp]  view plain  copy
  1. ntStatus = FltCreateFile(pFilter,  
  2.     pDstInstance,  
  3.     &hDstFile,  
  4.     GENERIC_WRITE | SYNCHRONIZE,  
  5.     &objDstAttrib,  
  6.     &ioStatus,  
  7.     0,  
  8.     FILE_ATTRIBUTE_NORMAL,  
  9.     FILE_SHARE_READ |   
  10.     FILE_SHARE_WRITE |   
  11.     FILE_SHARE_DELETE,  
  12.     FILE_CREATE,  
  13.     CreateOptions,  
  14.     NULL,0,0);  

Minfilter上下文:
Context上下文:其实就是附着在某个对象上的一段数据,这段数据由自己定义;
FltAllocateContext
FltReleaseContext


Stream Context - 流上下文,也就是大家常用的FCB(File Control Block)的上下文,文件和FCB是一对一的关系;
FltGetStreamContext
FltSetStreamContext
Stream Handle Context -  流句柄上下文,也就是大家常见的FO(File Object)的上下文,一个文件可以对应多个FO,属一对多关系;
FltGetStreamHandleContext
FltSetStreamHandleContext
Instance Context - 实例上下文,也就是过滤驱动在文件系统的设备堆栈上创建的一个过滤器实例;
FltGetInstanceContext
FltSetInstanceContext
Volume Context - 卷上下文,卷就是大家通常看到的C,D,E盘以及网络重定向器,一般情况下一个卷对应一个过滤器实例对象,在实际应用上经常用Instance Context来代替Volume Context。
FltGetVolumeContext 
FltSetVolumeContext
文件上下文(vista之后)
FltGetFileContext
FltSetFileContext


[cpp]  view plain  copy
  1. PFLT_FILTER g_pFilter = NULL;  
  2. const FLT_CONTEXT_REGISTRATION   
  3. ContextRegistration[] =   
  4. {//在释放context之前调用,可以在此释放context里的内存等  
  5. {     
  6. FLT_INSTANCE_CONTEXT,  
  7. 0,  
  8. CtxContextCleanup,  
  9. CTX_INSTANCE_CONTEXT_SIZE,  
  10. CTX_INSTANCE_CONTEXT_TAG   
  11. },  
  12. {      
  13.     FLT_FILE_CONTEXT,  
  14. 0,  
  15. CtxContextCleanup,  
  16. CTX_FILE_CONTEXT_SIZE,  
  17. CTX_FILE_CONTEXT_TAG   
  18. },  
  19. {     
  20.     FLT_STREAM_CONTEXT,  
  21. 0,  
  22. CtxContextCleanup,  
  23. CTX_STREAM_CONTEXT_SIZE,  
  24. CTX_STREAM_CONTEXT_TAG  
  25.  },  
  26. {     
  27.     FLT_STREAMHANDLE_CONTEXT,  
  28. 0,  
  29. CtxContextCleanup,  
  30. CTX_STREAMHANDLE_CONTEXT_SIZE,  
  31. CTX_STREAMHANDLE_CONTEXT_TAG  
  32.  },  
  33. { FLT_CONTEXT_END }  
  34. };  


Context使用例子

[cpp]  view plain  copy
  1. typedef struct _INSTANCE_CONTEXT {  
  2. …  
  3. } INSTANCE_CONTEXT, *PINSTANCE_CONTEXT;  
  4. PINSTANCE_CONTEXT pContext = NULL;  
  5. //分配与设置  
  6. ntStatus = FltGetInstanceContext(FltObjects->Instance, & pContext);//尝试获取  
  7. if(NT_SUCCESS(Status) == FALSE)  
  8. {  
  9.     ntStatus = FltAllocateContext(g_pFilter,FLT_INSTANCE_CONTEXT,  
  10.         sizeof(INSTANCE_CONTEXT),  
  11.         PagedPool,& pContext);  
  12.     if(NT_SUCCESS(Status) == FALSE)  
  13.     {  
  14.         return STATUS_SUCCESS;  
  15.     }  
  16.     RtlZeroMemory(pContext, sizeof(INSTANCE_CONTEXT));  
  17. }  
  18. pContext ->m_DeviceType = VolumeDeviceType;  
  19. pContext->m_FSType = VolumeFilesystemType;  
  20. FltSetInstanceContext(FltObjects->Instance, FLT_SET_CONTEXT_REPLACE_IF_EXISTS,pContext,NULL);  
  21. if (pContext)  
  22. {  
  23.     FltReleaseContext(pContext);  
  24. }  

//获取访问
[cpp]  view plain  copy
  1. PINSTANCE_CONTEXT pContext = NULL;  
  2. Status = FltGetInstanceContext(FltObjects->Instance,&pContext);  
  3. pContext->xxx = xxx;  



Minifilter R3与R0通信
不用像NT框架里面的通信方式了,Minifilter为我们提供了专门的函数进行通信
在通信时,我们使用Port进行通信
在R0,我们创建一个Port,R3在通信前会得到Port的句柄,我们就可以通过这个port进行通信了
R0创建端口代码:

[cpp]  view plain  copy
  1. RtlInitUnicodeString( &uniString, ScannerPortName );  
  2.   
  3.   
  4.     //  
  5.     //  We secure the port so only ADMINs & SYSTEM can acecss it.  
  6.     //  
  7.     //设置通信端口权限 ,只有管理员和系统进程才能操作  
  8.     status = FltBuildDefaultSecurityDescriptor( &sd, FLT_PORT_ALL_ACCESS );  
  9.   
  10.   
  11.     if (NT_SUCCESS( status )) {  
  12.   
  13.   
  14.         InitializeObjectAttributes( &oa,  
  15.                                     &uniString,  
  16.                                     OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,  
  17.                                     NULL,  
  18.                                     sd );  
  19.   
  20.   
  21.         //创建通信端口,并设置对应的回调函数  
  22.         status = FltCreateCommunicationPort( ScannerData.Filter,  
  23.                                              &ScannerData.ServerPort,  
  24.                                              &oa,//设置的名字  
  25.                                              NULL,  
  26.                                              ScannerPortConnect,//当R3连接时回调 主要是记录R3的进程ID或EPROCESS以便放过本进程 还有记录R3的通信端口,给后面主动通信的时候用  
  27.                                              ScannerPortDisconnect,//当R3离线时回调 主要是关闭R3端口和设置R3的进程信息为NULL  
  28.                                              NULL,//处理R3主动函数 比如R3下新的规则,  
  29.                                              1 );//最后一个常为1  
  30.         //  
  31.         //  Free the security descriptor in all cases. It is not needed once  
  32.         //  the call to FltCreateCommunicationPort() is made.  
  33.         //  
  34.         //设置好后需要释放权限的设置  
  35.         FltFreeSecurityDescriptor( sd );  
  36.         //下面就是判断是否创建成功,成功后就开始开启过滤  

先说说HIPS的实现,
r3,首先得到R0通信端口的句柄
使用FilterConnectCommunicationPort 只需要注意第一个参数和最后一个参数即可 其它都为0或NULL
然后绑定这个端口(我理解为绑定)
使用CreateIoCompletionPort 只需要注意第一个参数最后一个参数即可,最后一个参数:为这个工作线程设置几个线程
这样有助于高效率 一般小于64 ,也可以设置请求次数 这样回复也会高效率一些(具体看后面的代码)
我们首先使用FiltetGetMessage异步获取一下消息,如果有信息,则下面的GetQueuedCompletionStatus就会恢复(如果没有消息,GetQueuedCompletionStatus就会暂停下来,并让出CPU,等待有信息)


有了信息后我们就可以进行扫描 过滤,搞定之后就调用FilterReplyMessage返回给内核
然后继续调用FilterGetMessage-等待--处理--返回给内核
代码:
   
[cpp]  view plain  copy
  1.    FilterConnectCommunicationPort( ScannerPortName,//与R0的名字一致  
  2.                                                    0,  
  3.                                            NULL,  
  4.                                                    0,  
  5.                                                    NULL,  
  6.                                                    &port );//R0端口  
  7.   
  8.   
  9. //处理从R0来的请求,即R0调用FltSendMessage的请求  
  10. completion = CreateIoCompletionPort( port,NULL,0,1);  
  11. FilterGetMessage( Port,  
  12.             &message->MessageHeader,  
  13.             FIELD_OFFSET( SANDBOX_MESSAGE, Ovlp ),  
  14.             &message->Ovlp );  
  15. while(1)  
  16. {  
  17. GetQueuedCompletionStatus( lpContext->Completion, &outSize, &key, &pOvlp, INFINITE );  
  18. //过滤,扫描  
  19. FilterReplyMessage(Port,  
  20.             (PFILTER_REPLY_HEADER) &replyMessage,  
  21.             sizeof( replyMessage ) );  
  22. FilterGetMessage( Port,  
  23.             &message->MessageHeader,  
  24.             FIELD_OFFSET( SANDBOX_MESSAGE, Ovlp ),  
  25.             &message->Ovlp );  
  26. }  


注意:这里的FILTER_REPLY_HEADER结构,里面有一项是固定的,有一项是可以自定义的,包括增加自己的结构
同样的Message对应的结构里面有一项也是可以自定义的 ,这要跟内核对应起来就可以了,内核里面只有自定义的那一项

比如:R0数据结构 这个就是自定义的
[cpp]  view plain  copy
  1. typedef struct _SCANNER_NOTIFICATION   
  2. {  
  3.     ULONG BytesToScan;  
  4.     ULONG Reserved;   
  5.     UCHAR Contents[SCANNER_READ_BUFFER_SIZE];  
  6.       
  7. } SCANNER_NOTIFICATION, *PSCANNER_NOTIFICATION;  
  8.   
  9.   
  10. typedef struct _SCANNER_REPLY   
  11. {  
  12.     BOOLEAN SafeToOpen;  
  13.   
  14.   
  15. } SCANNER_REPLY, *PSCANNER_REPLY;  

R3的结构
[cpp]  view plain  copy
  1. typedef struct _SCANNER_MESSAGE   
  2. {  
  3.     FILTER_MESSAGE_HEADER MessageHeader;  
  4.     SCANNER_NOTIFICATION Notification;//可以自定义的 ,跟内核结构对应起来  
  5.     OVERLAPPED Ovlp;  
  6. } SCANNER_MESSAGE, *PSCANNER_MESSAGE;  
  7.   
  8.   
  9. typedef struct _SCANNER_REPLY_MESSAGE   
  10. {  
  11.     FILTER_REPLY_HEADER ReplyHeader;  
  12.     SCANNER_REPLY Reply;//可以自定义的,跟内核结构对应起来  
  13. } SCANNER_REPLY_MESSAGE,  
  14.   *PSCANNER_REPLY_MESSAGE;  

那R0怎么发送消息给R3呢
使用FltSendMessage
实例代码:
[cpp]  view plain  copy
  1. //发送消息给R3  
  2. timeout.QuadPart = (LONGLONG)40 * -10000000i64; // 内核等待 40 seconds  
  3. Status = FltSendMessage( g_pFilter,  
  4.             &g_pClientPort,//给R3发消息  
  5.             &request,  
  6.             sizeof(SCANNER_NOTIFICATION),  
  7.             &reply,  
  8.             &replySize,  
  9.             &timeout );  

主动通信就讲完了,不过需要注意的时,应用程序可能已经退出了,带sys还在,那要怎么办呢,
R3的程序退出时,R0中那个断开连接的回调就会触发,我们需要在那个回调中设置用户通信端口为NULL

其它过滤函数中需要判断这个是不是NULL 不是NULL就通信,是NULL就放行


什么是R3通信端口?

其实这个是一个R3端口的句柄,当用户使用FilterConnectCommunicationPort建立连接时,
内核中那个连接函数就会被调用,在那里面就有用户的通信端口(句柄)(不记得了?往上拉看看吧,我们还在那里面设置本进程的ID呢)


说完了主动通信,我们来说说缓冲区的使用
比如写操作,写的数据可能在MDLbuff中,也可能在USERbuff中,那要怎么操作呢,我记得上面提到过
判断MDLbuff是不是为空,不为空则数据就在这个里面,否则就是userbuff中


注意这里需要使用异常处理结构块,主流程使用tyr and finally 内存操作使用try and except( EXCEPTION_EXECUTE_HANDLER )


这里还介绍了上下文的使用 只不过这里是很简单的处理了下
首先在CreatePre事前回调中,我们设置上下文,然后再后面操作中,我们获取这个上下文,如果获取不到就不是我们要操作的文件
这里其实没啥用,只是演示如果使用上下文,当然这里的上下文结构里面可以自定义,我这里是设置了需要不需要重新扫描


[cpp]  view plain  copy
  1. typedef struct _SCANNER_STREAM_HANDLE_CONTEXT {  
  2.   
  3.   
  4.     BOOLEAN RescanRequired;  
  5.       
  6. } SCANNER_STREAM_HANDLE_CONTEXT, *PSCANNER_STREAM_HANDLE_CONTEXT;  


代码例子:内核处理写操作 需要注意的事,有一个IRP是FLT管理器发的,有点特殊,需要放过,见代码尾巴
[cpp]  view plain  copy
  1. //处理写关闭  
  2. FLT_PREOP_CALLBACK_STATUS  
  3. ScannerPreWrite (  
  4.     __inout PFLT_CALLBACK_DATA Data,  
  5.     __in PCFLT_RELATED_OBJECTS FltObjects,  
  6.     __deref_out_opt PVOID *CompletionContext  
  7.     )  
  8. /*++ 
  9.  
  10.  
  11. Routine Description: 
  12.  
  13.  
  14.     Pre write callback.  We want to scan what's being written now. 
  15.  
  16.  
  17. Arguments: 
  18.  
  19.  
  20.     Data - The structure which describes the operation parameters. 
  21.  
  22.  
  23.     FltObject - The structure which describes the objects affected by this 
  24.         operation. 
  25.  
  26.  
  27.     CompletionContext - Output parameter which can be used to pass a context 
  28.         from this pre-write callback to the post-write callback. 
  29.  
  30.  
  31. Return Value: 
  32.  
  33.  
  34.     Always FLT_PREOP_SUCCESS_NO_CALLBACK. 
  35.  
  36.  
  37. --*/  
  38. {  
  39.     FLT_PREOP_CALLBACK_STATUS returnStatus = FLT_PREOP_SUCCESS_NO_CALLBACK;  
  40.     NTSTATUS status;  
  41.     PSCANNER_NOTIFICATION notification = NULL;  
  42.     PSCANNER_STREAM_HANDLE_CONTEXT context = NULL;  
  43.     ULONG replyLength;  
  44.     BOOLEAN safe = TRUE;  
  45.     PUCHAR buffer;  
  46.   
  47.   
  48.     UNREFERENCED_PARAMETER( CompletionContext );  
  49.   
  50.   
  51.     //  
  52.     //  If not client port just ignore this write.  
  53.     //  
  54.     //如果R3进程退出了  
  55.     if (ScannerData.ClientPort == NULL) {  
  56.   
  57.   
  58.         return FLT_PREOP_SUCCESS_NO_CALLBACK;  
  59.     }  
  60.     //获取上下文  
  61.     status = FltGetStreamHandleContext( FltObjects->Instance,  
  62.                                         FltObjects->FileObject,  
  63.                                         &context );  
  64.     //不是我们要处理的文件,(可以在创建事前回调中设置上下文,比如判断这个文件是不是记事本,如果是,我们就给它设置一个上下文,然后到后我们就可以知道这个文件是不是我们设置过的记事本)  
  65.     //这也可以判断,不过一般不这么使用,一般是在上下文中插入自己想要信息,然后到这里我们到这个上下文中去取  
  66.     if (!NT_SUCCESS( status )) {  
  67.   
  68.   
  69.         //  
  70.         //  We are not interested in this file  
  71.         //  
  72.   
  73.   
  74.         return FLT_PREOP_SUCCESS_NO_CALLBACK;  
  75.   
  76.   
  77.     }  
  78.   
  79.   
  80.     //  
  81.     //  Use try-finally to cleanup  
  82.     //  
  83.   
  84.   
  85.     //必须使用异常处理结构  
  86.     try {  
  87.   
  88.   
  89.         //  
  90.         //  Pass the contents of the buffer to user mode.  
  91.         //  
  92.         //如果写的长度为0 就放行  
  93.         if (Data->Iopb->Parameters.Write.Length != 0) {  
  94.   
  95.   
  96.             //  
  97.             //  Get the users buffer address.  If there is a MDL defined, use  
  98.             //  it.  If not use the given buffer address.  
  99.             //  
  100.             //开始获取数据缓存区 有2个缓存区,需要判断在数据在哪个buff中 判断的方法前面说过了  
  101.             if (Data->Iopb->Parameters.Write.MdlAddress != NULL) {  
  102.   
  103.   
  104.                 buffer = MmGetSystemAddressForMdlSafe( Data->Iopb->Parameters.Write.MdlAddress,  
  105.                                                        NormalPagePriority );  
  106.   
  107.   
  108.                 //  
  109.                 //  If we have a MDL but could not get and address, we ran out  
  110.                 //  of memory, report the correct error  
  111.                 //  
  112.                 //如果获取失败了 就返回资源不足 并不下发了  
  113.                 if (buffer == NULL) {  
  114.   
  115.   
  116.                     Data->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;  
  117.                     Data->IoStatus.Information = 0;  
  118.                     returnStatus = FLT_PREOP_COMPLETE;  
  119.                     leave;  
  120.                 }  
  121.   
  122.   
  123.             } else {  
  124.   
  125.   
  126.                 //  
  127.                 //  Use the users buffer  
  128.                 //  
  129.                 //不是MDL就是USERbuff  
  130.                 buffer  = Data->Iopb->Parameters.Write.WriteBuffer;  
  131.             }  
  132.   
  133.   
  134.             //  
  135.             //  In a production-level filter, we would actually let user mode scan the file directly.  
  136.             //  Allocating & freeing huge amounts of non-paged pool like this is not very good for system perf.  
  137.             //  This is just a sample!  
  138.             //  
  139.             //为发送给R3数据申请内存  
  140.             notification = ExAllocatePoolWithTag( NonPagedPool,  
  141.                                                   sizeof( SCANNER_NOTIFICATION ),  
  142.                                                   'nacS' );  
  143.             if (notification == NULL) {  
  144.   
  145.   
  146.                 Data->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;  
  147.                 Data->IoStatus.Information = 0;  
  148.                 returnStatus = FLT_PREOP_COMPLETE;  
  149.                 leave;  
  150.             }  
  151.             //取最小啦 这里设置SCANNER_READ_BUFFER_SIZE为1024  
  152.             notification->BytesToScan = min( Data->Iopb->Parameters.Write.Length, SCANNER_READ_BUFFER_SIZE );  
  153.   
  154.   
  155.             //  
  156.             //  The buffer can be a raw user buffer. Protect access to it  
  157.             //  
  158.             //内存操作 必须使用结构化异常处理  
  159.             try  {  
  160.   
  161.   
  162.                 RtlCopyMemory( ¬ification->Contents,  
  163.                                buffer,  
  164.                                notification->BytesToScan );  
  165.   
  166.   
  167.             } except( EXCEPTION_EXECUTE_HANDLER ) {  
  168.   
  169.   
  170.                 //  
  171.                 //  Error accessing buffer. Complete i/o with failure  
  172.                 //  
  173.                 //出错就返回错误代码并阻止下发啦  
  174.                 Data->IoStatus.Status = GetExceptionCode() ;  
  175.                 Data->IoStatus.Information = 0;  
  176.                 returnStatus = FLT_PREOP_COMPLETE;  
  177.                 leave;  
  178.             }  
  179.   
  180.   
  181.             //  
  182.             //  Send message to user mode to indicate it should scan the buffer.  
  183.             //  We don't have to synchronize between the send and close of the handle  
  184.             //  as FltSendMessage takes care of that.  
  185.             //  
  186.             //发送数据给R3 处理  
  187.             replyLength = sizeof( SCANNER_REPLY );  
  188.   
  189.   
  190.             status = FltSendMessage( ScannerData.Filter,  
  191.                                      &ScannerData.ClientPort,  
  192.                                      notification,  
  193.                                      sizeof( SCANNER_NOTIFICATION ),  
  194.                                      notification,  
  195.                                      &replyLength,  
  196.                                      NULL );//永远等待,一般40秒吧  
  197.             //为什么共用一块内存呢 你猜  
  198.             if (STATUS_SUCCESS == status) {  
  199.                 //用户返回的处理结果  
  200.                safe = ((PSCANNER_REPLY) notification)->SafeToOpen;  
  201.   
  202.   
  203.            } else {  
  204.   
  205.   
  206.                //  
  207.                //  Couldn't send message. This sample will let the i/o through.  
  208.                //  
  209.   
  210.   
  211.                DbgPrint( "!!! scanner.sys --- couldn't send message to user-mode to scan file, status 0x%X\n", status );  
  212.            }  
  213.         }  
  214.         //这个是不安全的 你猜怎么办?  
  215.         if (!safe) {  
  216.   
  217.   
  218.             //  
  219.             //  Block this write if not paging i/o (as a result of course, this scanner will not prevent memory mapped writes of contaminated  
  220.             //  strings to the file, but only regular writes). The effect of getting ERROR_ACCESS_DENIED for many apps to delete the file they  
  221.             //  are trying to write usually.  
  222.             //  To handle memory mapped writes - we should be scanning at close time (which is when we can really establish that the file object  
  223.             //  is not going to be used for any more writes)  
  224.             //  
  225.   
  226.   
  227.             DbgPrint( "!!! scanner.sys -- foul language detected in write !!!\n" );  
  228.   
  229.   
  230.             //如果不是Flt管理发送的,这个IRP很特殊 ,必须放行,如果不是这个IRP就阻止了,因为它是不安全的  
  231.             if (!FlagOn( Data->Iopb->IrpFlags, IRP_PAGING_IO )) {  
  232.   
  233.   
  234.                 DbgPrint( "!!! scanner.sys -- blocking the write !!!\n" );  
  235.   
  236.   
  237.                 Data->IoStatus.Status = STATUS_ACCESS_DENIED;  
  238.                 Data->IoStatus.Information = 0;  
  239.                 returnStatus = FLT_PREOP_COMPLETE;  
  240.             }  
  241.         }  
  242.   
  243.   
  244.     } finally {  
  245.         //该释放的释放  
  246.         if (notification != NULL) {  
  247.   
  248.   
  249.             ExFreePoolWithTag( notification, 'nacS' );  
  250.         }  
  251.   
  252.   
  253.         if (context) {  
  254.   
  255.   
  256.             FltReleaseContext( context );  
  257.         }  
  258.     }  
  259.   
  260.   
  261.     return returnStatus;  
  262. }  


MF实现的一个封转的处理函数,这个函数可以将文件的内容发给R3,让R3处理并返回一个结果

为什么需要这个函数呢?

如果不是写,我们不能直接缓存区数据,那么我们需要读到这个文件的内容发给R3,这个函数就是这个功能


代码:其中包括了Minifilter读文件操作
其实注意的是申请的大小,我们是不知道这个文件到底有多大的,但我们确定的是这个文件一般比这个卷的大小小,所以我们暂时先申请卷的大小
然后下面读的时候会返回文件的大小,到时候就可以知道有多大了


[cpp]  view plain  copy
  1. NTSTATUS  
  2. ScannerpScanFileInUserMode (  
  3.     __in PFLT_INSTANCE Instance,  
  4.     __in PFILE_OBJECT FileObject,  
  5.     __out PBOOLEAN SafeToOpen  
  6.     )  
  7. /*++ 
  8.  
  9.  
  10. Routine Description: 
  11.  
  12.  
  13.     This routine is called to send a request up to user mode to scan a given 
  14.     file and tell our caller whether it's safe to open this file. 
  15.  
  16.  
  17.     Note that if the scan fails, we set SafeToOpen to TRUE.  The scan may fail 
  18.     because the service hasn't started, or perhaps because this create/cleanup 
  19.     is for a directory, and there's no data to read & scan. 
  20.  
  21.  
  22.     If we failed creates when the service isn't running, there'd be a 
  23.     bootstrapping problem -- how would we ever load the .exe for the service? 
  24.  
  25.  
  26. Arguments: 
  27.  
  28.  
  29.     Instance - Handle to the filter instance for the scanner on this volume. 
  30.  
  31.  
  32.     FileObject - File to be scanned. 
  33.  
  34.  
  35.     SafeToOpen - Set to FALSE if the file is scanned successfully and it contains 
  36.                  foul language. 
  37.  
  38.  
  39. Return Value: 
  40.  
  41.  
  42.     The status of the operation, hopefully STATUS_SUCCESS.  The common failure 
  43.     status will probably be STATUS_INSUFFICIENT_RESOURCES. 
  44.  
  45.  
  46. --*/  
  47.   
  48.   
  49. {  
  50.     NTSTATUS status = STATUS_SUCCESS;  
  51.     PVOID buffer = NULL;  
  52.     ULONG bytesRead;  
  53.     PSCANNER_NOTIFICATION notification = NULL;  
  54.     FLT_VOLUME_PROPERTIES volumeProps;  
  55.     LARGE_INTEGER offset;  
  56.     ULONG replyLength, length;  
  57.     PFLT_VOLUME volume = NULL;  
  58.   
  59.   
  60.     *SafeToOpen = TRUE;  
  61.   
  62.   
  63.     //  
  64.     //  If not client port just return.  
  65.     //  
  66.   
  67.   
  68.     if (ScannerData.ClientPort == NULL) {  
  69.   
  70.   
  71.         return STATUS_SUCCESS;  
  72.     }  
  73.   
  74.   
  75.     try {  
  76.   
  77.   
  78.         //  
  79.         //  Obtain the volume object .  
  80.         //  
  81.   
  82.   
  83.         status = FltGetVolumeFromInstance( Instance, &volume );  
  84.   
  85.   
  86.         if (!NT_SUCCESS( status )) {  
  87.   
  88.   
  89.             leave;  
  90.         }  
  91.   
  92.   
  93.         //  
  94.         //  Determine sector size. Noncached I/O can only be done at sector size offsets, and in lengths which are  
  95.         //  multiples of sector size. A more efficient way is to make this call once and remember the sector size in the  
  96.         //  instance setup routine and setup an instance context where we can cache it.  
  97.         //  
  98.   
  99.   
  100.         status = FltGetVolumeProperties( volume,  
  101.                                          &volumeProps,  
  102.                                          sizeof( volumeProps ),  
  103.                                          &length );  
  104.         //  
  105.         //  STATUS_BUFFER_OVERFLOW can be returned - however we only need the properties, not the names  
  106.         //  hence we only check for error status.  
  107.         //  
  108.   
  109.   
  110.         if (NT_ERROR( status )) {  
  111.   
  112.   
  113.             leave;  
  114.         }  
  115.   
  116.   
  117.         length = max( SCANNER_READ_BUFFER_SIZE, volumeProps.SectorSize );  
  118.   
  119.   
  120.         //  
  121.         //  Use non-buffered i/o, so allocate aligned pool  
  122.         //  
  123.   
  124.   
  125.         buffer = FltAllocatePoolAlignedWithTag( Instance,  
  126.                                                 NonPagedPool,  
  127.                                                 length,  
  128.                                                 'nacS' );  
  129.   
  130.   
  131.         if (NULL == buffer) {  
  132.   
  133.   
  134.             status = STATUS_INSUFFICIENT_RESOURCES;  
  135.             leave;  
  136.         }  
  137.   
  138.   
  139.         notification = ExAllocatePoolWithTag( NonPagedPool,  
  140.                                               sizeof( SCANNER_NOTIFICATION ),  
  141.                                               'nacS' );  
  142.   
  143.   
  144.         if(NULL == notification) {  
  145.   
  146.   
  147.             status = STATUS_INSUFFICIENT_RESOURCES;  
  148.             leave;  
  149.         }  
  150.   
  151.   
  152.         //  
  153.         //  Read the beginning of the file and pass the contents to user mode.  
  154.         //  
  155.   
  156.   
  157.         offset.QuadPart = bytesRead = 0;  
  158.         status = FltReadFile( Instance,  
  159.                               FileObject,  
  160.                               &offset,  
  161.                               length,  
  162.                               buffer,  
  163.                               FLTFL_IO_OPERATION_NON_CACHED |  
  164.                                FLTFL_IO_OPERATION_DO_NOT_UPDATE_BYTE_OFFSET,  
  165.                               &bytesRead,  
  166.                               NULL,  
  167.                               NULL );  
  168.   
  169.   
  170.         if (NT_SUCCESS( status ) && (0 != bytesRead)) {  
  171.   
  172.   
  173.             notification->BytesToScan = (ULONG) bytesRead;  
  174.   
  175.   
  176.             //  
  177.             //  Copy only as much as the buffer can hold  
  178.             //  
  179.   
  180.   
  181.             RtlCopyMemory( ¬ification->Contents,  
  182.                            buffer,  
  183.                            min( notification->BytesToScan, SCANNER_READ_BUFFER_SIZE ) );  
  184.   
  185.   
  186.             replyLength = sizeof( SCANNER_REPLY );  
  187.   
  188.   
  189.             status = FltSendMessage( ScannerData.Filter,  
  190.                                      &ScannerData.ClientPort,  
  191.                                      notification,  
  192.                                      sizeof(SCANNER_NOTIFICATION),  
  193.                                      notification,  
  194.                                      &replyLength,  
  195.                                      NULL );  
  196.   
  197.   
  198.             if (STATUS_SUCCESS == status) {  
  199.   
  200.   
  201.                 *SafeToOpen = ((PSCANNER_REPLY) notification)->SafeToOpen;  
  202.   
  203.   
  204.             } else {  
  205.   
  206.   
  207.                 //  
  208.                 //  Couldn't send message  
  209.                 //  
  210.   
  211.   
  212.                 DbgPrint( "!!! scanner.sys --- couldn't send message to user-mode to scan file, status 0x%X\n", status );  
  213.             }  
  214.         }  
  215.   
  216.   
  217.     } finally {  
  218.   
  219.   
  220.         if (NULL != buffer) {  
  221.   
  222.   
  223.             FltFreePoolAlignedWithTag( Instance, buffer, 'nacS' );  
  224.         }  
  225.   
  226.   
  227.         if (NULL != notification) {  
  228.   
  229.   
  230.             ExFreePoolWithTag( notification, 'nacS' );  
  231.         }  
  232.   
  233.   
  234.         if (NULL != volume) {  
  235.   
  236.   
  237.             FltObjectDereference( volume );  
  238.         }  
  239.     }  
  240.   
  241.   
  242.     return status;  
  243. }  



思考:传BUFF给R3干什么?
解答:你猜


说一说一种比较特殊的情况
一个文件已写权限打开(创建)了,刚开始我们扫描过它没有问题
问:一个人现在是好人,那么他一辈子都是好人吗?


所以,我们需要会他设置一个上下文,上下文中有一个标志,改标志的作用是告诉Close时在扫描一次
其实这就是介绍上下文使用啦
核心代码:在创建事后回调中(别以为事后回调没有控制权了,它还是可以返回取消前面的操作哦 见最后面的代码)


[cpp]  view plain  copy
  1. //前面是扫描过这个文件了而且这个文件是安全的,但它有写权限,那么就要注意了  
  2. if (FltObjects->FileObject->WriteAccess) {  
  3.   
  4.   
  5.         //  
  6.         //  
  7.         //  The create has requested write access, mark to rescan the file.  
  8.         //  Allocate the context.  
  9.         //  
  10.   
  11.   
  12.         status = FltAllocateContext( ScannerData.Filter,  
  13.                                      FLT_STREAMHANDLE_CONTEXT,  
  14.                                      sizeof(SCANNER_STREAM_HANDLE_CONTEXT),  
  15.                                      PagedPool,  
  16.                                      &scannerContext );  
  17.   
  18.   
  19.         if (NT_SUCCESS(status)) {  
  20.   
  21.   
  22.             //  
  23.             //  Set the handle context.  
  24.             //  
  25.   
  26.   
  27.             scannerContext->RescanRequired = TRUE;  
  28.   
  29.   
  30.             (VOID) FltSetStreamHandleContext( FltObjects->Instance,  
  31.                                               FltObjects->FileObject,  
  32.                                               FLT_SET_CONTEXT_REPLACE_IF_EXISTS,  
  33.                                               scannerContext,  
  34.                                               NULL );  
  35.   
  36.   
  37.             //  
  38.             //  Normally we would check the results of FltSetStreamHandleContext  
  39.             //  for a variety of error cases. However, The only error status   
  40.             //  that could be returned, in this case, would tell us that  
  41.             //  contexts are not supported.  Even if we got this error,  
  42.             //  we just want to release the context now and that will free  
  43.             //  this memory if it was not successfully set.  
  44.             //  
  45.   
  46.   
  47.             //  
  48.             //  Release our reference on the context (the set adds a reference)  
  49.             //  
  50.   
  51.   
  52.             FltReleaseContext( scannerContext );  
  53.         }  


然后再close的时候我们处理
这里说一说cleanup和closeup有什么区别,前者是使用zwclose或者closehandle 后者使用Obdef (忘记了对象计数减1的那个)


[cpp]  view plain  copy
  1. //处理打开时 有写权限但 打开成功时是安全的,等它关闭的时候的我们来扫描它  
  2. //触发这个回调的条件是文件引用技术为0,这个包括内核+R3的计数,一般是在上层使用了ZwClose或者CloseHandle时调用  
  3. FLT_PREOP_CALLBACK_STATUS  
  4. ScannerPreCleanup (  
  5.     __inout PFLT_CALLBACK_DATA Data,  
  6.     __in PCFLT_RELATED_OBJECTS FltObjects,  
  7.     __deref_out_opt PVOID *CompletionContext  
  8.     )  
  9. /*++ 
  10.  
  11.  
  12. Routine Description: 
  13.  
  14.  
  15.     Pre cleanup callback.  If this file was opened for write access, we want 
  16.     to rescan it now. 
  17.  
  18.  
  19. Arguments: 
  20.  
  21.  
  22.     Data - The structure which describes the operation parameters. 
  23.  
  24.  
  25.     FltObject - The structure which describes the objects affected by this 
  26.         operation. 
  27.  
  28.  
  29.     CompletionContext - Output parameter which can be used to pass a context 
  30.         from this pre-cleanup callback to the post-cleanup callback. 
  31.  
  32.  
  33. Return Value: 
  34.  
  35.  
  36.     Always FLT_PREOP_SUCCESS_NO_CALLBACK. 
  37.  
  38.  
  39. --*/  
  40. {  
  41.     NTSTATUS status;  
  42.     PSCANNER_STREAM_HANDLE_CONTEXT context;  
  43.     BOOLEAN safe;  
  44.   
  45.   
  46.     UNREFERENCED_PARAMETER( Data );  
  47.     UNREFERENCED_PARAMETER( CompletionContext );  
  48.   
  49.   
  50.     status = FltGetStreamHandleContext( FltObjects->Instance,  
  51.                                         FltObjects->FileObject,  
  52.                                         &context );  
  53.   
  54.   
  55.     if (NT_SUCCESS( status )) {  
  56.   
  57.   
  58.         if (context->RescanRequired) {  
  59.   
  60.   
  61.             (VOID) ScannerpScanFileInUserMode( FltObjects->Instance,  
  62.                                                FltObjects->FileObject,  
  63.                                                &safe );  
  64.   
  65.   
  66.             if (!safe) {  
  67.   
  68.   
  69.                 DbgPrint( "!!! scanner.sys -- foul language detected in precleanup !!!\n" );  
  70.             }  
  71.         }  
  72.   
  73.   
  74.         FltReleaseContext( context );  
  75.     }  
  76.   
  77.   
  78.   
  79.   
  80.     return FLT_PREOP_SUCCESS_NO_CALLBACK;  
  81. }  


例子:这个例子拦截后缀为txt的文件,如果txt中的内容有foul就被认定为病毒
这个例子演示了


通信方式(HIPS)
上下文的使用
文件名的获得
缓冲的使用



共有头文件
scannuk.h

[cpp]  view plain  copy
  1. /*++ 
  2.  
  3.  
  4. Copyright (c) 1999-2002  Microsoft Corporation 
  5.  
  6.  
  7. Module Name: 
  8.  
  9.  
  10.     scanuk.h 
  11.  
  12.  
  13. Abstract: 
  14.  
  15.  
  16.     Header file which contains the structures, type definitions, 
  17.     constants, global variables and function prototypes that are 
  18.     shared between kernel and user mode. 
  19.  
  20.  
  21. Environment: 
  22.  
  23.  
  24.     Kernel & user mode 
  25.  
  26.  
  27. --*/  
  28.   
  29.   
  30. #ifndef __SCANUK_H__  
  31. #define __SCANUK_H__  
  32.   
  33.   
  34. //  
  35. //  Name of port used to communicate  
  36. //  
  37.   
  38.   
  39. const PWSTR ScannerPortName = L"\\ScannerPort";  
  40.   
  41.   
  42.   
  43.   
  44. #define SCANNER_READ_BUFFER_SIZE   1024  
  45.   
  46.   
  47. typedef struct _SCANNER_NOTIFICATION {  
  48.   
  49.   
  50.     ULONG BytesToScan;  
  51.     ULONG Reserved;             // for quad-word alignement of the Contents structure  
  52.     UCHAR Contents[SCANNER_READ_BUFFER_SIZE];  
  53.       
  54. } SCANNER_NOTIFICATION, *PSCANNER_NOTIFICATION;  
  55.   
  56.   
  57. typedef struct _SCANNER_REPLY {  
  58.   
  59.   
  60.     BOOLEAN SafeToOpen;  
  61.       
  62. } SCANNER_REPLY, *PSCANNER_REPLY;  
  63.   
  64.   
  65. #endif //  __SCANUK_H__  


内核.h文件

[cpp]  view plain  copy
  1. /*++ 
  2.  
  3.  
  4. Copyright (c) 1999-2002  Microsoft Corporation 
  5.  
  6.  
  7. Module Name: 
  8.  
  9.  
  10.     scrubber.h 
  11.  
  12.  
  13. Abstract: 
  14.     Header file which contains the structures, type definitions, 
  15.     constants, global variables and function prototypes that are 
  16.     only visible within the kernel. 
  17.  
  18.  
  19. Environment: 
  20.  
  21.  
  22.     Kernel mode 
  23.  
  24.  
  25. --*/  
  26. #ifndef __SCANNER_H__  
  27. #define __SCANNER_H__  
  28.   
  29.   
  30.   
  31.   
  32. ///////////////////////////////////////////////////////////////////////////  
  33. //  
  34. //  Global variables  
  35. //  
  36. ///////////////////////////////////////////////////////////////////////////  
  37.   
  38.   
  39.   
  40.   
  41. typedef struct _SCANNER_DATA {  
  42.   
  43.   
  44.     //  
  45.     //  The object that identifies this driver.  
  46.     //  
  47.   
  48.   
  49.     PDRIVER_OBJECT DriverObject;  
  50.   
  51.   
  52.     //  
  53.     //  The filter handle that results from a call to  
  54.     //  FltRegisterFilter.  
  55.     //  
  56.   
  57.   
  58.     PFLT_FILTER Filter;  
  59.   
  60.   
  61.     //  
  62.     //  Listens for incoming connections  
  63.     //  
  64.   
  65.   
  66.     PFLT_PORT ServerPort;  
  67.   
  68.   
  69.     //  
  70.     //  User process that connected to the port  
  71.     //  
  72.   
  73.   
  74.     PEPROCESS UserProcess;  
  75.   
  76.   
  77.     //  
  78.     //  Client port for a connection to user-mode  
  79.     //  
  80.   
  81.   
  82.     PFLT_PORT ClientPort;  
  83.   
  84.   
  85. } SCANNER_DATA, *PSCANNER_DATA;  
  86.   
  87.   
  88. extern SCANNER_DATA ScannerData;  
  89.   
  90.   
  91. typedef struct _SCANNER_STREAM_HANDLE_CONTEXT {  
  92.   
  93.   
  94.     BOOLEAN RescanRequired;  
  95.       
  96. } SCANNER_STREAM_HANDLE_CONTEXT, *PSCANNER_STREAM_HANDLE_CONTEXT;  
  97.   
  98.   
  99. #pragma warning(push)  
  100. #pragma warning(disable:4200) // disable warnings for structures with zero length arrays.  
  101.   
  102.   
  103. typedef struct _SCANNER_CREATE_PARAMS {  
  104.   
  105.   
  106.     WCHAR String[0];  
  107.   
  108.   
  109. } SCANNER_CREATE_PARAMS, *PSCANNER_CREATE_PARAMS;  
  110.   
  111.   
  112. #pragma warning(pop)  
  113.   
  114.   
  115.   
  116.   
  117. ///////////////////////////////////////////////////////////////////////////  
  118. //  
  119. //  Prototypes for the startup and unload routines used for   
  120. //  this Filter.  
  121. //  
  122. //  Implementation in scanner.c  
  123. //  
  124. ///////////////////////////////////////////////////////////////////////////  
  125. DRIVER_INITIALIZE DriverEntry;  
  126. NTSTATUS  
  127. DriverEntry (  
  128.     __in PDRIVER_OBJECT DriverObject,  
  129.     __in PUNICODE_STRING RegistryPath  
  130.     );  
  131.   
  132.   
  133. NTSTATUS  
  134. ScannerUnload (  
  135.     __in FLT_FILTER_UNLOAD_FLAGS Flags  
  136.     );  
  137.   
  138.   
  139. NTSTATUS  
  140. ScannerQueryTeardown (  
  141.     __in PCFLT_RELATED_OBJECTS FltObjects,  
  142.     __in FLT_INSTANCE_QUERY_TEARDOWN_FLAGS Flags  
  143.     );  
  144.   
  145.   
  146. FLT_PREOP_CALLBACK_STATUS  
  147. ScannerPreCreate (  
  148.     __inout PFLT_CALLBACK_DATA Data,  
  149.     __in PCFLT_RELATED_OBJECTS FltObjects,  
  150.     __deref_out_opt PVOID *CompletionContext  
  151.     );  
  152.   
  153.   
  154. FLT_POSTOP_CALLBACK_STATUS  
  155. ScannerPostCreate (  
  156.     __inout PFLT_CALLBACK_DATA Data,  
  157.     __in PCFLT_RELATED_OBJECTS FltObjects,  
  158.     __in_opt PVOID CompletionContext,  
  159.     __in FLT_POST_OPERATION_FLAGS Flags  
  160.     );  
  161.   
  162.   
  163. FLT_PREOP_CALLBACK_STATUS  
  164. ScannerPreCleanup (  
  165.     __inout PFLT_CALLBACK_DATA Data,  
  166.     __in PCFLT_RELATED_OBJECTS FltObjects,  
  167.     __deref_out_opt PVOID *CompletionContext  
  168.     );  
  169.   
  170.   
  171. FLT_PREOP_CALLBACK_STATUS  
  172. ScannerPreWrite (  
  173.     __inout PFLT_CALLBACK_DATA Data,  
  174.     __in PCFLT_RELATED_OBJECTS FltObjects,  
  175.     __deref_out_opt PVOID *CompletionContext  
  176.     );  
  177.   
  178.   
  179. NTSTATUS  
  180. ScannerInstanceSetup (  
  181.     __in PCFLT_RELATED_OBJECTS FltObjects,  
  182.     __in FLT_INSTANCE_SETUP_FLAGS Flags,  
  183.     __in DEVICE_TYPE VolumeDeviceType,  
  184.     __in FLT_FILESYSTEM_TYPE VolumeFilesystemType  
  185.     );  
  186.   
  187.   
  188.   
  189.   
  190. #endif /* __SCANNER_H__ */  



内核.c文件
[cpp]  view plain  copy
  1. /*++ 
  2.  
  3.  
  4. Copyright (c) 1999-2002  Microsoft Corporation 
  5.  
  6.  
  7. Module Name: 
  8.  
  9.  
  10.     scanner.c 
  11.  
  12.  
  13. Abstract: 
  14.  
  15.  
  16.     This is the main module of the scanner filter. 
  17.  
  18.  
  19.     This filter scans the data in a file before allowing an open to proceed.  This is similar 
  20.     to what virus checkers do. 
  21.  
  22.  
  23. Environment: 
  24.  
  25.  
  26.     Kernel mode 
  27.  
  28.  
  29. --*/  
  30.   
  31.   
  32. #include <fltKernel.h>  
  33. #include <dontuse.h>  
  34. #include <suppress.h>  
  35. #include "scanuk.h"  
  36. #include "scanner.h"  
  37.   
  38.   
  39. #pragma prefast(disable:__WARNING_ENCODE_MEMBER_FUNCTION_POINTER, "Not valid for kernel mode drivers")  
  40.   
  41.   
  42. //  
  43. //  Structure that contains all the global data structures  
  44. //  used throughout the scanner.  
  45. //  
  46.   
  47.   
  48. SCANNER_DATA ScannerData;  
  49.   
  50.   
  51. //  
  52. //  This is a static list of file name extensions files we are interested in scanning  
  53. //  
  54.   
  55.   
  56. const UNICODE_STRING ScannerExtensionsToScan[] =  
  57.     { RTL_CONSTANT_STRING( L"doc"),  
  58.       RTL_CONSTANT_STRING( L"txt"),  
  59.       RTL_CONSTANT_STRING( L"bat"),  
  60.       RTL_CONSTANT_STRING( L"cmd"),  
  61.       RTL_CONSTANT_STRING( L"inf"),  
  62.       /*RTL_CONSTANT_STRING( L"ini"),   Removed, to much usage*/  
  63.       {0, 0, NULL}  
  64.     };  
  65.   
  66.   
  67.   
  68.   
  69. //  
  70. //  Function prototypes  
  71. //  
  72.   
  73.   
  74. NTSTATUS  
  75. ScannerPortConnect (  
  76.     __in PFLT_PORT ClientPort,  
  77.     __in_opt PVOID ServerPortCookie,  
  78.     __in_bcount_opt(SizeOfContext) PVOID ConnectionContext,  
  79.     __in ULONG SizeOfContext,  
  80.     __deref_out_opt PVOID *ConnectionCookie  
  81.     );  
  82.   
  83.   
  84. VOID  
  85. ScannerPortDisconnect (  
  86.     __in_opt PVOID ConnectionCookie  
  87.     );  
  88.   
  89.   
  90. NTSTATUS  
  91. ScannerpScanFileInUserMode (  
  92.     __in PFLT_INSTANCE Instance,  
  93.     __in PFILE_OBJECT FileObject,  
  94.     __out PBOOLEAN SafeToOpen  
  95.     );  
  96.   
  97.   
  98. BOOLEAN  
  99. ScannerpCheckExtension (  
  100.     __in PUNICODE_STRING Extension  
  101.     );  
  102.   
  103.   
  104. //  
  105. //  Assign text sections for each routine.  
  106. //  
  107.   
  108.   
  109. #ifdef ALLOC_PRAGMA  
  110.     #pragma alloc_text(INIT, DriverEntry)  
  111.     #pragma alloc_text(PAGE, ScannerInstanceSetup)  
  112.     #pragma alloc_text(PAGE, ScannerPreCreate)  
  113.     #pragma alloc_text(PAGE, ScannerPortConnect)  
  114.     #pragma alloc_text(PAGE, ScannerPortDisconnect)  
  115. #endif  
  116.   
  117.   
  118.   
  119.   
  120. //  
  121. //  Constant FLT_REGISTRATION structure for our filter.  This  
  122. //  initializes the callback routines our filter wants to register  
  123. //  for.  This is only used to register with the filter manager  
  124. //  
  125.   
  126.   
  127. const FLT_OPERATION_REGISTRATION Callbacks[] = {  
  128.   
  129.   
  130.     { IRP_MJ_CREATE,  
  131.       0,  
  132.       ScannerPreCreate,  
  133.       ScannerPostCreate},  
  134.   
  135.   
  136.     { IRP_MJ_CLEANUP,  
  137.       0,  
  138.       ScannerPreCleanup,  
  139.       NULL},  
  140.   
  141.   
  142.     { IRP_MJ_WRITE,  
  143.       0,  
  144.       ScannerPreWrite,  
  145.       NULL},  
  146.   
  147.   
  148.     { IRP_MJ_OPERATION_END}  
  149. };  
  150.   
  151.   
  152.   
  153.   
  154. const FLT_CONTEXT_REGISTRATION ContextRegistration[] = {  
  155.   
  156.   
  157.     { FLT_STREAMHANDLE_CONTEXT,  
  158.       0,  
  159.       NULL,  
  160.       sizeof(SCANNER_STREAM_HANDLE_CONTEXT),  
  161.       'chBS' },  
  162.   
  163.   
  164.     { FLT_CONTEXT_END }  
  165. };  
  166.   
  167.   
  168. const FLT_REGISTRATION FilterRegistration = {  
  169.   
  170.   
  171.     sizeof( FLT_REGISTRATION ),         //  Size  
  172.     FLT_REGISTRATION_VERSION,           //  Version  
  173.     0,                                  //  Flags  
  174.     ContextRegistration,                //  Context Registration.  
  175.     Callbacks,                          //  Operation callbacks  
  176.     ScannerUnload,                      //  FilterUnload  
  177.     ScannerInstanceSetup,               //  InstanceSetup  
  178.     ScannerQueryTeardown,               //  InstanceQueryTeardown  
  179.     NULL,                               //  InstanceTeardownStart  
  180.     NULL,                               //  InstanceTeardownComplete  
  181.     NULL,                               //  GenerateFileName  
  182.     NULL,                               //  GenerateDestinationFileName  
  183.     NULL                                //  NormalizeNameComponent  
  184. };  
  185.   
  186.   
  187. ////////////////////////////////////////////////////////////////////////////  
  188. //  
  189. //    Filter initialization and unload routines.  
  190. //  
  191. ////////////////////////////////////////////////////////////////////////////  
  192.   
  193.   
  194. NTSTATUS  
  195. DriverEntry (  
  196.     __in PDRIVER_OBJECT DriverObject,  
  197.     __in PUNICODE_STRING RegistryPath  
  198.     )  
  199. /*++ 
  200.  
  201.  
  202. Routine Description: 
  203.  
  204.  
  205.     This is the initialization routine for the Filter driver.  This 
  206.     registers the Filter with the filter manager and initializes all 
  207.     its global data structures. 
  208.  
  209.  
  210. Arguments: 
  211.  
  212.  
  213.     DriverObject - Pointer to driver object created by the system to 
  214.         represent this driver. 
  215.  
  216.  
  217.     RegistryPath - Unicode string identifying where the parameters for this 
  218.         driver are located in the registry. 
  219.  
  220.  
  221. Return Value: 
  222.  
  223.  
  224.     Returns STATUS_SUCCESS. 
  225. --*/  
  226. {  
  227.     OBJECT_ATTRIBUTES oa;  
  228.     UNICODE_STRING uniString;  
  229.     PSECURITY_DESCRIPTOR sd;  
  230.     NTSTATUS status;  
  231.   
  232.   
  233.     UNREFERENCED_PARAMETER( RegistryPath );  
  234.   
  235.   
  236.     //  
  237.     //  Register with filter manager.  
  238.     //  
  239.   
  240.   
  241.     status = FltRegisterFilter( DriverObject,  
  242.                                 &FilterRegistration,  
  243.                                 &ScannerData.Filter );  
  244.   
  245.   
  246.   
  247.   
  248.     if (!NT_SUCCESS( status )) {  
  249.   
  250.   
  251.         return status;  
  252.     }  
  253.   
  254.   
  255.     //  
  256.     //  Create a communication port.  
  257.     //  
  258.   
  259.   
  260.     RtlInitUnicodeString( &uniString, ScannerPortName );  
  261.   
  262.   
  263.     //  
  264.     //  We secure the port so only ADMINs & SYSTEM can acecss it.  
  265.     //  
  266.     //设置通信端口权限 ,只有管理员和系统进程才能操作  
  267.     status = FltBuildDefaultSecurityDescriptor( &sd, FLT_PORT_ALL_ACCESS );  
  268.   
  269.   
  270.     if (NT_SUCCESS( status )) {  
  271.   
  272.   
  273.         InitializeObjectAttributes( &oa,  
  274.                                     &uniString,  
  275.                                     OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,  
  276.                                     NULL,  
  277.                                     sd );  
  278.   
  279.   
  280.         //创建通信端口,并设置对应的回调函数  
  281.         status = FltCreateCommunicationPort( ScannerData.Filter,  
  282.                                              &ScannerData.ServerPort,  
  283.                                              &oa,//设置的名字  
  284.                                              NULL,  
  285.                                              ScannerPortConnect,//当R3连接时回调 主要是记录R3的进程ID或EPROCESS以便放过本进程 还有记录R3的通信端口,给后面主动通信的时候用  
  286.                                              ScannerPortDisconnect,//当R3离线时回调 主要是关闭R3端口和设置R3的进程信息为NULL  
  287.                                              NULL,//处理R3主动函数 比如R3下新的规则,  
  288.                                              1 );//最后一个常为1  
  289.         //  
  290.         //  Free the security descriptor in all cases. It is not needed once  
  291.         //  the call to FltCreateCommunicationPort() is made.  
  292.         //  
  293.         //设置好后需要释放权限的设置  
  294.         FltFreeSecurityDescriptor( sd );  
  295.   
  296.   
  297.         if (NT_SUCCESS( status )) {  
  298.   
  299.   
  300.             //  
  301.             //  Start filtering I/O.  
  302.             //  
  303.             //开始过滤  
  304.             status = FltStartFiltering( ScannerData.Filter );  
  305.   
  306.   
  307.             if (NT_SUCCESS( status )) {  
  308.   
  309.   
  310.                 return STATUS_SUCCESS;  
  311.             }  
  312.             //失败就滚吧  
  313.             FltCloseCommunicationPort( ScannerData.ServerPort );  
  314.         }  
  315.     }  
  316.     //失败就滚吧  
  317.     FltUnregisterFilter( ScannerData.Filter );  
  318.   
  319.   
  320.     return status;  
  321. }  
  322.   
  323.   
  324.   
  325.   
  326. NTSTATUS  
  327. ScannerPortConnect (  
  328.     __in PFLT_PORT ClientPort,  
  329.     __in_opt PVOID ServerPortCookie,  
  330.     __in_bcount_opt(SizeOfContext) PVOID ConnectionContext,  
  331.     __in ULONG SizeOfContext,  
  332.     __deref_out_opt PVOID *ConnectionCookie  
  333.     )  
  334. /*++ 
  335.  
  336.  
  337. Routine Description 
  338.  
  339.  
  340.     This is called when user-mode connects to the server port - to establish a 
  341.     connection 
  342.  
  343.  
  344. Arguments 
  345.  
  346.  
  347.     ClientPort - This is the client connection port that will be used to 
  348.         send messages from the filter 
  349.  
  350.  
  351.     ServerPortCookie - The context associated with this port when the 
  352.         minifilter created this port. 
  353.  
  354.  
  355.     ConnectionContext - Context from entity connecting to this port (most likely 
  356.         your user mode service) 
  357.  
  358.  
  359.     SizeofContext - Size of ConnectionContext in bytes 
  360.  
  361.  
  362.     ConnectionCookie - Context to be passed to the port disconnect routine. 
  363.  
  364.  
  365. Return Value 
  366.  
  367.  
  368.     STATUS_SUCCESS - to accept the connection 
  369.  
  370.  
  371. --*/  
  372. {  
  373.     PAGED_CODE();  
  374.   
  375.   
  376.     UNREFERENCED_PARAMETER( ServerPortCookie );  
  377.     UNREFERENCED_PARAMETER( ConnectionContext );  
  378.     UNREFERENCED_PARAMETER( SizeOfContext);  
  379.     UNREFERENCED_PARAMETER( ConnectionCookie );  
  380.   
  381.   
  382.     ASSERT( ScannerData.ClientPort == NULL );  
  383.     ASSERT( ScannerData.UserProcess == NULL );  
  384.   
  385.   
  386.     //  
  387.     //  Set the user process and port.  
  388.     //  
  389.     //设置本身进程 和 R3的的通信端口 给后面判断和通信时使用  
  390.     ScannerData.UserProcess = PsGetCurrentProcess();  
  391.     ScannerData.ClientPort = ClientPort;  
  392.   
  393.   
  394.     DbgPrint( "!!! scanner.sys --- connected, port=0x%p\n", ClientPort );  
  395.   
  396.   
  397.     return STATUS_SUCCESS;  
  398. }  
  399.   
  400.   
  401.   
  402. VOID  
  403. ScannerPortDisconnect(  
  404.      __in_opt PVOID ConnectionCookie  
  405.      )  
  406. /*++ 
  407.  
  408.  
  409. Routine Description 
  410.  
  411.  
  412.     This is called when the connection is torn-down. We use it to close our 
  413.     handle to the connection 
  414.  
  415.  
  416. Arguments 
  417.  
  418.  
  419.     ConnectionCookie - Context from the port connect routine 
  420.  
  421.  
  422. Return value 
  423.  
  424.  
  425.     None 
  426.  
  427.  
  428. --*/  
  429. {  
  430.     UNREFERENCED_PARAMETER( ConnectionCookie );  
  431.   
  432.   
  433.     PAGED_CODE();  
  434.   
  435.   
  436.     DbgPrint( "!!! scanner.sys --- disconnected, port=0x%p\n", ScannerData.ClientPort );  
  437.   
  438.   
  439.     //  
  440.     //  Close our handle to the connection: note, since we limited max connections to 1,  
  441.     //  another connect will not be allowed until we return from the disconnect routine.  
  442.     //  
  443.   
  444.   
  445.     //关闭R3通信端口  
  446.     FltCloseClientPort( ScannerData.Filter, &ScannerData.ClientPort );  
  447.   
  448.   
  449.     //  
  450.     //  Reset the user-process field.  
  451.     //  
  452.   
  453.   
  454.     //设置R3进程为0  
  455.     ScannerData.UserProcess = NULL;  
  456. }  
  457.   
  458.   
  459.   
  460. NTSTATUS  
  461. ScannerUnload (  
  462.     __in FLT_FILTER_UNLOAD_FLAGS Flags  
  463.     )  
  464. /*++ 
  465.  
  466.  
  467. Routine Description: 
  468.  
  469.  
  470.     This is the unload routine for the Filter driver.  This unregisters the 
  471.     Filter with the filter manager and frees any allocated global data 
  472.     structures. 
  473.  
  474.  
  475. Arguments: 
  476.  
  477.  
  478.     None. 
  479.  
  480.  
  481. Return Value: 
  482.  
  483.  
  484.     Returns the final status of the deallocation routines. 
  485.  
  486.  
  487. --*/  
  488. {  
  489.     UNREFERENCED_PARAMETER( Flags );  
  490.   
  491.   
  492.     //  
  493.     //  Close the server port.  
  494.     //  
  495.   
  496.   
  497.     FltCloseCommunicationPort( ScannerData.ServerPort );  
  498.   
  499.   
  500.     //  
  501.     //  Unregister the filter  
  502.     //  
  503.   
  504.   
  505.     FltUnregisterFilter( ScannerData.Filter );  
  506.   
  507.   
  508.     return STATUS_SUCCESS;  
  509. }  
  510.   
  511.   
  512. NTSTATUS  
  513. ScannerInstanceSetup (  
  514.     __in PCFLT_RELATED_OBJECTS FltObjects,  
  515.     __in FLT_INSTANCE_SETUP_FLAGS Flags,  
  516.     __in DEVICE_TYPE VolumeDeviceType,  
  517.     __in FLT_FILESYSTEM_TYPE VolumeFilesystemType  
  518.     )  
  519. /*++ 
  520.  
  521.  
  522. Routine Description: 
  523.  
  524.  
  525.     This routine is called by the filter manager when a new instance is created. 
  526.     We specified in the registry that we only want for manual attachments, 
  527.     so that is all we should receive here. 
  528.  
  529.  
  530. Arguments: 
  531.  
  532.  
  533.     FltObjects - Describes the instance and volume which we are being asked to 
  534.         setup. 
  535.  
  536.  
  537.     Flags - Flags describing the type of attachment this is. 
  538.  
  539.  
  540.     VolumeDeviceType - The DEVICE_TYPE for the volume to which this instance 
  541.         will attach. 
  542.  
  543.  
  544.     VolumeFileSystemType - The file system formatted on this volume. 
  545.  
  546.  
  547. Return Value: 
  548.  
  549.  
  550.   FLT_NOTIFY_STATUS_ATTACH              - we wish to attach to the volume 
  551.   FLT_NOTIFY_STATUS_DO_NOT_ATTACH       - no, thank you 
  552.  
  553.  
  554. --*/  
  555. {  
  556.     UNREFERENCED_PARAMETER( FltObjects );  
  557.     UNREFERENCED_PARAMETER( Flags );  
  558.     UNREFERENCED_PARAMETER( VolumeFilesystemType );  
  559.   
  560.   
  561.     PAGED_CODE();  
  562.   
  563.   
  564.     ASSERT( FltObjects->Filter == ScannerData.Filter );  
  565.   
  566.   
  567.     //  
  568.     //  Don't attach to network volumes.  
  569.     //  
  570.   
  571.   
  572.     if (VolumeDeviceType == FILE_DEVICE_NETWORK_FILE_SYSTEM) {  
  573.   
  574.   
  575.        return STATUS_FLT_DO_NOT_ATTACH;  
  576.     }  
  577.   
  578.   
  579.     return STATUS_SUCCESS;  
  580. }  
  581.   
  582.   
  583. NTSTATUS  
  584. ScannerQueryTeardown (  
  585.     __in PCFLT_RELATED_OBJECTS FltObjects,  
  586.     __in FLT_INSTANCE_QUERY_TEARDOWN_FLAGS Flags  
  587.     )  
  588. /*++ 
  589.  
  590.  
  591. Routine Description: 
  592.  
  593.  
  594.     This is the instance detach routine for the filter. This 
  595.     routine is called by filter manager when a user initiates a manual instance 
  596.     detach. This is a 'query' routine: if the filter does not want to support 
  597.     manual detach, it can return a failure status 
  598.  
  599.  
  600. Arguments: 
  601.  
  602.  
  603.     FltObjects - Describes the instance and volume for which we are receiving 
  604.         this query teardown request. 
  605.  
  606.  
  607.     Flags - Unused 
  608.  
  609.  
  610. Return Value: 
  611.  
  612.  
  613.     STATUS_SUCCESS - we allow instance detach to happen 
  614.  
  615.  
  616. --*/  
  617. {  
  618.     UNREFERENCED_PARAMETER( FltObjects );  
  619.     UNREFERENCED_PARAMETER( Flags );  
  620.   
  621.   
  622.     return STATUS_SUCCESS;  
  623. }  
  624.   
  625.   
  626.   
  627.   
  628. FLT_PREOP_CALLBACK_STATUS  
  629. ScannerPreCreate (  
  630.     __inout PFLT_CALLBACK_DATA Data,  
  631.     __in PCFLT_RELATED_OBJECTS FltObjects,  
  632.     __deref_out_opt PVOID *CompletionContext  
  633.     )  
  634. /*++ 
  635.  
  636.  
  637. Routine Description: 
  638.  
  639.  
  640.     Pre create callback.  We need to remember whether this file has been 
  641.     opened for write access.  If it has, we'll want to rescan it in cleanup. 
  642.     This scheme results in extra scans in at least two cases: 
  643.     -- if the create fails (perhaps for access denied) 
  644.     -- the file is opened for write access but never actually written to 
  645.     The assumption is that writes are more common than creates, and checking 
  646.     or setting the context in the write path would be less efficient than 
  647.     taking a good guess before the create. 
  648.  
  649.  
  650. Arguments: 
  651.  
  652.  
  653.     Data - The structure which describes the operation parameters. 
  654.  
  655.  
  656.     FltObject - The structure which describes the objects affected by this 
  657.         operation. 
  658.  
  659.  
  660.     CompletionContext - Output parameter which can be used to pass a context 
  661.         from this pre-create callback to the post-create callback. 
  662.  
  663.  
  664. Return Value: 
  665.  
  666.  
  667.    FLT_PREOP_SUCCESS_WITH_CALLBACK - If this is not our user-mode process. 
  668.    FLT_PREOP_SUCCESS_NO_CALLBACK - All other threads. 
  669.  
  670.  
  671. --*/  
  672. {  
  673.     UNREFERENCED_PARAMETER( FltObjects );  
  674.     UNREFERENCED_PARAMETER( CompletionContext );  
  675.   
  676.   
  677.     PAGED_CODE();  
  678.   
  679.   
  680.     //  
  681.     //  See if this create is being done by our user process.  
  682.     //  
  683.   
  684.   
  685.     if (IoThreadToProcess( Data->Thread ) == ScannerData.UserProcess) {  
  686.   
  687.   
  688.         DbgPrint( "!!! scanner.sys -- allowing create for trusted process \n" );  
  689.   
  690.   
  691.         return FLT_PREOP_SUCCESS_NO_CALLBACK;  
  692.     }  
  693.   
  694.   
  695.     return FLT_PREOP_SUCCESS_WITH_CALLBACK;  
  696. }  
  697.   
  698.   
  699. BOOLEAN  
  700. ScannerpCheckExtension (  
  701.     __in PUNICODE_STRING Extension  
  702.     )  
  703. /*++ 
  704.  
  705.  
  706. Routine Description: 
  707.  
  708.  
  709.     Checks if this file name extension is something we are interested in 
  710.  
  711.  
  712. Arguments 
  713.  
  714.  
  715.     Extension - Pointer to the file name extension 
  716.  
  717.  
  718. Return Value 
  719.  
  720.  
  721.     TRUE - Yes we are interested 
  722.     FALSE - No 
  723. --*/  
  724. {  
  725.     const UNICODE_STRING *ext;  
  726.   
  727.   
  728.     if (Extension->Length == 0) {  
  729.   
  730.   
  731.         return FALSE;  
  732.     }  
  733.   
  734.   
  735.     //  
  736.     //  Check if it matches any one of our static extension list  
  737.     //  
  738.   
  739.   
  740.     ext = ScannerExtensionsToScan;  
  741.   
  742.   
  743.     while (ext->Buffer != NULL) {  
  744.   
  745.   
  746.         if (RtlCompareUnicodeString( Extension, ext, TRUE ) == 0) {  
  747.   
  748.   
  749.             //  
  750.             //  A match. We are interested in this file  
  751.             //  
  752.   
  753.   
  754.             return TRUE;  
  755.         }  
  756.         ext++;  
  757.     }  
  758.   
  759.   
  760.     return FALSE;  
  761. }  
  762.   
  763.   
  764. //处理打开,创建时(一般这个时候提示的话就是已经被感染了)  
  765. FLT_POSTOP_CALLBACK_STATUS  
  766. ScannerPostCreate (  
  767.     __inout PFLT_CALLBACK_DATA Data,  
  768.     __in PCFLT_RELATED_OBJECTS FltObjects,  
  769.     __in_opt PVOID CompletionContext,  
  770.     __in FLT_POST_OPERATION_FLAGS Flags  
  771.     )  
  772. /*++ 
  773.  
  774.  
  775. Routine Description: 
  776.  
  777.  
  778.     Post create callback.  We can't scan the file until after the create has 
  779.     gone to the filesystem, since otherwise the filesystem wouldn't be ready 
  780.     to read the file for us. 
  781.  
  782.  
  783. Arguments: 
  784.  
  785.  
  786.     Data - The structure which describes the operation parameters. 
  787.  
  788.  
  789.     FltObject - The structure which describes the objects affected by this 
  790.         operation. 
  791.  
  792.  
  793.     CompletionContext - The operation context passed fron the pre-create 
  794.         callback. 
  795.  
  796.  
  797.     Flags - Flags to say why we are getting this post-operation callback. 
  798.  
  799.  
  800. Return Value: 
  801.  
  802.  
  803.     FLT_POSTOP_FINISHED_PROCESSING - ok to open the file or we wish to deny 
  804.                                      access to this file, hence undo the open 
  805.  
  806.  
  807. --*/  
  808. {  
  809.     PSCANNER_STREAM_HANDLE_CONTEXT scannerContext;  
  810.     FLT_POSTOP_CALLBACK_STATUS returnStatus = FLT_POSTOP_FINISHED_PROCESSING;  
  811.     PFLT_FILE_NAME_INFORMATION nameInfo;  
  812.     NTSTATUS status;  
  813.     BOOLEAN safeToOpen, scanFile;  
  814.   
  815.   
  816.     UNREFERENCED_PARAMETER( CompletionContext );  
  817.     UNREFERENCED_PARAMETER( Flags );  
  818.   
  819.   
  820.     //  
  821.     //  If this create was failing anyway, don't bother scanning now.  
  822.     //  
  823.   
  824.   
  825.     if (!NT_SUCCESS( Data->IoStatus.Status ) ||  
  826.         (STATUS_REPARSE == Data->IoStatus.Status)) {  
  827.   
  828.   
  829.         return FLT_POSTOP_FINISHED_PROCESSING;  
  830.     }  
  831.   
  832.   
  833.     //  
  834.     //  Check if we are interested in this file.  
  835.     //  
  836.   
  837.   
  838.     status = FltGetFileNameInformation( Data,  
  839.                                         FLT_FILE_NAME_NORMALIZED |  
  840.                                             FLT_FILE_NAME_QUERY_DEFAULT,  
  841.                                         &nameInfo );  
  842.   
  843.   
  844.     if (!NT_SUCCESS( status )) {  
  845.   
  846.   
  847.         return FLT_POSTOP_FINISHED_PROCESSING;  
  848.     }  
  849.   
  850.   
  851.     FltParseFileNameInformation( nameInfo );  
  852.   
  853.   
  854.     //  
  855.     //  Check if the extension matches the list of extensions we are interested in  
  856.     //  
  857.   
  858.   
  859.     scanFile = ScannerpCheckExtension( &nameInfo->Extension );  
  860.   
  861.   
  862.     //  
  863.     //  Release file name info, we're done with it  
  864.     //  
  865.   
  866.   
  867.     FltReleaseFileNameInformation( nameInfo );  
  868.   
  869.   
  870.     if (!scanFile) {  
  871.   
  872.   
  873.         //  
  874.         //  Not an extension we are interested in  
  875.         //  
  876.   
  877.   
  878.         return FLT_POSTOP_FINISHED_PROCESSING;  
  879.     }  
  880.   
  881.   
  882.     (VOID) ScannerpScanFileInUserMode( FltObjects->Instance,  
  883.                                        FltObjects->FileObject,  
  884.                                        &safeToOpen );  
  885.   
  886.   
  887.     if (!safeToOpen) {  
  888.   
  889.   
  890.         //  
  891.         //  Ask the filter manager to undo the create.  
  892.         //  
  893.   
  894.   
  895.         DbgPrint( "!!! scanner.sys -- foul language detected in postcreate !!!\n" );  
  896.   
  897.   
  898.         DbgPrint( "!!! scanner.sys -- undoing create \n" );  
  899.   
  900.   
  901.         FltCancelFileOpen( FltObjects->Instance, FltObjects->FileObject );  
  902.   
  903.   
  904.         Data->IoStatus.Status = STATUS_ACCESS_DENIED;  
  905.         Data->IoStatus.Information = 0;  
  906.   
  907.   
  908.         returnStatus = FLT_POSTOP_FINISHED_PROCESSING;  
  909.   
  910.   
  911.     } else if (FltObjects->FileObject->WriteAccess) {  
  912.   
  913.   
  914.         //  
  915.         //  
  916.         //  The create has requested write access, mark to rescan the file.  
  917.         //  Allocate the context.  
  918.         //  
  919.   
  920.   
  921.         status = FltAllocateContext( ScannerData.Filter,  
  922.                                      FLT_STREAMHANDLE_CONTEXT,  
  923.                                      sizeof(SCANNER_STREAM_HANDLE_CONTEXT),  
  924.                                      PagedPool,  
  925.                                      &scannerContext );  
  926.   
  927.   
  928.         if (NT_SUCCESS(status)) {  
  929.   
  930.   
  931.             //  
  932.             //  Set the handle context.  
  933.             //  
  934.   
  935.   
  936.             scannerContext->RescanRequired = TRUE;  
  937.   
  938.   
  939.             (VOID) FltSetStreamHandleContext( FltObjects->Instance,  
  940.                                               FltObjects->FileObject,  
  941.                                               FLT_SET_CONTEXT_REPLACE_IF_EXISTS,  
  942.                                               scannerContext,  
  943.                                               NULL );  
  944.   
  945.   
  946.             //  
  947.             //  Normally we would check the results of FltSetStreamHandleContext  
  948.             //  for a variety of error cases. However, The only error status   
  949.             //  that could be returned, in this case, would tell us that  
  950.             //  contexts are not supported.  Even if we got this error,  
  951.             //  we just want to release the context now and that will free  
  952.             //  this memory if it was not successfully set.  
  953.             //  
  954.   
  955.   
  956.             //  
  957.             //  Release our reference on the context (the set adds a reference)  
  958.             //  
  959.   
  960.   
  961.             FltReleaseContext( scannerContext );  
  962.         }  
  963.     }  
  964.   
  965.   
  966.     return returnStatus;  
  967. }  
  968.   
  969.   
  970. //处理打开时 有写权限但 打开成功时是安全的,等它关闭的时候的我们来扫描它  
  971. //触发这个回调的条件是文件引用技术为0,这个包括内核+R3的计数,一般是在上层使用了ZwClose或者CloseHandle时调用  
  972. FLT_PREOP_CALLBACK_STATUS  
  973. ScannerPreCleanup (  
  974.     __inout PFLT_CALLBACK_DATA Data,  
  975.     __in PCFLT_RELATED_OBJECTS FltObjects,  
  976.     __deref_out_opt PVOID *CompletionContext  
  977.     )  
  978. /*++ 
  979.  
  980.  
  981. Routine Description: 
  982.  
  983.  
  984.     Pre cleanup callback.  If this file was opened for write access, we want 
  985.     to rescan it now. 
  986.  
  987.  
  988. Arguments: 
  989.  
  990.  
  991.     Data - The structure which describes the operation parameters. 
  992.  
  993.  
  994.     FltObject - The structure which describes the objects affected by this 
  995.         operation. 
  996.  
  997.  
  998.     CompletionContext - Output parameter which can be used to pass a context 
  999.         from this pre-cleanup callback to the post-cleanup callback. 
  1000.  
  1001.  
  1002. Return Value: 
  1003.  
  1004.  
  1005.     Always FLT_PREOP_SUCCESS_NO_CALLBACK. 
  1006.  
  1007.  
  1008. --*/  
  1009. {  
  1010.     NTSTATUS status;  
  1011.     PSCANNER_STREAM_HANDLE_CONTEXT context;  
  1012.     BOOLEAN safe;  
  1013.   
  1014.   
  1015.     UNREFERENCED_PARAMETER( Data );  
  1016.     UNREFERENCED_PARAMETER( CompletionContext );  
  1017.   
  1018.   
  1019.     status = FltGetStreamHandleContext( FltObjects->Instance,  
  1020.                                         FltObjects->FileObject,  
  1021.                                         &context );  
  1022.   
  1023.   
  1024.     if (NT_SUCCESS( status )) {  
  1025.   
  1026.   
  1027.         if (context->RescanRequired) {  
  1028.   
  1029.   
  1030.             (VOID) ScannerpScanFileInUserMode( FltObjects->Instance,  
  1031.                                                FltObjects->FileObject,  
  1032.                                                &safe );  
  1033.   
  1034.   
  1035.             if (!safe) {  
  1036.   
  1037.   
  1038.                 DbgPrint( "!!! scanner.sys -- foul language detected in precleanup !!!\n" );  
  1039.             }  
  1040.         }  
  1041.   
  1042.   
  1043.         FltReleaseContext( context );  
  1044.     }  
  1045.   
  1046.   
  1047.   
  1048.   
  1049.     return FLT_PREOP_SUCCESS_NO_CALLBACK;  
  1050. }  
  1051.   
  1052.   
  1053. //处理写关闭  
  1054. FLT_PREOP_CALLBACK_STATUS  
  1055. ScannerPreWrite (  
  1056.     __inout PFLT_CALLBACK_DATA Data,  
  1057.     __in PCFLT_RELATED_OBJECTS FltObjects,  
  1058.     __deref_out_opt PVOID *CompletionContext  
  1059.     )  
  1060. /*++ 
  1061.  
  1062.  
  1063. Routine Description: 
  1064.  
  1065.  
  1066.     Pre write callback.  We want to scan what's being written now. 
  1067.  
  1068.  
  1069. Arguments: 
  1070.  
  1071.  
  1072.     Data - The structure which describes the operation parameters. 
  1073.  
  1074.  
  1075.     FltObject - The structure which describes the objects affected by this 
  1076.         operation. 
  1077.  
  1078.  
  1079.     CompletionContext - Output parameter which can be used to pass a context 
  1080.         from this pre-write callback to the post-write callback. 
  1081.  
  1082.  
  1083. Return Value: 
  1084.  
  1085.  
  1086.     Always FLT_PREOP_SUCCESS_NO_CALLBACK. 
  1087.  
  1088.  
  1089. --*/  
  1090. {  
  1091.     FLT_PREOP_CALLBACK_STATUS returnStatus = FLT_PREOP_SUCCESS_NO_CALLBACK;  
  1092.     NTSTATUS status;  
  1093.     PSCANNER_NOTIFICATION notification = NULL;  
  1094.     PSCANNER_STREAM_HANDLE_CONTEXT context = NULL;  
  1095.     ULONG replyLength;  
  1096.     BOOLEAN safe = TRUE;  
  1097.     PUCHAR buffer;  
  1098.   
  1099.   
  1100.     UNREFERENCED_PARAMETER( CompletionContext );  
  1101.   
  1102.   
  1103.     //  
  1104.     //  If not client port just ignore this write.  
  1105.     //  
  1106.     //如果R3进程退出了  
  1107.     if (ScannerData.ClientPort == NULL) {  
  1108.   
  1109.   
  1110.         return FLT_PREOP_SUCCESS_NO_CALLBACK;  
  1111.     }  
  1112.     //获取上下文  
  1113.     status = FltGetStreamHandleContext( FltObjects->Instance,  
  1114.                                         FltObjects->FileObject,  
  1115.                                         &context );  
  1116.     //不是我们要处理的文件,(可以在创建事前回调中设置上下文,比如判断这个文件是不是记事本,如果是,我们就给它设置一个上下文,然后到后我们就可以知道这个文件是不是我们设置过的记事本)  
  1117.     //这也可以判断,不过一般不这么使用,一般是在上下文中插入自己想要信息,然后到这里我们到这个上下文中去取  
  1118.     if (!NT_SUCCESS( status )) {  
  1119.   
  1120.   
  1121.         //  
  1122.         //  We are not interested in this file  
  1123.         //  
  1124.   
  1125.   
  1126.         return FLT_PREOP_SUCCESS_NO_CALLBACK;  
  1127.   
  1128.   
  1129.     }  
  1130.   
  1131.   
  1132.     //  
  1133.     //  Use try-finally to cleanup  
  1134.     //  
  1135.   
  1136.   
  1137.     //必须使用异常处理结构  
  1138.     try {  
  1139.   
  1140.   
  1141.         //  
  1142.         //  Pass the contents of the buffer to user mode.  
  1143.         //  
  1144.         //如果写的长度为0 就放行  
  1145.         if (Data->Iopb->Parameters.Write.Length != 0) {  
  1146.   
  1147.   
  1148.             //  
  1149.             //  Get the users buffer address.  If there is a MDL defined, use  
  1150.             //  it.  If not use the given buffer address.  
  1151.             //  
  1152.             //开始获取数据缓存区 有2个缓存区,需要判断在数据在哪个buff中 判断的方法前面说过了  
  1153.             if (Data->Iopb->Parameters.Write.MdlAddress != NULL) {  
  1154.   
  1155.   
  1156.                 buffer = MmGetSystemAddressForMdlSafe( Data->Iopb->Parameters.Write.MdlAddress,  
  1157.                                                        NormalPagePriority );  
  1158.   
  1159.   
  1160.                 //  
  1161.                 //  If we have a MDL but could not get and address, we ran out  
  1162.                 //  of memory, report the correct error  
  1163.                 //  
  1164.                 //如果获取失败了 就返回资源不足 并不下发了  
  1165.                 if (buffer == NULL) {  
  1166.   
  1167.   
  1168.                     Data->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;  
  1169.                     Data->IoStatus.Information = 0;  
  1170.                     returnStatus = FLT_PREOP_COMPLETE;  
  1171.                     leave;  
  1172.                 }  
  1173.   
  1174.   
  1175.             } else {  
  1176.   
  1177.   
  1178.                 //  
  1179.                 //  Use the users buffer  
  1180.                 //  
  1181.                 //不是MDL就是USERbuff  
  1182.                 buffer  = Data->Iopb->Parameters.Write.WriteBuffer;  
  1183.             }  
  1184.   
  1185.   
  1186.             //  
  1187.             //  In a production-level filter, we would actually let user mode scan the file directly.  
  1188.             //  Allocating & freeing huge amounts of non-paged pool like this is not very good for system perf.  
  1189.             //  This is just a sample!  
  1190.             //  
  1191.             //为发送给R3数据申请内存  
  1192.             notification = ExAllocatePoolWithTag( NonPagedPool,  
  1193.                                                   sizeof( SCANNER_NOTIFICATION ),  
  1194.                                                   'nacS' );  
  1195.             if (notification == NULL) {  
  1196.   
  1197.   
  1198.                 Data->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;  
  1199.                 Data->IoStatus.Information = 0;  
  1200.                 returnStatus = FLT_PREOP_COMPLETE;  
  1201.                 leave;  
  1202.             }  
  1203.             //取最小啦 这里设置SCANNER_READ_BUFFER_SIZE为1024  
  1204.             notification->BytesToScan = min( Data->Iopb->Parameters.Write.Length, SCANNER_READ_BUFFER_SIZE );  
  1205.   
  1206.   
  1207.             //  
  1208.             //  The buffer can be a raw user buffer. Protect access to it  
  1209.             //  
  1210.             //内存操作 必须使用结构化异常处理  
  1211.             try  {  
  1212.   
  1213.   
  1214.                 RtlCopyMemory( ¬ification->Contents,  
  1215.                                buffer,  
  1216.                                notification->BytesToScan );  
  1217.   
  1218.   
  1219.             } except( EXCEPTION_EXECUTE_HANDLER ) {  
  1220.   
  1221.   
  1222.                 //  
  1223.                 //  Error accessing buffer. Complete i/o with failure  
  1224.                 //  
  1225.                 //出错就返回错误代码并阻止下发啦  
  1226.                 Data->IoStatus.Status = GetExceptionCode() ;  
  1227.                 Data->IoStatus.Information = 0;  
  1228.                 returnStatus = FLT_PREOP_COMPLETE;  
  1229.                 leave;  
  1230.             }  
  1231.   
  1232.   
  1233.             //  
  1234.             //  Send message to user mode to indicate it should scan the buffer.  
  1235.             //  We don't have to synchronize between the send and close of the handle  
  1236.             //  as FltSendMessage takes care of that.  
  1237.             //  
  1238.             //发送数据给R3 处理  
  1239.             replyLength = sizeof( SCANNER_REPLY );  
  1240.   
  1241.   
  1242.             status = FltSendMessage( ScannerData.Filter,  
  1243.                                      &ScannerData.ClientPort,  
  1244.                                      notification,  
  1245.                                      sizeof( SCANNER_NOTIFICATION ),  
  1246.                                      notification,  
  1247.                                      &replyLength,  
  1248.                                      NULL );//永远等待,一般40秒吧  
  1249.             //为什么共用一块内存呢 你猜  
  1250.             if (STATUS_SUCCESS == status) {  
  1251.                 //用户返回的处理结果  
  1252.                safe = ((PSCANNER_REPLY) notification)->SafeToOpen;  
  1253.   
  1254.   
  1255.            } else {  
  1256.   
  1257.   
  1258.                //  
  1259.                //  Couldn't send message. This sample will let the i/o through.  
  1260.                //  
  1261.   
  1262.   
  1263.                DbgPrint( "!!! scanner.sys --- couldn't send message to user-mode to scan file, status 0x%X\n", status );  
  1264.            }  
  1265.         }  
  1266.         //这个是不安全的 你猜怎么办?  
  1267.         if (!safe) {  
  1268.   
  1269.   
  1270.             //  
  1271.             //  Block this write if not paging i/o (as a result of course, this scanner will not prevent memory mapped writes of contaminated  
  1272.             //  strings to the file, but only regular writes). The effect of getting ERROR_ACCESS_DENIED for many apps to delete the file they  
  1273.             //  are trying to write usually.  
  1274.             //  To handle memory mapped writes - we should be scanning at close time (which is when we can really establish that the file object  
  1275.             //  is not going to be used for any more writes)  
  1276.             //  
  1277.   
  1278.   
  1279.             DbgPrint( "!!! scanner.sys -- foul language detected in write !!!\n" );  
  1280.   
  1281.   
  1282.             //如果不是Flt管理发送的,这个IRP很特殊 ,必须放行,如果不是这个IRP就阻止了,因为它是不安全的  
  1283.             if (!FlagOn( Data->Iopb->IrpFlags, IRP_PAGING_IO )) {  
  1284.   
  1285.   
  1286.                 DbgPrint( "!!! scanner.sys -- blocking the write !!!\n" );  
  1287.   
  1288.   
  1289.                 Data->IoStatus.Status = STATUS_ACCESS_DENIED;  
  1290.                 Data->IoStatus.Information = 0;  
  1291.                 returnStatus = FLT_PREOP_COMPLETE;  
  1292.             }  
  1293.         }  
  1294.   
  1295.   
  1296.     } finally {  
  1297.         //该释放的释放  
  1298.         if (notification != NULL) {  
  1299.   
  1300.   
  1301.             ExFreePoolWithTag( notification, 'nacS' );  
  1302.         }  
  1303.   
  1304.   
  1305.         if (context) {  
  1306.   
  1307.   
  1308.             FltReleaseContext( context );  
  1309.         }  
  1310.     }  
  1311.   
  1312.   
  1313.     return returnStatus;  
  1314. }  
  1315.   
  1316.   
  1317. //////////////////////////////////////////////////////////////////////////  
  1318. //  Local support routines.  
  1319. //  
  1320. /////////////////////////////////////////////////////////////////////////  
  1321.   
  1322. NTSTATUS  
  1323. ScannerpScanFileInUserMode (  
  1324.     __in PFLT_INSTANCE Instance,  
  1325.     __in PFILE_OBJECT FileObject,  
  1326.     __out PBOOLEAN SafeToOpen  
  1327.     )  
  1328. /*++ 
  1329.  
  1330.  
  1331. Routine Description: 
  1332.  
  1333.  
  1334.     This routine is called to send a request up to user mode to scan a given 
  1335.     file and tell our caller whether it's safe to open this file. 
  1336.  
  1337.  
  1338.     Note that if the scan fails, we set SafeToOpen to TRUE.  The scan may fail 
  1339.     because the service hasn't started, or perhaps because this create/cleanup 
  1340.     is for a directory, and there's no data to read & scan. 
  1341.  
  1342.  
  1343.     If we failed creates when the service isn't running, there'd be a 
  1344.     bootstrapping problem -- how would we ever load the .exe for the service? 
  1345.  
  1346.  
  1347. Arguments: 
  1348.  
  1349.  
  1350.     Instance - Handle to the filter instance for the scanner on this volume. 
  1351.  
  1352.  
  1353.     FileObject - File to be scanned. 
  1354.  
  1355.  
  1356.     SafeToOpen - Set to FALSE if the file is scanned successfully and it contains 
  1357.                  foul language. 
  1358.  
  1359.  
  1360. Return Value: 
  1361.  
  1362.  
  1363.     The status of the operation, hopefully STATUS_SUCCESS.  The common failure 
  1364.     status will probably be STATUS_INSUFFICIENT_RESOURCES. 
  1365.  
  1366.  
  1367. --*/  
  1368.   
  1369.   
  1370. {  
  1371.     NTSTATUS status = STATUS_SUCCESS;  
  1372.     PVOID buffer = NULL;  
  1373.     ULONG bytesRead;  
  1374.     PSCANNER_NOTIFICATION notification = NULL;  
  1375.     FLT_VOLUME_PROPERTIES volumeProps;  
  1376.     LARGE_INTEGER offset;  
  1377.     ULONG replyLength, length;  
  1378.     PFLT_VOLUME volume = NULL;  
  1379.   
  1380.   
  1381.     *SafeToOpen = TRUE;  
  1382.   
  1383.   
  1384.     //  
  1385.     //  If not client port just return.  
  1386.     //  
  1387.   
  1388.   
  1389.     if (ScannerData.ClientPort == NULL) {  
  1390.   
  1391.   
  1392.         return STATUS_SUCCESS;  
  1393.     }  
  1394.   
  1395.   
  1396.     try {  
  1397.   
  1398.   
  1399.         //  
  1400.         //  Obtain the volume object .  
  1401.         //  
  1402.   
  1403.   
  1404.         status = FltGetVolumeFromInstance( Instance, &volume );  
  1405.   
  1406.   
  1407.         if (!NT_SUCCESS( status )) {  
  1408.   
  1409.   
  1410.             leave;  
  1411.         }  
  1412.   
  1413.   
  1414.         //  
  1415.         //  Determine sector size. Noncached I/O can only be done at sector size offsets, and in lengths which are  
  1416.         //  multiples of sector size. A more efficient way is to make this call once and remember the sector size in the  
  1417.         //  instance setup routine and setup an instance context where we can cache it.  
  1418.         //  
  1419.   
  1420.   
  1421.         status = FltGetVolumeProperties( volume,  
  1422.                                          &volumeProps,  
  1423.                                          sizeof( volumeProps ),  
  1424.                                          &length );  
  1425.         //  
  1426.         //  STATUS_BUFFER_OVERFLOW can be returned - however we only need the properties, not the names  
  1427.         //  hence we only check for error status.  
  1428.         //  
  1429.   
  1430.   
  1431.         if (NT_ERROR( status )) {  
  1432.   
  1433.   
  1434.             leave;  
  1435.         }  
  1436.   
  1437.   
  1438.         length = max( SCANNER_READ_BUFFER_SIZE, volumeProps.SectorSize );  
  1439.   
  1440.   
  1441.         //  
  1442.         //  Use non-buffered i/o, so allocate aligned pool  
  1443.         //  
  1444.   
  1445.   
  1446.         buffer = FltAllocatePoolAlignedWithTag( Instance,  
  1447.                                                 NonPagedPool,  
  1448.                                                 length,  
  1449.                                                 'nacS' );  
  1450.   
  1451.   
  1452.         if (NULL == buffer) {  
  1453.   
  1454.   
  1455.             status = STATUS_INSUFFICIENT_RESOURCES;  
  1456.             leave;  
  1457.         }  
  1458.   
  1459.   
  1460.         notification = ExAllocatePoolWithTag( NonPagedPool,  
  1461.                                               sizeof( SCANNER_NOTIFICATION ),  
  1462.                                               'nacS' );  
  1463.   
  1464.   
  1465.         if(NULL == notification) {  
  1466.   
  1467.   
  1468.             status = STATUS_INSUFFICIENT_RESOURCES;  
  1469.             leave;  
  1470.         }  
  1471.   
  1472.   
  1473.         //  
  1474.         //  Read the beginning of the file and pass the contents to user mode.  
  1475.         //  
  1476.   
  1477.   
  1478.         offset.QuadPart = bytesRead = 0;  
  1479.         status = FltReadFile( Instance,  
  1480.                               FileObject,  
  1481.                               &offset,  
  1482.                               length,  
  1483.                               buffer,  
  1484.                               FLTFL_IO_OPERATION_NON_CACHED |  
  1485.                                FLTFL_IO_OPERATION_DO_NOT_UPDATE_BYTE_OFFSET,  
  1486.                               &bytesRead,  
  1487.                               NULL,  
  1488.                               NULL );  
  1489.   
  1490.   
  1491.         if (NT_SUCCESS( status ) && (0 != bytesRead)) {  
  1492.   
  1493.   
  1494.             notification->BytesToScan = (ULONG) bytesRead;  
  1495.   
  1496.   
  1497.             //  
  1498.             //  Copy only as much as the buffer can hold  
  1499.             //  
  1500.   
  1501.   
  1502.             RtlCopyMemory( ¬ification->Contents,  
  1503.                            buffer,  
  1504.                            min( notification->BytesToScan, SCANNER_READ_BUFFER_SIZE ) );  
  1505.   
  1506.   
  1507.             replyLength = sizeof( SCANNER_REPLY );  
  1508.   
  1509.   
  1510.             status = FltSendMessage( ScannerData.Filter,  
  1511.                                      &ScannerData.ClientPort,  
  1512.                                      notification,  
  1513.                                      sizeof(SCANNER_NOTIFICATION),  
  1514.                                      notification,  
  1515.                                      &replyLength,  
  1516.                                      NULL );  
  1517.   
  1518.   
  1519.             if (STATUS_SUCCESS == status) {  
  1520.   
  1521.   
  1522.                 *SafeToOpen = ((PSCANNER_REPLY) notification)->SafeToOpen;  
  1523.   
  1524.   
  1525.             } else {  
  1526.   
  1527.   
  1528.                 //  
  1529.                 //  Couldn't send message  
  1530.                 //  
  1531.   
  1532.   
  1533.                 DbgPrint( "!!! scanner.sys --- couldn't send message to user-mode to scan file, status 0x%X\n", status );  
  1534.             }  
  1535.         }  
  1536.   
  1537.   
  1538.     } finally {  
  1539.   
  1540.   
  1541.         if (NULL != buffer) {  
  1542.   
  1543.   
  1544.             FltFreePoolAlignedWithTag( Instance, buffer, 'nacS' );  
  1545.         }  
  1546.   
  1547.   
  1548.         if (NULL != notification) {  
  1549.   
  1550.   
  1551.             ExFreePoolWithTag( notification, 'nacS' );  
  1552.         }  
  1553.   
  1554.   
  1555.         if (NULL != volume) {  
  1556.   
  1557.   
  1558.             FltObjectDereference( volume );  
  1559.         }  
  1560.     }  
  1561.   
  1562.   
  1563.     return status;  
  1564. }  




r3.h文件
[cpp]  view plain  copy
  1. /*++ 
  2.  
  3.  
  4. Copyright (c) 1999-2002  Microsoft Corporation 
  5.  
  6.  
  7. Module Name: 
  8.  
  9.  
  10.     scanuser.h 
  11.  
  12.  
  13. Abstract: 
  14.  
  15.  
  16.     Header file which contains the structures, type definitions, 
  17.     constants, global variables and function prototypes for the 
  18.     user mode part of the scanner. 
  19.  
  20.  
  21. Environment: 
  22.  
  23.  
  24.     Kernel & user mode 
  25.  
  26.  
  27. --*/  
  28. #ifndef __SCANUSER_H__  
  29. #define __SCANUSER_H__  
  30.   
  31.   
  32. #pragma pack(1)  
  33.   
  34.   
  35. typedef struct _SCANNER_MESSAGE {  
  36.   
  37.   
  38.     //  
  39.     //  Required structure header.  
  40.     //  
  41.   
  42.   
  43.     FILTER_MESSAGE_HEADER MessageHeader;  
  44.   
  45.   
  46.   
  47.   
  48.     //  
  49.     //  Private scanner-specific fields begin here.  
  50.     //  
  51.   
  52.   
  53.     SCANNER_NOTIFICATION Notification;  
  54.   
  55.   
  56.     //  
  57.     //  Overlapped structure: this is not really part of the message  
  58.     //  However we embed it instead of using a separately allocated overlap structure  
  59.     //  
  60.   
  61.   
  62.     OVERLAPPED Ovlp;  
  63.       
  64. } SCANNER_MESSAGE, *PSCANNER_MESSAGE;  
  65.   
  66.   
  67. typedef struct _SCANNER_REPLY_MESSAGE {  
  68.   
  69.   
  70.     //  
  71.     //  Required structure header.  
  72.     //  
  73.   
  74.   
  75.     FILTER_REPLY_HEADER ReplyHeader;  
  76.   
  77.   
  78.     //  
  79.     //  Private scanner-specific fields begin here.  
  80.     //  
  81.   
  82.   
  83.     SCANNER_REPLY Reply;  
  84.   
  85.   
  86. } SCANNER_REPLY_MESSAGE, *PSCANNER_REPLY_MESSAGE;  
  87.   
  88.   
  89. #endif //  __SCANUSER_H__  


r3.c文件
[cpp]  view plain  copy
  1. /*++ 
  2.  
  3.  
  4. Copyright (c) 1999-2002  Microsoft Corporation 
  5.  
  6.  
  7. Module Name: 
  8.  
  9.  
  10.     scanUser.c 
  11.  
  12.  
  13. Abstract: 
  14.  
  15.  
  16.     This file contains the implementation for the main function of the 
  17.     user application piece of scanner.  This function is responsible for 
  18.     actually scanning file contents. 
  19.  
  20.  
  21. Environment: 
  22.  
  23.  
  24.     User mode 
  25.  
  26.  
  27. --*/  
  28.   
  29.   
  30. #include <windows.h>  
  31. #include <stdlib.h>  
  32. #include <stdio.h>  
  33. #include <winioctl.h>  
  34. #include <string.h>  
  35. #include <crtdbg.h>  
  36. #include <assert.h>  
  37. #include <fltuser.h>  
  38. #include "../MiniFliter_Scaner/scanuk.h"  
  39. #include "scanuser.h"  
  40. #include <dontuse.h>  
  41.   
  42.   
  43. #pragma comment(lib,"fltlib.lib")  
  44.   
  45.   
  46.   
  47.   
  48. #define SCANNER_DEFAULT_REQUEST_COUNT       5  
  49. #define SCANNER_DEFAULT_THREAD_COUNT        2  
  50. #define SCANNER_MAX_THREAD_COUNT            64  
  51.   
  52.   
  53. UCHAR FoulString[] = "foul";  
  54.   
  55.   
  56. //  
  57. //  Context passed to worker threads  
  58. //  
  59.   
  60.   
  61. typedef struct _SCANNER_THREAD_CONTEXT {  
  62.   
  63.   
  64.     HANDLE Port;  
  65.     HANDLE Completion;  
  66.   
  67.   
  68. } SCANNER_THREAD_CONTEXT, *PSCANNER_THREAD_CONTEXT;  
  69.   
  70.   
  71.   
  72.   
  73. VOID  
  74. Usage (  
  75.     VOID  
  76.     )  
  77. /*++ 
  78.  
  79.  
  80. Routine Description 
  81.  
  82.  
  83.     Prints usage 
  84.  
  85.  
  86. Arguments 
  87.  
  88.  
  89.     None 
  90.  
  91.  
  92. Return Value 
  93.  
  94.  
  95.     None 
  96.  
  97.  
  98. --*/  
  99. {  
  100.   
  101.   
  102.     printf( "Connects to the scanner filter and scans buffers \n" );  
  103.     printf( "Usage: scanuser [requests per thread] [number of threads(1-64)]\n" );  
  104. }  
  105.   
  106.   
  107. BOOL  
  108. ScanBuffer (  
  109.     __in_bcount(BufferSize) PUCHAR Buffer,  
  110.     __in ULONG BufferSize  
  111.     )  
  112. /*++ 
  113.  
  114.  
  115. Routine Description 
  116.  
  117.  
  118.     Scans the supplied buffer for an instance of FoulString. 
  119.  
  120.  
  121.     Note: Pattern matching algorithm used here is just for illustration purposes, 
  122.     there are many better algorithms available for real world filters 
  123.  
  124.  
  125. Arguments 
  126.  
  127.  
  128.     Buffer      -   Pointer to buffer 
  129.     BufferSize  -   Size of passed in buffer 
  130.  
  131.  
  132. Return Value 
  133.  
  134.  
  135.     TRUE        -    Found an occurrence of the appropriate FoulString 
  136.     FALSE       -    Buffer is ok 
  137.  
  138.  
  139. --*/  
  140. {  
  141.     PUCHAR p;  
  142.     ULONG searchStringLength = sizeof(FoulString) - sizeof(UCHAR);  
  143.   
  144.   
  145.     for (p = Buffer;  
  146.          p <= (Buffer + BufferSize - searchStringLength);  
  147.          p++) {  
  148.   
  149.   
  150.         if (RtlEqualMemory( p, FoulString, searchStringLength )) {  
  151.   
  152.   
  153.             printf( "Found a string\n" );  
  154.   
  155.   
  156.             //  
  157.             //  Once we find our search string, we're not interested in seeing  
  158.             //  whether it appears again.  
  159.             //  
  160.   
  161.   
  162.             return TRUE;  
  163.         }  
  164.     }  
  165.   
  166.   
  167.     return FALSE;  
  168. }  
  169.   
  170.   
  171.   
  172.   
  173. DWORD  
  174. ScannerWorker(  
  175.     __in PSCANNER_THREAD_CONTEXT Context  
  176.     )  
  177. /*++ 
  178.  
  179.  
  180. Routine Description 
  181.  
  182.  
  183.     This is a worker thread that 
  184.  
  185.  
  186.  
  187.  
  188. Arguments 
  189.  
  190.  
  191.     Context  - This thread context has a pointer to the port handle we use to send/receive messages, 
  192.                 and a completion port handle that was already associated with the comm. port by the caller 
  193.  
  194.  
  195. Return Value 
  196.  
  197.  
  198.     HRESULT indicating the status of thread exit. 
  199.  
  200.  
  201. --*/  
  202. {  
  203.     PSCANNER_NOTIFICATION notification;  
  204.     SCANNER_REPLY_MESSAGE replyMessage;  
  205.     PSCANNER_MESSAGE message;  
  206.     LPOVERLAPPED pOvlp;  
  207.     BOOL result;  
  208.     DWORD outSize;  
  209.     HRESULT hr;  
  210.     ULONG_PTR key;  
  211.   
  212.   
  213. #pragma warning(push)  
  214. #pragma warning(disable:4127) // conditional expression is constant  
  215.   
  216.   
  217.     while (TRUE) {  
  218.   
  219.   
  220. #pragma warning(pop)  
  221.   
  222.   
  223.         //  
  224.         //  Poll for messages from the filter component to scan.  
  225.         //  
  226.   
  227.   
  228.         result = GetQueuedCompletionStatus( Context->Completion, &outSize, &key, &pOvlp, INFINITE );  
  229.   
  230.   
  231.         //  
  232.         //  Obtain the message: note that the message we sent down via FltGetMessage() may NOT be  
  233.         //  the one dequeued off the completion queue: this is solely because there are multiple  
  234.         //  threads per single port handle. Any of the FilterGetMessage() issued messages can be  
  235.         //  completed in random order - and we will just dequeue a random one.  
  236.         //  
  237.   
  238.   
  239.         message = CONTAINING_RECORD( pOvlp, SCANNER_MESSAGE, Ovlp );  
  240.   
  241.   
  242.         if (!result) {  
  243.   
  244.   
  245.             //  
  246.             //  An error occured.  
  247.             //  
  248.   
  249.   
  250.             hr = HRESULT_FROM_WIN32( GetLastError() );  
  251.             break;  
  252.         }  
  253.   
  254.   
  255.         printf( "Received message, size %d\n", pOvlp->InternalHigh );  
  256.   
  257.   
  258.         notification = &message->Notification;  
  259.   
  260.   
  261.         assert(notification->BytesToScan <= SCANNER_READ_BUFFER_SIZE);  
  262.         __analysis_assume(notification->BytesToScan <= SCANNER_READ_BUFFER_SIZE);  
  263.   
  264.   
  265.         result = ScanBuffer( notification->Contents, notification->BytesToScan );  
  266.   
  267.   
  268.         replyMessage.ReplyHeader.Status = 0;  
  269.         replyMessage.ReplyHeader.MessageId = message->MessageHeader.MessageId;  
  270.   
  271.   
  272.         //  
  273.         //  Need to invert the boolean -- result is true if found  
  274.         //  foul language, in which case SafeToOpen should be set to false.  
  275.         //  
  276.   
  277.   
  278.         replyMessage.Reply.SafeToOpen = !result;  
  279.   
  280.   
  281.         printf( "Replying message, SafeToOpen: %d\n", replyMessage.Reply.SafeToOpen );  
  282.   
  283.   
  284.         hr = FilterReplyMessage( Context->Port,  
  285.                                  (PFILTER_REPLY_HEADER) &replyMessage,  
  286.                                  sizeof( replyMessage ) );  
  287.   
  288.   
  289.         if (SUCCEEDED( hr )) {  
  290.   
  291.   
  292.             printf( "Replied message\n" );  
  293.   
  294.   
  295.         } else {  
  296.   
  297.   
  298.             printf( "Scanner: Error replying message. Error = 0x%X\n", hr );  
  299.             break;  
  300.         }  
  301.   
  302.   
  303.         memset( &message->Ovlp, 0, sizeof( OVERLAPPED ) );  
  304.   
  305.   
  306.         hr = FilterGetMessage( Context->Port,  
  307.                                &message->MessageHeader,  
  308.                                FIELD_OFFSET( SCANNER_MESSAGE, Ovlp ),  
  309.                                &message->Ovlp );  
  310.   
  311.   
  312.         if (hr != HRESULT_FROM_WIN32( ERROR_IO_PENDING )) {  
  313.   
  314.   
  315.             break;  
  316.         }  
  317.     }  
  318.   
  319.   
  320.     if (!SUCCEEDED( hr )) {  
  321.   
  322.   
  323.         if (hr == HRESULT_FROM_WIN32( ERROR_INVALID_HANDLE )) {  
  324.   
  325.   
  326.             //  
  327.             //  Scanner port disconncted.  
  328.             //  
  329.   
  330.   
  331.             printf( "Scanner: Port is disconnected, probably due to scanner filter unloading.\n" );  
  332.   
  333.   
  334.         } else {  
  335.   
  336.   
  337.             printf( "Scanner: Unknown error occured. Error = 0x%X\n", hr );  
  338.         }  
  339.     }  
  340.   
  341.   
  342.     free( message );  
  343.   
  344.   
  345.     return hr;  
  346. }  
  347.   
  348.   
  349.   
  350.   
  351. int _cdecl  
  352. main (  
  353.     __in int argc,  
  354.     __in_ecount(argc) char *argv[]  
  355.     )  
  356. {  
  357.     DWORD requestCount = SCANNER_DEFAULT_REQUEST_COUNT;  
  358.     DWORD threadCount = SCANNER_DEFAULT_THREAD_COUNT;  
  359.     HANDLE threads[SCANNER_MAX_THREAD_COUNT];  
  360.     SCANNER_THREAD_CONTEXT context;  
  361.     HANDLE port, completion;  
  362.     PSCANNER_MESSAGE msg;  
  363.     DWORD threadId;  
  364.     HRESULT hr;  
  365.     DWORD i, j;  
  366.   
  367.   
  368.     //  
  369.     //  Check how many threads and per thread requests are desired.  
  370.     //  
  371.   
  372.   
  373.     if (argc > 1) {  
  374.   
  375.   
  376.         requestCount = atoi( argv[1] );  
  377.   
  378.   
  379.         if (requestCount <= 0) {  
  380.   
  381.   
  382.             Usage();  
  383.             return 1;  
  384.         }  
  385.   
  386.   
  387.         if (argc > 2) {  
  388.   
  389.   
  390.             threadCount = atoi( argv[2] );  
  391.         }  
  392.   
  393.   
  394.         if (threadCount <= 0 || threadCount > 64) {  
  395.   
  396.   
  397.             Usage();  
  398.             return 1;  
  399.         }  
  400.     }  
  401.   
  402.   
  403.     //  
  404.     //  Open a commuication channel to the filter  
  405.     //  
  406.   
  407.   
  408.     printf( "Scanner: Connecting to the filter ...\n" );  
  409.   
  410.   
  411.     hr = FilterConnectCommunicationPort( ScannerPortName,  
  412.                                          0,  
  413.                                          NULL,  
  414.                                          0,  
  415.                                          NULL,  
  416.                                          &port );  
  417.   
  418.   
  419.     if (IS_ERROR( hr )) {  
  420.   
  421.   
  422.         printf( "ERROR: Connecting to filter port: 0x%08x\n", hr );  
  423.         return 2;  
  424.     }  
  425.   
  426.   
  427.     //  
  428.     //  Create a completion port to associate with this handle.  
  429.     //  
  430.   
  431.   
  432.     completion = CreateIoCompletionPort( port,  
  433.                                          NULL,  
  434.                                          0,  
  435.                                          threadCount );  
  436.   
  437.   
  438.     if (completion == NULL) {  
  439.   
  440.   
  441.         printf( "ERROR: Creating completion port: %d\n", GetLastError() );  
  442.         CloseHandle( port );  
  443.         return 3;  
  444.     }  
  445.   
  446.   
  447.     printf( "Scanner: Port = 0x%p Completion = 0x%p\n", port, completion );  
  448.   
  449.   
  450.     context.Port = port;  
  451.     context.Completion = completion;  
  452.   
  453.   
  454.     //  
  455.     //  Create specified number of threads.  
  456.     //  
  457.   
  458.   
  459.     for (i = 0; i < threadCount; i++) {  
  460.   
  461.   
  462.         threads[i] = CreateThread( NULL,  
  463.                                    0,  
  464.                                    (LPTHREAD_START_ROUTINE)ScannerWorker,  
  465.                                    &context,  
  466.                                    0,  
  467.                                    &threadId );  
  468.   
  469.   
  470.         if (threads[i] == NULL) {  
  471.   
  472.   
  473.             //  
  474.             //  Couldn't create thread.  
  475.             //  
  476.   
  477.   
  478.             hr = GetLastError();  
  479.             printf( "ERROR: Couldn't create thread: %d\n", hr );  
  480.             goto main_cleanup;  
  481.         }  
  482.   
  483.   
  484.         for (j = 0; j < requestCount; j++) {  
  485.   
  486.   
  487.             //  
  488.             //  Allocate the message.  
  489.             //  
  490.   
  491.   
  492. #pragma prefast(suppress:__WARNING_MEMORY_LEAK, "msg will not be leaked because it is freed in ScannerWorker")  
  493.             msg = malloc( sizeof( SCANNER_MESSAGE ) );  
  494.   
  495.   
  496.             if (msg == NULL) {  
  497.   
  498.   
  499.                 hr = ERROR_NOT_ENOUGH_MEMORY;  
  500.                 goto main_cleanup;  
  501.             }  
  502.   
  503.   
  504.             memset( &msg->Ovlp, 0, sizeof( OVERLAPPED ) );  
  505.   
  506.   
  507.             //  
  508.             //  Request messages from the filter driver.  
  509.             //  
  510.   
  511.   
  512.             hr = FilterGetMessage( port,  
  513.                                    &msg->MessageHeader,  
  514.                                    FIELD_OFFSET( SCANNER_MESSAGE, Ovlp ),  
  515.                                    &msg->Ovlp );  
  516.   
  517.   
  518.             if (hr != HRESULT_FROM_WIN32( ERROR_IO_PENDING )) {  
  519.   
  520.   
  521.                 free( msg );  
  522.                 goto main_cleanup;  
  523.             }  
  524.         }  
  525.     }  
  526.   
  527.   
  528.     hr = S_OK;  
  529.   
  530.   
  531.     WaitForMultipleObjectsEx( i, threads, TRUE, INFINITE, FALSE );  
  532.   
  533.   
  534. main_cleanup:  
  535.   
  536.   
  537.     printf( "Scanner:  All done. Result = 0x%08x\n", hr );  
  538.   
  539.   
  540.     CloseHandle( port );  
  541.     CloseHandle( completion );  
  542.   
  543.   
  544.     return hr;  
  545. }  


编译平台:VS2012 + WDK8.1
测试平台:Winxp Win7 x86 Win7x64



上面是R0主动通信 下面说说R3主动通信

这个通信一般是加规则


R3主动通信使用 FilterSendMessage

[cpp]  view plain  copy
  1. //主动发请求给R0  
  2.  FilterSendMessage(  
  3.     Port,  
  4.     request,  
  5.     sizeof(REQUEST),  
  6.     reply ? reply : NULL,  
  7.     reply ? sizeof(REPLY) : 0,  
  8.     &dwRtn);  




R0处理R3的主动消息
[cpp]  view plain  copy
  1. NTSTATUS  
  2. fnMessageFromClient(  
  3.       IN PVOID PortCookie,  
  4.       IN PVOID InputBuffer OPTIONAL,  
  5.       IN ULONG InputBufferLength,  
  6.       OUT PVOID OutputBuffer OPTIONAL,  
  7.       IN ULONG OutputBufferLength,  
  8.       OUT PULONG ReturnOutputBufferLength  
  9.       )  
  10. {  
  11.     __try  
  12.     {  
  13.         ProbeForRead(InputBuffer, InputBufferLength, sizeof(ULONG));  
  14.         //GET InputBuffer  
  15.         //Do something  
  16.         ProbeForWrite(OutputBuffer, OutputBufferLength, sizeof(ULONG));  
  17.         //Copy Result to Outputbuffer  
  18.     }  
  19.     __except(EXCEPTION_EXECUTE_HANDLER)  
  20.     {  
  21.         return STATUS_NOT_IMPLEMENTED;  
  22.     }  
  23.   
  24.   
  25.     return STATUS_SUCCESS;  
  26. }  



例子:来自http://bbs.pediy.com/showthread.php?t=186931
标 题: 【原创】minifilter通讯之简单示例之一
作 者: correy
时 间: 2014-04-24,14:10:34
链 接: http://bbs.pediy.com/showthread.php?t=186931


made by correy
made at 2013.11.13
email:kouleguan at hotmail dot com
homepage:http://correy.webs.com


效果如下(包括驱动打印的消息):
用户发来的信息是:test
[1124] FilterSendMessage ok!
[1124] 从内核发来的信息是:
[1124] to user client
[1124]


[cpp]  view plain  copy
  1. */  
  2.   
  3.   
  4. #include <windows.h>  
  5.   
  6.   
  7. //这两个文件在VS中没有,在WDK中有.  
  8. //如果要用VS编译要拷贝相应的文件到相应的目录或者改变目录的设置等.  
  9. #include <fltuser.h>  
  10. #pragma comment(lib, "fltLib.lib")  
  11.   
  12.   
  13. int _tmain(int argc, _TCHAR* argv[])  
  14. {  
  15.     MessageBox(0,L"请附加调试器",L"调试专用",0);//如果是远程调试的话,这行特别有用.  
  16.   
  17.   
  18.     HANDLE port = INVALID_HANDLE_VALUE;  
  19.     HRESULT hResult = S_OK;  
  20.   
  21.   
  22.     hResult = FilterConnectCommunicationPort( L"\\CommunicationPort", 0, NULL, 0, NULL, &port );  
  23.     if (IS_ERROR( hResult )) {  
  24.         OutputDebugString(L"FilterConnectCommunicationPort fail!\n");  
  25.         return hResult;  
  26.     }  
  27.   
  28.   
  29.     wchar_t InBuffer[] = L"test";  
  30.     wchar_t OutBuffer[MAX_PATH] = {0};  
  31.     DWORD bytesReturned = 0;  
  32.     hResult = FilterSendMessage(port, InBuffer, lstrlen(InBuffer), OutBuffer, sizeof(OutBuffer), &bytesReturned);  
  33.     if (IS_ERROR( hResult )) {  
  34.         OutputDebugString(L"FilterSendMessage fail!\n");  
  35.         CloseHandle( port );  
  36.         return hResult;  
  37.     } else {  
  38.         OutputDebugString(L"FilterSendMessage ok!\n");  
  39.     }  
  40.   
  41.   
  42.     OutputDebugString(L"从内核发来的信息是:");  
  43.     OutputDebugString(OutBuffer);  
  44.     OutputDebugString(L"\n");  
  45.   
  46.   
  47.     CloseHandle( port );  
  48.   
  49.   
  50.  return 0;  
  51. }  



驱动的代码如下:


[cpp]  view plain  copy
  1. /* 
  2. 内核中没有:FltGetMessage,FltReplyMessage函数. 
  3. 个人认为:MessageNotifyCallback有FltGetMessage,FltReplyMessage,FltSendMessage这三个函数的功能. 
  4. 所以在MessageNotifyCallback里面调用这些函数是不对的,得到一些意想不到的效果.建议不要这样做. 
  5.  
  6.  
  7. FltGetMessage除了在MessageNotifyCallback里面,大多的地方都可以调用,但是用户层最好开启线程处理函数. 
  8.  
  9.  
  10. FltGetMessage函数调用示例代码如下: 
  11. //{ 
  12. //    wchar_t SenderBuffer[] = L"SenderBuffer"; 
  13. //    wchar_t ReplyBuffer[] = L"ReplyBuffer"; 
  14. //    ULONG replyLength = sizeof(ReplyBuffer); 
  15. // 
  16. //    status = FltSendMessage( gFilterHandle, &g_ClientPort, SenderBuffer, sizeof(SenderBuffer), ReplyBuffer, &replyLength, NULL); 
  17. //    if (STATUS_SUCCESS == status) { 
  18. //        DbgPrint( "send message to user-mode\n");        
  19. //    } else { 
  20. //        DbgPrint( "couldn't send message to user-mode to scan file, status 0x%X\n", status ); 
  21. //    } 
  22. //} 
  23. */  
  24.   
  25.   
  26. #include <fltKernel.h>  
  27.   
  28.   
  29. PFLT_FILTER gFilterHandle;  
  30. PFLT_PORT g_ServerPort;  
  31. PFLT_PORT g_ClientPort;  
  32.   
  33.   
  34. NTSTATUS MessageNotifyCallback (  
  35.     IN PVOID PortCookie,  
  36.     IN PVOID InputBuffer OPTIONAL,  
  37.     IN ULONG InputBufferLength,  
  38.     OUT PVOID OutputBuffer OPTIONAL,  
  39.     IN ULONG OutputBufferLength,//用户可以接受的数据的最大长度.  
  40.     OUT PULONG ReturnOutputBufferLength)  
  41.     /* 
  42.     这里要注意:1.数据地址的对齐. 
  43.                2.文档建议使用:try/except处理. 
  44.                3.如果是64位的驱动要考虑32位的EXE发来的请求. 
  45.     */  
  46. {  
  47.     NTSTATUS status = 0;  
  48.     wchar_t buffer[] = L"to user client";//  
  49.       
  50.     PAGED_CODE();  
  51.   
  52.   
  53.     UNREFERENCED_PARAMETER(PortCookie);  
  54.   
  55.   
  56.     //打印用户发来的信息  
  57.     KdPrint(("用户发来的信息是:%ls\n",InputBuffer));  
  58.   
  59.   
  60.     //返回用户一些信息.  
  61.     *ReturnOutputBufferLength = sizeof(buffer);  
  62.     RtlCopyMemory(OutputBuffer,buffer,* ReturnOutputBufferLength);  
  63.   
  64.   
  65.     /* 
  66.     minispy在这里用FilterSendMessage获取信息的,对就是FilterSendMessage. 
  67.     这里某个类型里面获取信息,这些信息是在各种操作时(IRP的MJ_)加入链表的. 
  68.     注意链表的操作一定要同步,支持多线程. 
  69.     然后用户的一个线程在不停的获取这些信息. 
  70.     */  
  71.   
  72.   
  73.     return status;  
  74. }  
  75.   
  76.   
  77. VOID DisconnectNotifyCallback (_In_opt_ PVOID ConnectionCookie)  
  78. {  
  79.     PAGED_CODE();  
  80.   
  81.   
  82.     UNREFERENCED_PARAMETER(ConnectionCookie);  
  83.   
  84.   
  85.     FltCloseClientPort(gFilterHandle, &g_ClientPort);//应该加判断,如果ConnectionCookie == 我们的值就执行这行.  
  86. }  
  87.   
  88.   
  89. NTSTATUS ConnectNotifyCallback (IN PFLT_PORT ClientPort, IN PVOID ServerPortCookie, IN PVOID ConnectionContext, IN ULONG SizeOfContext, OUT PVOID * ConnectionPortCookie)  
  90. {  
  91.     PAGED_CODE();  
  92.   
  93.   
  94.     UNREFERENCED_PARAMETER( ServerPortCookie );  
  95.     UNREFERENCED_PARAMETER( ConnectionContext );  
  96.     UNREFERENCED_PARAMETER( SizeOfContext);  
  97.     UNREFERENCED_PARAMETER( ConnectionPortCookie);  
  98.   
  99.   
  100.     //可以加以判断,禁止非法的连接,从而给予保护.  
  101.     g_ClientPort = ClientPort;//保存以供以后使用.  
  102.   
  103.   
  104.     return STATUS_SUCCESS;  
  105. }  
  106.   
  107.   
  108. #pragma PAGEDCODE  
  109. NTSTATUS PtInstanceQueryTeardown (__in PCFLT_RELATED_OBJECTS FltObjects,__in FLT_INSTANCE_QUERY_TEARDOWN_FLAGS Flags)  
  110. {  
  111.     return STATUS_SUCCESS;  
  112. }  
  113.   
  114.   
  115. #pragma PAGEDCODE//#pragma alloc_text(PAGE, PtUnload)  
  116. NTSTATUS PtUnload (__in FLT_FILTER_UNLOAD_FLAGS Flags)  
  117. {  
  118.     FltCloseCommunicationPort(g_ServerPort);//没有这一行是停止不了驱动的,查询也是永远等待中.  
  119.     FltUnregisterFilter( gFilterHandle );  
  120.     return STATUS_SUCCESS;  
  121. }  
  122.   
  123.   
  124. CONST FLT_REGISTRATION FilterRegistration = {  
  125.     sizeof( FLT_REGISTRATION ),         //  Size  
  126.     FLT_REGISTRATION_VERSION,           //  Version  
  127.     0,                                  //  Flags  
  128.     NULL,                               //  Context  
  129.     NULL,                               //  Operation callbacks  
  130.     PtUnload,                           //  MiniFilterUnload  
  131.     NULL,                               //  InstanceSetup  
  132.     PtInstanceQueryTeardown,            //  InstanceQueryTeardown  
  133.     NULL,                               //  InstanceTeardownStart  
  134.     NULL,                               //  InstanceTeardownComplete  
  135.     NULL,                               //  GenerateFileName  
  136.     NULL,                               //  GenerateDestinationFileName  
  137.     NULL                                //  NormalizeNameComponent  
  138. };  
  139.   
  140.   
  141. DRIVER_INITIALIZE DriverEntry;  
  142. #pragma alloc_text(INIT, DriverEntry)//#pragma INITCODE  
  143. NTSTATUS DriverEntry (_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath)  
  144. {  
  145.     NTSTATUS status;  
  146.     PSECURITY_DESCRIPTOR sd;  
  147.     OBJECT_ATTRIBUTES oa;  
  148.     UNICODE_STRING uniString;  
  149.   
  150.   
  151.     UNREFERENCED_PARAMETER(RegistryPath);  
  152.   
  153.   
  154.     KdBreakPoint();  
  155.   
  156.   
  157.     __try  
  158.     {  
  159.         status = FltRegisterFilter(DriverObject, &FilterRegistration, &gFilterHandle);   
  160.         if (!NT_SUCCESS(status)) //;  
  161.         {         
  162.             __leave;  
  163.         }  
  164.   
  165.   
  166.         status  = FltBuildDefaultSecurityDescriptor(&sd, FLT_PORT_ALL_ACCESS);  
  167.         if (!NT_SUCCESS( status )) {  
  168.             __leave;  
  169.         }  
  170.   
  171.   
  172.         RtlInitUnicodeString(&uniString, L"\\CommunicationPort");  
  173.         InitializeObjectAttributes( &oa, &uniString, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, sd);  
  174.         status = FltCreateCommunicationPort(gFilterHandle, &g_ServerPort, &oa, NULL, ConnectNotifyCallback, DisconnectNotifyCallback, MessageNotifyCallback, 1);  
  175.         FltFreeSecurityDescriptor( sd );  
  176.         if (!NT_SUCCESS( status )) {  
  177.             __leave;  
  178.         }  
  179.   
  180.   
  181.         status = FltStartFiltering(gFilterHandle);//这个结果在下面判断.  
  182.     } __finally {  
  183.         if (!NT_SUCCESS( status ) )  
  184.         {  
  185.             if (NULL != g_ServerPort) {  
  186.                 FltCloseCommunicationPort(g_ServerPort);  
  187.             }  
  188.   
  189.   
  190.             if (NULL != gFilterHandle) {  
  191.                 FltUnregisterFilter(gFilterHandle);  
  192.             }  
  193.         }         
  194.     }  
  195.   
  196.   
  197.     return status;  
  198. }  




上面的部分代码最好放到线程中去指向,原因你猜
一些参考文章:
http://www.cnblogs.com/huangyong9527/archive/2012/09/07/2674720.html minifilter 与用户态的通信
http://bbs.pediy.com/showthread.php?t=186931 //minifilter通讯之简单示例之一
http://bbs.pediy.com/showthread.php?t=186932 //minifilter通讯之二:使用FilterGetMessage获取内核拦截的目录的创建
http://blog.csdn.net/caimouse/article/details/1855142 //Windows API一日一练(60)CreateIoCompletionPort和GetQueuedCompletionStatus函数


《Windows内核安全和驱动开发》Minifliter 例子:简单的MiniFilter框架实现了记事本文件无法使用的代码

[cpp]  view plain  copy
  1. #include "fltKernel.h"    
  2. #include "ntddk.h"    
  3.     
  4. #pragma prefast(disable:__WARNING_ENCODE_MEMBER_FUNCTION_POINTER, "Not valid for kernel mode drivers")    
  5.     
  6. NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject,PUNICODE_STRING pReg);    
  7. NTSTATUS NPUnload(FLT_FILTER_UNLOAD_FLAGS Flags);    
  8.     
  9. FLT_PREOP_CALLBACK_STATUS NPPreCreate(        
  10.     __inout PFLT_CALLBACK_DATA Data,    
  11.     __in PCFLT_RELATED_OBJECTS FltObjects,    
  12.     __deref_out_opt PVOID *CompletionContext);    
  13.         
  14. FLT_POSTOP_CALLBACK_STATUS NPPostCreate(    
  15.     __inout PFLT_CALLBACK_DATA Data,    
  16.     __in PCFLT_RELATED_OBJECTS FltObjects,    
  17.     __in_opt PVOID CompletionContext,    
  18.     __in FLT_POST_OPERATION_FLAGS Flags);    
  19.     
  20. #ifdef ALLOC_PRAGMA    
  21.     #pragma alloc_text(INIT,DriverEntry)    
  22.     #pragma alloc_text(PAGE,NPUnload)    
  23.     #pragma alloc_text(PAGE,NPPreCreate)    
  24. #endif    
  25.     
  26.     
  27.     
  28. PFLT_FILTER gFilterHandle;    
  29.     
  30. const FLT_OPERATION_REGISTRATION Callbacks[] =    
  31. {    
  32.     {    
  33.         IRP_MJ_CREATE,    
  34.         0,    
  35.         NPPreCreate,    
  36.         NPPostCreate    
  37.     },    
  38.     {    
  39.         IRP_MJ_OPERATION_END    
  40.     }    
  41. };    
  42.     
  43. const FLT_REGISTRATION FltRegistration =     
  44. {    
  45.     sizeof(FLT_REGISTRATION),    
  46.     FLT_REGISTRATION_VERSION,    
  47.     0,    
  48.     NULL,    
  49.     Callbacks,    
  50.     NPUnload,    
  51.     NULL,    
  52.     NULL,    
  53.     NULL,    
  54.     NULL,    
  55.     NULL,    
  56.     NULL,    
  57.     NULL    
  58. };    
  59.     
  60. NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject,PUNICODE_STRING pReg)    
  61. {    
  62.     NTSTATUS st = STATUS_SUCCESS;    
  63.     st = FltRegisterFilter(pDriverObject,&FltRegistration,&gFilterHandle);    
  64.     if(NT_SUCCESS(st))    
  65.     {    
  66.         st = FltStartFiltering(gFilterHandle);    
  67.         if(!NT_SUCCESS(st))    
  68.         {    
  69.             FltUnregisterFilter(gFilterHandle);    
  70.         }    
  71.     }    
  72.     DbgPrint("[MiniFilter Entry]\n");    
  73.     return st;    
  74. }    
  75.     
  76. NTSTATUS NPUnload(FLT_FILTER_UNLOAD_FLAGS Flags)    
  77. {    
  78.     UNREFERENCED_PARAMETER(Flags);    
  79.     PAGED_CODE();    
  80.     DbgPrint("[MiniFilter Unload]\n");    
  81.     FltUnregisterFilter(gFilterHandle);    
  82.     return STATUS_SUCCESS;    
  83. }    
  84.     
  85. FLT_PREOP_CALLBACK_STATUS NPPreCreate(        
  86.     __inout PFLT_CALLBACK_DATA Data,    
  87.     __in PCFLT_RELATED_OBJECTS FltObjects,    
  88.     __deref_out_opt PVOID *CompletionContext)    
  89. {    
  90.     UNREFERENCED_PARAMETER(FltObjects);    
  91.     UNREFERENCED_PARAMETER(CompletionContext);    
  92.     PAGED_CODE();    
  93.     {    
  94.         UCHAR MajorFunction = 0;    
  95.         PFLT_FILE_NAME_INFORMATION nameInfo;    
  96.         MajorFunction = Data->Iopb->MajorFunction;    
  97.         if(IRP_MJ_CREATE == MajorFunction &&     
  98.             NT_SUCCESS(FltGetFileNameInformation(Data,FLT_FILE_NAME_NORMALIZED | FLT_FILE_NAME_QUERY_DEFAULT,&nameInfo)))    
  99.         {    
  100.             if(NT_SUCCESS(FltParseFileNameInformation(nameInfo)))    
  101.             {//查找notepad.exe字符串,并阻止    
  102.                 if(NULL!=wcsstr(nameInfo->Name.Buffer,L"notepad.exe"))    
  103.                 {    
  104.                     Data->IoStatus.Status = STATUS_ACCESS_DENIED;    
  105.                     Data->IoStatus.Information = 0;    
  106.                     FltReleaseFileNameInformation(nameInfo);    
  107.                     return FLT_PREOP_COMPLETE;    
  108.                 }    
  109.             }    
  110.             FltReleaseFileNameInformation(nameInfo);    
  111.         }    
  112.         //DbgPrint("ENTER CREATE_CALLBACK\n");    
  113.     }    
  114.     return FLT_PREOP_SUCCESS_WITH_CALLBACK;    
  115. }    
  116.     
  117. FLT_POSTOP_CALLBACK_STATUS NPPostCreate(    
  118.     __inout PFLT_CALLBACK_DATA Data,    
  119.     __in PCFLT_RELATED_OBJECTS FltObjects,    
  120.     __in_opt PVOID CompletionContext,    
  121.     __in FLT_POST_OPERATION_FLAGS Flags)    
  122. {    
  123.     return FLT_POSTOP_FINISHED_PROCESSING;    
  124. }    
  125.      





其他可以看TA的教程


至于沙盒
要注意的是
In and out 
重定向
删除的处理
路径的处理


再次说说sandbox的巨大漏洞
在沙盒中的程序如果使用剪切功能 是对外部文件的真正操作


WDK下有例子
在index下有一些帮助文档
wdk samples index ->Windows Driver Kit samples
以及
Windows Drvier Kit -> Device and Driver Technologies->Installable File System Drivers->File System Minifilter Drivers
其它的也可以到这里找哦

猜你喜欢

转载自blog.csdn.net/VHeroin/article/details/80458715
今日推荐