⚡ 站長快讀:核心重點
- 文章屬性:教學實戰(底層除錯)
- 適用系統:Windows 10 / Windows 11(核心模式偵錯,不分版本)
- 難易度 / 耗時:⭐⭐⭐ / 約 40 分鐘
- 核心結論:三個指令分工——
!process找人、!thread問供詞、!irp查贓物。 - 適用對象:遇過「滑鼠會動但整台沒反應」、已會開 WinDbg 讀 minidump 的人
📌 快速答案
一句話答案:卡死沒有藍屏就沒有傾印檔,先按住最右側 Ctrl 連按兩下 Scroll Lock 強制產生傾印,再用 WinDbg !process 0 17 列出所有執行緒堆疊,交叉 !thread 與 !irp 找出卡住的驅動。
🧰 開始前的準備
- 系統需求:Windows 10 / Windows 11(依官方文件,PS/2 鍵盤強制當機自 Windows 2000 起支援、USB 自 Vista 起、Hyper-V 鍵盤自 Windows 10 1903 起)
- 權限需求:系統管理員(改登錄檔、改傾印檔設定都需要)
- 需要工具:WinDbg(Microsoft Store / winget)、微軟公開符號伺服器
- 預計耗時:設定約 10 分鐘、重現卡死看運氣、分析約 30 分鐘
- 難度門檻:看得懂十六進位、知道 IRP 是「I/O 請求封包」的縮寫就夠了
⚠️ 執行前必讀(高風險操作):本文步驟一會故意讓電腦當機。當機的瞬間所有未存檔的資料都會消失,而且會在系統磁碟寫入一個數 GB 的傾印檔。開始前請先存檔、關掉正在寫入的程式,並確認系統磁碟至少有 RAM 容量 + 10 GB 的可用空間。這台機器如果是正在服役的工作機或伺服器,請不要在上班時間做。
停止條件(符合任一,請立刻停手):①手上沒有另一台可用的電腦可以查資料 ②系統磁碟可用空間不足 ③這台機器啟用了 BitLocker 而你手邊沒有復原金鑰 ④公司或學校控管的設備且沒有 IT 授權 ⑤不確定自己在改的是哪一個登錄檔機碼。
🔍 為什麼你需要這個?
卡死和藍屏是兩種完全不同的問題,而網路上九成的 WinDbg 教學只教得了藍屏那一種。 藍屏會自己留下 minidump,你事後開起來跑 !analyze -v,分析器會直接把嫌疑模組名稱印在 MODULE_NAME 欄位裡。卡死不會。畫面凍住、滑鼠還能動但點什麼都沒反應、工作管理員叫不出來——這種狀態下系統其實還活著,只是某條執行緒抓著資源不放、或某個 I/O 請求送下去就再也沒回來,而它從頭到尾不會觸發任何 bug check,所以硬碟上什麼證據都不會留。
證據要自己製造。微軟官方文件《Forcing a system crash from the keyboard》講得很直白:設好一個登錄檔值之後,按住右邊 Ctrl 再連按兩下 Scroll Lock,系統就會呼叫 KeBugCheck 並發出 Bug Check 0xE2 MANUALLY_INITIATED_CRASH,接著把傾印檔寫下來。這一下按下去,你就把「卡死當下」那一秒的系統狀態整包凍結成檔案了。
拿到檔案之後才是真正的分歧點:這份傾印跑 !analyze -v 幫助有限(經驗推論,非官方明文)——官方只把 0xE2 定義為「使用者刻意從核心偵錯器或鍵盤發起的傾印」,並未評價 !analyze -v 在這種情境的效用;但停止碼既然是你自己按出來的,分析器順著它推出的結論自然指向這次人為中斷,而不是原本的卡死成因。要從這份檔案裡挖出卡死原因,得改用手動路徑,而 !process、!thread、!irp 這三個指令就是那條路徑的三段:先看誰在等、再看等什麼、最後看卡在哪個驅動手上。
還沒設好符號路徑的話,先把WinDbg 安裝與符號路徑設定那一關過了再回來;沒有符號,下面所有指令印出來的都會是一堆 nt+0x3f1234,等於白做。
🛠️ 實戰步驟
步驟一:先製造一份「看得到全部執行緒」的傾印檔
這一步有兩個設定要同時做對,少做一個後面就會卡住:一是開啟鍵盤強制當機,二是把傾印檔型別調大。
先看第二件事,因為它比較容易被忽略。微軟官方《Varieties of Kernel-Mode Dump Files》列出五種核心模式傾印檔:完整記憶體傾印、主動記憶體傾印、核心記憶體傾印、自動記憶體傾印、小型記憶體傾印。差別只有一個字——大小。官方對小型記憶體傾印的描述是「only 64 KB in size」,而核心記憶體傾印「通常不含使用者模式記憶體」,完整記憶體傾印則「包含部分使用者模式記憶體」。
💡 為什麼要這樣做?(機制推論,非官方明文)官方沒有逐指令列出「哪種傾印跑得動
!process」,但推論並不難:!process 0 17要走遍系統上每一個 EPROCESS 與其下所有執行緒堆疊,這些結構全在核心記憶體裡。小型傾印只留當機那一刻的少量現場,列不出全系統;核心傾印能列出核心那一半,使用者模式那一段堆疊會缺;要把使用者態呼叫鏈也一起看到,才需要完整或主動記憶體傾印。保險起見選「完整記憶體傾印」,代價是檔案大小約等於實體記憶體容量。
設定路徑(官方《Generate a kernel or complete crash dump》給的是控制台路徑):控制台 → 系統及安全性 → 系統 → 進階系統設定 → 「進階」索引標籤 → 啟動及修復「設定」 → 把「寫入偵錯資訊」改成完整記憶體傾印。Windows 11 也可從設定 → 系統 → 系統資訊 → 進階系統設定進到同一個對話框,但「進階」索引標籤這一步不能跳過。
接著開啟鍵盤強制當機。依官方文件,要改的機碼看你的鍵盤是哪一種:
| 鍵盤型態 | 登錄檔機碼(Parameters 之下) |
|---|---|
| PS/2(多數筆電內建鍵盤) | ...\Services\i8042prt\Parameters |
| USB 外接鍵盤 | ...\Services\kbdhid\Parameters |
| Hyper-V 虛擬機鍵盤 | ...\Services\hyperkbd\Parameters |
三者都是在該路徑下建立名為 CrashOnCtrlScroll 的 REG_DWORD,值設為 0x01。官方另外提醒:有些筆電內建鍵盤走 PS/2 驅動、又同時接了外接 HID 鍵盤,這種機器建議兩個機碼都建,哪支鍵盤都能觸發。
以 USB 鍵盤為例,系統管理員命令提示字元:
reg add "HKLM\SYSTEM\CurrentControlSet\Services\kbdhid\Parameters" ^
/v CrashOnCtrlScroll /t REG_DWORD /d 1 /f改完必須重新開機設定才會生效。之後遇到卡死,按住最右邊的 Ctrl 鍵、連按兩下 Scroll Lock 即可。
⚠️ 官方明載的失效情境,而且它本身就是線索:文件寫明「若電腦停止回應在高 IRQL(interrupt request level),鍵盤強制當機不會作用」,原因是負責讓傾印流程跑起來的
Kbdhid.sys執行在比i8042prt.sys更低的 IRQL。所以按了沒反應不代表你設錯——它同時告訴你這次卡死很可能發生在高 IRQL,那是另一類問題(中斷風暴、DPC 逾時),追法也不一樣。
步驟二:!process 0 17 — 這串數字不是咒語,是四個位元
先講結論:0 是「所有處理程序」,17 是十六進位旗標,拆開來是 0x1、0x2、0x4、0x10 四個位元的組合。 官方 !process 文件把每個位元的意義列得清清楚楚:
| 位元 | 值 | 官方定義 |
|---|---|---|
| Bit 0 | 0x1 | 顯示時間與優先權統計 |
| Bit 1 | 0x2 | 顯示執行緒與事件清單,以及它們的等待狀態 |
| Bit 2 | 0x4 | 顯示執行緒清單;與 Bit 1 併用時,每條執行緒會附上呼叫堆疊 |
| Bit 4 | 0x10 | 把處理程序內容切換成該處理程序,讓堆疊顯示更準確 |
四個位元加起來:0x1 + 0x2 + 0x4 + 0x10 = 0x17。所以 !process 0 17 的白話意思是:把系統上每一個處理程序、每一條執行緒的等待狀態與完整呼叫堆疊,全部印出來。
這裡有個很容易踩的細節:官方對 Bit 4 特別加註「This flag is only effective when used with Bit 0 (0x1)」——0x10 必須和 0x1 一起用才有效。所以想省事只打 !process 0 10 是沒用的,0x17 這個組合之所以流傳,正是因為它把該開的都開了。
另外官方也寫明 Process 參數的三種行為:省略時只顯示目前的系統處理程序、給 0 且不指定 ImageName 時顯示所有作用中的處理程序、給 -1 時顯示目前處理程序。
!process 0 17輸出會非常長,不要從頭讀。 直接在輸出裡搜尋 WAIT:——每個等待中的執行緒後面括號裡就是等待原因。官方 !process 文件指出,WAIT 後面括號內的註解就是等待理由,而完整的等待理由清單可以用 dt nt!_KWAIT_REASON 印出來。
輸出量大到讀不動時,官方在同一頁建議了替代品:!stacks 會給出每條執行緒狀態的簡短摘要,文件明說它「特別適合偵錯多執行緒問題,例如資源衝突或死結」。!stacks 2 會連分頁出去的堆疊與完整參數一起印。卡死題我的習慣是先 !stacks 0 掃過一輪找可疑執行緒,再回頭對那幾條下 !process,比從頭讀六千行有效率。
步驟三:!thread — 鎖定單一執行緒,看它到底在等什麼
!process 給你的是全景,!thread 給你的是特寫。 從步驟二挑出可疑的執行緒位址(輸出裡 THREAD 後面那串十六進位),直接餵進去:
!thread ffffcb088f0a4480官方文件說明,!thread 顯示目標系統上某條執行緒的摘要資訊,含 ETHREAD 結構,同樣只能在核心模式偵錯時使用。它的旗標與 !process 類似但不完全一樣,預設值是 0x6:
- Bit 1(0x2):顯示執行緒的等待狀態
- Bit 2(0x4):單獨使用無效,必須與 Bit 1 併用才會附上呼叫堆疊
- Bit 3(0x8):加上返回位址與堆疊指標,並抑制函式引數顯示
- Bit 4(0x10):把處理程序內容切成該執行緒所屬的處理程序,堆疊會更準
另外兩個好用的開關:-p 會順便顯示擁有這條執行緒的處理程序摘要;-t 表示你給的是執行緒 ID 而非位址。
輸出裡要盯的欄位,官方逐項列在文件表格中:Cid 後面兩個十六進位數字是「處理程序 ID.執行緒 ID」;Owning Process 是擁有者 EPROCESS 位址;行末的 Thread State 才是關鍵——它會告訴你這條執行緒是 RUNNING 還是卡在某個等待上。
💡 為什麼要這樣做? 卡死案件裡真正有價值的資訊不是「誰在跑」,而是「誰在等、等了多久、等的東西誰握著」。
Wait Start TickCount搭配Ticks就能看出這條執行緒已經等了多久;如果Ticks大得離譜,它八成就是受害者或加害者之一。
步驟四:!irp — 追出送下去就沒回來的 I/O 請求
如果卡死的症狀是「檔案總管點某個磁碟就整個凍住」「USB 裝置插上去之後全系統卡住」,兇手多半躺在某個沒完成的 IRP 上。
官方定義很簡單:!irp Address [Detail]。位址給 IRP 的十六進位位址;Detail 只要填任何值(例如 1),輸出就會多出 IRP 狀態、記憶體描述元清單(MDL)位址、擁有者執行緒,以及每一層 I/O 堆疊的資訊,包含主要功能碼與次要功能碼的十六進位值。不填則只印摘要。
!irp ffffac598dc8 1輸出第一行長這樣:Irp is active with 2 stacks 1 is current,而前面帶 > 符號的那一層就是目前這個 IRP 停在哪一層。每層會印出裝置物件、驅動名稱(例如 \Driver\disk、\FileSystem\Ntfs)與完成常式。官方特別註明:Windows 10 起,IRP 的主要與次要功能碼會直接顯示文字,例如 IRP_MJ_FILE_SYSTEM_CONTROL,同時附上十六進位碼 (d);輸出裡的第三個引數是 IOCTL 碼,可以用 !ioctldecode 進一步解讀。
完成常式旁邊還會標 Success / Error / Cancel 三種條件,代表 IRP 完成時在什麼狀況下會呼叫該完成常式——這三種是官方 !irp 文件明確定義的。至於同一行常見的 pending 字樣,官方 !irp 參考頁並未解釋,它對應的是該堆疊位置被標記為「已回傳擱置」(驅動呼叫 IoMarkIrpPending 或回傳 STATUS_PENDING)——卡死案件裡,那個一直擱置又不往上走的層級,它掛的驅動名稱就是第一嫌疑人。
問題來了:IRP 位址從哪來? 兩條路。第一條是從步驟三的執行緒堆疊裡撈(等在 I/O 上的執行緒,堆疊會出現 IRP 位址)。第二條是官方的 !irpfind,它會列出目標系統上所有已配置的 IRP,或只列符合條件者:
!irpfind!irpfind 的搜尋條件官方列了六種,常用的是 thread(找 Irp.Tail.Overlay.Thread 等於指定值的 IRP)與 device(找堆疊位置的 DeviceObject 等於指定值者)。這條就是把步驟三與步驟四接起來的橋:
!irpfind 0 0 thread ffffcb088f0a4480意思是「在非分頁集區裡,找出屬於這條執行緒的所有 IRP」。!irpfind 預設搜尋非分頁集區(PoolType 0),其餘可選分頁集區 1、特殊集區 2、工作階段集區 4。
步驟五:驗證結果 — 三條線交叉才算數
單一指令的輸出都不算證據,三條線指向同一個驅動名稱才算。 收尾時照這個順序回頭對一次:
!process 0 17裡那條Ticks異常大的執行緒,WAIT的原因是什麼?!thread對這條執行緒單獨展開,Thread State 與呼叫堆疊裡出現哪個第三方驅動模組名稱?!irpfind ... thread <該執行緒位址>找出它掛著的 IRP,!irp <位址> 1展開後,標pending的那一層屬於哪個\Driver\xxx?
三個答案指到同一支驅動,才有把握說「就是它」。如果 2 和 3 指到不同驅動,通常代表你看到的是一條受害鏈——真正的源頭在更下層(檔案系統 → 磁碟區 → 磁碟 → 埠驅動),順著 !irp 的堆疊往下讀就會找到。
🔬 底層機制:這個問題到底在系統哪一層?
卡死的本質,是核心裡某個「等待」永遠等不到通知。
Windows 的執行緒不是被動輪詢,而是把自己掛在同步物件上睡著,等別人喚醒。!process 輸出裡的 WAIT: (WrFreePage) 這種標記,括號裡就是等待原因,官方文件指向 dt nt!_KWAIT_REASON 可以列出全部種類。當一條執行緒的等待原因對應到一個永遠不會被設定的事件,它就會一直睡下去——這不是當機,系統完全正常運作,只是這條路上的人全部在排隊。
I/O 這一側的機制更具體。應用程式讀一個檔案,I/O 管理員會建立一個 IRP,這個 IRP 帶著多層 I/O 堆疊位置,依序往驅動堆疊下走:檔案系統 → 磁碟區管理 → 分割管理 → 磁碟 → 儲存埠驅動。官方 !irp 文件裡那則標明取自 Windows Vista 的八層範例輸出,把這條鏈印得一清二楚,從 \FileSystem\Ntfs 經 \Driver\volmgr、\Driver\PartMgr 一路到 \Driver\disk(同頁的 Windows 10 範例只有兩層,不要拿來對照層數)。每一層驅動可以選擇把 IRP 標成 pending 先放著,等硬體回應再往上完成。只要中間任何一層拿了不還,上面所有層級全部卡住,而發起 I/O 的那條執行緒就永遠醒不過來。
再往上一層看,執行緒之間還有資源鎖。!process 文件提到,執行緒資訊裡會列出該執行緒持有鎖的資源,並建議把這些位址拿去和 !locks 的清單比對,就能知道哪些執行緒對資源有獨佔鎖。兩條執行緒互相等對方手上的鎖,就是典型死結——這種案子 !process 0 17 一次就能看出來,因為兩條執行緒的等待原因會互相指向。
最後是 IRQL 這一層。步驟一提到的官方限制——高 IRQL 卡死時鍵盤強制當機失效——背後的意義是:CPU 在高 IRQL 上執行時,低 IRQL 的程式碼(包含負責寫傾印的鍵盤驅動)根本排不進去。所以「按了 Ctrl+Scroll Lock 沒反應」本身就是一個分層訊號:問題不在等待,而在某段程式碼霸佔著 CPU 不下來。 那類問題的入口是 CLOCK_WATCHDOG_TIMEOUT(0x101) 這種看門狗型 bug check,不是本文這三個指令。
🔙 萬一翻車:回退步驟
這篇改了兩樣東西:一個登錄檔值、一個傾印檔型別設定。兩樣都可以完整還原。
情境一:設定生效但按了沒反應
先確認你按的是最右邊那顆 Ctrl(官方寫的是 rightmost CTRL key),Scroll Lock 要連按兩下。還是沒反應就換一種可能:你的鍵盤走的驅動和你改的機碼不同。筆電內建鍵盤常走 i8042prt,外接鍵盤走 kbdhid,官方建議兩個都建。都建了還是沒反應,回頭看步驟一那則高 IRQL 警語——這種情況下該換工具,不是硬試。
情境二:想把設定改回去
登錄檔值直接刪除即可,系統管理員命令提示字元:
reg delete "HKLM\SYSTEM\CurrentControlSet\Services\kbdhid\Parameters" ^
/v CrashOnCtrlScroll /fPS/2 與 Hyper-V 機碼同理,把 kbdhid 換成 i8042prt 或 hyperkbd。刪完要重開機才會生效。 傾印檔型別則回到啟動及修復 → 設定,把「寫入偵錯資訊」改回你原本的選項——改之前請先記下原值再動手,不要憑印象填,不同版本、不同版次的原廠預設值並不一致(常見預設為「自動記憶體傾印」,但這不是每台機器都成立的保證)。改完記得順手把系統磁碟裡幾 GB 大的 MEMORY.DMP 清掉。
情境三:系統無法正常開機
本文的兩個變更都不影響開機路徑,理論上不會走到這一步。真的開不起來,多半與你同時做的其他事有關(例如順手更新了驅動)。標準救援路徑是連續兩次開機失敗後自動進入 WinRE,選疑難排解 → 進階選項 → 啟動設定進安全模式,再用上面的 reg delete 還原;若連 WinRE 都進不去,用另一台電腦以官方媒體建立工具做一支開機 USB,從修復您的電腦進入。若這台機器啟用了 BitLocker,進 WinRE 會要求輸入復原金鑰——沒有金鑰就不要開始這篇的任何步驟。
💡 總結:進階玩法與底層邏輯
開頭那句「找人、問供詞、查贓物」不是順口溜,它就是執行順序:三者缺一都會停在「好像是這支驅動」的模糊地帶,湊齊了才敢寫進報告。站長我看過太多人只跑第一步就下結論,結果指到的是受害者不是加害者。
有幾個可驗證的錨點值得記起來,它們都寫在官方文件裡、任何人都能自己對:0x17 是 0x1|0x2|0x4|0x10 四個位元;!thread 的預設旗標是 0x6;!process 的 Bit 4 與 !thread 的 Bit 2 都有「單獨用無效」的但書;鍵盤強制當機發出的是 bug check 0xE2;!irpfind 預設只搜非分頁集區。這五件事記住,你在別人的教學文裡看到「就是要打 17」時,至少知道自己在打什麼。
進階延伸有兩條。 一條是 !stacks 2 加 FilterString,官方支援只顯示符號中含指定子字串的執行緒——追特定廠商驅動時,直接用它的模組名當過濾字串,六千行輸出瞬間變十行。另一條是 !ioctldecode,把 !irp 輸出的第三個引數丟進去,能直接把 IOCTL 碼還原成裝置類型與功能編號,對付「插上某台 USB 裝置就卡住」特別好用。
要誠實講清楚的是:本文所有指令語意、旗標定義與輸出範例,全部依微軟官方文件整理,不是站長在特定機器上的實測數據。 你手上那台機器的輸出長什麼樣、能不能重現,取決於你的傾印檔型別、符號是否完整、以及卡死的真實成因——這三件事我沒有你的機器,無法替你斷言。真的追不出來,把 !process 0 17 的輸出留檔,那是最有價值的一手證據。
❓ 常見問題
Q:我只有小型記憶體傾印(minidump),可以跑 !process 0 17 嗎?
不建議,而且大機率跑不出你要的東西。官方把小型記憶體傾印描述為五種傾印檔裡最小的一種(文件記為 64 KB),它保存的是當機瞬間的少量現場,不是全系統核心記憶體;!process 0 17 需要走遍所有 EPROCESS 與執行緒堆疊,資料不在檔案裡就印不出來。要追卡死,請在步驟一把型別改成核心或完整記憶體傾印,重新製造一份。
Q:一定要接第二台電腦做雙機偵錯嗎?
不用。官方在 !process 與 !thread 兩頁都明寫「本延伸指令只能在核心模式偵錯期間使用」,!irp 與 !irpfind 則同樣由核心偵錯延伸模組 Kdexts.dll 提供;而用 WinDbg 開啟核心模式傾印檔就屬於核心模式偵錯,不需要雙機連線。雙機的好處官方也講了:傾印檔是某個時間點的快照,即時偵錯才能隨程式執行觀察所有記憶體值——但對「找出卡死的驅動」這個目標,一份完整傾印通常就夠。
Q:!process 0 17 輸出太長,WinDbg 直接沒反應怎麼辦?
先確認不是符號還在下載(第一次連微軟符號伺服器可能要幾分鐘)。真的是輸出量問題,改用 !stacks 0 先掃摘要,官方就是把它定位成 !process 的快速替代品。另一招是用 .logopen 把輸出導到檔案再用文字編輯器搜尋,比在偵錯器視窗裡捲有效率得多。
Q:這個方法在舊版本也適用嗎?
!process、!thread、!irp 是行之有年的核心偵錯延伸指令,語法在 Windows 10 / 11 世代沒有變。要注意的是輸出格式差異:官方明載 Windows 10 起 !irp 才會把主要/次要功能碼顯示成文字(如 IRP_MJ_FILE_SYSTEM_CONTROL),更舊的系統只會印出 [ 3,34] 這種數字對,需要自己查功能碼對照表——官方 !irp 文件頁面就附有完整的對照表。鍵盤強制當機的支援起點也不同:PS/2 自 Windows 2000、USB 自 Windows Vista、Hyper-V 鍵盤自 Windows 10 1903。
Q:找到可疑驅動之後呢?
先確認它是不是第三方驅動(檔名不在 nt、ntoskrnl、win32k 這類系統模組裡),然後到裝置製造商官網找最新版更新;版本已經最新就試著回滾到前一版。如果懷疑是驅動記憶體誤用而非單純卡住,下一步工具是 Driver Verifier,那是另一條路線的開始。
📎 參考資料來源
📖 第一級|廠商官方:
- !process (WinDbg) — Microsoft Learn — 2026-08-10 查證
- !thread (WinDbg) — Microsoft Learn — 2026-08-10 查證
- !irp extension command — Microsoft Learn — 2026-08-10 查證
- !irpfind (WinDbg) — Microsoft Learn — 2026-08-10 查證
- !stacks (WinDbg) — Microsoft Learn — 2026-08-10 查證
- Forcing a system crash from the keyboard — Microsoft Learn — 2026-08-10 查證
- Varieties of Kernel-Mode Dump Files — Microsoft Learn — 2026-08-10 查證
- Bug Check 0xE2: MANUALLY_INITIATED_CRASH — Microsoft Learn — 2026-08-10 查證
- Generate a kernel or complete crash dump — Microsoft Learn — 2026-08-10 查證
⚠️ 本文核心事實以第一級為準。本文為官方文件整理與機制解讀,非站長第一手實測數據。
📅 本文查證戳記:2026-08-10 依微軟官方偵錯器文件撰寫。
若你在後續版本遇到步驟失效,歡迎在留言區回報,站長會更新文章。
🔗 延伸閱讀
- WinDbg !analyze -v 完整教學:逐欄位讀懂當機分析報告
- NO_MORE_IRP_STACK_LOCATIONS(0x35)藍屏怎麼修?揪出插隊裝置堆疊的過濾驅動
- 電腦睡一睡、關機就藍屏?DRIVER_POWER_STATE_FAILURE(0x9F)先揪出這支驅動程式
- stornvme Event 129 SSD 卡死排查:先別急著換碟
- WinDbg 藍畫面 minidump 分析教學:三行輸出找出真兇