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: 
相關文章
相關標籤/搜索