最新消息:想得多,做的少。一天到晚瞎鸡巴搞。

记录一次分析启动系统时Explorer崩溃问题

套路与反套路 阿虚 31浏览 0评论

如果不想看全文,直接拉到最后可以看总结

崩溃环境

.      崩溃环境:Win7 x86 Windows Embedded Standard 嵌入式版本

.      这个崩溃dump的起因是客户机器win7嵌入式版本系统上安装我司的XX软件后再每次启动系统第一次进入到桌面Explorer会产生崩溃。之后再启动桌面则不会有任何问题。每次启动机器都会有一次崩溃任谁都不会爽。因为不方便远程,客户直接将嵌入式机器直接顺丰过来了。

.      因为机器今天邮寄回去了,上班调试当时没有抓图。回家时才想起想记录下调试过程。

崩溃排查

获取dump文件

.     启动机器时可以直接看到本应该是展示桌面却变成了桌面崩溃的弹框(无图)。既然卡在了崩溃窗口那么表示进程还没有结束,可以通过任务管理器来创建一个dump文件。

.     创建dump文件后因为客户机器装了其他的安全软件将C盘给隐藏所以只能通过cmd命令将dmup文件拷贝到可见的D盘中。

copy C:\Users\XXXX\AppData\Local\Temp\explorer.DMP d:\dmp.dmp

设置符号路径

.     拿到dump中丢到windbg中,然后设置符号路径:File -> Symbol Search Path。并且勾上Reload,点击OK。

srv*G:\sym*http://msdl.microsoft.com/download/symbols;

Windbg分析

.     记得以前写过篇文章《WinDBG分析程序崩溃的Dump文件》加载完pdb后使用命令!analyze –v来查看崩溃原因,当然对于常规的测试例子来说这个好使,但是现在现场问题明显不好使了。(这也是我想记录的原因)

.     上图崩溃的原因可以看到是0x80000003读取到不可读的内存上了,但是其他的信息完全不对。FOLLOWUP_IP: shell32!CDesktopBrowser::_MessageLoop+5,也是指向在消息循环中,然并卵。忘了在哪看到过崩溃是是线程产生了异常那么会将所有的线程都给挂起,如果哪条线程没有被挂起那么那条线程可以猜测是崩溃产生的原因的地方。windbg中使用命令:【~】来查看所有的线程。

0:000>  ~

.  0  Id: 6d8.6dc Suspend: 1 Teb: 7ffdf000 Unfrozen

1  Id: 6d8.6e8 Suspend: 1 Teb: 7ffdd000 Unfrozen

2  Id: 6d8.740 Suspend: 1 Teb: 7ffda000 Unfrozen

3  Id: 6d8.750 Suspend: 1 Teb: 7ffd9000 Unfrozen

……..

10  Id: 6d8.1bc Suspend: 1 Teb: 7ff9e000 Unfrozen

  11  Id: 6d8.1f4 Suspend: 0 Teb: 7ff9d000 Unfrozen

12  Id: 6d8.2bc Suspend: 1 Teb: 7ff9c000 Unfrozen

13  Id: 6d8.198 Suspend: 1 Teb: 7ff9b000 Unfrozen

14  Id: 6d8.19c Suspend: 1 Teb: 7ff9a000 Unfrozen

…….

33  Id: 6d8.fb8 Suspend: 1 Teb: 7ffde000 Unfrozen

.     一共33条线程,只有11号线程没有被挂起,那么接下来对11号线程查看线程栈windbg命令:【~11k】

0:000> ~11k

ChildEBP RetAddr

0484f044 76dd65cc ntdll!KiFastSystemCallRet

*** ERROR: Symbol file could not be found.  Defaulted to export symbols for KERNELBASE.dll –

0484f048 75146a8e ntdll!NtWaitForMultipleObjects+0xc

*** ERROR: Symbol file could not be found.  Defaulted to export symbols for kernel32.dll –

WARNING: Stack unwind information not available. Following frames may be wrong.

0484f0e4 7621be2e KERNELBASE!InterlockedCompareExchange+0xbc

0484f12c 7621be9c kernel32!WaitForMultipleObjectsEx+0x8e

0484f148 762306b7 kernel32!WaitForMultipleObjects+0x18

0484f1b4 76230952 kernel32!GetThreadSelectorEntry+0x1ee

0484f1c8 76230900 kernel32!UnhandledExceptionFilter+0x249

0484f1d8 7623087b kernel32!UnhandledExceptionFilter+0x1f7

0484f264 76e62bad kernel32!UnhandledExceptionFilter+0x172

0484f27c 76e631d4 ntdll!TppExceptionFilter+0x59

0484f290 76e2aeab ntdll!TppWorkerpInnerExceptionFilter+0x12

0484f2a0 76dae3a4 ntdll!TppWorkerThread+0x57f

0484f2b4 76dae234 ntdll!_EH4_CallFilterFunc+0x12

0484f2dc 76dd6d79 ntdll!_except_handler4+0x8e

0484f300 76dd6d4b ntdll!ExecuteHandler2+0x26

0484f324 76dafa17 ntdll!ExecuteHandler+0x24

0484f3b0 76dd6bd7 ntdll!RtlDispatchException+0x127

0484f3b0 10001063 ntdll!KiUserExceptionDispatcher+0xf

*** ERROR: Symbol file could not be found.  Defaulted to export symbols for AAAAAA.dll –

0484f9f4 0484faf4 AAAAAA +0x1063

0484fb18 769ab9fc 0x484faf4

0484fb5c 769abaa4 shlwapi!_SHRegQueryValueW+0x5b

0484fba0 769a82c4 shlwapi!SHRegGetValueW+0x8d

0484fbcc 003267a4 shlwapi!SHRegGetValueFromHKCUHKLM+0x2e

0484fc00 0032a04b explorer!CMenuDescriptor::GetDisplayMode+0x6a

0484fc2c 76dbd7c4 explorer!SpecialFolderList::_HasEnoughChildrenThreadProc+0x3e

0484fca0 76dc0774 ntdll!RtlpTpWorkCallback+0x11d

0484fdf0 7621ee1c ntdll!TppWorkerThread+0x562

0484fdfc 76df367a kernel32!BaseThreadInitThunk+0x12

0484fe3c 76df364d ntdll!__RtlUserThreadStart+0x70

0484fe54 00000000 ntdll!_RtlUserThreadStart+0x1b

.     在列表中标记AAAA.DLL是我司产品的DLL,通过栈可以知道在执行shlwapi!_SHRegQueryValueW之后跳转到了我司的AAAA.DLL插件后引起了异常崩溃。其中在shlwapi!_SHRegQueryValueW有一条0484fb18 769ab9fc 0x484faf4栈信息,这里应该是没有包含AAAAA.DLL的PDB的问题。那么知道问题的DLL,那么此时还应该定位到问题的哪一行代码中。编译一个AAAA.DLL替换到客户的嵌入式系统中重启。

(以下因为环境原因以及PDB没有保存所以无图只能简述了。。。。。)

无图简述。。。

.     替换编译的DLL加载后获取到的dmp文件通过pdb知道崩溃的原因。在调用了shlwapi!_SHRegQueryValueW函数,因为我司的插件HOOK了‘ZwQueryValueKey’函数。在HOOK中执行了正真的‘ZwQueryValueKey’后会打开我司另一个server进程启动的共享内存。但是!这个共享内存在win7嵌入式版本中刚启动机器时获取到的共享内存的buffer是“不可读”的,这个时候对不可读的内存访问自然就产生了C03崩溃了。。。。

为什么知道原因是共享内存不可读?

.     因为我在编译dll后产生的PDB配合使用Windbg的反汇编‘u 0484f9f4’得知崩溃的地方是在取pNode->gb_super_mode;的时候。pNode指向的是通过‘OpenFileMappingW’函数打开的共享内存。如果要说写错代码了打死都不信,一般公司都有自己封装好的基础库,经历时间的考验是不会出错的。诡异的是在win7嵌入式系统在启动时Explorer得到的共享内存是不可读的状态。

.     我为了怕我自己分析错误我修改了一下代码,卡一个int 3中断,并且将windbg设置为默认调试器。

__asm int 3

return pNode->gb_super_mode;

设置windbg为默认调试器使用cmd执行命令,-I一定要说大写的!

“C:\Program Files (x86)\Debugging Tools for Windows (x86)\windbg.exe” -I

.     卡一个Int3是因为崩溃后无法看到当前函数pNode指向的内存共享的buffer空间是个什么样的。所以选择在上面卡一个int 3来观察共享内存空间。重启环境触发int 3断点时通过windbg命令‘db 0x12345678’查看pNode指向的共享内存空间全部为 ?? ?? ?? ?? ??。。。。。

结束

.     最终,可以确定在win7嵌入式系统中我司的插件在启动系统时第一次启动Explorer崩溃的原因是获取的内存共享空间是一块不可读的空间。那么如何解决呢?加个判断如果m_node为不可读的状态则返回NULL。

后记

.     解决了BUG但心里还是有疑问,就是为何在win7嵌入式系统时,server进程创建的共享内存此时为何是不可读的?这个问题暂时是没法想通了有点可惜。

总结

.     在使用!analyze –v分析不出名堂来时可以通过命令【~】来列出当前进程的所有线程,看看那个线程没有被‘挂起’那么就使用命令【~线程号k】来线程这条线程的线程栈就好。

转载请注明:虚无 » 记录一次分析启动系统时Explorer崩溃问题

发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址