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架构

MiniFilter文件系统学习_第1张图片


结构MiniFilter文件系统学习_第2张图片

在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   
  33. #include   
  34. #include   
  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.  

你可能感兴趣的:(Windows,Kernel,MiniFilter)