原文地址: 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
![](http://static.javashuo.com/static/loading.gif)
可卸載能力.
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中獲取(即創建成功後才能獲取到真實的數據))
- //在postcreate裏獲得
-
-
- PFLT_FILE_NAME_INFORMATION pNameInfo = NULL;
-
-
- ntStatus = FltGetFileNameInformation(Data,
- FLT_FILE_NAME_NORMALIZED|
- FLT_FILE_NAME_QUERY_DEFAULT,
- &pNameInfo);
- FltParseFileNameInformation(pNameInfo);
-
-
- pNameInfo->Name.Buffer
- pNameInfo->Volume
-
-
- FltReleaseFileNameInformation(pNameInfo);
//重命名的獲得:
- PFILE_RENAME_INFORMATION
- pFileRenameInfomation = (PFILE_RENAME_INFORMATION)Data->Iopb->Parameters.SetFileInformation.InfoBuffer;
-
-
- FltGetDestinationFileNameInformation //重命名獲得
安裝方式(.inf/動態加載)
通信方式(port)
同樣遵循IRQL,鎖等內核開發通用機制
FltCreateFile
Minfilter架構
![](http://static.javashuo.com/static/loading.gif)
結構![](http://static.javashuo.com/static/loading.gif)
在DriverEntry中只需要註冊Fliter和Start
- FltRegisterFilter( DriverObject,
- &fileMonitorRegistration,
- &g_pFilter );
- FltStartFiltering( g_pFilter );
fileMonitorRegistration是唯一我們需要做的
這是一個FLT_REGISTRATION 結構
- const FLT_REGISTRATION fileMonitorRegistration =
- {
- sizeof( FLT_REGISTRATION ), // Size
- FLT_REGISTRATION_VERSION, // Version
- 0, // Flags
- ContextRegistration, // ContextRegistration //上下文數組
- fileMonitorCallbacks, // Operation callbacks//最重要的
- fileMonUnload, // FilterUnload
- fileMonInstanceSetup, // InstanceSetup
- NULL, // InstanceQueryTeardown
- fileMonInstanceTeardownStart, // InstanceTeardownStart
- NULL, // InstanceTeardownComplete
- NULL, // GenerateFileName
- NULL, // GenerateDestinationFileName
- NULL // NormalizeNameComponent
- };
fileMonitorCallbacks 例子:
可以只需要一個回調如IRP_MJ_CLEANUP
- const FLT_OPERATION_REGISTRATION
- fileMonitorCallbacks[] =
- {
- {
- IRP_MJ_CREATE,
- FLTFL_OPERATION_REGISTRATION_SKIP_PAGING_IO,//這個是可以忽略的IRP
- HOOK_PreNtCreateFile,
- HOOK_PostNtCreateFile
- },
- {
- IRP_MJ_CLEANUP,
- 0,
- HOOK_PreNtCleanup,
- NULL
- },
- {
- IRP_MJ_WRITE,
- 0,
- HOOK_PreNtWriteFile,
- HOOK_PostNtWriteFile
- },
- {
- IRP_MJ_SET_INFORMATION,
- 0,
- HOOK_PreNtSetInformationFile,
- HOOK_PostNtSetInformationFile
- },
- {
- IRP_MJ_OPERATION_END//這個是必須要加的
- }
- };
//一個回調的例子:
- FLT_PREOP_CALLBACK_STATUS
- HOOK_PreNtCreateFile (
- PFLT_CALLBACK_DATA Data,
- PCFLT_RELATED_OBJECTS FltObjects,
- PVOID *CompletionContext
- //分配的一個context資源
- )
- {
- //sandbox?
- //主防??
- //殺毒引擎??
- //加解密??
- return XXX;
- }
- FLT_POSTOP_CALLBACK_STATUS
- HOOK_PostNtCreateFile (
- PFLT_CALLBACK_DATA Data,
- PCFLT_RELATED_OBJECTS FltObjects,
- PVOID CompletionContext,
- //在PRE-OP裏返回 //FLT_PREOP_SUCCESS_WITH_CALLBACK
- //時獲取裏面的上下文,並最後釋放
- FLT_POST_OPERATION_FLAGS Flags
- )
- {
- return XXX;
- }
上下位數組 例子:
- PFLT_FILTER g_pFilter = NULL;
- const FLT_CONTEXT_REGISTRATION
- ContextRegistration[] =
- {//在釋放context之前調用,可以在此釋放context裏的內存等
- {
- FLT_INSTANCE_CONTEXT,
- 0,
- CtxContextCleanup,
- CTX_INSTANCE_CONTEXT_SIZE,
- CTX_INSTANCE_CONTEXT_TAG
- },
- {
- FLT_FILE_CONTEXT,
- 0,
- CtxContextCleanup,
- CTX_FILE_CONTEXT_SIZE,
- CTX_FILE_CONTEXT_TAG
- },
- {
- FLT_STREAM_CONTEXT,
- 0,
- CtxContextCleanup,
- CTX_STREAM_CONTEXT_SIZE,
- CTX_STREAM_CONTEXT_TAG
- },
- {
- FLT_STREAMHANDLE_CONTEXT,
- 0,
- CtxContextCleanup,
- CTX_STREAMHANDLE_CONTEXT_SIZE,
- CTX_STREAMHANDLE_CONTEXT_TAG
- },
- { FLT_CONTEXT_END }
- };
Minifilter的啓動
- NTSTATUS initFileMonitor (PDRIVER_OBJECT DriverObject )
- {
- return FltRegisterFilter( DriverObject,
- &fileMonitorRegistration,
- &g_pFilter );
- }
-
-
-
-
- NTSTATUS startFileMonitor( )
- {
- if(g_pFilter)
- return FltStartFiltering( g_pFilter );
- return STATUS_INSUFFICIENT_RESOURCES;
- }
-
-
- VOID stopFileMonitor( )
- {
- if(g_pFilter)
- {
- FltUnregisterFilter( g_pFilter );
- g_pFilter = NULL;
- }
- }
.inf文件安裝minifilter
這個就是抄啊改的 沒什麼介紹的,只需要注意裏面的ClassGUID和Class必須對上
這是查詢網址
http://msdn.microsoft.com/en-us/library/windows/hardware/ff540394(v=vs.85).aspx
如果需要用自己的加載器加載Minfilter 只需要在註冊表服務對應的RegPath下創建REG_SZ類型的Instances子健
在這裏鍵下創建鍵值項,項值爲Altitude
- SYSTEM\\CurrentControlSet\\Services\\DriverName\\Instances子健下的鍵值項
- 例子:
- //-------------------------------------------------------------------------------------------------------
- // SYSTEM\\CurrentControlSet\\Services\\DriverName\\Instances子健下的鍵值項
- //-------------------------------------------------------------------------------------------------------
- strcpy(szTempStr,"SYSTEM\\CurrentControlSet\\Services\\");
- strcat(szTempStr,lpszDriverName);
- strcat(szTempStr,"\\Instances");
- if(RegCreateKeyEx(HKEY_LOCAL_MACHINE,szTempStr,0,"",REG_OPTION_NON_VOLATILE,KEY_ALL_ACCESS,NULL,&hKey,(LPDWORD)&dwData)!=ERROR_SUCCESS)
- {
- return FALSE;
- }
- // 註冊表驅動程序的DefaultInstance 值
- strcpy(szTempStr,lpszDriverName);
- strcat(szTempStr," Instance");
- if(RegSetValueEx(hKey,"DefaultInstance",0,REG_SZ,(CONST BYTE*)szTempStr,(DWORD)strlen(szTempStr))!=ERROR_SUCCESS)
- {
- return FALSE;
- }
- RegFlushKey(hKey);//刷新註冊表
- RegCloseKey(hKey);
-
-
-
- //-------------------------------------------------------------------------------------------------------
- // SYSTEM\\CurrentControlSet\\Services\\DriverName\\Instances\\DriverName Instance子健下的鍵值項
- //-------------------------------------------------------------------------------------------------------
- strcpy(szTempStr,"SYSTEM\\CurrentControlSet\\Services\\");
- strcat(szTempStr,lpszDriverName);
- strcat(szTempStr,"\\Instances\\");
- strcat(szTempStr,lpszDriverName);
- strcat(szTempStr," Instance");
- if(RegCreateKeyEx(HKEY_LOCAL_MACHINE,szTempStr,0,"",REG_OPTION_NON_VOLATILE,KEY_ALL_ACCESS,NULL,&hKey,(LPDWORD)&dwData)!=ERROR_SUCCESS)
- {
- return FALSE;
- }
- // 註冊表驅動程序的Altitude 值
- strcpy(szTempStr,lpszAltitude);
- if(RegSetValueEx(hKey,"Altitude",0,REG_SZ,(CONST BYTE*)szTempStr,(DWORD)strlen(szTempStr))!=ERROR_SUCCESS)
- {
- return FALSE;
- }
- // 註冊表驅動程序的Flags 值
- dwData=0x0;
- if(RegSetValueEx(hKey,"Flags",0,REG_DWORD,(CONST BYTE*)&dwData,sizeof(DWORD))!=ERROR_SUCCESS)
- {
- return FALSE;
- }
- RegFlushKey(hKey);//刷新註冊表
- RegCloseKey(hKey);
-
-
- return TRUE;
下面說一說回調
- FLT_PREOP_CALLBACK_STATUS
- HOOK_PreNtCreateFile (
- PFLT_CALLBACK_DATA Data,
- PCFLT_RELATED_OBJECTS FltObjects,
- PVOID *CompletionContext
- //分配的一個context資源
- )
- {
- //sandbox?
- //主防??
- //殺毒引擎??
- //加解密??
- return XXX;
- }
- FLT_POSTOP_CALLBACK_STATUS
- HOOK_PostNtCreateFile (
- PFLT_CALLBACK_DATA Data,
- PCFLT_RELATED_OBJECTS FltObjects,
- PVOID CompletionContext,
- //在PRE-OP裏返回 //FLT_PREOP_SUCCESS_WITH_CALLBACK
- //時獲取裏面的上下文,並最後釋放
- FLT_POST_OPERATION_FLAGS Flags
- )
- {
- return XXX;
- }
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是什麼操作的宏
- FLT_IS_IRP_OPERATION
- FLT_IS_FASTIO_OPERATION
- FLT_IS_FS_FILTER_OPERATION
- if(FLT_IS_FASTIO_OPERATION(Data))
- {
- ntStatus = STATUS_FLT_DISALLOW_FAST_IO;
- Data->IoStatus.Status = ntStatus;
- Data->IoStatus.Information = 0;
- return FLT_PREOP_DISALLOW_FASTIO;
-
-
- }
參數數據的獲取:
- PFLT_CALLBACK_DATA Data;
- PEPROCESS processObject =
- Data->Thread ? IoThreadToProcess(Data->Thread) : PsGetCurrentProcess();//獲取EPROCESS
- HandleToUlong(PsGetProcessId(processObject));//獲取PID
-
-
- Data->IoStatus.Status = ntStatus;//返回給R3的
- Data->IoStatus.Information = 0;//同上
-
-
- FltObjects->Volume,//卷
- FltObjects->Instance,//實例
- FltObjects->FileObject,//文件對象
- FltObjects->FileObject->DeviceObject//設備對象
-
-
- Data->Iopb->Parameters.Create.SecurityContext->DesiredAccess //創建的權限
比如這次是查詢目錄 (怎麼判斷是什麼操作?每個對應的回調就告訴你了這是什麼操作,不可以在Create的回調中收到寫操作把)
- PVOID pQueryBuffer =
- Data->Iopb->Parameters.DirectoryControl.QueryDirectory.DirectoryBuffer;
- ULONG uQueryBufferSize =
- Data->Iopb->Parameters.DirectoryControl.QueryDirectory.Length
//讀, 讀有可能是使用MDL可能使用其它buff 判斷的方法是看這個有沒有值,沒有值則是另一種
- PMDL pReadMdl = Data->Iopb->Parameters.Read. MdlAddress;
- PVOID pReadBuffer = Data->Iopb->Parameters.Read. ReadBuffer;
- ULONG uReadLength = Data->Iopb->Parameters.Read.Length;
寫同上面
路徑的獲取:
- //在postcreate裏獲得
-
-
- PFLT_FILE_NAME_INFORMATION pNameInfo = NULL;
-
-
- ntStatus = FltGetFileNameInformation(Data,
- FLT_FILE_NAME_NORMALIZED|
- FLT_FILE_NAME_QUERY_DEFAULT,
- &pNameInfo);
- FltParseFileNameInformation(pNameInfo);
-
-
- pNameInfo->Name.Buffer
- pNameInfo->Volume
-
-
- FltReleaseFileNameInformation(pNameInfo);
pNameInfo裏面還有很多東西
WDK裏面的例子:
- // look again at the first example string from above:
- //
- // \Device\HarddiskVolume1\Documents and Settings\MyUser\My Documents\Test Results.txt:stream1
- //
- // Extension = "txt"
- // Stream = ":stream1"
- // FinalComponent = "Test Results.txt:stream1"
- // ParentDir = "\Documents and Settings\MyUser\My Documents\"
//重命名的獲得:
- PFILE_RENAME_INFORMATION
- pFileRenameInfomation = (PFILE_RENAME_INFORMATION)Data->Iopb->Parameters.SetFileInformation.InfoBuffer;
-
-
- 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
其中的一個例子:
- ntStatus = FltCreateFile(pFilter,
- pDstInstance,
- &hDstFile,
- GENERIC_WRITE | SYNCHRONIZE,
- &objDstAttrib,
- &ioStatus,
- 0,
- FILE_ATTRIBUTE_NORMAL,
- FILE_SHARE_READ |
- FILE_SHARE_WRITE |
- FILE_SHARE_DELETE,
- FILE_CREATE,
- CreateOptions,
- 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
- PFLT_FILTER g_pFilter = NULL;
- const FLT_CONTEXT_REGISTRATION
- ContextRegistration[] =
- {//在釋放context之前調用,可以在此釋放context裏的內存等
- {
- FLT_INSTANCE_CONTEXT,
- 0,
- CtxContextCleanup,
- CTX_INSTANCE_CONTEXT_SIZE,
- CTX_INSTANCE_CONTEXT_TAG
- },
- {
- FLT_FILE_CONTEXT,
- 0,
- CtxContextCleanup,
- CTX_FILE_CONTEXT_SIZE,
- CTX_FILE_CONTEXT_TAG
- },
- {
- FLT_STREAM_CONTEXT,
- 0,
- CtxContextCleanup,
- CTX_STREAM_CONTEXT_SIZE,
- CTX_STREAM_CONTEXT_TAG
- },
- {
- FLT_STREAMHANDLE_CONTEXT,
- 0,
- CtxContextCleanup,
- CTX_STREAMHANDLE_CONTEXT_SIZE,
- CTX_STREAMHANDLE_CONTEXT_TAG
- },
- { FLT_CONTEXT_END }
- };
Context使用例子
- typedef struct _INSTANCE_CONTEXT {
- …
- } INSTANCE_CONTEXT, *PINSTANCE_CONTEXT;
- PINSTANCE_CONTEXT pContext = NULL;
- //分配與設置
- ntStatus = FltGetInstanceContext(FltObjects->Instance, & pContext);//嘗試獲取
- if(NT_SUCCESS(Status) == FALSE)
- {
- ntStatus = FltAllocateContext(g_pFilter,FLT_INSTANCE_CONTEXT,
- sizeof(INSTANCE_CONTEXT),
- PagedPool,& pContext);
- if(NT_SUCCESS(Status) == FALSE)
- {
- return STATUS_SUCCESS;
- }
- RtlZeroMemory(pContext, sizeof(INSTANCE_CONTEXT));
- }
- pContext ->m_DeviceType = VolumeDeviceType;
- pContext->m_FSType = VolumeFilesystemType;
- FltSetInstanceContext(FltObjects->Instance, FLT_SET_CONTEXT_REPLACE_IF_EXISTS,pContext,NULL);
- if (pContext)
- {
- FltReleaseContext(pContext);
- }
//獲取訪問
- PINSTANCE_CONTEXT pContext = NULL;
- Status = FltGetInstanceContext(FltObjects->Instance,&pContext);
- pContext->xxx = xxx;
Minifilter R3與R0通信
不用像NT框架裏面的通信方式了,Minifilter爲我們提供了專門的函數進行通信
在通信時,我們使用Port進行通信
在R0,我們創建一個Port,R3在通信前會得到Port的句柄,我們就可以通過這個port進行通信了
R0創建端口代碼:
- RtlInitUnicodeString( &uniString, ScannerPortName );
-
-
- //
- // We secure the port so only ADMINs & SYSTEM can acecss it.
- //
- //設置通信端口權限 ,只有管理員和系統進程才能操作
- status = FltBuildDefaultSecurityDescriptor( &sd, FLT_PORT_ALL_ACCESS );
-
-
- if (NT_SUCCESS( status )) {
-
-
- InitializeObjectAttributes( &oa,
- &uniString,
- OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
- NULL,
- sd );
-
-
- //創建通信端口,並設置對應的回調函數
- status = FltCreateCommunicationPort( ScannerData.Filter,
- &ScannerData.ServerPort,
- &oa,//設置的名字
- NULL,
- ScannerPortConnect,//當R3連接時回調 主要是記錄R3的進程ID或EPROCESS以便放過本進程 還有記錄R3的通信端口,給後面主動通信的時候用
- ScannerPortDisconnect,//當R3離線時回調 主要是關閉R3端口和設置R3的進程信息爲NULL
- NULL,//處理R3主動函數 比如R3下新的規則,
- 1 );//最後一個常爲1
- //
- // Free the security descriptor in all cases. It is not needed once
- // the call to FltCreateCommunicationPort() is made.
- //
- //設置好後需要釋放權限的設置
- FltFreeSecurityDescriptor( sd );
- //下面就是判斷是否創建成功,成功後就開始開啓過濾
先說說HIPS的實現,
r3,首先得到R0通信端口的句柄
使用FilterConnectCommunicationPort 只需要注意第一個參數和最後一個參數即可 其它都爲0或NULL
然後綁定這個端口(我理解爲綁定)
使用CreateIoCompletionPort 只需要注意第一個參數最後一個參數即可,最後一個參數:爲這個工作線程設置幾個線程
這樣有助於高效率 一般小於64 ,也可以設置請求次數 這樣回覆也會高效率一些(具體看後面的代碼)
我們首先使用FiltetGetMessage異步獲取一下消息,如果有信息,則下面的GetQueuedCompletionStatus就會恢復(如果沒有消息,GetQueuedCompletionStatus就會暫停下來,並讓出CPU,等待有信息)
有了信息後我們就可以進行掃描 過濾,搞定之後就調用FilterReplyMessage返回給內核
然後繼續調用FilterGetMessage-等待--處理--返回給內核
代碼:
- FilterConnectCommunicationPort( ScannerPortName,//與R0的名字一致
- 0,
- NULL,
- 0,
- NULL,
- &port );//R0端口
-
-
- //處理從R0來的請求,即R0調用FltSendMessage的請求
- completion = CreateIoCompletionPort( port,NULL,0,1);
- FilterGetMessage( Port,
- &message->MessageHeader,
- FIELD_OFFSET( SANDBOX_MESSAGE, Ovlp ),
- &message->Ovlp );
- while(1)
- {
- GetQueuedCompletionStatus( lpContext->Completion, &outSize, &key, &pOvlp, INFINITE );
- //過濾,掃描
- FilterReplyMessage(Port,
- (PFILTER_REPLY_HEADER) &replyMessage,
- sizeof( replyMessage ) );
- FilterGetMessage( Port,
- &message->MessageHeader,
- FIELD_OFFSET( SANDBOX_MESSAGE, Ovlp ),
- &message->Ovlp );
- }
注意:這裏的FILTER_REPLY_HEADER結構,裏面有一項是固定的,有一項是可以自定義的,包括增加自己的結構
同樣的Message對應的結構裏面有一項也是可以自定義的 ,這要跟內核對應起來就可以了,內核裏面只有自定義的那一項
比如:R0數據結構 這個就是自定義的
- typedef struct _SCANNER_NOTIFICATION
- {
- ULONG BytesToScan;
- ULONG Reserved;
- UCHAR Contents[SCANNER_READ_BUFFER_SIZE];
-
- } SCANNER_NOTIFICATION, *PSCANNER_NOTIFICATION;
-
-
- typedef struct _SCANNER_REPLY
- {
- BOOLEAN SafeToOpen;
-
-
- } SCANNER_REPLY, *PSCANNER_REPLY;
R3的結構
- typedef struct _SCANNER_MESSAGE
- {
- FILTER_MESSAGE_HEADER MessageHeader;
- SCANNER_NOTIFICATION Notification;//可以自定義的 ,跟內核結構對應起來
- OVERLAPPED Ovlp;
- } SCANNER_MESSAGE, *PSCANNER_MESSAGE;
-
-
- typedef struct _SCANNER_REPLY_MESSAGE
- {
- FILTER_REPLY_HEADER ReplyHeader;
- SCANNER_REPLY Reply;//可以自定義的,跟內核結構對應起來
- } SCANNER_REPLY_MESSAGE,
- *PSCANNER_REPLY_MESSAGE;
那R0怎麼發送消息給R3呢
使用FltSendMessage
實例代碼:
- //發送消息給R3
- timeout.QuadPart = (LONGLONG)40 * -10000000i64; // 內核等待 40 seconds
- Status = FltSendMessage( g_pFilter,
- &g_pClientPort,//給R3發消息
- &request,
- sizeof(SCANNER_NOTIFICATION),
- &reply,
- &replySize,
- &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事前回調中,我們設置上下文,然後再後面操作中,我們獲取這個上下文,如果獲取不到就不是我們要操作的文件
這裏其實沒啥用,只是演示如果使用上下文,當然這裏的上下文結構裏面可以自定義,我這裏是設置了需要不需要重新掃描
- typedef struct _SCANNER_STREAM_HANDLE_CONTEXT {
-
-
- BOOLEAN RescanRequired;
-
- } SCANNER_STREAM_HANDLE_CONTEXT, *PSCANNER_STREAM_HANDLE_CONTEXT;
代碼例子:內核處理寫操作 需要注意的事,有一個IRP是FLT管理器發的,有點特殊,需要放過,見代碼尾巴
- //處理寫關閉
- FLT_PREOP_CALLBACK_STATUS
- ScannerPreWrite (
- __inout PFLT_CALLBACK_DATA Data,
- __in PCFLT_RELATED_OBJECTS FltObjects,
- __deref_out_opt PVOID *CompletionContext
- )
- /*++
-
-
- Routine Description:
-
-
- Pre write callback. We want to scan what's being written now.
-
-
- Arguments:
-
-
- Data - The structure which describes the operation parameters.
-
-
- FltObject - The structure which describes the objects affected by this
- operation.
-
-
- CompletionContext - Output parameter which can be used to pass a context
- from this pre-write callback to the post-write callback.
-
-
- Return Value:
-
-
- Always FLT_PREOP_SUCCESS_NO_CALLBACK.
-
-
- --*/
- {
- FLT_PREOP_CALLBACK_STATUS returnStatus = FLT_PREOP_SUCCESS_NO_CALLBACK;
- NTSTATUS status;
- PSCANNER_NOTIFICATION notification = NULL;
- PSCANNER_STREAM_HANDLE_CONTEXT context = NULL;
- ULONG replyLength;
- BOOLEAN safe = TRUE;
- PUCHAR buffer;
-
-
- UNREFERENCED_PARAMETER( CompletionContext );
-
-
- //
- // If not client port just ignore this write.
- //
- //如果R3進程退出了
- if (ScannerData.ClientPort == NULL) {
-
-
- return FLT_PREOP_SUCCESS_NO_CALLBACK;
- }
- //獲取上下文
- status = FltGetStreamHandleContext( FltObjects->Instance,
- FltObjects->FileObject,
- &context );
- //不是我們要處理的文件,(可以在創建事前回調中設置上下文,比如判斷這個文件是不是記事本,如果是,我們就給它設置一個上下文,然後到後我們就可以知道這個文件是不是我們設置過的記事本)
- //這也可以判斷,不過一般不這麼使用,一般是在上下文中插入自己想要信息,然後到這裏我們到這個上下文中去取
- if (!NT_SUCCESS( status )) {
-
-
- //
- // We are not interested in this file
- //
-
-
- return FLT_PREOP_SUCCESS_NO_CALLBACK;
-
-
- }
-
-
- //
- // Use try-finally to cleanup
- //
-
-
- //必須使用異常處理結構
- try {
-
-
- //
- // Pass the contents of the buffer to user mode.
- //
- //如果寫的長度爲0 就放行
- if (Data->Iopb->Parameters.Write.Length != 0) {
-
-
- //
- // Get the users buffer address. If there is a MDL defined, use
- // it. If not use the given buffer address.
- //
- //開始獲取數據緩存區 有2個緩存區,需要判斷在數據在哪個buff中 判斷的方法前面說過了
- if (Data->Iopb->Parameters.Write.MdlAddress != NULL) {
-
-
- buffer = MmGetSystemAddressForMdlSafe( Data->Iopb->Parameters.Write.MdlAddress,
- NormalPagePriority );
-
-
- //
- // If we have a MDL but could not get and address, we ran out
- // of memory, report the correct error
- //
- //如果獲取失敗了 就返回資源不足 並不下發了
- if (buffer == NULL) {
-
-
- Data->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
- Data->IoStatus.Information = 0;
- returnStatus = FLT_PREOP_COMPLETE;
- leave;
- }
-
-
- } else {
-
-
- //
- // Use the users buffer
- //
- //不是MDL就是USERbuff
- buffer = Data->Iopb->Parameters.Write.WriteBuffer;
- }
-
-
- //
- // In a production-level filter, we would actually let user mode scan the file directly.
- // Allocating & freeing huge amounts of non-paged pool like this is not very good for system perf.
- // This is just a sample!
- //
- //爲發送給R3數據申請內存
- notification = ExAllocatePoolWithTag( NonPagedPool,
- sizeof( SCANNER_NOTIFICATION ),
- 'nacS' );
- if (notification == NULL) {
-
-
- Data->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
- Data->IoStatus.Information = 0;
- returnStatus = FLT_PREOP_COMPLETE;
- leave;
- }
- //取最小啦 這裏設置SCANNER_READ_BUFFER_SIZE爲1024
- notification->BytesToScan = min( Data->Iopb->Parameters.Write.Length, SCANNER_READ_BUFFER_SIZE );
-
-
- //
- // The buffer can be a raw user buffer. Protect access to it
- //
- //內存操作 必須使用結構化異常處理
- try {
-
-
- RtlCopyMemory( ¬ification->Contents,
- buffer,
- notification->BytesToScan );
-
-
- } except( EXCEPTION_EXECUTE_HANDLER ) {
-
-
- //
- // Error accessing buffer. Complete i/o with failure
- //
- //出錯就返回錯誤代碼並阻止下發啦
- Data->IoStatus.Status = GetExceptionCode() ;
- Data->IoStatus.Information = 0;
- returnStatus = FLT_PREOP_COMPLETE;
- leave;
- }
-
-
- //
- // Send message to user mode to indicate it should scan the buffer.
- // We don't have to synchronize between the send and close of the handle
- // as FltSendMessage takes care of that.
- //
- //發送數據給R3 處理
- replyLength = sizeof( SCANNER_REPLY );
-
-
- status = FltSendMessage( ScannerData.Filter,
- &ScannerData.ClientPort,
- notification,
- sizeof( SCANNER_NOTIFICATION ),
- notification,
- &replyLength,
- NULL );//永遠等待,一般40秒吧
- //爲什麼共用一塊內存呢 你猜
- if (STATUS_SUCCESS == status) {
- //用戶返回的處理結果
- safe = ((PSCANNER_REPLY) notification)->SafeToOpen;
-
-
- } else {
-
-
- //
- // Couldn't send message. This sample will let the i/o through.
- //
-
-
- DbgPrint( "!!! scanner.sys --- couldn't send message to user-mode to scan file, status 0x%X\n", status );
- }
- }
- //這個是不安全的 你猜怎麼辦?
- if (!safe) {
-
-
- //
- // Block this write if not paging i/o (as a result of course, this scanner will not prevent memory mapped writes of contaminated
- // strings to the file, but only regular writes). The effect of getting ERROR_ACCESS_DENIED for many apps to delete the file they
- // are trying to write usually.
- // To handle memory mapped writes - we should be scanning at close time (which is when we can really establish that the file object
- // is not going to be used for any more writes)
- //
-
-
- DbgPrint( "!!! scanner.sys -- foul language detected in write !!!\n" );
-
-
- //如果不是Flt管理髮送的,這個IRP很特殊 ,必須放行,如果不是這個IRP就阻止了,因爲它是不安全的
- if (!FlagOn( Data->Iopb->IrpFlags, IRP_PAGING_IO )) {
-
-
- DbgPrint( "!!! scanner.sys -- blocking the write !!!\n" );
-
-
- Data->IoStatus.Status = STATUS_ACCESS_DENIED;
- Data->IoStatus.Information = 0;
- returnStatus = FLT_PREOP_COMPLETE;
- }
- }
-
-
- } finally {
- //該釋放的釋放
- if (notification != NULL) {
-
-
- ExFreePoolWithTag( notification, 'nacS' );
- }
-
-
- if (context) {
-
-
- FltReleaseContext( context );
- }
- }
-
-
- return returnStatus;
- }
MF實現的一個封轉的處理函數,這個函數可以將文件的內容發給R3,讓R3處理並返回一個結果
爲什麼需要這個函數呢?
如果不是寫,我們不能直接緩存區數據,那麼我們需要讀到這個文件的內容發給R3,這個函數就是這個功能
代碼:其中包括了Minifilter讀文件操作
其實注意的是申請的大小,我們是不知道這個文件到底有多大的,但我們確定的是這個文件一般比這個卷的大小小,所以我們暫時先申請卷的大小
然後下面讀的時候會返回文件的大小,到時候就可以知道有多大了
- NTSTATUS
- ScannerpScanFileInUserMode (
- __in PFLT_INSTANCE Instance,
- __in PFILE_OBJECT FileObject,
- __out PBOOLEAN SafeToOpen
- )
- /*++
-
-
- Routine Description:
-
-
- This routine is called to send a request up to user mode to scan a given
- file and tell our caller whether it's safe to open this file.
-
-
- Note that if the scan fails, we set SafeToOpen to TRUE. The scan may fail
- because the service hasn't started, or perhaps because this create/cleanup
- is for a directory, and there's no data to read & scan.
-
-
- If we failed creates when the service isn't running, there'd be a
- bootstrapping problem -- how would we ever load the .exe for the service?
-
-
- Arguments:
-
-
- Instance - Handle to the filter instance for the scanner on this volume.
-
-
- FileObject - File to be scanned.
-
-
- SafeToOpen - Set to FALSE if the file is scanned successfully and it contains
- foul language.
-
-
- Return Value:
-
-
- The status of the operation, hopefully STATUS_SUCCESS. The common failure
- status will probably be STATUS_INSUFFICIENT_RESOURCES.
-
-
- --*/
-
-
- {
- NTSTATUS status = STATUS_SUCCESS;
- PVOID buffer = NULL;
- ULONG bytesRead;
- PSCANNER_NOTIFICATION notification = NULL;
- FLT_VOLUME_PROPERTIES volumeProps;
- LARGE_INTEGER offset;
- ULONG replyLength, length;
- PFLT_VOLUME volume = NULL;
-
-
- *SafeToOpen = TRUE;
-
-
- //
- // If not client port just return.
- //
-
-
- if (ScannerData.ClientPort == NULL) {
-
-
- return STATUS_SUCCESS;
- }
-
-
- try {
-
-
- //
- // Obtain the volume object .
- //
-
-
- status = FltGetVolumeFromInstance( Instance, &volume );
-
-
- if (!NT_SUCCESS( status )) {
-
-
- leave;
- }
-
-
- //
- // Determine sector size. Noncached I/O can only be done at sector size offsets, and in lengths which are
- // multiples of sector size. A more efficient way is to make this call once and remember the sector size in the
- // instance setup routine and setup an instance context where we can cache it.
- //
-
-
- status = FltGetVolumeProperties( volume,
- &volumeProps,
- sizeof( volumeProps ),
- &length );
- //
- // STATUS_BUFFER_OVERFLOW can be returned - however we only need the properties, not the names
- // hence we only check for error status.
- //
-
-
- if (NT_ERROR( status )) {
-
-
- leave;
- }
-
-
- length = max( SCANNER_READ_BUFFER_SIZE, volumeProps.SectorSize );
-
-
- //
- // Use non-buffered i/o, so allocate aligned pool
- //
-
-
- buffer = FltAllocatePoolAlignedWithTag( Instance,
- NonPagedPool,
- length,
- 'nacS' );
-
-
- if (NULL == buffer) {
-
-
- status = STATUS_INSUFFICIENT_RESOURCES;
- leave;
- }
-
-
- notification = ExAllocatePoolWithTag( NonPagedPool,
- sizeof( SCANNER_NOTIFICATION ),
- 'nacS' );
-
-
- if(NULL == notification) {
-
-
- status = STATUS_INSUFFICIENT_RESOURCES;
- leave;
- }
-
-
- //
- // Read the beginning of the file and pass the contents to user mode.
- //
-
-
- offset.QuadPart = bytesRead = 0;
- status = FltReadFile( Instance,
- FileObject,
- &offset,
- length,
- buffer,
- FLTFL_IO_OPERATION_NON_CACHED |
- FLTFL_IO_OPERATION_DO_NOT_UPDATE_BYTE_OFFSET,
- &bytesRead,
- NULL,
- NULL );
-
-
- if (NT_SUCCESS( status ) && (0 != bytesRead)) {
-
-
- notification->BytesToScan = (ULONG) bytesRead;
-
-
- //
- // Copy only as much as the buffer can hold
- //
-
-
- RtlCopyMemory( ¬ification->Contents,
- buffer,
- min( notification->BytesToScan, SCANNER_READ_BUFFER_SIZE ) );
-
-
- replyLength = sizeof( SCANNER_REPLY );
-
-
- status = FltSendMessage( ScannerData.Filter,
- &ScannerData.ClientPort,
- notification,
- sizeof(SCANNER_NOTIFICATION),
- notification,
- &replyLength,
- NULL );
-
-
- if (STATUS_SUCCESS == status) {
-
-
- *SafeToOpen = ((PSCANNER_REPLY) notification)->SafeToOpen;
-
-
- } else {
-
-
- //
- // Couldn't send message
- //
-
-
- DbgPrint( "!!! scanner.sys --- couldn't send message to user-mode to scan file, status 0x%X\n", status );
- }
- }
-
-
- } finally {
-
-
- if (NULL != buffer) {
-
-
- FltFreePoolAlignedWithTag( Instance, buffer, 'nacS' );
- }
-
-
- if (NULL != notification) {
-
-
- ExFreePoolWithTag( notification, 'nacS' );
- }
-
-
- if (NULL != volume) {
-
-
- FltObjectDereference( volume );
- }
- }
-
-
- return status;
- }
思考:傳BUFF給R3幹什麼?
解答:你猜
說一說一種比較特殊的情況
一個文件已寫權限打開(創建)了,剛開始我們掃描過它沒有問題
問:一個人現在是好人,那麼他一輩子都是好人嗎?
所以,我們需要會他設置一個上下文,上下文中有一個標誌,改標誌的作用是告訴Close時在掃描一次
其實這就是介紹上下文使用啦
核心代碼:在創建事後回調中(別以爲事後回調沒有控制權了,它還是可以返回取消前面的操作哦 見最後面的代碼)
- //前面是掃描過這個文件了而且這個文件是安全的,但它有寫權限,那麼就要注意了
- if (FltObjects->FileObject->WriteAccess) {
-
-
- //
- //
- // The create has requested write access, mark to rescan the file.
- // Allocate the context.
- //
-
-
- status = FltAllocateContext( ScannerData.Filter,
- FLT_STREAMHANDLE_CONTEXT,
- sizeof(SCANNER_STREAM_HANDLE_CONTEXT),
- PagedPool,
- &scannerContext );
-
-
- if (NT_SUCCESS(status)) {
-
-
- //
- // Set the handle context.
- //
-
-
- scannerContext->RescanRequired = TRUE;
-
-
- (VOID) FltSetStreamHandleContext( FltObjects->Instance,
- FltObjects->FileObject,
- FLT_SET_CONTEXT_REPLACE_IF_EXISTS,
- scannerContext,
- NULL );
-
-
- //
- // Normally we would check the results of FltSetStreamHandleContext
- // for a variety of error cases. However, The only error status
- // that could be returned, in this case, would tell us that
- // contexts are not supported. Even if we got this error,
- // we just want to release the context now and that will free
- // this memory if it was not successfully set.
- //
-
-
- //
- // Release our reference on the context (the set adds a reference)
- //
-
-
- FltReleaseContext( scannerContext );
- }
然後再close的時候我們處理
這裏說一說cleanup和closeup有什麼區別,前者是使用zwclose或者closehandle 後者使用Obdef (忘記了對象計數減1的那個)
- //處理打開時 有寫權限但 打開成功時是安全的,等它關閉的時候的我們來掃描它
- //觸發這個回調的條件是文件引用技術爲0,這個包括內核+R3的計數,一般是在上層使用了ZwClose或者CloseHandle時調用
- FLT_PREOP_CALLBACK_STATUS
- ScannerPreCleanup (
- __inout PFLT_CALLBACK_DATA Data,
- __in PCFLT_RELATED_OBJECTS FltObjects,
- __deref_out_opt PVOID *CompletionContext
- )
- /*++
-
-
- Routine Description:
-
-
- Pre cleanup callback. If this file was opened for write access, we want
- to rescan it now.
-
-
- Arguments:
-
-
- Data - The structure which describes the operation parameters.
-
-
- FltObject - The structure which describes the objects affected by this
- operation.
-
-
- CompletionContext - Output parameter which can be used to pass a context
- from this pre-cleanup callback to the post-cleanup callback.
-
-
- Return Value:
-
-
- Always FLT_PREOP_SUCCESS_NO_CALLBACK.
-
-
- --*/
- {
- NTSTATUS status;
- PSCANNER_STREAM_HANDLE_CONTEXT context;
- BOOLEAN safe;
-
-
- UNREFERENCED_PARAMETER( Data );
- UNREFERENCED_PARAMETER( CompletionContext );
-
-
- status = FltGetStreamHandleContext( FltObjects->Instance,
- FltObjects->FileObject,
- &context );
-
-
- if (NT_SUCCESS( status )) {
-
-
- if (context->RescanRequired) {
-
-
- (VOID) ScannerpScanFileInUserMode( FltObjects->Instance,
- FltObjects->FileObject,
- &safe );
-
-
- if (!safe) {
-
-
- DbgPrint( "!!! scanner.sys -- foul language detected in precleanup !!!\n" );
- }
- }
-
-
- FltReleaseContext( context );
- }
-
-
-
-
- return FLT_PREOP_SUCCESS_NO_CALLBACK;
- }
例子:這個例子攔截後綴爲txt的文件,如果txt中的內容有foul就被認定爲病毒
這個例子演示了
通信方式(HIPS)
上下文的使用
文件名的獲得
緩衝的使用
共有頭文件
scannuk.h
- /*++
-
-
- Copyright (c) 1999-2002 Microsoft Corporation
-
-
- Module Name:
-
-
- scanuk.h
-
-
- Abstract:
-
-
- Header file which contains the structures, type definitions,
- constants, global variables and function prototypes that are
- shared between kernel and user mode.
-
-
- Environment:
-
-
- Kernel & user mode
-
-
- --*/
-
-
- #ifndef __SCANUK_H__
- #define __SCANUK_H__
-
-
- //
- // Name of port used to communicate
- //
-
-
- const PWSTR ScannerPortName = L"\\ScannerPort";
-
-
-
-
- #define SCANNER_READ_BUFFER_SIZE 1024
-
-
- typedef struct _SCANNER_NOTIFICATION {
-
-
- ULONG BytesToScan;
- ULONG Reserved; // for quad-word alignement of the Contents structure
- UCHAR Contents[SCANNER_READ_BUFFER_SIZE];
-
- } SCANNER_NOTIFICATION, *PSCANNER_NOTIFICATION;
-
-
- typedef struct _SCANNER_REPLY {
-
-
- BOOLEAN SafeToOpen;
-
- } SCANNER_REPLY, *PSCANNER_REPLY;
-
-
- #endif // __SCANUK_H__
內核.h文件
- /*++
-
-
- Copyright (c) 1999-2002 Microsoft Corporation
-
-
- Module Name:
-
-
- scrubber.h
-
-
- Abstract:
- Header file which contains the structures, type definitions,
- constants, global variables and function prototypes that are
- only visible within the kernel.
-
-
- Environment:
-
-
- Kernel mode
-
-
- --*/
- #ifndef __SCANNER_H__
- #define __SCANNER_H__
-
-
-
-
- ///////////////////////////////////////////////////////////////////////////
- //
- // Global variables
- //
- ///////////////////////////////////////////////////////////////////////////
-
-
-
-
- typedef struct _SCANNER_DATA {
-
-
- //
- // The object that identifies this driver.
- //
-
-
- PDRIVER_OBJECT DriverObject;
-
-
- //
- // The filter handle that results from a call to
- // FltRegisterFilter.
- //
-
-
- PFLT_FILTER Filter;
-
-
- //
- // Listens for incoming connections
- //
-
-
- PFLT_PORT ServerPort;
-
-
- //
- // User process that connected to the port
- //
-
-
- PEPROCESS UserProcess;
-
-
- //
- // Client port for a connection to user-mode
- //
-
-
- PFLT_PORT ClientPort;
-
-
- } SCANNER_DATA, *PSCANNER_DATA;
-
-
- extern SCANNER_DATA ScannerData;
-
-
- typedef struct _SCANNER_STREAM_HANDLE_CONTEXT {
-
-
- BOOLEAN RescanRequired;
-
- } SCANNER_STREAM_HANDLE_CONTEXT, *PSCANNER_STREAM_HANDLE_CONTEXT;
-
-
- #pragma warning(push)
- #pragma warning(disable:4200) // disable warnings for structures with zero length arrays.
-
-
- typedef struct _SCANNER_CREATE_PARAMS {
-
-
- WCHAR String[0];
-
-
- } SCANNER_CREATE_PARAMS, *PSCANNER_CREATE_PARAMS;
-
-
- #pragma warning(pop)
-
-
-
-
- ///////////////////////////////////////////////////////////////////////////
- //
- // Prototypes for the startup and unload routines used for
- // this Filter.
- //
- // Implementation in scanner.c
- //
- ///////////////////////////////////////////////////////////////////////////
- DRIVER_INITIALIZE DriverEntry;
- NTSTATUS
- DriverEntry (
- __in PDRIVER_OBJECT DriverObject,
- __in PUNICODE_STRING RegistryPath
- );
-
-
- NTSTATUS
- ScannerUnload (
- __in FLT_FILTER_UNLOAD_FLAGS Flags
- );
-
-
- NTSTATUS
- ScannerQueryTeardown (
- __in PCFLT_RELATED_OBJECTS FltObjects,
- __in FLT_INSTANCE_QUERY_TEARDOWN_FLAGS Flags
- );
-
-
- FLT_PREOP_CALLBACK_STATUS
- ScannerPreCreate (
- __inout PFLT_CALLBACK_DATA Data,
- __in PCFLT_RELATED_OBJECTS FltObjects,
- __deref_out_opt PVOID *CompletionContext
- );
-
-
- FLT_POSTOP_CALLBACK_STATUS
- ScannerPostCreate (
- __inout PFLT_CALLBACK_DATA Data,
- __in PCFLT_RELATED_OBJECTS FltObjects,
- __in_opt PVOID CompletionContext,
- __in FLT_POST_OPERATION_FLAGS Flags
- );
-
-
- FLT_PREOP_CALLBACK_STATUS
- ScannerPreCleanup (
- __inout PFLT_CALLBACK_DATA Data,
- __in PCFLT_RELATED_OBJECTS FltObjects,
- __deref_out_opt PVOID *CompletionContext
- );
-
-
- FLT_PREOP_CALLBACK_STATUS
- ScannerPreWrite (
- __inout PFLT_CALLBACK_DATA Data,
- __in PCFLT_RELATED_OBJECTS FltObjects,
- __deref_out_opt PVOID *CompletionContext
- );
-
-
- NTSTATUS
- ScannerInstanceSetup (
- __in PCFLT_RELATED_OBJECTS FltObjects,
- __in FLT_INSTANCE_SETUP_FLAGS Flags,
- __in DEVICE_TYPE VolumeDeviceType,
- __in FLT_FILESYSTEM_TYPE VolumeFilesystemType
- );
-
-
-
-
- #endif /* __SCANNER_H__ */
內核.c文件
- /*++
-
-
- Copyright (c) 1999-2002 Microsoft Corporation
-
-
- Module Name:
-
-
- scanner.c
-
-
- Abstract:
-
-
- This is the main module of the scanner filter.
-
-
- This filter scans the data in a file before allowing an open to proceed. This is similar
- to what virus checkers do.
-
-
- Environment:
-
-
- Kernel mode
-
-
- --*/
-
-
- #include <fltKernel.h>
- #include <dontuse.h>
- #include <suppress.h>
- #include "scanuk.h"
- #include "scanner.h"
-
-
- #pragma prefast(disable:__WARNING_ENCODE_MEMBER_FUNCTION_POINTER, "Not valid for kernel mode drivers")
-
-
- //
- // Structure that contains all the global data structures
- // used throughout the scanner.
- //
-
-
- SCANNER_DATA ScannerData;
-
-
- //
- // This is a static list of file name extensions files we are interested in scanning
- //
-
-
- const UNICODE_STRING ScannerExtensionsToScan[] =
- { RTL_CONSTANT_STRING( L"doc"),
- RTL_CONSTANT_STRING( L"txt"),
- RTL_CONSTANT_STRING( L"bat"),
- RTL_CONSTANT_STRING( L"cmd"),
- RTL_CONSTANT_STRING( L"inf"),
- /*RTL_CONSTANT_STRING( L"ini"), Removed, to much usage*/
- {0, 0, NULL}
- };
-
-
-
-
- //
- // Function prototypes
- //
-
-
- NTSTATUS
- ScannerPortConnect (
- __in PFLT_PORT ClientPort,
- __in_opt PVOID ServerPortCookie,
- __in_bcount_opt(SizeOfContext) PVOID ConnectionContext,
- __in ULONG SizeOfContext,
- __deref_out_opt PVOID *ConnectionCookie
- );
-
-
- VOID
- ScannerPortDisconnect (
- __in_opt PVOID ConnectionCookie
- );
-
-
- NTSTATUS
- ScannerpScanFileInUserMode (
- __in PFLT_INSTANCE Instance,
- __in PFILE_OBJECT FileObject,
- __out PBOOLEAN SafeToOpen
- );
-
-
- BOOLEAN
- ScannerpCheckExtension (
- __in PUNICODE_STRING Extension
- );
-
-
- //
- // Assign text sections for each routine.
- //
-
-
- #ifdef ALLOC_PRAGMA
- #pragma alloc_text(INIT, DriverEntry)
- #pragma alloc_text(PAGE, ScannerInstanceSetup)
- #pragma alloc_text(PAGE, ScannerPreCreate)
- #pragma alloc_text(PAGE, ScannerPortConnect)
- #pragma alloc_text(PAGE, ScannerPortDisconnect)
- #endif
-
-
-
-
- //
- // Constant FLT_REGISTRATION structure for our filter. This
- // initializes the callback routines our filter wants to register
- // for. This is only used to register with the filter manager
- //
-
-
- const FLT_OPERATION_REGISTRATION Callbacks[] = {
-
-
- { IRP_MJ_CREATE,
- 0,
- ScannerPreCreate,
- ScannerPostCreate},
-
-
- { IRP_MJ_CLEANUP,
- 0,
- ScannerPreCleanup,
- NULL},
-
-
- { IRP_MJ_WRITE,
- 0,
- ScannerPreWrite,
- NULL},
-
-
- { IRP_MJ_OPERATION_END}
- };
-
-
-
-
- const FLT_CONTEXT_REGISTRATION ContextRegistration[] = {
-
-
- { FLT_STREAMHANDLE_CONTEXT,
- 0,
- NULL,
- sizeof(SCANNER_STREAM_HANDLE_CONTEXT),
- 'chBS' },
-
-
- { FLT_CONTEXT_END }
- };
-
-
- const FLT_REGISTRATION FilterRegistration = {
-
-
- sizeof( FLT_REGISTRATION ), // Size
- FLT_REGISTRATION_VERSION, // Version
- 0, // Flags
- ContextRegistration, // Context Registration.
- Callbacks, // Operation callbacks
- ScannerUnload, // FilterUnload
- ScannerInstanceSetup, // InstanceSetup
- ScannerQueryTeardown, // InstanceQueryTeardown
- NULL, // InstanceTeardownStart
- NULL, // InstanceTeardownComplete
- NULL, // GenerateFileName
- NULL, // GenerateDestinationFileName
- NULL // NormalizeNameComponent
- };
-
-
- ////////////////////////////////////////////////////////////////////////////
- //
- // Filter initialization and unload routines.
- //
- ////////////////////////////////////////////////////////////////////////////
-
-
- NTSTATUS
- DriverEntry (
- __in PDRIVER_OBJECT DriverObject,
- __in PUNICODE_STRING RegistryPath
- )
- /*++
-
-
- Routine Description:
-
-
- This is the initialization routine for the Filter driver. This
- registers the Filter with the filter manager and initializes all
- its global data structures.
-
-
- Arguments:
-
-
- DriverObject - Pointer to driver object created by the system to
- represent this driver.
-
-
- RegistryPath - Unicode string identifying where the parameters for this
- driver are located in the registry.
-
-
- Return Value:
-
-
- Returns STATUS_SUCCESS.
- --*/
- {
- OBJECT_ATTRIBUTES oa;
- UNICODE_STRING uniString;
- PSECURITY_DESCRIPTOR sd;
- NTSTATUS status;
-
-
- UNREFERENCED_PARAMETER( RegistryPath );
-
-
- //
- // Register with filter manager.
- //
-
-
- status = FltRegisterFilter( DriverObject,
- &FilterRegistration,
- &ScannerData.Filter );
-
-
-
-
- if (!NT_SUCCESS( status )) {
-
-
- return status;
- }
-
-
- //
- // Create a communication port.
- //
-
-
- RtlInitUnicodeString( &uniString, ScannerPortName );
-
-
- //
- // We secure the port so only ADMINs & SYSTEM can acecss it.
- //
- //設置通信端口權限 ,只有管理員和系統進程才能操作
- status = FltBuildDefaultSecurityDescriptor( &sd, FLT_PORT_ALL_ACCESS );
-
-
- if (NT_SUCCESS( status )) {
-
-
- InitializeObjectAttributes( &oa,
- &uniString,
- OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
- NULL,
- sd );
-
-
- //創建通信端口,並設置對應的回調函數
- status = FltCreateCommunicationPort( ScannerData.Filter,
- &ScannerData.ServerPort,
- &oa,//設置的名字
- NULL,
- ScannerPortConnect,//當R3連接時回調 主要是記錄R3的進程ID或EPROCESS以便放過本進程 還有記錄R3的通信端口,給後面主動通信的時候用
- ScannerPortDisconnect,//當R3離線時回調 主要是關閉R3端口和設置R3的進程信息爲NULL
- NULL,//處理R3主動函數 比如R3下新的規則,
- 1 );//最後一個常爲1
- //
- // Free the security descriptor in all cases. It is not needed once
- // the call to FltCreateCommunicationPort() is made.
- //
- //設置好後需要釋放權限的設置
- FltFreeSecurityDescriptor( sd );
-
-
- if (NT_SUCCESS( status )) {
-
-
- //
- // Start filtering I/O.
- //
- //開始過濾
- status = FltStartFiltering( ScannerData.Filter );
-
-
- if (NT_SUCCESS( status )) {
-
-
- return STATUS_SUCCESS;
- }
- //失敗就滾吧
- FltCloseCommunicationPort( ScannerData.ServerPort );
- }
- }
- //失敗就滾吧
- FltUnregisterFilter( ScannerData.Filter );
-
-
- return status;
- }
-
-
-
-
- NTSTATUS
- ScannerPortConnect (
- __in PFLT_PORT ClientPort,
- __in_opt PVOID ServerPortCookie,
- __in_bcount_opt(SizeOfContext) PVOID ConnectionContext,
- __in ULONG SizeOfContext,
- __deref_out_opt PVOID *ConnectionCookie
- )
- /*++
-
-
- Routine Description
-
-
- This is called when user-mode connects to the server port - to establish a
- connection
-
-
- Arguments
-
-
- ClientPort - This is the client connection port that will be used to
- send messages from the filter
-
-
- ServerPortCookie - The context associated with this port when the
- minifilter created this port.
-
-
- ConnectionContext - Context from entity connecting to this port (most likely
- your user mode service)
-
-
- SizeofContext - Size of ConnectionContext in bytes
-
-
- ConnectionCookie - Context to be passed to the port disconnect routine.
-
-
- Return Value
-
-
- STATUS_SUCCESS - to accept the connection
-
-
- --*/
- {
- PAGED_CODE();
-
-
- UNREFERENCED_PARAMETER( ServerPortCookie );
- UNREFERENCED_PARAMETER( ConnectionContext );
- UNREFERENCED_PARAMETER( SizeOfContext);
- UNREFERENCED_PARAMETER( ConnectionCookie );
-
-
- ASSERT( ScannerData.ClientPort == NULL );
- ASSERT( ScannerData.UserProcess == NULL );
-
-
- //
- // Set the user process and port.
- //
- //設置本身進程 和 R3的的通信端口 給後面判斷和通信時使用
- ScannerData.UserProcess = PsGetCurrentProcess();
- ScannerData.ClientPort = ClientPort;
-
-
- DbgPrint( "!!! scanner.sys --- connected, port=0x%p\n", ClientPort );
-
-
- return STATUS_SUCCESS;
- }
-
-
-
- VOID
- ScannerPortDisconnect(
- __in_opt PVOID ConnectionCookie
- )
- /*++
-
-
- Routine Description
-
-
- This is called when the connection is torn-down. We use it to close our
- handle to the connection
-
-
- Arguments
-
-
- ConnectionCookie - Context from the port connect routine
-
-
- Return value
-
-
- None
-
-
- --*/
- {
- UNREFERENCED_PARAMETER( ConnectionCookie );
-
-
- PAGED_CODE();
-
-
- DbgPrint( "!!! scanner.sys --- disconnected, port=0x%p\n", ScannerData.ClientPort );
-
-
- //
- // Close our handle to the connection: note, since we limited max connections to 1,
- // another connect will not be allowed until we return from the disconnect routine.
- //
-
-
- //關閉R3通信端口
- FltCloseClientPort( ScannerData.Filter, &ScannerData.ClientPort );
-
-
- //
- // Reset the user-process field.
- //
-
-
- //設置R3進程爲0
- ScannerData.UserProcess = NULL;
- }
-
-
-
- NTSTATUS
- ScannerUnload (
- __in FLT_FILTER_UNLOAD_FLAGS Flags
- )
- /*++
-
-
- Routine Description:
-
-
- This is the unload routine for the Filter driver. This unregisters the
- Filter with the filter manager and frees any allocated global data
- structures.
-
-
- Arguments:
-
-
- None.
-
-
- Return Value:
-
-
- Returns the final status of the deallocation routines.
-
-
- --*/
- {
- UNREFERENCED_PARAMETER( Flags );
-
-
- //
- // Close the server port.
- //
-
-
- FltCloseCommunicationPort( ScannerData.ServerPort );
-
-
- //
- // Unregister the filter
- //
-
-
- FltUnregisterFilter( ScannerData.Filter );
-
-
- return STATUS_SUCCESS;
- }
-
-
- NTSTATUS
- ScannerInstanceSetup (
- __in PCFLT_RELATED_OBJECTS FltObjects,
- __in FLT_INSTANCE_SETUP_FLAGS Flags,
- __in DEVICE_TYPE VolumeDeviceType,
- __in FLT_FILESYSTEM_TYPE VolumeFilesystemType
- )
- /*++
-
-
- Routine Description:
-
-
- This routine is called by the filter manager when a new instance is created.
- We specified in the registry that we only want for manual attachments,
- so that is all we should receive here.
-
-
- Arguments:
-
-
- FltObjects - Describes the instance and volume which we are being asked to
- setup.
-
-
- Flags - Flags describing the type of attachment this is.
-
-
- VolumeDeviceType - The DEVICE_TYPE for the volume to which this instance
- will attach.
-
-
- VolumeFileSystemType - The file system formatted on this volume.
-
-
- Return Value:
-
-
- FLT_NOTIFY_STATUS_ATTACH - we wish to attach to the volume
- FLT_NOTIFY_STATUS_DO_NOT_ATTACH - no, thank you
-
-
- --*/
- {
- UNREFERENCED_PARAMETER( FltObjects );
- UNREFERENCED_PARAMETER( Flags );
- UNREFERENCED_PARAMETER( VolumeFilesystemType );
-
-
- PAGED_CODE();
-
-
- ASSERT( FltObjects->Filter == ScannerData.Filter );
-
-
- //
- // Don't attach to network volumes.
- //
-
-
- if (VolumeDeviceType == FILE_DEVICE_NETWORK_FILE_SYSTEM) {
-
-
- return STATUS_FLT_DO_NOT_ATTACH;
- }
-
-
- return STATUS_SUCCESS;
- }
-
-
- NTSTATUS
- ScannerQueryTeardown (
- __in PCFLT_RELATED_OBJECTS FltObjects,
- __in FLT_INSTANCE_QUERY_TEARDOWN_FLAGS Flags
- )
- /*++
-
-
- Routine Description:
-
-
- This is the instance detach routine for the filter. This
- routine is called by filter manager when a user initiates a manual instance
- detach. This is a 'query' routine: if the filter does not want to support
- manual detach, it can return a failure status
-
-
- Arguments: