研讀楚狂人《檔案過濾驅動開發教程》第二版後深有感觸。筆者整理近年開發檔案過濾驅動的實戰經驗,涵蓋路徑獲取時機、IRP 建立與傳遞細節、加解密判斷、完成例程處理等核心議題,供同好參考。
僅在 IRP_MJ_CREATE 階段可靠獲取完整路徑。因為只有此處會呼叫 ObCreateObject() 建立有效的 FILE_OBJECT;在 IRP_MJ_READ/WRITE 中直接操作 FCB(File Control Block),FILE_OBJECT 相關資訊可能不完整。
若需在其他階段查詢路徑,必須自行建立 IRP 發送至下層裝置,但極易造成死結,非必要勿嘗試。
建立任何 IRP(IRP_MJ_CREATE、IRP_MJ_DIRECTORY_CONTROL 等)時,IRP->Flags、IO_STACK_LOCATION->Flags 等旗標組合直接決定成敗。特別是 IRP_MN_QUERY_DIRECTORY,不同旗標導致截然不同的結果,需嚴格對照文件設定。
IRP_MJ_CREATE、IRP_MJ_CLOSE 均需特殊處理IRP_MJ_CLEANUP 時對 FO_STREAM_FILE 類型亦需同步處理,否則易產生死結僅在 IRP_MJ_CREATE 可行,透過 IO_SECURITY_CONTEXT → AccessState → SubjectSecurityContext.Token 取得存取 Token。IFS Kit 提供導出函數可由 Token 解析用戶名/網域;若需相容 NT 4.0,需自行解析 SID。
勿直接信任 FileObject->FsContext 回傳資料(不同檔案系統結構不同)。正確做法:將 IRP_MJ_CREATE 傳遞至最底層檔案系統,待 IRP 完成返回上層後,再從完成的 IRP 取得準確資訊。
核心判斷三種旗標:
IRP_PAGING_IOIRP_SYNCHRONOUS_PAGING_IOIRP_NOCACHEFILE_OBJECT->Flags 中的 FO_NO_INTERMEDIATE_BUFFERING 最終會映射為 IRP_NOCACHE,故判斷 IRP 旗標即可,無需重複檢查 FILE_OBJECT。忽略 IRP_DEFER_IO_COMPLETION 等過渡性旗標。
將過濾驅動中的 IRP 分為兩大類:
IoCompleteRequest() 返回IoSkipCurrentIrpStackLocation() + IoCallDriver() 直接下傳IoBuildSynchronousFsdRequest() 或 IoBuildDeviceIoControlRequest() 建立的 IRP細分兩種回傳狀態:
狀態 1:回傳 STATUS_MORE_PROCESSING_REQUIRED
KeSetEvent() 同步等待IoCompleteRequest() 繼續流程狀態 2:使用 IoMarkIrpPending() 並回傳其他狀態
KeSetEvent() 同步機制MULTIPLE_IRP_COMPLETE_REQUESTS BSOD自建非同步 IRP(IoAllocateIrp()/IoBuildAsynchronousFsdRequest())的特殊處理:
IoFreeIrp() 釋放底層驅動呼叫 IoCompleteRequest() 後,I/O 管理器會:
STATUS_MORE_PROCESSING_REQUIRED 停止向上回滾MULTIPLE_IRP_COMPLETE_REQUESTSObQueryNameString 使用風險底層呼叫 ZwQueryObject(),從物件管理器 ObpRootDirectoryObject 遍歷查詢。Win2K 下處理 PIPE 類物件易導致系統凍結或 BSOD,XP 已修補。生產環境謹慎使用。
IFS FAQ Q34 列舉四種方案:
IoCreateFileSpecifyDeviceObjectHint()各方案在不同環境(本地/遠端/CIFS)有不同副作用,需依場景選擇。Q33 另說明 FILE_COMPLETE_IF_OPLOCKED 處理。
檔案過濾驅動開發細節極多,穩定性來自於對 IRP 生命週期、完成機制、同步原語的深度理解。建議配合《Programming the Microsoft Windows Driver Model》研讀,並大量實機驗證,方能構建生產級驅動程式。