翼度科技»论坛 编程开发 .net 查看内容

记一次 Windows10 内存压缩模块 崩溃分析

2

主题

2

帖子

6

积分

新手上路

Rank: 1

积分
6
一:背景

1. 讲故事

在给各位朋友免费分析 .NET程序 各种故障的同时,往往也会收到各种其他类型的dump,比如:Windows 崩溃,C++ 崩溃,Mono 崩溃,真的是啥都有,由于基础知识的相对缺乏,分析起来并不是那么的顺利,今天就聊一个 Windows 崩溃的内核dump 吧,这个 dump 是前几天有位朋友给到我的,让我帮忙看一下,有了dump之后上 windbg 分析。
二:WinDbg 分析

1. 从哪里入手

只要是 Windows 平台上的崩溃,操作系统都会维护一个 EXCEPTION_POINTERS 结构体,这个结构体的解读对分析问题非常重要,使用 !analyze -v 命令简要输出如下:
  1. 2: kd> !analyze -v
  2. *******************************************************************************
  3. *                                                                             *
  4. *                        Bugcheck Analysis                                    *
  5. *                                                                             *
  6. *******************************************************************************
  7. UNEXPECTED_STORE_EXCEPTION (154)
  8. The store component caught an unexpected exception.
  9. Arguments:
  10. Arg1: ffffb402b9851000, Pointer to the store context or data manager
  11. Arg2: ffffe607bc53df30, Exception information
  12. Arg3: 0000000000000002, Reserved
  13. Arg4: 0000000000000000, Reserved
  14. ...
  15. EXCEPTION_RECORD:  ffffe607bc53eeb8 -- (.exr 0xffffe607bc53eeb8)
  16. ExceptionAddress: fffff80025b04bd0 (nt!RtlDecompressBufferXpressLz+0x0000000000000050)
  17.    ExceptionCode: c0000006 (In-page I/O error)
  18.   ExceptionFlags: 00000000
  19. NumberParameters: 3
  20.    Parameter[0]: 0000000000000000
  21.    Parameter[1]: 0000023f30ee99f0
  22.    Parameter[2]: 00000000c0000185
  23. Inpage operation failed at 0000023f30ee99f0, due to I/O error 00000000c0000185
  24. EXCEPTION_PARAMETER1:  0000000000000000
  25. EXCEPTION_PARAMETER2:  0000023f30ee99f0
  26. CONTEXT:  ffffe607bc53e6f0 -- (.cxr 0xffffe607bc53e6f0)
  27. rax=fffff80025b04b80 rbx=ffff9d808d7fa000 rcx=ffff9d808d7fa000
  28. rdx=ffff9d808d7fa000 rsi=0000000000000002 rdi=0000023f30ee99f0
  29. rip=fffff80025b04bd0 rsp=ffffe607bc53f0f8 rbp=0000023f30eea2fe
  30. r8=0000023f30ee99f0  r9=0000000000000964 r10=ffff9d808d7faea0
  31. r11=0000023f30eea354 r12=ffffe607bc53f368 r13=ffffb402d84d8000
  32. r14=ffff9d808d7fb000 r15=0000000000000000
  33. iopl=0         nv up ei pl zr na po nc
  34. cs=0010  ss=0000  ds=002b  es=002b  fs=0053  gs=002b             efl=00050246
  35. nt!RtlDecompressBufferXpressLz+0x50:
  36. fffff800`25b04bd0 418b08          mov     ecx,dword ptr [r8] ds:002b:0000023f`30ee99f0=????????
  37. Resetting default scope
  38. ...
复制代码
从卦中信息看,是由于将地址 0000023f30ee99f0 所映射的物理内存页换入到内存中,抛了一个IO错误,从汇编指令 ecx,dword ptr [r8] ds:002b:0000023f30ee99f0=???????? 上也能看的出来。
如果大家不信,可以用 !vtop 和 !pte 观察下它们对应的物理地址和物理页号,都是找不到的。
  1. 2: kd> !vtop 0 000000006d34aca0
  2. Amd64VtoP: Virt 000000006d34aca0, pagedir 00000003d81fb002
  3. Amd64VtoP: PML4E 00000003d81fb002
  4. Amd64VtoP: PML4E read error 0x8000FFFF
  5. Virtual address 6d34aca0 translation fails, error 0x8000FFFF.
  6. 2: kd> !pte 000000006d34aca0
  7.                                            VA 000000006d34aca0
  8. PXE at FFFF86432190C000    PPE at FFFF864321800008    PDE at FFFF864300001B48    PTE at FFFF860000369A50
  9. contains 0000000000000000
  10. contains 0000000000000000
  11. not valid
复制代码
2. 洞察异常前的线程栈

有了这个初步信息之后,接下来就来观察异常时的寄存器上下文和线程栈信息,输出如下:
  1. 2: kd> .cxr 0xffffe607bc53e6f0 ; k
  2. rax=fffff80025b04b80 rbx=ffff9d808d7fa000 rcx=ffff9d808d7fa000
  3. rdx=ffff9d808d7fa000 rsi=0000000000000002 rdi=0000023f30ee99f0
  4. rip=fffff80025b04bd0 rsp=ffffe607bc53f0f8 rbp=0000023f30eea2fe
  5. r8=0000023f30ee99f0  r9=0000000000000964 r10=ffff9d808d7faea0
  6. r11=0000023f30eea354 r12=ffffe607bc53f368 r13=ffffb402d84d8000
  7. r14=ffff9d808d7fb000 r15=0000000000000000
  8. iopl=0         nv up ei pl zr na po nc
  9. cs=0010  ss=0000  ds=002b  es=002b  fs=0053  gs=002b             efl=00050246
  10. nt!RtlDecompressBufferXpressLz+0x50:
  11. fffff800`25b04bd0 418b08          mov     ecx,dword ptr [r8] ds:002b:0000023f`30ee99f0=????????
  12.   *** Stack trace for last set context - .thread/.cxr resets it
  13. # Child-SP          RetAddr               Call Site
  14. 00 ffffe607`bc53f0f8 fffff800`25a5bc10     nt!RtlDecompressBufferXpressLz+0x50
  15. 01 ffffe607`bc53f110 fffff800`25a5bb14     nt!RtlDecompressBufferEx+0x60
  16. 02 ffffe607`bc53f160 fffff800`25a5b9a1     nt!ST_STORE<SM_TRAITS>::StDmSinglePageCopy+0x150
  17. 03 ffffe607`bc53f220 fffff800`25b56ff0     nt!ST_STORE<SM_TRAITS>::StDmSinglePageTransfer+0xa5
  18. 04 ffffe607`bc53f270 fffff800`25b57904     nt!ST_STORE<SM_TRAITS>::StDmpSinglePageRetrieve+0x180
  19. 05 ffffe607`bc53f310 fffff800`25b57aed     nt!ST_STORE<SM_TRAITS>::StDmPageRetrieve+0xc8
  20. 06 ffffe607`bc53f3c0 fffff800`25a5c071     nt!SMKM_STORE<SM_TRAITS>::SmStDirectReadIssue+0x85
  21. 07 ffffe607`bc53f440 fffff800`25aad478     nt!SMKM_STORE<SM_TRAITS>::SmStDirectReadCallout+0x21
  22. 08 ffffe607`bc53f470 fffff800`25a5cb57     nt!KeExpandKernelStackAndCalloutInternal+0x78
  23. 09 ffffe607`bc53f4e0 fffff800`25a5713c     nt!SMKM_STORE<SM_TRAITS>::SmStDirectRead+0xc7
  24. 0a ffffe607`bc53f5b0 fffff800`25a56b70     nt!SMKM_STORE<SM_TRAITS>::SmStWorkItemQueue+0x1ac
  25. 0b ffffe607`bc53f600 fffff800`25b58727     nt!SMKM_STORE_MGR<SM_TRAITS>::SmIoCtxQueueWork+0xc0
  26. 0c ffffe607`bc53f690 fffff800`25b2b94b     nt!SMKM_STORE_MGR<SM_TRAITS>::SmPageRead+0x167
  27. 0d ffffe607`bc53f700 fffff800`25ad1020     nt!SmPageRead+0x33
  28. 0e ffffe607`bc53f750 fffff800`25ad023d     nt!MiIssueHardFaultIo+0x10c
  29. 0f ffffe607`bc53f7a0 fffff800`25a6e818     nt!MiIssueHardFault+0x29d
  30. 10 ffffe607`bc53f860 fffff800`25c0b6d8     nt!MmAccessFault+0x468
  31. 11 ffffe607`bc53fa00 00007ff8`c3089fa2     nt!KiPageFault+0x358
  32. 12 00000067`4ca7f270 00000000`00000000     0x00007ff8`c3089fa2
复制代码
从卦中的调用栈信息看,代码的源头是 用户态 (0x00007ff8c3089fa2) 过来的,应该是访问用户态地址 0000023f30ee99f0 上的内容,由于对应的物理页不在内存中,触发了 nt!KiPageFault 中断,也就是 idt 表中的 0xe 号标记的 缺页中断, 输出如下:
  1. lkd> !idt
  2. Dumping IDT: fffff8050ce87000
  3. 00:        fffff80506206400 nt!KiDivideErrorFault
  4. ...
  5. 0e:        fffff80506209980 nt!KiPageFault
复制代码
在缺页中断中触发了 IO 操作 MiIssueHardFaultIo 要从pagefiles 中捞页面,接下来就是页读取逻辑 SmPageRead,最后在 RtlDecompressBufferXpressLz 中引发了蓝屏。
如果心比较细的话,你会发现有一个关键词 Decompress ,对,就是解压缩,为什么换入的page还要解压缩呢? 这就是我们的突破点。
3. 为什么会解压缩

要找到这个问题的答案,需要观察下这个异常线程的详细信息,可以用 .thread 切到异常的线程上下文,再用 !thread 观察。
  1. 2: kd> .thread
  2. Implicit thread is now ffffb402`be04a080
  3. 2: kd> !thread ffffb402`be04a080
  4. THREAD ffffb402be04a080  Cid 0594.2228  Teb: 000000674c5b8000 Win32Thread: 0000000000000000 RUNNING on processor 2
  5. Not impersonating
  6. GetUlongFromAddress: unable to read from fffff8002641152c
  7. Owning Process            ffffb402b8d58080       Image:         <Invalid process>
  8. Attached Process          ffffb402b984a040       Image:         MemCompression
  9. fffff78000000000: Unable to get shared data
  10. Wait Start TickCount      649763      
  11. Context Switch Count      9              IdealProcessor: 0            
  12. ReadMemory error: Cannot get nt!KeMaximumIncrement value.
  13. UserTime                  00:00:00.000
  14. KernelTime                00:00:00.000
  15. Win32 Start Address 0x00007ff8c808afb0
  16. Stack Init ffffe607bc53fb90 Current ffffe607bc53e800
  17. Base ffffe607bc540000 Limit ffffe607bc539000 Call 0000000000000000
  18. Priority 8 BasePriority 7 PriorityDecrement 0 IoPriority 2 PagePriority 2
  19. Child-SP          RetAddr               : Args to Child                                                           : Call Site
  20. ffffe607`bc53de78 fffff800`25d9856e     : 00000000`00000154 ffffb402`b9851000 ffffe607`bc53df30 00000000`00000002 : nt!KeBugCheckEx
  21. ffffe607`bc53de80 fffff800`25c189db     : ffffb402`b9851000 ffffe607`bc53df30 ffffe607`00000002 ffffe607`bc53dfe0 : nt!SMKM_STORE<SM_TRAITS>::SmStUnhandledExceptionFilter+0x7e
  22. ffffe607`bc53ded0 fffff800`25bcfb1f     : fffff800`00000002 fffff800`258d905c ffffe607`bc539000 ffffe607`bc540000 : nt!`SMKM_STORE<SM_TRAITS>::SmStDirectReadIssue'::`1'::filt$0+0x22
  23. ffffe607`bc53df00 fffff800`25c062ff     : fffff800`258d905c ffffe607`bc53e4e0 fffff800`25bcfa80 00000000`00000000 : nt!_C_specific_handler+0x9f
  24. ...
复制代码
从卦中信息看,异常线程还有一个附加的进程 ffffb402b984a040,来自于 MemCompression 模块,从名字上看所谓的 压缩解压缩 逻辑应该和它有关系,接下来到网上去搜一下,有一篇文章说的非常好: https://www.howtogeek.com/319933/what-is-memory-compression-in-windows-10/
大意:这是 Windows10 新增的一个功能,用内存压缩技术让RAM中可以存储更多的内存页,相比传统的交换到 PageFiles.sys 有更高的性能,缺点就是需要耗费一些解压缩需要的 CPU 时间。
在 Windows10 上也能窥探一二:

4. 问题解决

解决办法很简单,学 4S 店的问题解决之道,能换的就坚决不修,让朋友把 内存压缩 给关掉,这样就不走
RtlDecompressBufferXpressLz 逻辑,理论上就不会有什么问题了。

关闭之后,据朋友反馈,这几天没有崩溃了。
三:总结

分析内核态相比用户态难度要大的多,需要对操作系统以及CPU的相关知识有一个比较深度的理解,任重道远。。。

来源:https://www.cnblogs.com/huangxincheng/archive/2023/04/26/17355938.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x

举报 回复 使用道具