Windows藍屏dump文件分析入門

之前的一篇筆記<Windows Dump文件分析>介紹了應用dump的生成方式和調試手法,有稍微提一句藍屏dump。但是實際在分析藍屏的dump文件的時候和普通應用的dump文件分析還是有一些差異的。這篇筆記就記錄下藍屏dump的一些相關知識。

藍屏dump文件的配置

首先我們可以在"右鍵選中我的電腦->屬性->高級系統設置->高級->啟動和故障恢復設置->系統失敗"里面設置藍屏時候生成dump文件的一些邏輯:

  • 將事件寫入系統日志 : 顧名思義
  • 自動重新啟動 : 藍屏dump保存完成之后釋放需要自動重啟,有時候可能需要保持藍屏的狀態usb線連接外部筆記本電腦,在外部筆記本使用WinDbg的Attach to kernal功能調試系統可以去掉這個勾選
  • 寫入調試信息 : 用于選擇生成藍屏dump的內容,例如截圖選擇的“完成內存轉儲”我們也叫full dump,即將整個物理內存dump下來保存成dump文件(可以參考官方文檔的詳細介紹)
  • 轉存文件 : 生成dump文件的路徑,例如截圖的“%SystemRoot%\MEMORY.DMP”指的就是“C:\Windows\MEMORY.DMP”
  • 覆蓋任何現有文件 : 如果有新的dump生成會覆蓋現有的dump文件
  • 禁止在磁盤空間不足時自動刪除內存轉儲 : 當磁盤空間不足的時候默認會刪除dump文件,可以勾選禁止自動刪除防止dump文件丟失
dump.png

藍屏一般是驅動之類的底層代碼出現異常導致的,在學習調試的時候可以使用NotMyFault去主動觸發藍屏獲取dump文件。

內核模式

拿到之后可以同樣用WinDbg打開它,打開full dump可以看到命令行提示為kd,意味著進入的是kernel debug內核模式:

kd.png

在這個模式下有些命令是不能使用的例如我們在調試應用crash的時候常用的~就只能在用戶模式下使用:

thread.png

如果在kd下輸入就會報錯:

5: kd> ~
       ^ Syntax error in '~'

不過依然可以直接!analyze -v分析:

DRIVER_IRQL_NOT_LESS_OR_EQUAL (d1)
...

myfault+0x1560:
fffff804`a0a41560 8b03            mov     eax,dword ptr [rbx] ds:00000000`00000000=????????
Resetting default scope

STACK_TEXT:  
ffff860c`933aec48 fffff802`3bc11aa9     : 00000000`0000000a ffff8904`92e54560 00000000`00000002 00000000`00000000 : nt!KeBugCheckEx
ffff860c`933aec50 fffff802`3bc0d563     : 00000000`00000000 00000000`00000000 00000000`00000f4d 00000000`00000000 : nt!KiBugCheckDispatch+0x69
ffff860c`933aed90 fffff804`a0a41560     : ffff9b0e`6e6470c0 fffff802`3ba4085f ffff9b0e`6e6470c0 ffff9b0e`61c0ee78 : nt!KiPageFault+0x463
ffff860c`933aef20 fffff804`a0a4191e     : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : myfault+0x1560
ffff860c`933aef50 fffff804`a0a41a81     : 00000000`00000002 00000000`00000000 ffff9b0e`00000001 fffff802`3be462c1 : myfault+0x191e
ffff860c`933af090 fffff802`3ba35cf5     : 00000000`00000002 00000000`00000000 ffff860c`933af480 00000000`00000000 : myfault+0x1a81
ffff860c`933af0f0 fffff802`3be452ac     : 00000000`00000001 00000000`83360018 ffff9b0e`728045d0 fffff802`00000000 : nt!IofCallDriver+0x55
ffff860c`933af130 fffff802`3be44f03     : ffff9b0e`00000000 ffff860c`933af480 00000000`00010000 00000000`83360018 : nt!IopSynchronousServiceTail+0x34c
ffff860c`933af1d0 fffff802`3be441d6     : ffff9b0e`70743ab0 00000000`00000000 00000000`00000000 00000000`00000000 : nt!IopXxxControlFile+0xd13
ffff860c`933af320 fffff802`3bc11235     : ffff9b0e`6e6470c0 ffff860c`933af480 000000a3`a65eead8 ffff860c`933af3a8 : nt!NtDeviceIoControlFile+0x56
ffff860c`933af390 00007ffd`3b06d0c4     : 00007ffd`386e591b 00000000`00010000 00007ff7`83a24e88 000000a3`a65ef77c : nt!KiSystemServiceCopyEnd+0x25
000000a3`a65ef618 00007ffd`386e591b     : 00000000`00010000 00007ff7`83a24e88 000000a3`a65ef77c 000000a3`a65ef6a0 : ntdll!NtDeviceIoControlFile+0x14
000000a3`a65ef620 00007ffd`3a6d5921     : 00000000`83360018 00007ff7`83a96500 00000000`00000001 00007ff7`839dae99 : KERNELBASE!DeviceIoControl+0x6b
000000a3`a65ef690 00007ff7`839db437     : 0000028a`91751d30 0000028a`91751d85 000000a3`a65ef830 00000000`00000003 : KERNEL32!DeviceIoControlImplementation+0x81
000000a3`a65ef6e0 00007ff7`839dd162     : 0000028a`91751d30 000000a3`a65ef830 00000000`00000001 0000028a`91730000 : notmyfaultc64+0xb437
000000a3`a65ef730 00007ff7`839dd8e8     : 00000000`00000000 00007ff7`839dda71 0000028a`91751d30 00000000`00000000 : notmyfaultc64+0xd162
000000a3`a65ef900 00007ffd`3a6d7344     : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : notmyfaultc64+0xd8e8
000000a3`a65ef940 00007ffd`3b0226b1     : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : KERNEL32!BaseThreadInitThunk+0x14
000000a3`a65ef970 00000000`00000000     : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : ntdll!RtlUserThreadStart+0x21

可以看到藍屏的代碼是DRIVER_IRQL_NOT_LESS_OR_EQUAL,然后從后面的匯編可以看出來是讀取0地址的內存到eax寄存器:

fffff804a0a41560 8b03 mov eax,dword ptr [rbx] ds:0000000000000000=????????

然后就是調用堆棧,可以看到的確是從notmyfault觸發的。

分析其他進程

有時候驅動的異常是應用層調用接口的流程異常導致的,默認情況下內存上下文是觸發藍屏的進程,我們也可以轉存full dump之后選擇其他的進程進行分析。

在內核模式下我們可以用!process 0 0這個命令列出所有的進程,如果你知道程序的exe名字也可以用在后面加上直接列舉,例如!process 0 0 Demo.exe:

4: kd> !process 0 0 Demo.exe
PROCESS ffff9b0e6ef94080
    SessionId: 1  Cid: 0b48    Peb: 74b5500000  ParentCid: 247c
    DirBase: 23b8b1000  ObjectTable: ffff890492285600  HandleCount:  45.
    Image: Demo.exe

這個命令里面的第二個0是Flags用于指定需要展示進程的什么信息,0的話就是摘要。如果是!process 0 0xf Demo.exe就會列舉出所有的Demo.exe的所有信息,例如全部的線程堆棧等,但是由于默認不會加載其他進程的pdb所以很多的符號看不到。

但可以從上面的信息看到進程的id是ffffe78e91d032c0,所以我們可以用.process /p /r ffff9b0e6ef94080指定用于進程上下文的進程并加載pdb。

然后用lm命令就可以看到Demo.exe已經加載了,然后括號里的deferred代表后面有需要的時候就會去加載這個模塊的pdb:

4: kd> lm
start             end                 module name
00007ff7`000b0000 00007ff7`000c0000   Demo       (deferred)   
...

之后再用!process 0 0xf Demo.exe就能看到具體的線程堆棧了:

4: kd> !process 0 0xf Demo.exe
PROCESS ffff9b0e6ef94080
    SessionId: 1  Cid: 0b48    Peb: 74b5500000  ParentCid: 247c
    DirBase: 23b8b1000  ObjectTable: ffff890492285600  HandleCount:  45.
    Image: Demo.exe
    VadRoot ffff9b0e720c7870 Vads 31 Clone 0 Private 143. Modified 0. Locked 0.
    DeviceMap ffff89047ff7a660
    Token                             ffff890492286060
    ElapsedTime                       00:00:19.086
    UserTime                          00:00:00.000
    KernelTime                        00:00:00.000
    QuotaPoolUsage[PagedPool]         25456
    QuotaPoolUsage[NonPagedPool]      4480
    Working Set Sizes (now,min,max)  (953, 50, 345) (3812KB, 200KB, 1380KB)
    PeakWorkingSetSize                916
    VirtualSize                       4145 Mb
    PeakVirtualSize                   4145 Mb
    PageFaultCount                    986
    MemoryPriority                    BACKGROUND
    BasePriority                      8
    CommitCharge                      164
    Job                               ffff9b0e6fb0e060

        THREAD ffff9b0e70a9f2c0  Cid 0b48.2bac  Teb: 00000074b5501000 Win32Thread: 0000000000000000 WAIT: (DelayExecution) UserMode Non-Alertable
            ffffffffffffffff  NotificationEvent
        Not impersonating
        DeviceMap                 ffff89047ff7a660
        Owning Process            ffff9b0e6ef94080       Image:         Demo.exe
        Attached Process          N/A            Image:         N/A
        Wait Start TickCount      194267         Ticks: 56 (0:00:00:00.875)
        Context Switch Count      107            IdealProcessor: 2             
        UserTime                  00:00:00.000
        KernelTime                00:00:00.000
        Win32 Start Address Demo!ILT+340(mainCRTStartup) (0x00007ff7000b1159)
        Stack Init ffff860c91fb7590 Current ffff860c91fb7070
        Base ffff860c91fb8000 Limit ffff860c91fb1000 Call 0000000000000000
        Priority 8 BasePriority 8 PriorityDecrement 0 IoPriority 2 PagePriority 5
        Child-SP          RetAddr               Call Site
        ffff860c`91fb70b0 fffff802`3ba41330     nt!KiSwapContext+0x76
        ffff860c`91fb71f0 fffff802`3ba4085f     nt!KiSwapThread+0x500
        ffff860c`91fb72a0 fffff802`3bacc132     nt!KiCommitThreadWait+0x14f
        ffff860c`91fb7340 fffff802`3be8be2f     nt!KeDelayExecutionThread+0x122
        ffff860c`91fb73d0 fffff802`3bc11235     nt!NtDelayExecution+0x5f
        ffff860c`91fb7400 00007ffd`3b06d664     nt!KiSystemServiceCopyEnd+0x25 (TrapFrame @ ffff860c`91fb7400)
        00000074`b56ff858 00007ffd`386fb62e     ntdll!NtDelayExecution+0x14
        00000074`b56ff860 00007ffd`08d1285c     KERNELBASE!SleepEx+0x9e
        00000074`b56ff900 00007ff7`000b16b3     MSVCP140!_Thrd_sleep+0x3c [d:\agent\_work\3\s\src\vctools\crt\crtw32\stdcpp\thr\cthread.cpp @ 70] 
        00000074`b56ff950 00007ff7`000b1619     Demo!std::this_thread::sleep_until<std::chrono::steady_clock,std::chrono::duration<__int64,std::ratio<1,1000000000> > >+0x83 [C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.36.32532\include\thread @ 199] 
        00000074`b56ff9a0 00007ff7`000b1736     Demo!std::this_thread::sleep_for<__int64,std::ratio<1,1> >+0x19 [C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.36.32532\include\thread @ 205] 
        00000074`b56ff9d0 00007ff7`000b175f     Demo!foo+0x36 [C:\Users\user\workspace\CppAutoRegisterDemo\main.cpp @ 8] 
        00000074`b56ffa00 00007ff7`000b1ab8     Demo!main+0xf [C:\Users\user\workspace\CppAutoRegisterDemo\main.cpp @ 12] 
        (Inline Function) --------`--------     Demo!invoke_main+0x22 (Inline Function @ 00007ff7`000b1ab8) [D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl @ 78] 
        00000074`b56ffa30 00007ffd`3a6d7344     Demo!__scrt_common_main_seh+0x10c [D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl @ 288] 
        00000074`b56ffa70 00007ffd`3b0226b1     KERNEL32!BaseThreadInitThunk+0x14
        00000074`b56ffaa0 00000000`00000000     ntdll!RtlUserThreadStart+0x21
...

此時再用lm命令也可以看到pdb的確被加載了:

4: kd> lm
start             end                 module name
00007ff7`000b0000 00007ff7`000c0000   Demo     C (private pdb symbols)  d:\symbols\Demo.pdb
...

然后可以用.thread ffff9b0e70a9f2c0設置線程上下文就能在堆棧窗口看到對應的線程堆棧了。接著就能雙擊對應的棧幀打開代碼窗口:

source.png

有時候還能在Locals窗口看到傳入函數的參數的值,雖然這個dump沒有抓到param的值。

dump對虛擬內存大小的要求

在具體分析dump的時候發現有時候就算加載了正確的pdb文件也會有看到一些符號無法解析,我猜測是因為抓出來的dump只包含物理內存的信息,而這部分符號的地址在虛擬內存上。

本來想關掉虛擬內存再抓取確認的。但是發現藍屏dump的抓取對虛擬內存大小是有要求的,可以在官方文檔上看到。例如full dump的要求如下:

物理內存 虛擬內存要求
256 MB–1,373 MB 物理內存大小的 1.5 倍
1,374 MB 或更大 32 位系統:2 GB 加 16 MB
64 位系統:物理內存的大小加上 128 MB

所以有時候藍屏dump抓不出來也可以看看是不是虛擬內存設置的小了或者直接被關掉了。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,431評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,637評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,555評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,900評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,629評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,976評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,976評論 3 448
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,139評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,686評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,411評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,641評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,129評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,820評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,233評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,567評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,362評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,604評論 2 380

推薦閱讀更多精彩內容