首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> 關於VC++

Windows 檔案過濾驅動開發實戰經驗總結

     編輯:關於VC++

前言

研讀楚狂人《檔案過濾驅動開發教程》第二版後深有感觸。筆者整理近年開發檔案過濾驅動的實戰經驗,涵蓋路徑獲取時機、IRP 建立與傳遞細節、加解密判斷、完成例程處理等核心議題,供同好參考。

核心經驗彙整

1. 獲取完整檔案路徑的正確時機

僅在 IRP_MJ_CREATE 階段可靠獲取完整路徑。因為只有此處會呼叫 ObCreateObject() 建立有效的 FILE_OBJECT;在 IRP_MJ_READ/WRITE 中直接操作 FCB(File Control Block),FILE_OBJECT 相關資訊可能不完整。

若需在其他階段查詢路徑,必須自行建立 IRP 發送至下層裝置,但極易造成死結,非必要勿嘗試。

2. 自行建立 IRP 發送的旗標陷阱

建立任何 IRP(IRP_MJ_CREATE、IRP_MJ_DIRECTORY_CONTROL 等)時,IRP->Flags、IO_STACK_LOCATION->Flags 等旗標組合直接決定成敗。特別是 IRP_MN_QUERY_DIRECTORY,不同旗標導致截然不同的結果,需嚴格對照文件設定。

3. 自建 IRP_MJ_QUERY_INFORMATION 獲取路徑的同步處理

  • IRP_MJ_CREATE、IRP_MJ_CLOSE 均需特殊處理
  • NTFS 檔案系統下,IRP_MJ_CLEANUP 時對 FO_STREAM_FILE 類型亦需同步處理,否則易產生死結

4. 獲取本地/遠端存取用戶身分(用戶名/網域/SID)

僅在 IRP_MJ_CREATE 可行,透過 IO_SECURITY_CONTEXT → AccessState → SubjectSecurityContext.Token 取得存取 Token。IFS Kit 提供導出函數可由 Token 解析用戶名/網域;若需相容 NT 4.0,需自行解析 SID。

5. 檔案與目錄判斷的相容性寫法

勿直接信任 FileObject->FsContext 回傳資料(不同檔案系統結構不同)。正確做法:將 IRP_MJ_CREATE 傳遞至最底層檔案系統,待 IRP 完成返回上層後,再從完成的 IRP 取得準確資訊。

6. 加解密過濾的 IRP 判斷依據

核心判斷三種旗標:

  • IRP_PAGING_IO
  • IRP_SYNCHRONOUS_PAGING_IO
  • IRP_NOCACHE

FILE_OBJECT->Flags 中的 FO_NO_INTERMEDIATE_BUFFERING 最終會映射為 IRP_NOCACHE,故判斷 IRP 旗標即可,無需重複檢查 FILE_OBJECT。忽略 IRP_DEFER_IO_COMPLETION 等過渡性旗標。

7. IRP 傳遞與完成例程的實戰分類

將過濾驅動中的 IRP 分為兩大類:

A. 無需安裝 CompletionRoutine 的情況

  1. 直接 IoCompleteRequest() 返回
  2. IoSkipCurrentIrpStackLocation() + IoCallDriver() 直接下傳
  3. 使用 IoBuildSynchronousFsdRequest() 或 IoBuildDeviceIoControlRequest() 建立的 IRP

B. 需安裝 CompletionRoutine 的情況

細分兩種回傳狀態:

狀態 1:回傳 STATUS_MORE_PROCESSING_REQUIRED

  • 搭配 KeSetEvent() 同步等待
  • CompletionRoutine 返回此狀態可暫停 IRP 向上傳遞
  • 驅動稍後自行呼叫 IoCompleteRequest() 繼續流程
  • 適用:需在上層 IRP 返回資料後修改內容、或需分階段處理(如查詢檔案大小後再決定是否調整指標)

狀態 2:使用 IoMarkIrpPending() 並回傳其他狀態

  • 無 KeSetEvent() 同步機制
  • 所有處理在 CompletionRoutine 內完成(如加解密修改回傳資料)
  • 嚴禁 在 CompletionRoutine 返回後再觸碰該 IRP,否則觸發 MULTIPLE_IRP_COMPLETE_REQUESTS BSOD

自建非同步 IRP(IoAllocateIrp()/IoBuildAsynchronousFsdRequest())的特殊處理:

  • CompletionRoutine 中必須呼叫 IoFreeIrp() 釋放
  • 不可讓 IRP 繼續向上傳遞(上層不知此 IRP 存在)
  • CompletionRoutine 返回後 IRP 已失效,任何操作皆導致 BSOD

8. IRP 完成機制底層觀念

底層驅動呼叫 IoCompleteRequest() 後,I/O 管理器會:

  1. 檢查 IRP 旗標、處理 APC
  2. 沿裝置堆疊向上呼叫各層 CompletionRoutine
  3. 遇到 STATUS_MORE_PROCESSING_REQUIRED 停止向上回滾
  4. 若重複完成同一 IRP 拋出 MULTIPLE_IRP_COMPLETE_REQUESTS

9. ObQueryNameString 使用風險

底層呼叫 ZwQueryObject(),從物件管理器 ObpRootDirectoryObject 遍歷查詢。Win2K 下處理 PIPE 類物件易導致系統凍結或 BSOD,XP 已修補。生產環境謹慎使用。

10. 重入問題與解決方案

IFS FAQ Q34 列舉四種方案:

  1. 自建 IRP 發送
  2. Shadow Device
  3. 特徵字串標記
  4. 執行緒 ID 追蹤
  5. XP 新增 IoCreateFileSpecifyDeviceObjectHint()

各方案在不同環境(本地/遠端/CIFS)有不同副作用,需依場景選擇。Q33 另說明 FILE_COMPLETE_IF_OPLOCKED 處理。

結語

檔案過濾驅動開發細節極多,穩定性來自於對 IRP 生命週期、完成機制、同步原語的深度理解。建議配合《Programming the Microsoft Windows Driver Model》研讀,並大量實機驗證,方能構建生產級驅動程式。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved