一个做网吧维护的朋友提供的DUMP.现象是桌面崩溃,可重现.

突发性,频繁重现的进程崩溃问题 ,  文章最后会有一个基本通用, 并且没什么技术难度的经验总结.  对dump分析流程不感兴趣的直接跳到文章最末尾看结论就好.

===============================

前置基础:

1. http://support.icafe8.com/technologynews/focus/932.html  (无盘蓝屏DUMP分析教程)

2.每个进程至少有一个或多个线程.  进程崩溃的本质 , 是某个线程的某条指令执行时触发了"异常"被系统检测到.   而分析dump , 也就是找到这条出问题的线程 , 根据线程异常信息做相关分析.

分析流程:

 1. windbg 设置好符号路径 , 打开DUMP. 

    windbg默认并不会为所有模块(DLL)加载符号, 所以要手动输入 .reload /f 强制加载所有符号.

    顺便说一句, 通过网络下载所有符号可能非常慢 , 如果需要经常分析dump , 最好还是固定在一台电脑上分析比较好. 因为符号文件可以缓存,不用每次临时下载.

    .reload /f 运行后的结果: (部分无关信息省略,避免占篇幅)

0:000> .reload /f

..........*** ERROR: Symbol file could not be found.

....................

************* Symbol Loading Error Summary **************

Module name            Error

user32                 The system cannot find the file specified : srv*\\fe-tp\sy

slc                    The system cannot find the file specified : srv*\\fe-tp\symbo

shutdownCtrl           The system cannot find the file specified : srv*\\fe-tp\sy

ieres64                The system cannot find the file specified : srv*\\fe-tp\symb

twain2                 The system cannot find the file specified : srv*\\fe-tp\symb

winvrdi64              The system cannot find the file specified : srv*\\fe-tp\s

GPkgQryX64             The system cannot find the file specified : srv*\\fe-t

winhdd                 The system cannot find the file specified : srv*\\fe-tp\

gjHfghUUz              The system cannot find the file specified : srv*\\fe-t

oQc9OE                 No data is available : srv*\\fe-tp\symbols\microsof

zLmNbE                 No data is available : srv*\\fe-tp\symbols\microsof

W4wli0                 No data is available : srv*\\fe-tp\symbols\microso

    上方" Symbol Loading Error Summary " 提示的是所有加载符号失败的模块列表. 这个列表中的所包含的DLL,就是当前进程中加载的所有第三方DLL,或者是被篡改的系统DLL.

    比如列表中包含user32,  这是因为user32.dll被修改, 文件内容变化导致在微软官方服务器找不到对应的符号文件 . (这个文件是被激活工具修改,slc.dll可能也是)

    查看进程加载的所有第三方DLL,主要目的是对当前进程"健康状态"有一个大致的了解. (但要注意,并不是所有第三方DLL一定有问题 也可能是正常功能 , 比如shutdownCtrl可能与快速关机有关,user32.dll和slc.dll与激活工具有关)

 2. 符号加载完毕后 , 按照多数其他dump分析教程的描述,都是让运行 !analyze -v 来让windbg自动分析  . 下面是执行后结果:  (部分信息省略)

0:000> !analyze -v

 

PROCESS_NAME:  explorer.exe

ERROR_CODE: (NTSTATUS) 0x80000003 - {

STACK_TEXT:  

00000000`0020f408 000007fe`fe9964a2 :  user32!WaitMessage+0xa

00000000`0020f410 000007fe`fe8f7795 :  shell32!CDesktopBrowser::_MessageLoop+0x51

00000000`0020f450 00000000`ffd90ac1 :  shell32!SHDesktopMessageLoop+0x7e

00000000`0020f490 00000000`ffd9b911 :  : explorer!wWinMain+0xb1e

00000000`0020fb40 00000000`777c59ed :  explorer!DelayLoadFailureHook+0x208

00000000`0020fc00 00000000`779fc541 :   kernel32!BaseThreadInitThunk+0xd

00000000`0020fc30 00000000`00000000 :   ntdll!RtlUserThreadStart+0x1d

STACK_COMMAND:  ~0s; .ecxr ; kb

FOLLOWUP_IP:

shell32!CDesktopBrowser::_MessageLoop+51

000007fe`fe9964a2 ebe8            jmp     shell32!CDesktopBrowser::_MessageLoop+0x1c (000007fe`fe99648c)

PRIMARY_PROBLEM_CLASS:  X64_STATUS_BREAKPOINT_shell32!CDesktopBrowser::_MessageLoop+5

 

可能其他dump分析教程都是说观察调用栈(STACK_TEXT) 出现了哪些模块名 , 来确定是哪个模块的问题 , 但是这个dump自动分析后所显示的调用栈中出现的全部是系统DLL .  根据常识来看 , 系统DLL自身原因导致崩溃的几率是非常非常低的. 但是windbg自动分析的结果,的确没有出现第三方DLL.

这里涉及一个经验 :  对于ProcExp创建的DUMP , windbg传统的自动分析命令!analyze -v分析出来的结果,  基本上不能为我们提供任何有用的信息 .

也就是说,在这个例子中, 自动分析的结果 , 跟崩溃本质原因无关. (蓝屏dump也是一样,某些情况下,自动分析结果只能作为参考)

3. 自动分析找不到原因,又该如何从DUMP中分析更多信息?

前面已经说过, 进程崩溃的本质原因是某个线程的某条指令触发了异常 , 分析dump, 要先想办法找到出问题的线程 , 才能分析出更多的信息.

windbg自动分析 ,它是默认认为当前线程就是出问题的线程 ,对于蓝屏DUMP , windbg这样做多半没有问题 , 但对于procEXP创建的dump , 这样分析的结果往往不可靠.

现在我们不知道到底是哪条线程的问题, 那就先看下当前进程到底有哪些线程:

输入 ~ , 查看当前进程的所有线程, 显示结果: (部分省略)

0:000> ~

.  0  Id: 754.758 Suspend: 1 Teb: 000007ff`fffdd000 Unfrozen

1  Id: 754.764 Suspend: 1 Teb: 000007ff`fffdb000 Unfrozen

........

37  Id: 754.1600 Suspend: 1 Teb: 000007ff`fff56000 Unfrozen

38  Id: 754.160c Suspend: 0 Teb: 000007ff`fff54000 Unfrozen

39  Id: 754.1610 Suspend: 1 Teb: 000007ff`fff50000 Unfrozen

40  Id: 754.1614 Suspend: 1 Teb: 000007ff`fff4e000 Unfrozen

41  Id: 754.168c Suspend: 1 Teb: 000007ff`fff98000 Unfrozen

42  Id: 754.1714 Suspend: 1 Teb: 000007ff`fff8a000 Unfrozen

43  Id: 754.1794 Suspend: 1 Teb: 000007ff`fff68000 Unfrozen

一共有44条线程 . 全是数字, 看上去没有什么有用的信息 .   但实际上已经可以看出是编号为38的线程导致的崩溃 , 原因是:

系统在检测到一个进程出错, 弹出错误框之前 , 有这样一个机制 : 系统会把这个进程的所有线程挂起 , 只保留触发异常的线程. 那我们只要找到崩溃进程中 , 没有被挂起的那条线程, 就找到了出问题的线程. (在XP上可能没有这个机制)

从上面显示的线程列表中 ,可以明确看到 编号为38的线程的Suspend值为0 , 其他线程都为1  .(线程Suspend值大于等于1 , 表示线程处于挂起状态 , 为0表示运行状态)

所以这可以明确说明编号38的线程就是出问题的线程 , 而每个线程 , 都有调用栈 , 找到出问题的线程 , 观察它的调用栈, 就可以大致知道崩溃前, 这个线程正在做什么.

3. 查看编号为38的线程调用栈 . windbg 输入 ~38 k ,(38是线程编号)  显示结果:

00 00000000`077dc798 000007fe`fdb51430 ntdll!ZwWaitForMultipleObjects+0xa

01 00000000`077dc7a0 00000000`777d1723 KERNELBASE!WaitForMultipleObjectsEx+0xe8

02 00000000`077dc8a0 00000000`7784b5e5 kernel32!WaitForMultipleObjectsExImplementation+0xb3

03 00000000`077dc930 00000000`7784b767 kernel32!WerpReportFaultInternal+0x215

04 00000000`077dc9d0 00000000`7784b7bf kernel32!WerpReportFault+0x77

05 00000000`077dca00 00000000`7784b9dc kernel32!BasepReportFault+0x1f

06 00000000`077dca30 00000000`67e703b4 kernel32!UnhandledExceptionFilter+0x1fc

07 00000000`077dcb10 00000000`67e70468 msvcr100!call_reportfault+0x110

08 00000000`077dd120 00000000`67e704f6 msvcr100!invoke_watson+0x18

09 00000000`077dd150 00000000`67e70519 msvcr100!invalid_parameter+0x6e

0a 00000000`077dd190 00000000`67e23668 msvcr100!invalid_parameter_noinfo+0x19

0b 00000000`077dd1d0 00000000`67e23752 msvcr100!xtoa_s+0x30

0c 00000000`077dd200 000007fe`f67033f2 msvcr100!itoa_s+0x22

0d 00000000`077dd240 000007fe`f67039e5 winhdd+0x133f2

0e 00000000`077dfb40 00000000`777c59ed winhdd+0x139e5

0f 00000000`077dfcc0 00000000`779fc541 kernel32!BaseThreadInitThunk+0xd

10 00000000`077dfcf0 00000000`00000000 ntdll!RtlUserThreadStart+0x1d

    看到上方红色文字, 就完全可以确定这个线程一定出现了异常 (涉及到编程相关的经验).

    剩下的步骤 , 就是按照其他蓝屏分析教程的方法一样, 观察调用栈中出现的第三方模块名 , 上方信息中只有一个winhdd.dll是第三方DLL .

    (根据调用栈,  也可以看出是winhdd.dll内部调用了itoa这个函数 , 进入到微软的VC2010运行库msvcr100.dll , 然后触发了异常. 当然这些信息对于维护人员并不重要)

4. 查看winhdd.dll的相关信息. 

    执行lm v m winhdd

Browse full module list

start             end                 module name

000007fe`f66f0000 000007fe`f6742000   winhdd     (no symbols)

Loaded symbol image file: winhdd.dll

Image path: c:\Windows\System32\winhdd.dll

Image name: winhdd.dll

Browse all global symbols  functions  data

Timestamp:        Thu Mar 26 16:18:15 2015 (5513C0C7)

CheckSum:         00056F62

ImageSize:        00052000

File version:     0.0.0.0

Product version:  0.0.0.0

File flags:       0 (Mask 0)

File OS:          0 Unknown Base

File type:        0.0 Unknown

File date:        00000000.00000000

Translations:     0000.04b0 0000.04e4 0409.04b0 0409.04e4

找出文件路径这些信息,对于维护人员,已经基本够了, 到这里,  只要测试一下屏蔽这个DLL之后, 桌面是否依旧崩溃 , 就可以确定到底是不是这个DLL的问题 .

(提供dump的网维朋友反应, 在屏蔽winhdd.dll后, 崩溃问题消失 , 说明分析结果是没错的)

但是要注意 , DUMP只能还原出犯罪后的现场情况, 无法看出具体的犯罪过程 , 比如无法看出这个DLL是哪来的.  要深究DLL来源,  只能是在客户机使用监视工具, 分析软件行为来确定.

5.关于这个winhdd.dll的其他信息

   DLL被释放后,文件修改和创建时间会被伪装成系统的安装时间,给人感觉就像是系统母盘就自带了这个DLL;

   DLL开发者源码保存路径 : F:\work\CLIENT6\AD\AD\bsloadx64_copy\bsload\;

   DLL中出现的某些日志信息:(直接从dump中保存出来的,乱码多,将就着看)

进程值[%s][%d]

ctfmon.exe      CWork::AdWork::人为控制禁止下载!

CWork::AdWork::Excutefilelist failed!

CWork::AdWork::filelist[%s] from url[%s] download ok

CWork::AdWork::download filelist failed!url[%s]

CWork::AdWork::Download1();nRet=%d

CWork::AdWork::Filelist have downloaded,Don't download!

Download AD list from the AD server!

"?   `!            ?                    CWork::Work::人为控制禁止下载!

CWork::Work::休眠1分钟!

consolemain.exe         xs鳋  ?o鳋  t鋛鳋          string too long         invalid string position         "?   ?    ?    $                    "?   ?            ? 0                  =   ==  ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/                `s鳋  ?o鳋      0   rb  ru  cd  fd  www     1234567890123456        CAdUrl::GetFileRequestUrl:%s

http://%s:%d%s/rs/cr/%s?info=%s         /%s     %s-%d-%d+%s-%s-%d-%s-%lu        /rs/cr/ru?info=%s       %s-%s-%s+%d-%s-%s-%d-%d-%d-%u-%lu       上传加载广告Url(密文):%s

上传加载广告Url(明文):%s

CBroadcastAdOpt::RecvListFileName::CopyFile from %s to %s

filelist.tea    本机为32位,目标机器位64位,类型不匹配

本机为64位,目标机器为32位,类型不匹配

收到state: %x

找到不同类型机器,发送state失败

找到相同类型机器,发送state成功  %x

CBroadcastAdOpt::RecvFileList::Receive file fail!

文件类型不匹配,本机为32,目标为64

文件类型不匹配, 本机为64,目标为32

CBroadcastAdOpt::RecvFileList::DeleteFile:%s

%Y%m%d%H%M%S    旧文件名称:[%s],新文件名称[%s]         url .exec   _   -       fileInfo        CBroadcastAdOpt::ExcuteFileList1::filelist 格式错误!

"?   孊            擝 `                  CBroadcastAdOpt::TcpSendThread::ExcuteFileList1

Result[广告列表文件是否接收成功[%d],广告列表文件是否相等[%d]

]

%s  Connect success!

newfilelist1.tea        "?   蹷            養 ?

CBroadcastAdOpt::SendFileList::filelist 格式错误!

"?   @C            HC (                  CBroadcastAdOpt::TcpSendThread::SendFileList!

CBroadcastAdOpt::TcpSendThread::WaitForClient success,ClientIp:%s

CBroadcastAdOpt::TcpSendThread::InitServer

P *#ab+     ic00u.com   9001        "?   dD    4D    €D 8                  Exception:

%s

有效时间上传ip[%s],port[%d],uri[%s]         GET "?   0E     E    LE @       

/   :   https:  http:   CServerAdOpt::DownloadFile::内存申请失败                        CServerAdOpt::DownloadFile::filename[%s] len[%d] content[%s] from url[%s] TEA解密失败!                  file.tmp

 X                  上传存活时间Exception:

%s

上传存活时间 (超过了45分钟)

上传存活时间 (低于45分钟)

广告动态库不存在

添加新文件[%s]

旧文件名称:[%s],新文件名称[%s]

CServerAdOpt::ExcuteFileList::AddDownloadLogInfo::request fail!                 CServerAdOpt::ExcuteFileList::AddDownloadLogInfo::request success!

下载广告动态库文件:[%s] 成功            CServerAdOpt::ExcuteFileList::filelist 格式错误!                "?   V            LV         

wxCltAidEx.exe          pubwinclient.exe        clsmn.exe       udo.exe         recreation.exe          hintclient.exe          barclientview.exe       "?   鳹             W (                  检查次数[%d]

即将卸载广告动态库[%s]

检查到计费/网维进程:[%s]存在

检查到计费/网维进程:[%s]

"?   |W            刉                    "?   碬            糤                    GetNativeSystemInfo     kernel32.dll    \       cmd.exe     .dll        sc delete       80      读取文件[%s]完成

rb+     读取文件[%s]

"?   Z    鑉    ,Z `                  CCommon::DecodeFile::文件写入失败:

filename[%s]

len[%d]

wb  CCommon::DecodeFile::TEA解密成功:

##Start##filename[%s]

len[%d]

content[%s]##End##!

CCommon::DecodeFile::TEA解密失败:

############

filename[%s]

len[%d]

content[%s]############

CCommon::DecodeFile::文件读取为503错误:

filename[%s]

len[%d]

content[%s]

503     CCommon::DecodeFile::文件读取为空流:

filename[%s]

len[%d]

content[%s]

CCommon::DecodeFile::文件读取失败:

filename[%s]

len[%d]

"?   竄    圸    蘘 `                  CCommon::DecodeFile::TEA加密成功:

filename[%s]

len[%d]

ip  net stop        卸载动态库模块[%s]失败

卸载动态库模块[%s]成功

准备卸载动态库模块[%s]

NtQueryInformationThread        n t d l l . d l l       %c      ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz            %s\%s%s         %02X%02X%02X%02X%02X%02X        CCommon::GetAuthInfo::%s

%s-%s-%s-%s-%s      %ld CCommon::GetAuthInfo2::%s

%s-%s-%s-%s-%s-%d-%d-%s-%s-%d       dt  mi

CCommon::SearchAppcation::发现pubwin程序:pubwinclient.exe!

CCommon::SearchAppcation::发现程序:clsmn.exe!

CCommon::SearchAppcation::发现嘟嘟牛程序:udo.exe!

CCommon::GetEncodeBarcode::获取到网吧编码[%s]

\\.\pipe\BARCODE_MSG            CCommon::GetEncodeBarcode::开始获取网吧编码

;       CCommon::GetDecodeBarcode::param:%s

Netb0x_FnSmS_rEl    url=        CCommon::CompareAdListFile::Compare result:equal!

CCommon::CompareAdListFile::Compare result:unequal!

CompareAdListFile::CompareFile:%s=%s

CCommon::KillRemoveAdProcess::文件[%s]删除失败!错误码[%d]

CCommon::KillRemoveAdProcess::文件[%s]删除成功!

CCommon::KillRemoveAdProcess::进程[%s]kill成功!

CCommon::KillRemoveAdProcess::进程[%s]kill失败!

用户账号为%s,  获取run_lib函数地址失败

用户账号为%s,  获取到的run_lib函数地址为%x,   返回为为%d

run_lib         WinSta0\Default         "?   P_            X_ 0                  %s\%s_  SecondLog_S     %d_%s_%s.rar    %Y%m%d  %s.log  %Y%m%d%H%M      %s %s           "?   a    郹    $a                    "?   蘟    渁    郺 0                  \*.log  "?   攂            渂                    165.193.126.229

windbg分析dump , 并没有通用的办法 , 需要具体情况具体对待 , 不可一概而论.上述分析方法 , 也不能套用于所有dump.

本文涉及到的windbg命令:

  1. k  查看当前线程调用栈
  2. ~ 查看当前进程的所有线程
  3. ~38 k  查看编号为38的线程的调用栈.
  4. lm v m winhdd   查看winhdd.dll的信息 (主要是文件路径比较有用)

最后的经验总结:

处理进程崩溃问题 (桌面,QQ,浏览器等)  , 如果只是想解决问题本身 , 有一个通用的非常简单的办法:

检查进程加载的DLL列表, 凡是第三方DLL , 一个个尝试屏蔽并观察屏蔽后结果即可 .   注意要能够辨别某些正常DLL,比如实名,或无盘相关的不可屏蔽的DLL.

就这样一个简单办法, 至少在目前 , 能够定位,解决70 - 90%的的突发进程崩溃问题 , 只是需要反复测试, 才能准确知道到底是哪个DLL的问题.

同时, 发现问题DLL 后, 建议向相关软件厂商反应 , 由他们给出解决方案 , 不建议自行屏蔽处理 .

(注意此方法只是适用于具有 : "突发", "大范围", "频繁重现" 这几个特征的进程崩溃问题,  正常范围内的小几率进程崩溃问题 , 不可用此方法解决 )

本站赞助者在碰到类似问题时 , 如果无法自行定位问题原因, 可联系本人协助查找问题原因 .

本文转载自热爱学习、技术牛X、为人低调、值得学习的370safe技术博客

370Safe-[DUMP分析] 实例1:explorer.exe崩溃原因 以及 类似的 "进程崩溃问题" 的通用排查方法