快訊
2026-10-15
電腦疑難雜症

WinDbg lmvm 教學:一行指令看懂當機驅動模組與版本資訊

約 16 分鐘閱讀 · 13 次瀏覽
廣告

⚡ 站長快讀:核心重點

  • 文章屬性:教學實戰
  • 適用系統:Windows 11(所有版本)/ Windows 10 1607 以上,x64 與 ARM64
  • 難易度 / 耗時:⭐⭐(看得懂英文欄位即可)/ 約 15 分鐘
  • 核心結論:lmvm 不是一個獨立指令,而是 lm 指令加上 v(詳細)與 m(模組名比對)兩個修飾符;它負責回答「這個模組到底是誰、哪個版本、哪一天編出來的」,是 !analyze -v 指出兇手之後的下一棒身分核對。
  • 適用對象:已經會開 minidump、跑得出 !analyze -v,但看到 MODULE_NAME 之後不知道下一步該做什麼的人

📌 快速答案

一句話答案:WinDbg lmvm 的用法是在指令列輸入 lmvm 模組名(不加副檔名),即可列出該模組的映像路徑、時間戳記、檢查碼與映像大小四類欄位,逐欄判讀方式見下方步驟三。


🧰 開始前的準備

  • 系統需求:Windows 11 全版本,或 Windows 10 1607(Anniversary Update)以上;處理器架構限 x64 與 ARM64(官方安裝頁明載)
  • 權限需求:一般使用者即可開啟傾印檔;站長經驗上,C:\Windows\Minidump 底下的檔案多半得用系統管理員身分開啟,或先複製到其他目錄再讀(此為實務經驗,非官方需求)
  • 需要工具:WinDbg(微軟官方,可從 Microsoft Store、官方安裝檔,或以 winget install Microsoft.WinDbg 安裝)
  • 需要素材:一份 .dmp 檔(minidump 或完整傾印皆可),以及設好的符號路徑
  • 預計耗時:約 15 分鐘
  • 難度門檻:只要會在 WinDbg 指令列打字就能做;不需要看得懂組合語言

💡 符號路徑還沒設好的話,先去把 WinDbg 的符號伺服器設定好,否則本文後半段的欄位有一半會是空的或問號。


🔍 為什麼你需要這個?

因為 !analyze -v 只會給你一個名字,不會告訴你這個名字是誰。

跑完 !analyze -v,報告最後通常會出現 MODULE_NAME: NETw4v32 或 IMAGE_NAME: nvlddmkm.sys 這類結果。多數教學到這裡就結束了,留下讀者對著一個八個字母的縮寫發呆:這是哪家公司的東西?我電腦裡怎麼會有它?它是二十年前的老驅動,還是上週剛更新的?更新驅動到底該去哪一家的網站下載?

這些問題,lmvm 一行就能回答一大半。它會把模組的映像路徑(檔案實際放在哪)、時間戳記(這個二進位檔什麼時候編出來的)、映像大小與版本資訊一次列出來。時間戳記尤其關鍵——微軟自家顧問在官方部落格示範這個流程時,判斷的依據就是一句「Timestamp 是 2007 年 8 月,這驅動相當老了」,接著才決定去下載新版驅動。

站長要補充的是,這一步在實務上還有三個常被忽略的價值:

  1. 確認你要更新的是哪一家的驅動。NETw4v32 這種代號看不出廠商;當映像路徑落在廠商自己的目錄下、或版本資訊區塊有讀出來時,才看得出它屬於誰。兩者都沒有的話,官方部落格的建議是去看該檔案的內容屬性;站長補充一句:可以直接照 Image path 定位到那個檔案,不必自己找。名字對不上廠商時,你去官網下載的往往是錯的東西。
  2. 確認你「已經更新過」是不是真的生效。很多人更新完驅動再當一次,重新分析仍看到同一個模組名就崩潰了——其實只要比對時間戳記,就知道系統載入的到底是新版還是舊版還留在那裡。
  3. 確認這個模組值不值得懷疑。如果 lmvm 顯示它是微軟自家、與系統同一批建置日期的核心元件(例如 ntoskrnl),那它多半只是代罪羔羊,真兇在堆疊更下面——微軟官方對責任歸屬的說明是:偵錯器會從堆疊最上層的錯誤框架開始查該模組的負責人,查不到或被標記略過時才往下一個框架找,所以掛名的未必就是肇事者。

這篇跟站內其他 WinDbg 文章的分工

本站已有逐欄解讀 !analyze -v 報告與用 !poolused、!handle、!vm 追資源洩漏兩篇。三者的位置是這樣的:!analyze -v 回答「大概是誰」、lmvm 回答「這個誰的身分證」、洩漏診斷那套回答「資源被誰吃掉」。本文只專心把第二棒講到底。


🛠️ 實戰步驟

步驟一:先從當機報告拿到模組名

這一步的目的,是拿到一個「模組名」而不是「檔名」。

廣告

開啟傾印檔後執行 !analyze -v,在報告中找這三個欄位:

IMAGE_NAME:  NETw4v32.sys
MODULE_NAME: NETw4v32
FAULTING_MODULE: b100c000 NETw4v32

注意 IMAGE_NAME 帶副檔名、MODULE_NAME 不帶。下一步要用的是 MODULE_NAME 那個不帶副檔名的版本,這是後面最多人踩到的坑,稍後在步驟二會說明原因。

如果報告裡出現這兩行警告,先不要慌:

*** WARNING: Unable to verify timestamp for NETw4v32.sys
*** ERROR: Module load completed but symbols could not be loaded for NETw4v32.sys

這代表偵錯器找不到這個模組的符號檔——第三方驅動本來就不會把符號放上微軟的公開符號伺服器,這是常態,不是你設錯。它會影響你能看到的欄位多寡,但不影響 lmvm 列出路徑與時間戳記。

步驟二:拆開 lmvm 這四個字母

lmvm 不是一個指令,是 lm 加上兩個選項的縮寫連寫。 微軟的偵錯器指令參考裡沒有 lmvm 這個獨立條目,只有 lm(官方文章行文時仍會直接說「lmvm 指令」),語法是:

lm Options [a Address] [m Pattern | M Pattern]

拆解如下:

廣告
字母身分作用
lm指令List Loaded Modules,列出已載入的模組
v選項verbose,詳細模式
m參數後面接模組名比對樣式

所以 lmvm netw4v32 完全等價於 lm v m netw4v32,你要打空格版本也可以,輸出一模一樣。理解這件事的價值在於:一旦知道它是組合出來的,你就能自由換零件,這是本文後半「進階玩法」的基礎。

現在執行它:

lmvm netw4v32

⚠️ 最常見的錯誤:多打了 .sys。 官方文件對 m Pattern 的說明是「模組名通常是不含副檔名的檔名」,並直接舉例:要看 Flpydisk.sys 這個驅動,要打 lm mflpydisk,不是 lm mflpydisk.sys。官方文件只寫了命名規則,沒有描述比對不到時的畫面;實務上你會看不到預期的模組資訊,很容易誤以為這個模組根本沒載入。官方另有一句提醒:少數情況下,模組名與檔名差異很大。站長的做法是這時改用大寫 M——官方對它的定義是「比對映像路徑」,拿完整路徑去撈會比猜模組名穩。

WinDbg lmvm 輸出的四個關鍵欄位與判讀重點資訊圖

步驟三:逐欄讀懂輸出

看到的欄位數量,取決於這個模組的標頭與符號狀態。 以微軟官方部落格那份真實案例為例,一個沒有符號的第三方網卡驅動,lmvm 的輸出長這樣:

Loaded symbol image file: NETw4v32.sys
Image path: \SystemRoot\system32\DRIVERS\NETw4v32.sys
Image name: NETw4v32.sys
Timestamp:        Wed Aug 08 16:26:03 2007 (46B9E08B)
CheckSum:         00221C6E
ImageSize:        00229000
Translations:     0000.04b0 0000.04e0 0409.04b0 0409.04e0

逐欄拆解:

欄位意義判讀重點
Image path映像檔完整路徑判斷是系統驅動、廠商驅動或第三方外掛
Timestamp二進位檔的時間戳記括號內是十六進位原值,與版本新舊直接相關
CheckSum標頭中的檢查碼為 0 或取不到時,符號狀態會標 C
ImageSize映像在記憶體中的大小與 lm 的 start/end 區間互相對照
Translations版本資源的語言與字碼頁組合(站長補充)決定版本資源要用哪一組語言讀出來

Image path 是這一整段最有價值的欄位。 \SystemRoot\system32\DRIVERS\ 之下是隨系統或驅動安裝程式放進去的標準位置;路徑落在別處(例如 Program Files 底下的廠商目錄),代表它不是隨系統附帶的驅動,得自行辨識廠商。站長的經驗法則是:這類非標準路徑的模組多半來自防毒、虛擬光碟、遊戲反作弊或 VPN 這種會掛核心過濾器的軟體,排查時值得多看兩眼——這是經驗判斷,不是官方判準。

廣告

Timestamp 要看括號外的人類可讀時間。 上面那個例子是 2007 年 8 月,對 Windows Vista 時代的機器來說已經是「該換了」的訊號。括號內的 46B9E08B 是同一個值的十六進位形式,同一份案例的 !analyze -v 報告中,DEBUG_FLR_IMAGE_TIMESTAMP 印出的也是這個值——兩者取自同一份傾印檔的同一個模組,本來就會相同,所以它不是拿來判斷傾印檔新舊的依據。要確認「機器上現在那顆驅動是不是還是這一版」,得照 Image path 走到實體檔案,直接看它的檔案屬性。

沒看到 File version 與公司名稱不是你的錯。 官方文件對 v 選項的說明是,詳細模式會顯示符號檔名、映像檔名、檢查碼資訊、版本資訊、日期與時間戳記,以及該模組是否為 Managed Code(CLR);但緊接著補了一句關鍵限制:若相關標頭遺失或已被分頁置換出去,這些資訊就不會顯示。所以在 minidump 這種只保留暫存器與堆疊的小型傾印檔裡,版本資訊區塊經常直接消失。這是傾印檔本身的資訊量限制,不是指令打錯,也不是驅動有問題。

步驟四:驗證與交叉比對

驗證的方式是換一個角度再問一次系統。 有三個互補的做法:

1. 用 lm 看它在整份模組清單裡的位置與符號狀態

lm m netw*

輸出會是 start、end、module name 與符號狀態四欄。這裡有個官方文件寫得很清楚、卻很容易被誤讀的細節:end 是模組結束之後的第一個位址,不是模組的最後一個位元組。官方舉例:start 是 faab4000、end 是 faab8000 時,模組實際涵蓋的範圍是 0xFAAB4000 到 0xFAAB7FFF。差這一個位址,在你手動判斷某個堆疊位址落在哪個模組時就會判錯邊界。

2. 用位址反查模組

當堆疊裡出現一個裸位址、!analyze -v 也沒指出模組時,不需要人工比對區間,直接讓偵錯器算:

lm a b100c000

a Address 的作用是「只顯示包含這個位址的模組」。官方另有提醒:位址若寫成運算式,必須加上括號。

3. 用 !lmi 讀標頭層級的資訊

!lmi netw4v32

!lmi 與 lmvm 的差別在於資訊來源:!lmi 直接解析模組標頭並整理成摘要,會多給 Machine Type、Characteristics 與 Load Report 這幾個 lmvm 沒有的欄位;符號狀態則是兩邊都有,只是 !lmi 用具名的 Symbol Type 欄位呈現,lm 系列則把它放在模組名後方那個沒有標題的欄位。官方範例的輸出是這樣:

Loaded Module Info: [00400000]
         Module: Prymes
   Base Address: 00400000
     Image Name: Prymes.exe
   Machine Type: 332 (I386)
     Time Stamp: 3c76c346 Fri Feb 22 14:16:38 2002
           Size: 2d000
       CheckSum: 0
Characteristics: 230e stripped
Debug Data Dirs: Type Size     VA  Pointer
                 MISC  110,     0,   77a00 [Data not mapped]
    Symbol Type: EXPORT   - PDB not found
    Load Report: export symbols

注意 !lmi 的 Base Address 加 Size 的語意與 lm 的 start/end 不同:官方說明是 Base Address 為 faab4000、Size 為 2000 時,模組範圍是 0xFAAB4000 到 0xFAAB5FFF。另外,若模組標頭已被分頁置換出去,!lmi 會直接回錯誤訊息——這時要看更完整的標頭內容,官方指定的工具是 !dh。


🔬 底層機制:這個問題到底在系統哪一層?

lmvm 的主要資料來源不是你硬碟上那顆檔案,而是偵錯器對「載入模組清單」的一份快照。(官方文件另有提到,偵錯器在小型傾印檔偵錯等情況會去映射映像檔,映射到的檔名會顯示在 mapped memory image file 欄位;即使如此,它反映的仍不必然是你這台機器現在那顆檔案。)

Windows 核心維護著一份已載入模組清單(在核心偵錯的初始輸出中,你會看到 PsLoadedModuleList 這個位址被印出來)。當機當下,傾印檔會把這份清單連同必要的記憶體頁一起寫出去。lm 系列指令做的事,就是走訪這份清單、把每個模組的載入基底位址、大小,以及偵錯器對它的符號處理狀態呈現出來。

這個層級解釋了三件在實務上很容易誤判的事。

第一,為什麼有些模組的資訊特別少。 官方文件用了一個精準的措辭:資訊「若相關標頭遺失或已被分頁置換出去,就不會顯示」。也就是說,你看到的欄位多寡,反映的是當機那一瞬間有多少東西還留在實體記憶體裡,而不是這個驅動本身的品質。小型傾印檔天生就會少很多。

第二,符號狀態不是二選一,而是一整組縮寫。 模組名後面那一欄沒有標題,但它承載了偵錯器對符號的全部判斷。官方的對照表如下(節錄常見者):

縮寫意義
deferred模組已載入,但偵錯器還沒去載符號,要用到才載
Export找不到符號檔,資訊是從二進位檔的匯出表萃取的
#符號檔與執行檔的時間戳記或檢查碼不符
T / C時間戳記 / 檢查碼遺失、無法存取或為零
M兩者不符,但依符號選項設定仍強制載入了

看到 deferred 就以為「符號沒載到」是很常見的誤會——它只是還沒去載而已,官方稱之為延遲符號載入。真正該警覺的是 # 與 M:符號與二進位檔對不起來時,堆疊上的函式名稱可能是錯的,官方在符號驗證那篇甚至展示過一個案例:錯誤的符號讓堆疊看起來像是 win32k.sys 在畫矩形時出錯,載入正確符號後,真兇其實是另一個 AGP 相關驅動。

第三,Windows 會另外保留一份「已卸載模組清單」。 官方文件明載,對使用者模式行程或傾印檔執行 lm 時,輸出也會列出已卸載的模組(Unloaded modules: 區段)。這在追查「某個驅動已經卸載,但它留下的東西仍被碰到」這類問題時,多提供了一份可查的名單;要注意官方文件是在使用者模式行程與傾印檔的情境下描述這份清單,實際看得到什麼仍以你手上的傾印檔類型為準。

一個容易被跳過的前置動作

若你發現整份清單的符號狀態一片混亂,先別急著懷疑驅動,而是先確認符號本身是對的。官方建議的順序是:用 lml 只列出已載入符號資訊的模組,用 .sympath 確認符號路徑,必要時 .reload 重載;還是不對就開啟 !sym noisy 進入詳細模式,直接觀察偵錯器到底去哪些路徑找檔案、以及為什麼不接受它找到的那一份。你會看到類似 mismatched timestamp 這種明確的拒絕理由,比盲猜有效得多。


💡 總結:進階玩法與底層邏輯

站長我要說的是,lmvm 的真正價值不在它自己,而在「知道它是組合出來的」之後,你能拿 lm 的零件做什麼。官方文件列出的選項相當多,以下四種組合是站長認為最值回票價的:

一、lm e:只列出有符號問題的模組。 官方定義是列出完全沒有符號的模組,以及符號狀態為 C、T、#、M 或 Export 的模組。當你懷疑「是不是我符號沒設好才看不到函式名」時,這一行就能把問題模組全部抓出來,不必自己掃兩百行清單。

二、lm 1m 配 .foreach:把模組名餵給另一個指令。 1m 的作用是把輸出精簡到只剩模組名,官方明講它的用途就是搭配 .foreach 語彙基元把輸出接到別的指令輸入。這是把手動比對變成批次處理的入口。

三、lm sm:改用模組名排序。 預設是依起始位址排序,人腦不好找;sm 之後按字母排,肉眼掃描的效率完全不同。官方文件裡剛好給了同一份清單的兩種排序對照,值得自己跑一次感受差異。

四、lmv 與 !lmi 一起看。 前者給你路徑與版本層的答案,後者給你標頭與符號層的答案(Machine Type、Characteristics、Load Report)。官方對 !lmi 的定位是「解析模組標頭並顯示格式化摘要」,與 lm 的清單視角互補;兩邊都看過,你對這個模組的認識才算完整。

至於可驗證的具體數字,官方部落格那份案例可以自己核對:驅動時間戳記十六進位值為 46B9E08B,偵錯器在該案例主機上顯示為 2007 年 8 月 8 日 16:26:03(顯示時間依偵錯器所在時區而定,以 UTC 換算為同日 15:26:03,兩者相差的一小時是時區差、不是資料不一致)。這個「同一個值、兩種呈現」的細節值得記住:讀者自行用線上工具換算時,經常會因為時區而以為對不上。

⚠️ 最後提醒一件誠實的事:lmvm 告訴你的是身分,不是罪證。時間戳記老舊只代表版本舊,不等於它就是元兇;微軟自家的 ntoskrnl 出現在報告裡更是家常便飯。要從嫌疑走到定罪,還需要堆疊、IRP 或資源使用層面的證據,那是另外幾支指令的工作。


❓ 常見問題

Q:lmvm 跟 lm 到底差在哪?我兩個都打過,輸出完全不一樣

差在 v 與 m 兩個修飾符。lm 單獨執行是列出所有模組的四欄摘要(起始位址、結束位址、模組名、符號狀態);lmvm 模組名 則是只挑一個模組、並用詳細模式列出它的路徑、時間戳記、大小與版本資訊。前者是清單,後者是單一模組的檔案卡。

Q:我打了 lmvm nvlddmkm.sys,結果什麼都沒出現

把 .sys 拿掉,改打 lmvm nvlddmkm。官方文件明確指出模組名通常是不含副檔名的檔名,並以 lm mflpydisk 而非 lm mflpydisk.sys 為例。官方文件只載明命名規則、未描述比對不到時的輸出;讀者實際遇到的情況是看不到預期的模組資訊,很容易被誤讀成「這個模組沒載入」。若模組名與檔名差異很大,改用大寫 M(比對完整映像路徑)。

Q:怎麼看驅動的公司與版本?我的輸出只有五行

先確認你的傾印檔類型。官方對 v 選項的說明是版本資訊屬於詳細模式的一部分,但若相關標頭遺失或被分頁置換出去就不會顯示——小型傾印檔缺這些欄位是常態。可行的替代路線有三條:改用完整記憶體傾印重新抓一次、改用 !lmi 讀標頭層資訊、或直接到 Image path 指出的檔案位置,用檔案總管看該檔案的「屬性 → 詳細資料」。最後這條在你手上就有那台機器時最快。

Q:輸出裡的 deferred 是不是代表出問題了?

不是。官方對照表的定義是「模組已載入,但偵錯器尚未嘗試載入其符號,需要時才會載入」,屬於延遲符號載入的正常狀態。真正需要處理的是 #(符號與執行檔不符)、T/C(時間戳記或檢查碼取不到)與 Export(只能從匯出表推),這些會直接影響堆疊上函式名稱的可信度。

Q:這個方法在舊版 WinDbg 也適用嗎?

適用。lm 是 Debugging Tools for Windows 長期存在的核心指令,使用者模式與核心模式、即時偵錯與傾印檔皆可用(官方環境表列明 Modes 為 User mode 與 Kernel mode、Targets 為 Live 與 crash dump、Platforms 為 All)。現行版 WinDbg 官方也註明與 WinDbg(classic)使用同一套底層引擎,支援相同的指令、擴充功能與工作流程;要偵錯更舊版本的 Windows,官方才建議改用隨 Debugging Tools for Windows 提供的 WinDbg(classic)。

Q:一定要有符號才能用 lmvm 嗎?

不用。路徑、時間戳記、檢查碼與映像大小這幾欄來自模組標頭,與符號無關;上面那份第三方網卡驅動的範例正是在「符號無法載入」的狀態下產生的。符號影響的是堆疊上的函式名稱與 Symbol Type 那一欄,不影響身分核對這件事本身。


📎 參考資料來源

📖 第一級|廠商官方:

⚠️ 本文核心事實以第一級為準。文中 lmvm 與 !lmi 的輸出範例逐字取自上列微軟官方文件與官方部落格封存文章,非站長實測環境產出。

🔗 延伸閱讀

📅 本文查證戳記:2026-09-08 依微軟官方 Windows 偵錯器文件撰寫。

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


廣告