一个做网吧维护的朋友提供的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命令:
- k 查看当前线程调用栈
- ~ 查看当前进程的所有线程
- ~38 k 查看编号为38的线程的调用栈.
- lm v m winhdd 查看winhdd.dll的信息 (主要是文件路径比较有用)
最后的经验总结:
处理进程崩溃问题 (桌面,QQ,浏览器等) , 如果只是想解决问题本身 , 有一个通用的非常简单的办法:
检查进程加载的DLL列表, 凡是第三方DLL , 一个个尝试屏蔽并观察屏蔽后结果即可 . 注意要能够辨别某些正常DLL,比如实名,或无盘相关的不可屏蔽的DLL.
就这样一个简单办法, 至少在目前 , 能够定位,解决70 - 90%的的突发进程崩溃问题 , 只是需要反复测试, 才能准确知道到底是哪个DLL的问题.
同时, 发现问题DLL 后, 建议向相关软件厂商反应 , 由他们给出解决方案 , 不建议自行屏蔽处理 .
(注意此方法只是适用于具有 : "突发", "大范围", "频繁重现" 这几个特征的进程崩溃问题, 正常范围内的小几率进程崩溃问题 , 不可用此方法解决 )
本站赞助者在碰到类似问题时 , 如果无法自行定位问题原因, 可联系本人协助查找问题原因 .
本文转载自热爱学习、技术牛X、为人低调、值得学习的370safe技术博客
370Safe-[DUMP分析] 实例1:explorer.exe崩溃原因 以及 类似的 "进程崩溃问题" 的通用排查方法