Minifilter微過濾框架:框架介紹以及驅動層和應用層的通訊

minifilter是sfilter後微軟推出的過濾驅動框架。相比於sfilter,他更容易使用,需要程序員做的編碼更簡潔。
系統爲minifilter專門製作了一個過濾管理器,這個管理器本身其實是一個傳統過濾驅動,它向minifilter的使用者提供許多接口,讓原本複雜的文件過濾驅動變得方便簡單。之所以簡單是因爲傳統的過濾驅動把大量的工作放在綁定設備上,而現在這些工作都交給minifilter中的過濾管理器來完成。
缺點:純粹的使用minifilter提供的接口看不見設備對象和IRP的,所以編程自由度不大。
對minifilter的編寫的第一步是向過濾管理器註冊一個微過濾器,這個未過濾器是一個組件,包含了一些在文件操作的時候可能需要的回調函數。
驅動入口中最簡單的版本是隻包含兩個函數:註冊函數和開始函數。
NTSTARTUS DriverEntry(__in PDRIVER_OBJECT DriverObject,__in PUNICODE_STRING RegistryPath)
{
	NTSTATUS status;
	UNREFERENCED_PARAMETER(registryPath);

	status = FltRegisterFilter(DriverObject,&FilterRegisteraion,&gFilterHandle);
	ASSERT(NT_SUCCESS(status));
	if(NT_SUCCESS(status)){
		status = FltStartFiltering(gFilterHandle);
		if(!NT_SUCCESSS(status)){
			FltUnregisterFilter(gFilterHandle);
		}
	}
	return status;
}


1.註冊函數FltRegisterFilter
它的第二個參數是個結構體要自己填寫完整,這個結構體中的內容包含微過濾器的方方面面。
上面說的結構名字叫FLT_REGISTRATION,這個結構中有些部分是基本信息,有些部分是回調函數。所以這個結構有點面嚮對象語言中類的感覺。這個結構中最NB(中文意思是“重要”)的字段就是FLT_OPERATION_REGISTRATION(大家都知道,當操作系統要對文件系統進行操作的時候,其實就是通過發送各種各樣的事件請求(IRP),而文件系統就負責處理好這些請求),而字段FLT_OPERATION_REGISTRATION就是一個事件請求數組(這個數組包含該過濾驅動可以處理的所有事件),每個數組元素本身又是一個五元組,包括1.當前要處理的事件,2.標識位(這個標誌位一般寫0,表示全過濾,還有兩種值分別是不過濾緩存讀寫和不過濾頁讀寫操作),3.事件被處理前函數(Pre-operation),4.事件被處理完成後的函數(Post-operation)。
【關於過濾函數:現在的過濾函數是有標準格式的(??是嗎?),因爲現在訪問不到IRP,所以minifilter設置了一個結構用來存放請求包中的所有信息,在個結構往往是過濾函數的第一個參數。。。。傳統的過濾驅動,和對應的請求相綁定的直接處理函數的格式好像也是固定的。。。想自定義處理函數格式也行,就要封裝在第一級處理函數裏面。】
第一個參數是知道我們自己的這個驅動的驅動對象。這個對象是我們的驅動在初始化的時候,系統幫我們生成的。
第三個參數是一個輸出值,當我們的驅動成功的註冊的時候,這個參數就是指向我們的微過濾驅動的句柄。

2.開始函數FltStartFiltering
就一個參數——過濾驅動的句柄,就是上面註冊函數的輸出值。

自己編寫設備過濾驅動,說白了就是自己編寫想要過濾的事件的預處理(pre-operation)或者完成(post-operation)函數。就像上面介紹的,對應每一個事件的預處理和完成函數都在結構FLT_REGISTRATION中的FLT_OPERATION_REGISTRATION結構裏聲明好的。
所以我們只要編寫出每一個在FLT_OPERATION_REGISTRATION中給出的預處理和完成函數的函數體就行了。
比如在FLT_OPERATION_REGISTRATION中我們寫了一個字段{IRP_IO_CREATE,0,NPPreCreate,NPPostCreate}。這裏我們就針對事件IRP_IO_CREATE設置了這個事件的預處理函數NPPreCreate和完成函數NPPostCreate。
作爲簡單的例子,下面實現NPPreCreate:
FLT_PREOP_CALLBACK_STATUS NPPreCreate(
__inout PFLT_CALLBACK_DATA Data,
__in PCFLT_RELATED_OBJECTS FltObjects,
__deref_out_opt PVOID *CompletionContext
)
{
	...
	Data->IoStatus.Status = STATUS_ACCESS_DENIED;
	Data->IoStatus.Information = 0;
	return FLT_PREOP_COMPLETE;
}


這裏就是一個過濾函數的框架,先看下這個函數的參數表。第一個參數是最重要的,PFLT_CALLBACK_DATA Data。對於接觸過傳統sfilter框架過濾驅動的朋友一定知道,在我們的過濾驅動過濾到上層發來的請求時,攔截到的就是一個IRP請求包,這個包中有這一次請求的幾乎所有信息。現在在MINIFILTER框架中,眼前的這個參數就是當年的IRP,只是變了名字,我們操作時需要的(IRP)信息都在這個結構裏。
一次文件請求操作的基本原理:
對於沒接觸過文件過濾驅動的朋友,這裏簡單說下文件過濾驅動的工作原理。當上層發生了某些文件系統請求的時候,這個請求會打包成IRP,發給底層的文件系統處理,當任務處理完的時候,文件系統會把任務完成情況打成IRP包回發給上層,通知上層請求被處理了。當我們把自己編寫的過濾驅動安裝到文件系統上後,我們的過濾驅動就可以攔截到IRP。這個時候,我們可以打開看看IRP裏的東西,做點記錄,然後什麼都不改變的把IRP繼續往下發,當然,也可以直接填寫IRP中的一些字段然後直接回發給上層,上層收到IRP後就認爲上一次的請求結束了,它根本不管這個IRP是不是文件系統發給他的。
所以大家可以看到上面的例子函數裏,填寫了PFLT_CALLBACK_DATA結構中的兩個字段。最後的返回值FLT_PREOP_COMPLETE就表示請求已經結束了,不用再把IRP往下傳了。
在minifilter中,我們除了要自己編寫希望過濾的請求的預處理和完成函數。還有其他的回調函數可以編寫,不過他們都是可選的,不一定要實現。具體有哪些這裏就不列舉了。

MINIFILTER的另一個特色:與應用層的通信
我們在編寫文件過濾驅動的時候,不免會經常和上層的應用程序進行通信,在傳統的文件過濾驅動框架中,想要實現驅動層和應用層的通信一般都是通過DiviceIoControl配合內核模塊中的處理控制請求,或者申請一塊共享存儲區實現,都比較麻煩。minifilter中專門提供了通信用的API,並且這種API在使用的時候,就像是網絡編程中的socket通信一樣方便簡單。
下面的代碼是建立一個通信端口的過程:
PSECURITY_DESCRIPTOR sd;
OBJECT_ATTRIBUTES oa;

status = FltBuildDefaultSecurityDescriptor(&sd,FLT_PORT_ALL_ACCESS);

if(!NT_SUCCESS(status)){
	goto final;
}
RtlInitUnicodeString(&uniString,MINISPY_PORT_NAME);

InitializeObejectAttributes(&oa,&uniString,OBJ_KERNEL_HANDLE|OBJ_CASE_INSENSITIVE,NULL,sd);

status = FltCreateCommunicationPort(gFilterHandle,&gServerPort,&oa,NULL,NPMiniConnect,NPMiniDisconnect,NPMiniMessage,1);


首先函數FltBuildDefaultSecurityDescriptor是用來申請一個安全敘述子(額,簡單點,就是給使用通信端口的用戶申請個權限,這裏可以看到申請的權限是FLT_PORT_ALL_ACCESS,意思就是:用戶層的程序連接到設置了這個權限級別的通信端口後,可以獲得所有操作權限)。
下面的InitializeObejectAttributes就是用來給我們要創建的對象(名稱是:MINISPY_PORT_NAME)設置一些屬性值。
最後最重要的FltCreateCommunicationPort就是給這個端口定義所需要的三個函數,同時註冊這個端口(註冊了才能用)。這裏註冊的三個函數分別是:
NPMiniConnect用戶層和內核層建立連接的時候會調用該函數 
NPMiniDisconnect用戶層和內核層斷開連接的時候會調用該函數 
NPMiniMessage用戶層和內核層進行通訊的時候會調用
當然,既然稱他們爲回調函數,那他們就不是我們用戶層的程序去調用的,工作原理是這樣的,我們在用戶層通過兩個api:FilterConnectCommunicationPort和FilterSendMessage來發出請求,然後通訊端口會根據我們的請求自己去調用這三個函數完成具體的工作。其中前者對應NPMiniConnect,後者對應NPMiniMessage。
完成上面三個回調函數後,內核中的通訊代碼已經準備好了。
下面就是完成通訊的另一端內容:用戶層(應用層)。這裏要注意的是在編寫程序的時候,需要包含幾個minifilter必須的頭文件和庫文件:FltUser.h,fltLib.lib,fltMgr.lib,具體如下:
#include <FltUser.h>
#progma comment(lib,"fltLib.lib")
#progma comment(lib,"fltMgr.lib")
後面的代碼需要了解的就是一個簡單的流程:先FilterConnectCommunicationPort連接上目標端口,再FilterSendMessage發送消息。原理就介紹這麼多,具體的代碼在下載連接中,其中,用戶層和通訊端口的連接是做成了dll,首先要生成dll,然後要使用dll就用哪個app工程,裏面會裝載dll。另一個minifilter可以生成一個sys系統文件,把系統文件用inf文件安裝上,並在cmd裏面輸入net start XXX(這裏是sys的文件名,其實是服務名,只不過兩個名稱大部分情況下是一樣的)通訊端口就打開了,然後app就可以試着連接和通訊了。
minifilter代碼下載http://download.csdn.net/detail/arvon2012/4687632
技術相關更多文章猛擊:哇啦天堂論壇技術區
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章