基于Minifilter框架的文件过滤驱动理解
概述
?
Minifilter即File System Minifilter Drivers,是Windows為了簡(jiǎn)化第三方開發(fā)人員開發(fā)文件過濾驅(qū)動(dòng)而提供的一套框架,這個(gè)框架依賴于一個(gè)稱之為Filter Manager(后面簡(jiǎn)寫為FltMgr)的傳統(tǒng)文件系統(tǒng)過濾驅(qū)動(dòng)。這套框架應(yīng)用到內(nèi)核中的結(jié)構(gòu)如下圖所示:
?
?
FltMgr以傳統(tǒng)文件過濾驅(qū)動(dòng)的形式插入到I/O處理隊(duì)列中去接收不同的I/O請(qǐng)求,然后將這個(gè)請(qǐng)求遍歷發(fā)布到它所維護(hù)的Minifilter對(duì)象中,然后根據(jù)各個(gè)Minifilter對(duì)這個(gè)I/O請(qǐng)求的處理結(jié)果來決定后續(xù)的操作。
?
這種模式在很多軟件架構(gòu)中使用,類似于插件一樣,每一個(gè)Minifilter遵守一定的接口規(guī)范插入到FltMgr中,然后就能執(zhí)行過濾控制。
?
上面是對(duì)整個(gè)Minifilter框架進(jìn)行描述,實(shí)際內(nèi)部需要注意的細(xì)節(jié)牽涉到很多內(nèi)核知識(shí),比如中斷級(jí)別、I/O請(qǐng)求被封裝成IRP包和fast I/O請(qǐng)求等相對(duì)復(fù)雜的概念。這里不做深究,主要以研究Minifilter的開發(fā)過程和相應(yīng)注意的地方為主。此外還有FltMgr在內(nèi)核中的位置等相關(guān)知識(shí),也只在必要的地方提及一下。
?
Minifilter流程
?
Minifilter通過注冊(cè)并啟動(dòng)后,根據(jù)在注冊(cè)表中設(shè)置的相應(yīng)值,插入到對(duì)應(yīng)的FltMgr實(shí)例(Frame)隊(duì)列中,然后關(guān)聯(lián)上需要過濾的卷。FltMgr會(huì)根據(jù)Minifilter所注冊(cè)的I/O操作類型,調(diào)用對(duì)應(yīng)的pre和post操作函數(shù),并根據(jù)對(duì)應(yīng)的返回值執(zhí)行不同的流程。這里假設(shè)有A、B、C三個(gè)Minifilter從上往下掛載在FltMgr實(shí)例上,那么當(dāng)接收到I/O請(qǐng)求時(shí),執(zhí)行的步驟為A-pre、B-pre、C-pre,一旦某個(gè)Minifilter返回了FLT_PREOP_COMPLETE,即表明這個(gè)I/O請(qǐng)求被它完成處理了,則立即按照相反的順序調(diào)用對(duì)應(yīng)的post函數(shù)(不再繼續(xù)往下調(diào))。
?
注冊(cè)和關(guān)聯(lián)
?
Minifilter根據(jù)FltRegisterFilter函數(shù)介紹說明,為響應(yīng)操作設(shè)置對(duì)應(yīng)的回調(diào)函數(shù)和數(shù)據(jù)結(jié)構(gòu)后,就可以在DriverEntry中調(diào)用FltRegisterFilter進(jìn)行注冊(cè)了,然后調(diào)用FltStartFiltering來通知FltMgr當(dāng)前Minifilter已經(jīng)準(zhǔn)備好關(guān)聯(lián)到要過濾的卷了。
?
FltMgr會(huì)在系統(tǒng)啟動(dòng)時(shí)或者接收到手動(dòng)關(guān)聯(lián)命令時(shí),調(diào)用Minifilter的InstanceSetupCallback回調(diào)函數(shù),當(dāng)然前提是Minifilter在注冊(cè)的時(shí)候增設(shè)置了這個(gè)函數(shù)的地址,這個(gè)回調(diào)函數(shù)會(huì)傳入要關(guān)聯(lián)的卷標(biāo)信息,FltMgr會(huì)根據(jù)這個(gè)函數(shù)的返回值判斷是否關(guān)聯(lián)成功。這里和對(duì)應(yīng)卷相關(guān)聯(lián)的Minifilter實(shí)例叫做instance。一個(gè)卷上可以掛多個(gè)instance。只有對(duì)指定卷進(jìn)行關(guān)聯(lián)后,才能過濾其I/O請(qǐng)求。
?
取消關(guān)聯(lián)的過程可以理解成釋放實(shí)例的過程,釋放后就無法繼續(xù)過濾對(duì)應(yīng)卷了。
?
Pre回調(diào)函數(shù)(PFLT_PRE_OPERATION_CALLBACK)
?
FLT_PREOP_COMPLETE:表示當(dāng)前的過濾驅(qū)動(dòng)完成了本次I/O操作,過濾管理器就不再往下發(fā)送本次I/O請(qǐng)求,而是依次向上調(diào)用post回調(diào)函數(shù)。這種情況下IoStatus.Status的值就是最終I/O操作的執(zhí)行結(jié)果(不能是STATUS_PENDING)。
?
FLT_PREOP_SUCCESS_NO_CALLBACK/FLT_PREOP_SUCCESS_WITH_CALLBACK:這個(gè)返回值表示處理成功,讓過濾管理器去做自己的事,區(qū)別在于WITH_CALLBACK的返回值會(huì)標(biāo)明需要回調(diào)post函數(shù)。而NO_CALLBACK的則標(biāo)明不需要。
?
FLT_PREOP_PENDING:顧名思義,表明當(dāng)前過濾驅(qū)動(dòng)將本次I/O操作掛起了,過濾管理器需要等待當(dāng)前驅(qū)動(dòng)調(diào)用FltCompletePendedPreOperation函數(shù)后才會(huì)繼續(xù)本次I/0操作處理流程。注意只有對(duì)于基于IRP中斷的I/O操作(用FLT_IS_IRP_OPERATION宏測(cè)試)才可以掛起。
?
FLT_PREOP_DISALLOW_FASTIO:只有操作是fast I/O操作(用FLT_IS_FASTIO_OPERATION(Data)進(jìn)行測(cè)試)時(shí)才可以返回這個(gè)值,表明過濾驅(qū)動(dòng)不允許fast I/O操作繼續(xù)執(zhí)行。因此過濾管理器不會(huì)再下發(fā)該請(qǐng)求,而是依次向上調(diào)用post回調(diào)函數(shù)。這種情況下不需要設(shè)置IoStatus.Status的值,過濾管理器會(huì)自動(dòng)設(shè)置這個(gè)值。
?
FLT_PREOP_SYNCHRONIZE:這個(gè)返回值表明處理未完成,保持當(dāng)前過濾驅(qū)動(dòng)上下文線程環(huán)境,交由過濾管理器繼續(xù)下發(fā)后調(diào)用post回調(diào)函數(shù)后繼續(xù)處理。也只對(duì)基于IRP中斷的操作有效,并且必須有post函數(shù),如果不是基于IRP中斷的,就會(huì)和FLT_PREOP_SUCCESS_WITH_CALLBACK一樣。注意:對(duì)于Create操作,不應(yīng)該返回這個(gè)值,因?yàn)槲募芾砥饕呀?jīng)為這個(gè)操作進(jìn)行同步了。此外對(duì)于同步的讀和寫操作,如果返回這個(gè)值會(huì)嚴(yán)重影響驅(qū)動(dòng)和系統(tǒng)性能。
?
如果在pre和post函數(shù)中更改了Data的內(nèi)容,必須調(diào)用FltSetCallbackDataDirty函數(shù)(更改IoStatus除外)。
?
Post回調(diào)函數(shù)(PFLT_POST_OPERATION_CALLBACK)
?
這個(gè)回調(diào)函數(shù)執(zhí)行的中斷等級(jí)為IRQL <= DISPATCH_LEVEL。所以需要注意以下幾點(diǎn):1、不能安全調(diào)用必須低于IRQL級(jí)別的任何內(nèi)核模式的派遣函數(shù)。2、在這個(gè)函數(shù)內(nèi)開辟的任何數(shù)據(jù)結(jié)構(gòu)必須位于非頁內(nèi)存。3、該函數(shù)不可分頁。4、不能請(qǐng)求資源(resource)、信號(hào)量(mutextes)和快速信號(hào)量(fast mutexes),只能獲取互斥鎖(spin lock)。5、不能獲取、設(shè)置或者刪除上下文,但可以釋放上下文。
?
相對(duì)于Pre回調(diào)函數(shù)多了最后一個(gè)參數(shù)Flags,這個(gè)參數(shù)如果存在FLTFL_POST_OPERATION_DRAINING標(biāo)記位,則表明當(dāng)前過濾驅(qū)動(dòng)實(shí)例正在被取消關(guān)聯(lián),本次調(diào)用是為了清理pre回調(diào)函數(shù)傳入的completion context,返回值必須是FLT_POSTOP_FINISHED_PROCESSING,并且這個(gè)回調(diào)是在IRQL<=APC_LEVEL執(zhí)行的。
?
FLT_POSTOP_FINISHED_PROCESSING:表明本過濾驅(qū)動(dòng)完成了對(duì)I/0操作的處理并將控制交還給過濾管理器。
?
FLT_POSTOP_MORE_PROCESSING_REQUIRED:只有當(dāng)微過濾驅(qū)動(dòng)將本次I/O操作發(fā)送到工作隊(duì)列中時(shí),才能返回這個(gè)值,微過濾驅(qū)動(dòng)最后必須負(fù)責(zé)完成這個(gè)I/O操作。過濾管理器會(huì)繼續(xù)等待FltCompletePendedPostOperation函數(shù)被調(diào)用后才繼續(xù)執(zhí)行控制。注意:這個(gè)返回值也必須對(duì)基于IRP中斷的操作執(zhí)行。
?
任何要被執(zhí)行在IRQL
?
除了以下情況外,要確保在Flags參數(shù)沒有FLTFL_POST_OPERATION_DRAINING標(biāo)記位的時(shí)候才能調(diào)用FltDoCompletionRpocessingWhenSafe函數(shù):
?
1、如果微過濾驅(qū)動(dòng)的pre回調(diào)函數(shù)為一個(gè)基于IRP中斷的操作返回FLT_PREOP_SYNCHRONIZE,那么對(duì)應(yīng)的post回調(diào)要保證和pre回調(diào)都處在IRQL<=APC_LEVEL的線程上下文中。
?
2、對(duì)于create操作的post回調(diào)要保證中斷級(jí)別為IRQL_PASSIVE_LEVEL(原始IRP_MJ_CREATE操作所處的線程上下文)。
總結(jié)
以上是生活随笔為你收集整理的基于Minifilter框架的文件过滤驱动理解的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: overflow 的各种用法
- 下一篇: overflow详解