FIELD NOTES /
Windows Kernel:物件管理、排程與驅動模型
深入 Executive、Object Manager、scheduler、IRQL、IRP、minifilter、pool 與 kernel debugging 的完整實務地圖。
Kernel 不是「一個大程式」
Windows 採用 hybrid kernel 設計。ntoskrnl.exe 內同時包含低階 Kernel 與多個 Executive manager;HAL 隔離部分硬體差異,kernel-mode drivers 則透過 I/O model 參與裝置、檔案系統、網路與其他子系統。
| 區域 | 核心責任 | 分析時常見入口 |
|---|---|---|
| Kernel | Thread dispatch、interrupt、exception、低階同步 | KTHREAD、PRCB、DPC、trap frame |
| Executive | Process、memory、I/O、object、security、configuration | EPROCESS、VAD、IRP、object namespace |
| HAL | Interrupt controller、timer、平台硬體差異 | ISR/DPC、clock、DMA 相關問題 |
| Drivers | 裝置或功能實作,組成 layered stack | DRIVER_OBJECT、DEVICE_OBJECT、dispatch routines |
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。
HANDLE(process-local value)
→ HANDLE_TABLE_ENTRY
→ OBJECT_HEADER
→ typed body(EPROCESS、ETHREAD、FILE_OBJECT…)HANDLE Table Lab — index → kernel object
0x4_EPROCESSUser 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 會進一步影響解析結果。遇到「同名但開不到」的問題時,要確認:
- 呼叫者所在 session。
- Object type 與完整 native path。
- Symbolic link 最終指向。
- 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 1 | Process 與 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_LEVEL | APC delivery、部分 memory-manager 路徑 | 一般 kernel APC 受限制,能做的事比 PASSIVE 少 |
| DISPATCH_LEVEL | DPC、持有部分 spin lock | 不可 page fault、不可做阻塞式 wait |
| DIRQL | Device ISR | 僅做最少硬體處理,將後續工作排入 DPC |
ISR、DPC 與 Work Item
可把延遲工作分成三層:
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 的生命週期
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。
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 intent | Create disposition 與 desired access 很重要 |
| IRP_MJ_WRITE | 寫入內容 | Paging I/O、cached I/O 與 noncached I/O 路徑不同 |
| IRP_MJ_SET_INFORMATION | Rename、delete disposition、metadata | Rename source / destination 與 transaction context |
| IRP_MJ_ACQUIRE_FOR_SECTION_SYNCHRONIZATION | Image/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 mutex | PASSIVE_LEVEL 較長 critical section | Lock ordering、recursive assumption |
| ERESOURCE | Reader/writer access | Upgrade 與 teardown 競爭 |
| Interlocked operations | 簡單 atomic state/counter | 誤以為單一 atomic 就保證整體資料一致性 |
| Rundown protection | 保護 callback 使用中的 object | Unload 時未等待 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
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_EQUAL | Faulting IRQL、address、read/write、instruction、memory 是否 pageable |
DRIVER_IRQL_NOT_LESS_OR_EQUAL | Faulting module、DPC/ISR path、buffer lifetime |
PAGE_FAULT_IN_NONPAGED_AREA | Invalid pointer、use-after-free、corruption、hardware possibility |
DRIVER_VERIFIER_DETECTED_VIOLATION | Verifier rule、target driver、原始錯誤之前的 call stack |
DRIVER_POWER_STATE_FAILURE | Power IRP、device stack、blocked thread、timeout owner |
!analyze -v 是索引,不是判決。最上方出現某 driver 可能只是受害者;要沿 call stack、object lifetime、pool state 與事件時序證明 root cause。
驗證與可觀測性工具鏈
| 工具 | 用途 |
|---|---|
| WinDbg | Live kernel debugging、dump、資料結構與 stacks |
| Driver Verifier | IRQL、pool、I/O、deadlock 等規則驗證 |
| WPP / ETW | 低開銷 driver tracing 與 timeline |
| WPA | CPU、DPC/ISR、I/O 與 latency 分析 |
| Process Monitor | File、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 常延遲到別處才爆炸。
延伸閱讀
- Microsoft Learn:Kernel-Mode Driver Architecture
- Microsoft Learn:End-User I/O Requests and File Objects
- Microsoft Learn:Filter Manager Concepts
- Microsoft Learn:Processing I/O Operations
- Windows Internals, 7th Edition, Part 2:I/O、storage、file systems、startup 與 management mechanisms
下一篇會從防禦者角度分析 malware execution chain:如何建立 timeline、如何辨識 memory anomaly,以及如何把單一 IOC 提升為可驗證的行為證據。
