檔案系統Minifilter驅動(七)
寫Minifilter驅動的DriverEntry例程
每一個檔案系統minifilter驅動都必須有一個DriverEntry 例程.當minifilter驅動被載入時該例程會被呼叫.
DriverEntry例程執行全域性初始化,註冊minifilter驅動並初始化過濾.此例程在一個系統執行緒上下文中且在IRQL PASSIVE_LEVEL執行.
它的定義如下:
NTSTATUS (*PDRIVER_INITIALIZE) ( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath );
DriverEntry有兩個入參.首先是DriverObject,它是驅動物件在minifilter驅動載入時被建立.第二個是RegistryPath, 它是包含minifilter驅動的註冊key的一個路徑的Unicode串.
Minifilter驅動的DriverEntry 例程必須按序執行以下步驟:
1. 執行minifilter驅動的一切所需的全域性初始化.
2. 呼叫FltRegisterFilter註冊minifilter驅動.
3. 呼叫FltStartFiltering發起過濾..
4. 返回一個適當的NTSTATUS 值.
本節包括:
一、註冊Minifilter驅動
每一個minifilter驅動都必須從它的DriverEntry例程中呼叫FltRegisterFilter來新增它自己到已註冊的minifilter驅動的全域性列表中並向filter管理器提供一套callback例程和其他驅動相關的資訊.
在MiniSpy例子中,minifilter驅動的註冊過程如下:
NTSTATUS status;status = FltRegisterFilter( DriverObject, //Driver &FilterRegistration, //Registration
FltRegisterFilter有兩個入參.第一個Driver, 是minifilter驅動在它的DriverEntry例程的入參DriverObject中收到的驅動物件的指標. 其次Registration, 是包含minifilter驅動callback例程的入口點的FLT_REGISTRATION結構的一個指標.
另外, FltRegisterFilter 有一個出參RetFilter,它接收minifilter驅動的一個不透明的過濾器指標.這個過濾器指標是許多FltXxx支援例程的一個必需的入參,包括FltStartFiltering和FltUnregisterFilter.
二、發起過濾
在呼叫FltRegisterFilter後,minifilter驅動的DriverEntry例程一般會呼叫FltStartFiltering 來開始過濾I/O操作.
每一個minifilter驅動都必須從它的DriverEntry例程中呼叫FltStartFiltering來通過filter管理器,該minifilter驅動已經準備好開始繫結到捲上並開始過濾I/O請求.在minifilter驅動呼叫了FltStartFiltering之後, filter管理器會把它當做一個完全活動的minifilter驅動,把I/O請求和要繫結的卷的通知提供給它. Minifilter驅動甚至要在FltStartFiltering返回之前就必須準備好開始接收這些I/O請求和通知.
在MiniSpy驅動例子中, FltStartFiltering 如下被呼叫:
status = FltStartFiltering( MiniSpyData.FilterHandle );if( !NT_SUCCESS( status )) { FltUnregisterFilter( MiniSpyData.FilterHandle );}
如果對FltStartFiltering 的呼叫不返回STATUS_SUCCESS, minifilter驅動必須呼叫FltUnregisterFilter 來登出它自己.
三、從一個minifilter DriverEntry例程中返回狀態
一個FSFD的DriverEntry 例程通常返回STATUS_SUCCESS.不過,如果驅動初始化失敗了,DriverEntry 例程應該返回一個適當的錯誤狀態值.
如果DriverEntry例程返回一個非正確的狀態值,系統會通過解除安裝該驅動來做出響應.由於這個原因, DriverEntry 例程必須總是在返回一個非正確的狀態值之前free一切為像裝置物件這樣的系統資源分配的記憶體.
寫Minifilter驅動的FilterUnloadCallback例程
minifilter驅動可隨意地註冊一個 PFLT_FILTER_UNLOAD_CALLBACK型別的例程作為它的FilterUnloadCallback 例程.這個callback例程也可以說是minifilter驅動的解除安裝例程.
Minifilter驅動不一定要註冊一個FilterUnloadCallback 例程.不過,我們強烈地推薦要註冊這個callback例程,因為如果一個minifilter驅動不註冊一個FilterUnloadCallback 例程,那麼這個驅動就不可以被解除安裝.
要註冊這個callback例程, minifilter驅動得在FLT_REGISTRATION結構的成員FilterUnloadCallback中存一個PFLT_FILTER_UNLOAD_CALLBACK型別的例程的地址,該結構會被minifilter驅動作為它的DriverEntry例程中的 FltRegisterFilter的一個引數.
本節包括:
一、FilterUnloadCallback例程什麼時候會被呼叫
Filter管理器會在以下列方式之一解除安裝minifilter驅動之前呼叫該驅動的 FilterUnloadCallback 例程:
· 非強制解除安裝.當某個使用者模式應用程式已經呼叫了FilterUnload或某個核心模式驅動已經呼叫了FltUnloadFilter時會發生這種型別的解除安裝. 當你在命令提示符裡打fltmc unload時這種型別的解除安裝也會發生.
· 強制解除安裝. 當你通過在命令提示符裡打sc stop或net stop來發出一個服務停止請求時會發生這種型別的解除安裝. (更多關於sc stop和net stop 命令的資訊,點選開始選單中的Help and Support .) 當某個使用者模式應用程式呼叫了微軟Win32 ControlService 函式,在引數dwControl中傳SERVICE_CONTROL_STOP控制程式碼時它也會發生. (更多關於Win32 服務函式的資訊,參考Microsoft Windows SDK documentation.)
對一個非強制解除安裝來說,如果minifilter驅動的FilterUnloadCallback 例程返回了一個錯誤或警告的NTSTATUS 值如STATUS_FLT_DO_NOT_DETACH, filter管理器就不會解除安裝該驅動.
對一個強制解除安裝來說,filter管理器在minifilter驅動的FilterUnloadCallback例程被呼叫之後,即使該例程返回了一個錯誤或警告NTSTATUS值比如STATUS_FLT_DO_NOT_DETACH這個minifilter驅動也會被解除安裝.
要禁用某個minifilter驅動的強制解除安裝,該驅動得在FLT_REGISTRATION結構的成員Flags中設定FLTFL_REGISTRATION_DO_NOT_SUPPORT_SERVICE_STOP標記,該結構會被minifilter驅動作為它的DriverEntry例程中的 FltRegisterFilter的一個引數.當設定了這個標記時,filter管理器通常執行非強制解除安裝請求.不過,強制解除安裝請求會失敗.filter管理器為失敗的解除安裝請求呼叫minifilter驅動的FilterUnloadCallback 例程.
注意如果某個minifilter驅動的DriverEntry 例程返回了一個警告或錯誤的 NTSTATUS 值,那麼FilterUnloadCallback 例程就不會被呼叫;filter管理器會簡單地解除安裝這個minifilter驅動.
FilterUnloadCallback 不會在系統關閉期間被呼叫.一個必須執行關閉處理的minifilter驅動應為IRP_MJ_SHUTDOWN操作註冊一個pre-oper callback 例程.
二、寫一個FilterUnloadCallback例程
FilterUnloadCallback 例程的定義如下:
typedef NTSTATUS(*PFLT_FILTER_UNLOAD_CALLBACK) ( FLT_FILTER_UNLOAD_FLAGS Flags );
FilterUnloadCallback 有一個入參Flags, 它可以是NULL或者 FLTFL_FILTER_UNLOAD_MANDATORY. Filter管理器設定這個引數為FLTFL_FILTER_UNLOAD_MANDATORY來指示解除安裝操作是強制的. 更多此引數的資訊,參考PFLT_FILTER_UNLOAD_CALLBACK.
Minifilter驅動的FilterUnloadCallback 例程必須執行以下步驟:
· 關閉一切核心模式通訊伺服器埠控制代碼.
· 呼叫FltUnregisterFilter 來註冊這個minifilter驅動.
· 執行一切所需的全域性cleanup.
· 返回一個合適的NTSTATUS值.
本節包括:
1.關閉通訊伺服器埠
如果minifilter驅動之前呼叫FltCreateCommunicationPort打開了一個核心模式通訊伺服器埠,則它必須呼叫FltCloseCommunicationPort關閉這個埠. 為防止系統在解除安裝處理期間掛起,minifilter驅動的FilterUnloadCallback 例程必須在呼叫FltUnregisterFilter之前關閉這個埠.
如果某個使用者模式應用程式對該通訊伺服器埠有了一個開啟的連線,在FltCloseCommunicationPort返回之後該連線的一切客戶埠仍被保持開啟狀態.不過, filter管理器會在minifilter驅動被解除安裝時關閉一切客戶埠.
2.登出Minifilter
Minifilter驅動的FilterUnloadCallback 例程必須呼叫FltUnregisterFilter 來登出這個驅動.呼叫FltUnregisterFilter 會引起下列事情的發生:
· Minifilter驅動的callback例程被登出.
· Minifilter驅動的例項被拆卸,它的InstanceTeardownStartCallback 和InstanceTeardownCompleteCallback 例程都會為每一個minifilter驅動例項被呼叫.
· 如果minifilter驅動設定了卷、例項、流或流控制代碼上的一切上下文,這些上下文都會被刪除.如果該驅動已經為某個給定的上下文型別註冊了一個CleanupContext callback 例程,那麼filter管理器就會在刪除該上下文之前呼叫CleanupContext 例程.
如果minifilter驅動的不透明的過濾器指標上還有未決rundown引用, 那麼FltUnregisterFilter就會進入一個等待狀態直到它們被移除.未決rundown引用的發生常常是因為minifilter驅動已經呼叫了FltQueueGenericWorkItem來插入一個工作項到一個系統工作佇列中, 且該工作項還沒有被出列和處理. (filter管理器會在minifilter驅動呼叫FltQueueGenericWorkItem時新增rundown引用而在minifilter驅動的工作例程返回時移除該引用.)
如果minifilter驅動已經呼叫了任何會新增一個到其不透明的過濾器指標上的未決rundown引用的例程,比如FltObjectReference和FltGetFilterFromInstance,但後來沒有呼叫FltObjectDereference,也會發生未決rundown引用.
3.執行全域性Cleanup
Minifilter驅動的FilterUnloadCallback 例程必須執行一切所需的全域性cleanup.以下是一個minifilter驅動可能執行的全域性cleanup任務:
· 呼叫ExDeleteResourceLite 來刪除一個被ExInitializeResourceLite 初始化了的全域性資源變數.
· 呼叫ExFreePool或ExFreePoolWithTag來free被ExAllocatePoolWithTag 這樣的例程分配的全域性記憶體.
· 分別呼叫ExDeleteNPagedLookasideList或ExDeletePagedLookasideList來刪除由ExInitializeNPagedLookasideList或ExInitializePagedLookasideList分配的一個lookaside列表.
· 呼叫PsRemoveCreateThreadNotifyRoutine或PsRemoveLoadImageNotifyRoutine來分別登出由PsSetCreateThreadNotifyRoutine 或PsSetLoadImageNotifyRoutine註冊的一個全域性callback例程.
4.從一個FilterUnloadCallback例程中返回狀態
Minifilter驅動的FilterUnloadCallback 例程通常返回STATUS_SUCCESS.
要拒絕一個非強制的解除安裝操作,minifilter驅動應返回一個合適的警告或錯誤NTSTATUS值比如STATUS_FLT_DO_NOT_DETACH.強制解除安裝操作的詳情參考寫FilterUnloadCallback例程和FLT_FILTER_UNLOAD_CALLBACK.
如果FilterUnloadCallback 例程返回一個警告或錯誤的NTSTATUS值且解除安裝操作是非強制的,minifilter驅動不會被解除安裝.