← 回到筆記

FIELD NOTES /

Windows Kernel:物件管理、排程與驅動模型

深入 Executive、Object Manager、scheduler、IRQL、IRP、minifilter、pool 與 kernel debugging 的完整實務地圖。

#Windows Kernel#Driver#WinDbg

Kernel 不是「一個大程式」

Windows 採用 hybrid kernel 設計。ntoskrnl.exe 內同時包含低階 Kernel 與多個 Executive manager;HAL 隔離部分硬體差異,kernel-mode drivers 則透過 I/O model 參與裝置、檔案系統、網路與其他子系統。

區域核心責任分析時常見入口
KernelThread dispatch、interrupt、exception、低階同步KTHREAD、PRCB、DPC、trap frame
ExecutiveProcess、memory、I/O、object、security、configurationEPROCESS、VAD、IRP、object namespace
HALInterrupt controller、timer、平台硬體差異ISR/DPC、clock、DMA 相關問題
Drivers裝置或功能實作,組成 layered stackDRIVER_OBJECT、DEVICE_OBJECT、dispatch routines
Windows I/O stack 示意
Device stack 由 PDO、FDO 與 filter device objects 組成;I/O request 向下傳遞,completion 再反向返回。 — Microsoft Learn — Kernel-Mode Driver Architecture

Object Manager:核心資源的共同模型

Process、Thread、File、Section、Event、Mutant、Semaphore、Token 與 Driver 等資源都以 object model 管理。這套模型統一了:

  • 命名與 Object Manager namespace。
  • Handle table 與 access rights。
  • Reference counting 與 lifetime。
  • Object type-specific operations。
  • Security descriptor 與 access check。
Plain Text
HANDLE(process-local value)
  → HANDLE_TABLE_ENTRY
    → OBJECT_HEADER
      → typed body(EPROCESS、ETHREAD、FILE_OBJECT…)

HANDLE Table Lab — index → kernel object

HANDLE0x4
→ Table[index]_EPROCESS
TypeProcess
Namenotepad.exe

User mode 的 HANDLE 是 process handle table 的 index;kernel 透過 ObReferenceObjectByHandle 還原成 _OBJECT_HEADER + body。

Handle count 與 pointer count

Object lifetime 不只看 user-mode handle。Handle count 表示開啟的 handle 數量;pointer/reference count 還包含 kernel components 暫時或長期持有的 references。關閉最後一個 handle 後,object 可能仍因 kernel reference 存活;反過來,driver 若漏掉 dereference,便可能形成 resource leak。

Driver 取得 object pointer 時,應透過文件化 routine 執行 type 與 access validation,並對成功取得的 reference 成對釋放。不要把 user handle 強制轉型成 kernel pointer,也不要把 process A 的 handle 直接套到 process B。

Namespace 與路徑

Win32 的 C:\...、\\.\DeviceName 與 kernel namespace 中的 \Device\...、\BaseNamedObjects\... 屬於不同抽象層。Symbolic link 與 per-session namespace 會進一步影響解析結果。遇到「同名但開不到」的問題時,要確認:

  1. 呼叫者所在 session。
  2. Object type 與完整 native path。
  3. Symbolic link 最終指向。
  4. Token、integrity level 與 desired access。

常用 WinDbg 命令

命令用途
!object \瀏覽 Object Manager namespace
!object <address>Object header、type、counts 與 name
!handle <value> 3 <process>Handle type、granted access 與 object
!process 0 1Process 與 thread 摘要
dt nt!_OBJECT_HEADER <address>依 symbols 解讀 object header

Scheduler:真正被排程的是 Thread

Windows 使用 priority-driven、preemptive scheduler。每個 processor 維護與 runnable threads 有關的狀態;thread 的動態 priority、affinity、ideal processor、quantum 與 wait history 都會影響實際執行。

常見 thread state

State意義調查方向
Running正在某個 logical processor 執行看 current stack、CPU time、IRQL
Ready可執行,等待取得 CPU長期 Ready 可能是 CPU contention
Standby已被選為某 processor 下一條 thread短暫過渡狀態
Waiting等待 dispatcher object、I/O、timer 等Wait reason、wait object、timeout
Transition準備回到 ready queue觀察記憶體與 scheduling context
Terminated已結束但結構可能尚未完全回收Reference 是否仍被持有

Priority 高不代表永遠執行。Thread 可能在等待 I/O、鎖、event 或 page fault;高 priority 也可能造成 starvation。分析「程式卡住」時,通常先看所有 thread stacks 與 wait chain,而不是只看 CPU 百分比。

Dispatcher objects 與等待

Event、Mutex/Mutant、Semaphore、Timer、Process 與 Thread 都能參與 dispatcher wait。Synchronization event 喚醒一個 waiter 後自動 reset;notification event 則維持 signaled,直到明確 reset。等待錯誤常見於:

  • Lock ordering 不一致造成 deadlock。
  • 在持有 spin lock 時執行可能阻塞的操作。
  • 忘記處理 timeout、cancel 或 teardown。
  • User event 與 kernel reference 的 lifetime 不一致。

IRQL:限制現在能做什麼

IRQL 是 interrupt request priority,不是 thread priority,也不是一般意義的權限等級。提高 IRQL 會屏蔽部分較低優先級事件,因此高 IRQL 程式碼必須短、可預測,而且不能觸發需要等待的工作。

IRQL典型情境重要限制
PASSIVE_LEVEL一般 thread context、多數 driver work item可 wait;在適當條件下可碰 pageable code
APC_LEVELAPC delivery、部分 memory-manager 路徑一般 kernel APC 受限制,能做的事比 PASSIVE 少
DISPATCH_LEVELDPC、持有部分 spin lock不可 page fault、不可做阻塞式 wait
DIRQLDevice ISR僅做最少硬體處理,將後續工作排入 DPC
IRQL 層級示意
IRQL 越高,可安全呼叫的 API 與可存取的記憶體越受限。ISR 應快速確認與清除硬體狀態,再把耗時工作交給 DPC。 — Microsoft Learn

ISR、DPC 與 Work Item

可把延遲工作分成三層:

Plain Text
ISR(DIRQL)
  → 確認中斷、保存最小狀態
    → DPC(DISPATCH_LEVEL)
      → 完成不會阻塞的 deferred work
        → Work item / system thread(PASSIVE_LEVEL)
          → 需要 wait、pageable code 或複雜 I/O 的工作

若 DPC 執行過久,會增加 system-wide latency;若 ISR 過久,影響更嚴重。WPA 的 DPC/ISR analysis 適合定位 audio glitch、input lag 與 driver latency。

I/O Manager 與 IRP

I/O Manager 提供一致模型,讓 caller 不需要了解實體裝置與 driver stack 細節。IRP(I/O Request Packet)保存整個 I/O request 的狀態,而每一層 driver 透過自己的 I/O stack location 讀取參數並決定:處理、轉送、pending 或完成。

一個 IRP 的生命週期

Plain Text
User / kernel caller
  → I/O Manager 建立 IRP
    → top device object dispatch routine
      → filter / function / bus driver 逐層向下
        → device 或 lower stack 完成
      ← completion routines 由下往上執行
  ← caller 收到 status 與 information

關鍵規則包括:

  • 每層使用自己的 current/next stack location。
  • 回傳 STATUS_PENDING 代表稍後完成,不代表失敗。
  • Completion routine 可能在與原 caller 不同的 thread context 執行。
  • Cancel、timeout、PnP remove 與 surprise removal 必須納入設計。
  • Double completion、漏 completion、錯誤 pending propagation 都可能造成 crash 或 hang。

Device stack:PDO、FDO、Filter

  • PDO(Physical Device Object)代表 bus enumerator 發現的裝置。
  • FDO(Functional Device Object)由主要功能 driver 建立。
  • Filter DO 在 stack 上加入監控或額外功能。

不要用「一個裝置等於一個 driver」理解 Windows I/O。同一 request 往往穿過多個 device objects 與 drivers。

File-system Minifilter

Filter Manager(FltMgr.sys)提供檔案系統 filter 共用機制。Minifilter 只註冊需要處理的 operations;FltMgr 依 altitude 與 instance 順序呼叫 pre-operation callbacks,I/O 完成後再以反向順序呼叫 post-operation callbacks。

Plain Text
CreateFile
  → I/O Manager / FltMgr
    → high-altitude filter PreCreate
      → lower filters PreCreate
        → file system
      ← lower filters PostCreate
    ← high-altitude filter PostCreate
Operation防禦產品常見用途分析注意事項
IRP_MJ_CREATE檔案開啟、建立、overwrite intentCreate disposition 與 desired access 很重要
IRP_MJ_WRITE寫入內容Paging I/O、cached I/O 與 noncached I/O 路徑不同
IRP_MJ_SET_INFORMATIONRename、delete disposition、metadataRename source / destination 與 transaction context
IRP_MJ_ACQUIRE_FOR_SECTION_SYNCHRONIZATIONImage/memory mapping 相關協調可連結 executable mapping 與後續 process 行為

Microsoft 建議新的 file-system filter 優先使用 minifilter model,而不是 legacy filter。即使有 FltMgr,driver 仍要正確處理 callback IRQL、reentrancy、name query、context lifetime 與 teardown。

Kernel Memory:Pool、MDL 與 Ownership

Paged 與 Nonpaged

  • Paged pool 可被換出;只能在允許 page fault 的 context 使用。
  • Nonpaged pool 保證 resident,適合高 IRQL 或硬體相關路徑。
  • NonPagedPoolNx 預設不可執行,能降低資料被當成 code 執行的風險。

Driver allocation 必須有明確 ownership:誰配置、誰釋放、失敗路徑是否釋放、IRP cancel 時是否仍被 callback 引用。Pool tag 是查漏的重要線索。

MDL 不等於 buffer

MDL(Memory Descriptor List)描述一組 physical pages 與 mapping 狀態,本身不是資料 buffer。處理 direct I/O 時,需要分清楚:原 user virtual address、locked pages、system-space mapping 與 mapping lifetime。對 user pointer 的任何信任都可能帶來 TOCTOU、invalid address 或權限問題。

Synchronization 與常見失敗模式

Primitive適用情境常見錯誤
Spin lock短小、不可阻塞、較高 IRQL 區段鎖內呼叫 pageable/blocking code
Mutex / Guarded mutexPASSIVE_LEVEL 較長 critical sectionLock ordering、recursive assumption
ERESOURCEReader/writer accessUpgrade 與 teardown 競爭
Interlocked operations簡單 atomic state/counter誤以為單一 atomic 就保證整體資料一致性
Rundown protection保護 callback 使用中的 objectUnload 時未等待 active users 離開

Driver 的困難通常不在 happy path,而是 concurrent I/O、cancel、PnP remove、power transition 與 unload 同時發生時仍能維持 lifetime 正確。

PatchGuard、VBS 與 Kernel Integrity

PatchGuard(Kernel Patch Protection)會保護特定核心結構與程式碼不被未授權修改;VBS/HVCI 則利用 virtualization-based isolation 強化 code integrity 與部分敏感狀態。它們不是單一「禁止 hook」開關,也不能取代 driver 安全設計。

研究 kernel instrumentation 時應使用文件化機制,例如 ETW、object callbacks、process/thread/image notify routines、minifilter、WFP 或 WDK 提供的 frameworks。修改 SSDT、IDT、核心 code 或 undocumented lists 不只版本脆弱,也可能觸發 bugcheck 並破壞系統完整性。

Kernel Debugging:從現象到 root cause

建議環境

  • Hyper-V、VMware 或其他可還原 snapshot 的測試 VM。
  • 與 target build 相符的 WDK、WinDbg 與 Microsoft symbol server。
  • Kernel debugging transport 或完整/核心 memory dump。
  • Driver Verifier 只對目標測試 driver 開啟,避免把整台機器變成噪音來源。

Crash dump triage

Plain Text
vertarget              ; OS、build、architecture
!analyze -v            ; 初始分類,不把結果當最終答案
.bugcheck               ; bugcheck code 與 parameters
k / kv                  ; current stack 與參數
!thread                 ; current thread、IRQL、wait
!process 0 0            ; process context
lmvm <driver>           ; driver version、timestamp、symbols
!irp <address>          ; 涉及 I/O 時檢查 IRP stack
!locks                  ; deadlock 或 resource contention

常見 bugcheck 思考方式

類型優先確認
IRQL_NOT_LESS_OR_EQUALFaulting IRQL、address、read/write、instruction、memory 是否 pageable
DRIVER_IRQL_NOT_LESS_OR_EQUALFaulting module、DPC/ISR path、buffer lifetime
PAGE_FAULT_IN_NONPAGED_AREAInvalid pointer、use-after-free、corruption、hardware possibility
DRIVER_VERIFIER_DETECTED_VIOLATIONVerifier rule、target driver、原始錯誤之前的 call stack
DRIVER_POWER_STATE_FAILUREPower IRP、device stack、blocked thread、timeout owner

!analyze -v 是索引,不是判決。最上方出現某 driver 可能只是受害者;要沿 call stack、object lifetime、pool state 與事件時序證明 root cause。

驗證與可觀測性工具鏈

工具用途
WinDbgLive kernel debugging、dump、資料結構與 stacks
Driver VerifierIRQL、pool、I/O、deadlock 等規則驗證
WPP / ETW低開銷 driver tracing 與 timeline
WPACPU、DPC/ISR、I/O 與 latency 分析
Process MonitorFile、registry、process/thread 活動關聯
Static Driver Verifier / CodeQL在執行前找 contract 與路徑問題

常見誤區

  • IRQL 等於 thread priority:兩者用途不同。
  • Nonpaged memory 永遠安全:pointer 仍可能失效,函式仍可能違反 IRQL contract。
  • IRP 回傳就結束:pending 與 completion 可能在稍後、不同 context 發生。
  • Handle 就是 object pointer:handle 是 process-local table entry。
  • Driver unload 只要刪除 device object:還需停止 callback、timer、DPC、work item 與 active I/O。
  • Dump 顯示的 blamed module 就是 root cause:memory corruption 常延遲到別處才爆炸。

延伸閱讀

下一篇會從防禦者角度分析 malware execution chain:如何建立 timeline、如何辨識 memory anomaly,以及如何把單一 IOC 提升為可驗證的行為證據。