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阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345

推荐阅读更多精彩内容