應用程式異常終止的除錯(WinDBG)
這篇文章主要說明應用程式異常終止的錯誤除錯,
Windows的使用者相信對這些畫面都不陌生,
也就是所謂的應用程式異常終止,或是稱為 Application Crash
到底是什麼原因造成這樣的異常終止?
遇到這樣問題時可否初步的分析進一步釐清原因呢?
我們將用 WinDBG舉幾個實例說明基本的分析方法,協助進一步釐清問題的原因。
安裝 WinDBG
首先,先到微軟的網站安裝 WinDBG。
https://msdn.microsoft.com/en-us/windows/hardware/hh852365.aspx
啟動安裝時,我們只需選取 “Debugging Tools For Windows”安裝 WinDBG 工具即可。其它的並不需要。
WinDBG分析方法
方法一: Attach to Process
當process 執行時,可以透過這個方式即時監控。
或是當該 process 或是 Application 出現異常終止畫面的當下 (按下 Enter確認該異常終止前),
用這個方式 Attach process,將當下的記憶體狀態做分析
方法二: Attach to Process
方法二是事後分析產生的 Dump 檔案。前提是該異常終止的相關 Dump 檔案已經產生,
因此可以用 Open Crash Dump將該Dump檔案開啟分析。
一般來說都會建議使用這個方式。因為可以將Dump檔案保存,事後可以隨時分析。
如何產生 Dump 檔案?
產生 dump (Windows 當下記憶體的系統訊息)檔案有兩種模式。
User Dump
一種是產生 User Dump 也就是一般使用者執行的應用程式。這一類的錯誤通常就是應用程式異常終止。
要抓取應用程式的 Dump,筆者建議這個工具 ProcessDump。
這個工具可以指定一些條件產生Dump。例如,如果 CPU 連續5秒超過 50% ,每隔 3秒產生一個 Dump。
https://technet.microsoft.com/en-us/sysinternals/dd996900
Kernel Dump
另外一種是產生 Kernel Dump 也就是Windows 作業系統的系統運作,例如驅動程式、作業系統核心等。
這一類的錯誤通常是藍色畫面。也就是必須要重開機的系統當機。
比較簡單可以抓取 Kernel Dump的方式就是直接產生一個藍色畫面。可以利用這個工具 NotMyFault。
- NotMyFault: Use this executable and driver to crash your system in several different ways. Chapter 7 uses Notmyfault to demonstrate pool leak troubleshooting and Chapter 14 uses it for crash analysis examples. The download includes x86 (in the exe\release directory) and x64 versions (in the exe\relamd directory) as well as full source.
Crash 除錯分析基本步驟
整體除錯的步驟是從大處著眼,接著慢慢縮小範圍
- 整體系統環境 (peb)
- Attach Process 到出問題的 Process
- 出問題的 Threads (~)
- 列出該 Threads 的 Stacks 得知 module!function 執行的順序 (k)
- 進一步驗證該 module (lm) 或是特定記憶體內容 (dc)
基本環境資訊分析
當 File > Open Crash Dump之後,我們可以得知基本的環境資訊,
當該 Dump 檔案載入的時候,一開頭會顯示該Dump 檔案產生時的電腦系統環境資訊,如下圖所示。
列出電腦系統變數
例外可以使用 PEB 列出電腦系統相關變數內容
列出所有執行緒 ~
例如這個例子,該應用程式process(Process ID = 1240),共有兩個執行緒。Thread 0 (ThreadID = 12c0)與 Thread 1 (ThreadID = f30)
ProcessID. ThreadID
16進位轉換 ?
由於WinDBG 所顯示資訊內容皆為 16進位。所以可以用 ? 將該數值轉換為10進位。
例如 ?12c0 經過轉換 12c0的十進位為 4800
進一步查看該執行緒執行什麼?
我們使用 ~ 列出所有的執行緒之後,接著可以用 k 了解該執行緒的 Stack,可以看出該執行緒先後執行哪些 Function
當執行緒有很多的時候,也可以透過這個指令 ~* k 將所有執行緒的 Stacks 列出
越下面的function 是最早被執行,最上面的 function 是最後且最新被執行。
上面的 function 是被下面的 function 呼叫。
例如這個例子,我們可以知道,ntdll!RtlUserThreadStart > 呼叫 Kernel32!BaseThreatInit > 呼叫 ntdll!DbgUiRemoteBreakin >最後呼叫 ntdll!DbgBreakPoint
如果持續追蹤,我們會發現一個 malware+0x1178
表示有一個module name 為malware,function name 未知,所以顯示為 0x1178
追查特定 Module Name
我們可以透過 lm 的指令列出相關的 Module name 資訊。這個個案由於我們從 Stacks 中查出malware,所以進一步可以追查 malware相關資訊。
lm v m malware
malware.dll 相關資訊如下。因此我們可以根據這些資訊判斷該DLL 是否為潛在的病毒或是版本錯誤所造成的問題。
Stacks 的關聯性
Stacks 主要紀錄 function 如何被呼叫的過程,最上面的為最後被執行,最下面是一開始執行。
例如這個例子,記憶體位址 69508b5c 為 faultrep!ReportFault 這個函數。
因此我們可以透過這個方式反查最原始 function 呼叫位址
這個例子中,00d7f555 開始我們無法對應到已知的 module ! function name
所以到底 78040065 與d7f5c8所對應的是什麼 module or function 呢?
我們可以用 dc 這個指令查看
記憶體內容為何?
dc 78040065
可以看得出來都是 ????
另外當我們進一步查看 d7f5c8
dc d7f5c8
發現一些有趣的線索,該記憶體內容有 urlmon 的指令,
同時另外有一個奇怪的 Http://10.2.113.60:8198/….
這是一個可疑有可能是病毒造成的內部的電腦http 連線。
小結
先查看相關環境資訊,利用 !peb
接著,這個個案中我們主要透過 ~ 的指令,先列出所有的threads與導致異常的那個 thread
之後,利用 k的指令,列出 stacks來得知相關 module!function 的執行順序關係
另外,可以使用 ~*k 列出所有 threads 的 stack
針對 stack 所得知的 module 與function 資訊
可以使用 lm 查詢 module 資訊,或是 dc 將記憶體的內容印出
整體除錯的步驟是從大處著眼,接著慢慢縮小範圍
- 整體系統環境 (peb)
- Attach Process 到出問題的 Process
- 出問題的 Threads (~)
- 列出該 Threads 的 Stacks 得知 module!function 執行的順序 (k)
- 進一步驗證該 module (lm) 或是特定記憶體內容 (dc)
http://windbg.info/download/doc/pdf/WinDbg_cmds.pdf
http://windbg.info/doc/1-common-cmds.html
(畫面特定個案範例,部分取自 Microsoft TechEd)