快訊
2026-08-04
電腦疑難雜症

NO_MORE_IRP_STACK_LOCATIONS(0x35)藍屏怎麼修?揪出插隊裝置堆疊的過濾驅動

約 17 分鐘閱讀
廣告

⚡ 站長快讀:核心重點

  • 屬性 / 系統:疑難排除(底層除錯)/ Windows 10、11
  • 難易度 / 耗時:⭐⭐⭐ / 約 40–90 分鐘
  • 核心結論:這是驅動層的結構性錯誤,不是硬體衰退——先把「換記憶體」那一步往後放。
  • 適用對象:藍屏停止碼顯示 NO_MORE_IRP_STACK_LOCATIONS,或 minidump 裡 bugcheck code 是 35(0x00000035)的人。

📌 快速答案

一句話答案:NO_MORE_IRP_STACK_LOCATIONS 0x35 是上層驅動透過 IoCallDriver 往下呼叫時,封包內已無剩餘 I/O 堆疊位置;依站長經驗先盤點最近安裝的分層過濾驅動,再用 WinDbg 讀那顆 IRP 驗證。


🧰 開始前的準備

  • 適用系統:Windows 10、Windows 11(Driver Verifier 位於 %WinDir%\system32\Verifier.exe;Microsoft 註明 Windows 10 S 未內含此工具)
  • 權限需求:系統管理員(官方明訂必須是 Administrators 群組成員才能使用 Driver Verifier)
  • 需要工具:WinDbg、記憶體傾印檔、命令提示字元(系統管理員);走到最後一節才會用到 WDK 內附的 DC2WMIParser
  • 預計耗時:約 40–90 分鐘(含至少一次重開機)
  • 事前必做:重要資料先備份、建立系統還原點、確認手上有可開機的救援 USB,並且先確認自己知道怎麼進安全模式——本文的「🔙 萬一翻車:回退步驟」一節有完整步驟,動手前請先讀一遍

🔍 症狀描述與錯誤訊息

先講結論:這顆藍屏的四個參數裡,只有第一個有意義,所以「盯著參數猜」在 0x35 上是死路,真正的線索在那顆 IRP 的內部結構裡。

典型畫面長這樣:

🙁 您的電腦發生問題,需要重新啟動。

停止碼:NO_MORE_IRP_STACK_LOCATIONS

Microsoft Learn 對這顆碼的參數表寫得非常乾脆:Parameter 1 是 IRP 的位址,Parameter 2、3、4 全部標為 Reserved(保留)。也就是說,官方沒有給你第二條、第三條可以交叉比對的線索,你只能從第一個參數指到的那顆封包往下挖。

觸發樣態上,以站長的經驗,0x35 有幾個很明顯的共同點(這一段是經驗歸納,官方文件並未描述觸發情境):

  • 通常不是隨機發生,而是跟某一類 I/O 動作綁在一起——存取某顆磁碟、掛載某個虛擬光碟、防毒開始掃描、備份軟體排程啟動的當下。
  • 幾乎都伴隨著「最近裝了什麼」:新的防毒或端點防護、磁碟加密、虛擬磁碟機、雲端同步硬碟、系統備份或還原軟體、老舊的檔案過濾工具。
  • 有些機器每次跳的停止碼還不一樣,今天 0x35、明天變成別的碼——這件事非常關鍵,下一節會解釋為什麼它是 0x35 的正常表現,而不是「兩個獨立故障」。

🔎 問題根因

先講結論:官方把 0x35 的成因寫成一句話——上層驅動透過 IoCallDriver 呼叫下層驅動,但封包裡已經沒有堆疊位置了。

Microsoft Learn 的 Cause 段原文說明:較高層的驅動嘗試透過 IoCallDriver 介面呼叫較低層的驅動,但封包中已無剩餘的堆疊位置,這會使下層驅動無法存取自己的參數。

廣告

真正該讓人背脊發涼的是官方接在後面的第二段:官方形容這是「災難性的情況」(a disastrous situation),因為上層驅動是當作自己已經填好下層參數在繼續執行的;既然下層根本沒有位置,那上層剛剛其實是寫到封包尾端之外去了,意思是另外有一塊記憶體也一起被破壞了

這段話有三個對排查方向影響極大的推論:

  1. 0x35 是「已經出事」的訊號,不是「剛要出事」的訊號。 系統偵測到的時候,越界寫入已經發生。
  2. 停止碼會漂移是正常的。 既然旁邊的記憶體已經被寫壞,下一次崩潰完全可能報成別的碼——被寫壞的是誰,就由誰去踩雷。所以在 0x35 的案子裡,「這台機器跳過三種不同藍屏」不代表有三個故障,更可能是同一個根因的三種表現。
  3. 這是驅動層的結構性錯誤,不是硬體衰退。 記憶體條老化不會讓 IRP 的堆疊位置變少;堆疊層數是 I/O 管理員在建立封包時就決定好的數字。這也是為什麼 0x35 的排查順序跟大多數藍屏相反——先查軟體、後查硬體

如果你習慣一看到藍屏就先跑記憶體測試,0x35 是少數幾顆值得你先把那步往後放的停止碼。順帶一提,同樣跟 IRP 有關但成因完全不同的是 DRIVER_POWER_STATE_FAILURE(0x9F)——官方對 0x9F 的定義是「驅動處於不一致或無效的電源狀態」(電源 IRP 未及時完成只是其中一種子類型),這顆 0x35 則是封包裡沒位置了,兩者不要混著查。


🔬 底層機制:IRP 的堆疊位置到底是誰配的?

要看懂 0x35,只需要弄懂一件事:一顆 IRP 裡有幾個「格子」,是誰、在什麼時候決定的。

一顆 IRP = 一疊格子,每層驅動各拿一格

依照 Microsoft Learn 的說明,I/O 管理員會為每一顆 IRP 建立一個 I/O 堆疊位置(I/O stack location)陣列,分層驅動鏈中的每一支驅動,對應到陣列中的一個元素;每支驅動擁有其中一格,並呼叫 IoGetCurrentIrpStackLocation 取得屬於自己的那份資訊。

每一格裡放的東西也很具體:主要功能代碼(IRP_MJ_XXX)、必要時的次要功能代碼(IRP_MN_XXX)、該次操作的參數(例如緩衝區長度與起始位置)、指向目標裝置物件的指標,以及指向檔案物件的指標。

廣告

往下傳之前,上層有義務先把下一格填好

官方對「把 IRP 往下傳」的流程規定得很清楚:驅動的 dispatch 常式若無法自己完成請求,要往下送時,必須先呼叫 IoSkipCurrentIrpStackLocationIoCopyCurrentIrpStackLocationToNext設定下一層驅動的 I/O 堆疊位置,接著(視需要)呼叫 IoSetCompletionRoutine,最後才呼叫 IoCallDriver

這裡要誠實標一句:官方這頁只說明「兩者都是用來設定下一層的堆疊位置」,並沒有逐字解釋兩者對剩餘格數的影響;兩者的差別在於一個是讓下層沿用同一格、一個是把內容複製到下一格,這部分屬於機制推導,不是官方原句。但方向是明確的——呼叫 IoCallDriver 之前沒有把下一格準備好,或是這疊格子根本不夠深,就會走到 0x35。

格子有幾個?由 StackSize 與「誰後來插隊」決定

這是整篇文章最關鍵的一段。官方說明兩件事:

  • 任何自行為下層配置 IRP 的上層驅動(例如呼叫 IoAllocateIrp),要依照下一層裝置物件的 StackSize 值,決定這顆新 IRP 該有幾個 I/O 堆疊位置。
  • 系統支援把新驅動加進既有的驅動鏈中;當新驅動掛上裝置堆疊時,I/O 管理員會調整它送給該鏈上各驅動的所有 IRP 的堆疊位置數

官方甚至舉了鏡像驅動(mirror driver)的例子:一支中介驅動被插進檔案系統驅動與最底層驅動之間,原本檔案系統配置的每顆 IRP 就會多帶一格給這支新驅動。

把兩件事合起來看,0x35 的成因就浮出來了:格子數是「當下這條裝置堆疊有幾層」的快照。當有驅動在錯誤的時機掛上去、掛的方式不對,或是自己配置 IRP 時抄了過期的 StackSize,就會出現「格子數比實際層數少」的狀態;此時最上層那支驅動照常呼叫 IoCallDriver,系統一看沒格子了,就是 0x35。這段合起來的推論同樣屬於機制推導——上面兩條敘述各自都有官方出處,但官方文件只描述正常運作,並未描述失效情境。

官方也提醒了設計上的限制:分層驅動鏈中的上層驅動,只能安全存取自己與下一層的堆疊位置,而且在設計時無法預測何時會有新驅動被插到自己底下。這句話等於直接點名了 0x35 的高風險族群——動態掛載、會插進別人裝置堆疊的過濾式驅動

廣告
NO_MORE_IRP_STACK_LOCATIONS 0x35 四項官方要點:Parameter 1 為 IRP 位址而參數 2 到 4 標示保留、觸發點在 IoCallDriver 已無剩餘堆疊位置、官方指出此時另有記憶體同時被破壞、堆疊位置數依下層裝置物件 StackSize 決定且新驅動掛入時由 I/O 管理員調整

哪些軟體會裝這種驅動?

以站長的經驗,下面這幾類軟體幾乎都會在磁碟或檔案系統的裝置堆疊上插一層(屬經驗歸納,不是官方清單):防毒與端點防護、磁碟或資料夾加密、虛擬光碟與虛擬磁碟機、雲端硬碟的隨選檔案功能、備份與磁碟映像工具、以及某些遊戲反作弊模組。它們掛得越多層,這疊格子就越深,出錯的機會也越大。


🧭 0x35 跟 0xC4、0xD1 差在哪?一張表分乾淨

先講結論:三顆碼都會把矛頭指向驅動,但「誰在告狀」完全不同,對應的下一步也不同。

比較項0x350xC40xD1
官方定義IoCallDriver 已無剩餘堆疊位置Driver Verifier 偵測到違規驅動在過高 IRQL 存取無效記憶體
誰觸發I/O 管理員(結構不足)你自己開的 Driver Verifier記憶體存取當下的核心
有用參數只有 Parameter 1(IRP 位址)Parameter 1 為違規子碼四個參數都有用
第一步盤點分層/過濾驅動查違規子碼讀第一與第四參數

三點重點摘要:

  1. 0xC4 是你請來的檢查員抓到現行犯,細節看 DRIVER_VERIFIER_DETECTED_VIOLATION(0xC4)專文;而 0x35 是系統自己在正常執行時撞上的結構性錯誤,兩者的「證據強度」不同。官方說明 0xC4 是以 Parameter 1 的違規子碼(subcode)指出違規原因、可偵測的違規逾 200 種,其中只有 DDI 合規檢查類違規才是 0x200nn 形式的規則編號。
  2. 0xD1 的四個參數是主要線索來源(見 DRIVER_IRQL_NOT_LESS_OR_EQUAL(0xD1)專文),0x35 則只有一個參數可用,所以必須進 WinDbg 讀 IRP 本體。
  3. 如果你在開了 Driver Verifier 之後才跳 0x35,處理順序是:先 verifier /reset 回到乾淨狀態,確認不開 Verifier 時是否還會跳,再判斷這是不是原本就存在的問題被提前引爆。

🛠️ 解決方案

⚠️ 執行前警語(⭐⭐⭐):本節方法三會啟用 Driver Verifier。官方明確警告:執行 Driver Verifier 可能導致電腦當機,只應在測試或除錯用的電腦上執行。動手前務必完成資料備份、建立系統還原點、確認可以進安全模式。

停止條件清單(符合任一,請不要繼續往下做):不確定自己的 Windows 版本或機型、尚未完成備份、啟用 BitLocker 但手邊沒有復原金鑰、公司或學校管控的設備且未取得 IT 授權、沒有可開機的救援 USB、指令輸出與本文描述不符。

方法一:盤點最近安裝的分層驅動(成功率最高、風險最低)

先講結論:以站長的經驗,不少 0x35 案例不必進偵錯器就能收斂,因為肇事者往往是「最近才加進來的那一層」(此為經驗歸納,官方並未提供任何解決率或肇事者統計)。

依序做這幾件事:

  1. 回想並列出最近一到兩週安裝或更新過的防毒、加密、虛擬光碟、雲端同步、備份、反作弊類軟體。
  2. 一次只停用或移除一項,每次之間讓機器正常使用一段時間(以站長的經驗,至少要跨過一次會觸發藍屏的情境,例如一輪完整的備份或掃描)。
  3. 移除時優先用該軟體自己的官方移除工具,而不是只把服務停掉——過濾驅動常常是靠自己的安裝程式登記到裝置堆疊上的,服務停了驅動仍然掛著。
  4. 若移除後不再跳,再把該軟體升到最新版重裝一次,並觀察是否復發;會復發就回報原廠,那是它的臭蟲,不是你的機器。

為什麼一次只動一項:0x35 的表現本來就會漂移(前面解釋過,旁邊的記憶體已被寫壞),同時動兩項會讓你完全無法判斷是哪一項有效。

方法二:用 WinDbg 讀出那顆 IRP 卡在第幾層(定位精準度最高)

先講結論:Parameter 1 給的就是 IRP 位址,把它丟給 !irp,你會直接看到這顆封包有幾層、目前在第幾層。

在 WinDbg 開啟傾印檔後,先跑基本分析:

!analyze -v

從輸出中取得 Arg1(IRP 位址),接著把位址交給 !irp。官方對這個命令的語法定義是 !irp Address [Detail],並說明:若加上任意值的 Detail 參數(例如 1),輸出會包含該 IRP 的狀態、MDL 位址、擁有它的執行緒,以及所有 I/O 堆疊的堆疊資訊,包含每一層的主要與次要功能代碼(十六進位)。省略 Detail 時只會給摘要。

!irp fffffa80`0a1b2c30 1

官方範例輸出的第一行長這樣(以下數值取自 Microsoft Learn 官方範例,非站長實測):

Irp is active with 2 stacks 1 is current (= 0xac598e38)

這一行就是 0x35 的關鍵證據:with N stacks 是這顆封包總共配了幾格,M is current 是目前落在第幾格。接著往下看,官方範例會逐格印出裝置與驅動名稱與完成常式——上面引用的首行取自該頁的 Windows 10 範例(2 stacks),印出的是 \FileSystem\Npfs\FileSystem\FltMgrfltmgr!FltpPassThroughCompletion;同一頁另有一個 Windows Vista 範例(8 stacks),印出的則是 \Driver\disk\Driver\PartMgr\Driver\volmgr\FileSystem\Ntfs

三個判讀重點:

  1. 逐格印出來的驅動名稱,就是這條裝置堆疊的實際成員清單。 裡面出現你不認得的第三方 .sys,那就是重點嫌疑犯。
  2. 看「current」落在最後一格,代表已經走到底了還要再往下呼叫——這正是 0x35 的情境(官方 !irp 文件並未定義這條判讀規則,屬除錯經驗推論)。
  3. 完成常式的模組名同樣有效,官方範例特別說明完成常式旁邊印的模組,是由下一行那支驅動設定的;它揭露的是「誰在這條路徑上插手」。

如果 !analyze -v 給的位址已經無法解析(封包被回收或記憶體已損壞),官方另有 !irpfind 可以在集區中搜尋 IRP,以及 !ioctldecode 解讀 IOCTL 代碼。要更完整地把傾印檔讀懂,可以搭配開機期間的檔案系統活動紀錄交叉比對,確認那支驅動是在哪個階段掛上去的。

方法三:用 Driver Verifier 的 IRP Logging 把兇手記錄下來(最後手段)

先講結論:當你已經知道嫌疑範圍、但需要證據時,IRP Logging 會把每支驅動的 IRP 使用情形記成 WMI 紀錄。

官方對這個選項的規格說明:

  • IRP Logging 在命令列上以 0x400(Bit 10) 表示,而且必須同時啟用 I/O Verification(0x10),所以實際要下的旗標值是 0x410
  • 設定完成後下次開機才生效
  • Windows Vista(含)以後可加 /volatile 不重開機就生效,但關機或重開後設定會消失。
  • 這個選項僅在 Windows Server 2003(含)以後的版本提供。

指令本身很短(一行一件事,不要串在一起):

verifier /flags 0x410 /driver MyDriver.sys

不想重開機時改用揮發性設定:

verifier /volatile /flags 0x410 /adddriver MyDriver.sys

紀錄的兩個硬限制,官方寫得很白:

  1. 每個裝置最多只保留 20 筆 IRP 紀錄,第 21 筆進來就會覆蓋第 1 筆;而且雖然留下的一定是最近的 20 筆,卻無法得知其中哪一筆最新
  2. 紀錄存在記憶體裡,重開機就消失,所以必須用 WDK 內附的 DC2WMIParser 把它存成檔案。

轉存工具的語法是 dc2wmiparser [/f File] [/t Time]:/f 指定輸出檔案路徑(省略時預設寫成目前目錄下的 dc2verifier.act),/t 指定持續執行的分鐘數;/t 為 0 表示把已累積的紀錄倒出來就結束,設正值則會持續執行並收新資料——官方也提到,用 /t 持續跑時,每個裝置可以收到超過 20 筆(每個取樣區間各 20 筆)。

選擇要驗證哪幾支驅動時,請整條裝置堆疊一起選。官方在說明「Select driver names from a list」時明講:選取裝置堆疊中的所有驅動,可讓 Enhanced I/O Verification 追蹤物件並檢查合規性,因為 IRP 會在堆疊中的每支驅動之間傳遞,偵測到錯誤時能提供更高的細節層級。對 0x35 這種「層數不對」的問題,這正是需要的視角。

也請留意官方對「自動選取全部驅動」的警告:那會耗盡 Special Pool 與部分資源追蹤可用的資源,並可能明顯影響系統效能。

方法四:確認是否為驅動安裝順序造成的暫時狀態

先講結論:如果 0x35 只在特定順序下出現(例如某軟體開機自動啟動時才跳),把該軟體改成手動啟動再測一次,可以快速驗證假設。

這個做法的價值不在修好,而在把「跟掛載時機有關」這件事證實或推翻——如果改成手動啟動、等系統完全開機後再啟動就不跳,那幾乎可以確定是掛進裝置堆疊的時機問題,回報原廠時這是極有價值的資訊。


✅ 驗證修復結果

改完之後,不要只看「今天沒跳」就收工。建議做完這四項:

  1. 把觸發情境重跑一遍:原本是備份時跳,就完整跑一次備份;原本是掛虛擬光碟時跳,就再掛一次。
  2. 確認 Driver Verifier 已經關掉(下一節有指令),避免把驗證模式當成日常狀態使用。
  3. 檢查事件檢視器是否還有同一支驅動的相關錯誤。
  4. 觀察停止碼是否換了一顆:因為 0x35 伴隨記憶體破壞,如果根因沒解決,常見的表現是換一顆碼繼續跳。有跳出新的碼,代表還沒解決,不是新問題。

🔙 萬一翻車:回退步驟

⭐⭐⭐ 本節針對三種情況,請對照自己的狀況照做。

情況一:開了 Driver Verifier 之後開不了機

  1. 連續中斷開機讓系統進入復原環境,選擇安全模式啟動。
  2. 進入系統後開啟系統管理員命令提示字元,執行重設:
verifier /reset
  1. 重新啟動電腦。官方對「停止或重設 Driver Verifier」的作法即為執行 verifier /reset 後重新啟動,或在 Driver Verifier Manager 中選擇「Delete existing settings」再按 Finish。

情況二:移除了某支驅動之後裝置不能用

  1. 先用系統還原點還原到操作前的狀態(這就是前面要求先建立還原點的原因)。
  2. 還原後從該裝置原廠官網重新下載對應版本的驅動安裝,不要只靠裝置管理員的自動搜尋。

情況三:想確認目前 Verifier 到底開了什麼

查詢目前設定與統計資料的官方指令各一行:

verifier /querysettings
verifier /query

還原原則(重要):上面三種情況的目標都是回到你動手之前的狀態,而不是套用某個固定值。你機器上原本有哪些驅動、原本的啟動類型是什麼,請以操作前的紀錄或還原點為準——不同版本、不同機型的原廠預設並不相同,照抄別人的設定值反而會把機器帶到另一個不一樣的狀態。


💡 總結:預防再次發生

站長我處理過的分層驅動問題,結論幾乎每次都一樣:這類藍屏是被「疊」出來的,不是被「用壞」的。同一台機器上同時裝兩套防毒、再加一套磁碟加密與一套虛擬光碟,裝置堆疊就會疊得又高又脆;真正的預防動作不是換硬體,而是控制層數。

給三個具體做法:

  1. 同一個功能只留一套:防毒留一套、加密留一套、虛擬光碟用完就移除。功能重疊的過濾驅動是 0x35 的溫床。
  2. 把安裝時間點記下來:每次裝這類軟體時記一筆日期。0x35 的排查極度依賴「最近多了什麼」,有紀錄可以省掉一半時間。
  3. 更新前先建立還原點:這類驅動的更新常常伴隨裝置堆疊的重新掛載,還原點是最便宜的保險。

最後提醒一次官方的定性:0x35 發生時已經有另一塊記憶體被破壞了。所以請不要用「重開機就好了」的心態放著它——它今天以 0x35 現身,明天可能換一顆碼,而且下一次不見得只是藍屏,也可能是靜默的資料損壞。


❓ 常見問題

Q:NO_MORE_IRP_STACK_LOCATIONS 0x35 是記憶體壞掉嗎?

依官方定義,這顆碼描述的是「IoCallDriver 呼叫時封包已無剩餘堆疊位置」,屬於驅動層的結構性問題,不是記憶體模組故障的判定。不過官方也說明,發生時另有記憶體被寫壞,所以你可能會在同一台機器上看到其他停止碼。先查分層驅動,記憶體測試可以晚一步做。

Q:0x35 的四個參數要怎麼讀?

官方參數表寫得很明確:Parameter 1 是 IRP 的位址,Parameter 2、3、4 皆為 Reserved。所以只要拿 Parameter 1 進 WinDbg 跑 !irp,不用嘗試解讀後三個。

Q:一定要開 Driver Verifier 嗎?

不一定。多數案例在方法一(盤點並移除最近安裝的分層驅動)就會停止復發。Driver Verifier 是取得證據用的工具,而且官方明確警告它可能導致當機、只應在測試用電腦上執行,請當成最後手段。

Q:IRP Logging 的紀錄怎麼看起來只有一點點?

那是官方設計:WMI 紀錄每個裝置最多保留 20 筆,超過就覆蓋最舊的,而且重開機即消失。要留完整紀錄請用 DC2WMIParser 的 /t 參數持續收集並寫檔。

Q:修完之後又復發怎麼辦?

先確認復發時的停止碼是否相同。若仍是 0x35,把 !irp 的逐層驅動清單與復發前後的軟體異動一起整理,回報給該支驅動的原廠;若換了別的碼,請把它當成同一個根因的延伸,而不是新的獨立故障——這正是官方所說「另有記憶體被破壞」的典型後果。


🔗 延伸閱讀


📎 參考資料來源

📖 第一級|廠商官方:

⚠️ 本文核心事實全部以第一級官方文件為準;文中所有參數值與指令輸出均取自 Microsoft Learn 官方範例,非站長實測數據;標明為經驗歸納者屬站長長期處理分層驅動問題的定性觀察,不含任何實測數字。

📅 本文查證戳記:2026-08-04 依 Microsoft Learn 現行官方文件撰寫。

若你在後續版本遇到步驟失效,歡迎在留言區回報,站長會更新文章。


廣告