一:背景

1. 讲故事

前段时间有位训练营的学员找到我,说他们的软件在客户那边崩溃了,没找到是什么原因,比较着急,让我帮忙看下是怎么回事?毕竟我的学员是永久的免费dump分析,必须给他上一卦。

二:崩溃分析

1. 为什么会崩溃

关于怎么分析崩溃dump,这个在训练营里面早已整出来了套路,先用 !analyze -v 自动化分析崩溃原因,简化后如下:


0:000> !analyze -v
*******************************************************************************
* *
* Exception Analysis *
* *
*******************************************************************************
CONTEXT: (.ecxr)
eax=15c96638 ebx=010fecb0 ecx=00000000 edx=000109a8 esi=000109a8 edi=0000001c
eip=02f1d218 esp=010fec7c ebp=010feca8 iopl=0 nv up ei pl nz na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010206
02f1d218 8b410c mov eax,dword ptr [ecx+0Ch] ds:002b:0000000c=????????
Resetting default scope EXCEPTION_RECORD: (.exr -1)
ExceptionAddress: 02f1d218
ExceptionCode: c0000005 (Access violation)
ExceptionFlags: 00000000
NumberParameters: 2
Parameter[0]: 00000000
Parameter[1]: 0000000c
Attempt to read from address 0000000c STACK_TEXT:
WARNING: Frame IP not in any known module. Following frames may be wrong.
010feca8 758d139b 000109a8 0000001c 00000000 0x2f1d218
010fecd4 758c836a 15c9664e 000109a8 0000001c user32!_InternalCallWinProc+0x2b
010fedb8 758c7f6a 15c9664e 00000000 0000001c user32!UserCallWinProcCheckWow+0x33a
010fee1c 758cbb2f 01aef180 00000000 0000001c user32!DispatchClientMessage+0xea
010fee58 77a64f5d 010fee74 00000020 010ff110 user32!__fnDWORD+0x3f
010feee0 758cbdca 010fefb8 00000000 00000000 ntdll!KiUserCallbackDispatcher+0x4d
010feee0 758cbd3e 00000000 00000000 00000000 user32!_PeekMessage+0x2a
010fef1c 6f8a707c 010fefb8 00000000 00000000 user32!PeekMessageW+0x16e
010fef68 6f85443a 00000000 00000000 00000000 System_Windows_Forms_ni+0x22707c
010feffc 6f8540d1 00000000 ffffffff 00000000 System_Windows_Forms_ni!System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop+0x1b6
010ff050 6f853f23 00000000 00000000 00000000 System_Windows_Forms_ni!System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner+0x175
010ff07c 6f82c83d 00000000 00000000 00000000 System_Windows_Forms_ni!System.Windows.Forms.Application.ThreadContext.RunMessageLoop+0x4f
010ff094 02fa0b04 00000000 00000000 00000000 System_Windows_Forms_ni!System.Windows.Forms.Application.Run+0x35
010ff0f8 7337f066 00000000 00000000 00000000 xxx!xxx.Program.Main+0x2bc
...

从卦中的 DispatchClientMessage 来看,这是提取到了消息队列中的消息,在 0x2f1d218 处出现了访问违例,接下来的问题是寻找到底在处理啥消息?

2. 到底在处理什么消息

要想找到这个问题的答案,可以通过 !dso 在调用栈上寻找 MSG 结构体,简化后的输出如下:


0:000> !dso
OS Thread Id: 0x20b0 (0)
ESP/REG Object Name
010FEF9C 175ea6ec System.Windows.Forms.NativeMethods+MSG[] 0:000> !mdt -e:2 175ea6ec
175ea6ec (System.Windows.Forms.NativeMethods+MSG[], Elements: 1, ElementMT=6f688e60)
[0] (System.Windows.Forms.NativeMethods+MSG) VALTYPE (MT=6f688e60, ADDR=175ea6f4)
hwnd:00140488 (System.IntPtr)
message:0x113 (System.Int32)
wParam:00000531 (System.IntPtr)
lParam:00000000 (System.IntPtr)
time:0xfbf4f32 (System.Int32)
pt_x:0x118 (System.Int32)
pt_y:0x42d (System.Int32)

从卦中的 message:0x113 来看,这是经典的 WM_TIMER 消息,即定时器事件,用 C# 的话术就是窗体的 Timer 控件,参考MSDN截图:

接下来的关注点就是分析崩溃处的汇编代码了,使用 ub 命令反编译,输出如下:


0:000> .ecxr
eax=15c96638 ebx=010fecb0 ecx=00000000 edx=000109a8 esi=000109a8 edi=0000001c
eip=02f1d218 esp=010fec7c ebp=010feca8 iopl=0 nv up ei pl nz na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010206
02f1d218 8b410c mov eax,dword ptr [ecx+0Ch] ds:002b:0000000c=????????
0:000> ub 02f1d218 La
02f1d200 50 push eax
02f1d201 107567 adc byte ptr [ebp+67h],dh
02f1d204 51 push ecx
02f1d205 83ec04 sub esp,4
02f1d208 ff7304 push dword ptr [ebx+4]
02f1d20b ff7308 push dword ptr [ebx+8]
02f1d20e ff730c push dword ptr [ebx+0Ch]
02f1d211 8b13 mov edx,dword ptr [ebx]
02f1d213 8b4808 mov ecx,dword ptr [eax+8]
02f1d216 8b09 mov ecx,dword ptr [ecx]

由于 02f1d218 处没有显示函数名,根据经验猜测,这个应该是 JIT 动态生成的小函数,并且 02f1d204 是函数的入口点,程序崩溃是因为执行了 ecx=0 导致的,接下来根据 ecx 的来源进行反推看看有没有新的发现,输出如下:


0:000> dp 15c96638+0x8 L1
15c96640 015a8658 0:000> dp 015a8658 L1
015a8658 00000000 0:000> !do 015a8658
<Note: this object has an invalid CLASS field>
Invalid object 0:000> !dumpmd 015a8658
015a8658 is not a MethodDesc 0:000> !dumpmt 015a8658
015a8658 is not a MethodTable

从卦中看没有任何发现,015a8658 既不是 obj,也不是 mt,也不是 md ,这一下子就把我打入了黑暗之渊。。。

3. 在绝望中寻找希望

一时也没想到好办法,到门口边抽烟边思考, message:0x113 是一个 Win32 的 Timer,应该是 Timer 的定时回调在JIT的函数中意外崩掉了,按道理说在崩溃处的内存附近应该能找到与之对应的C# Timer,有了这个想法之后就在 015a8658 附近内存查找,还真给找到了,参考如下:


0:000> dp 015a8658 L4
015a8658 00000000 2d61d1a8 2d4ef48c 00000000
0:000> !do 2d61d1a8
Name: System.Windows.Forms.NativeMethods+WndProc
MethodTable: 6f687200
EEClass: 6f681458
Size: 32(0x20) bytes
File: C:\windows\Microsoft.Net\assembly\GAC_MSIL\System.Windows.Forms\v4.0_4.0.0.0__b77a5c561934e089\System.Windows.Forms.dll
Fields:
MT Field Offset Type VT Attr Value Name
71ec2734 40002f3 4 System.Object 0 instance 2d61d164 _target
71ec2734 40002f4 8 System.Object 0 instance 00000000 _methodBase
71ec7b18 40002f5 c System.IntPtr 1 instance 5b73c34 _methodPtr
71ec7b18 40002f6 10 System.IntPtr 1 instance 0 _methodPtrAux
71ec2734 4000300 14 System.Object 0 instance 00000000 _invocationList
71ec7b18 4000301 18 System.IntPtr 1 instance 0 _invocationCount 0:000> !do 2d61d164
Name: System.Windows.Forms.Timer+TimerNativeWindow
MethodTable: 6f6995e4
EEClass: 6f6ede04
Size: 56(0x38) bytes
File: C:\windows\Microsoft.Net\assembly\GAC_MSIL\System.Windows.Forms\v4.0_4.0.0.0__b77a5c561934e089\System.Windows.Forms.dll
Fields:
MT Field Offset Type VT Attr Value Name
71ec2734 40005ba 4 System.Object 0 instance 00000000 __identity
71ec7b18 4001cf9 18 System.IntPtr 1 instance 0 handle
6f687200 4001cfa 8 ...veMethods+WndProc 0 instance 2d61d1a8 windowProc
71ec7b18 4001cfb 1c System.IntPtr 1 instance 15ca1bee windowProcPtr
71ec7b18 4001cfc 20 System.IntPtr 1 instance 77a77f70 defWindowProc
71ec878c 4001cfd 28 System.Boolean 1 instance 1 suppressedGC
71ec878c 4001cfe 29 System.Boolean 1 instance 0 ownHandle
6f685da8 4001cff c ...orms.NativeWindow 0 instance 00000000 previousWindow
6f685da8 4001d00 10 ...orms.NativeWindow 0 instance 00000000 nextWindow
71ec6018 4001d01 14 System.WeakReference 0 instance 2d61d19c weakThisPtr
70229854 4001d02 24 System.Int32 1 instance 0 windowDpiAwarenessContext
713fe7cc 4001ce3 b88 ...stics.TraceSwitch 0 static 00000000 WndProcChoice
71ec426c 4001ce4 b8c System.Int32[] 0 static 03111988 primes
71ec878c 4001ceb 1312 System.Boolean 1 static 1 anyHandleCreatedInApp
71ec42a8 4001ced 1304 System.Int32 1 static 1786 handleCount
71ec42a8 4001cee 1308 System.Int32 1 static 2915 hashLoadSize
6f685e9c 4001cef b90 ...ow+HandleBucket[] 0 static 2c7b5f14 hashBuckets
71ec7b18 4001cf0 130c System.IntPtr 1 static 77a77f70 userDefWindowProc
71ec3a08 4001cf3 1313 System.Byte 1 static 0 userSetProcFlagsForApp
71ec882c 4001cf4 1310 System.Int16 1 static 1 globalID
71f1c594 4001cf5 b94 ...ntPtr, mscorlib]] 0 static 03111bc8 hashForIdHandle
71f1c6d0 4001cf6 b98 ...Int16, mscorlib]] 0 static 03111c3c hashForHandleId
71ec2734 4001cf7 b9c System.Object 0 static 03111b90 internalSyncObject
71ec2734 4001cf8 ba0 System.Object 0 static 03111b9c createWindowSyncObject
71ec878c 4001cea 979 System.Boolean 1 TLstatic anyHandleCreated
>> Thread:Value 20b0:1 <<
71ec3a08 4001cf1 97a System.Byte 1 TLstatic wndProcFlags
>> Thread:Value 20b0:1 <<
71ec3a08 4001cf2 97b System.Byte 1 TLstatic userSetProcFlags
>> Thread:Value 20b0:1 <<
6f69ad98 400415e 2c ...ndows.Forms.Timer 0 instance 14462858 _owner
71ec42a8 400415f 30 System.Int32 1 instance 0 _timerID
71ec878c 4004161 2a System.Boolean 1 instance 0 _stoppingTimer
71ec42a8 4004160 190c System.Int32 1 static 2462 TimerID

冥冥之中自有天意。。。一顿欣喜若狂之后,赶紧看看这个 Timer 来自于哪里,使用 !gcroot 2d61d164 即可。


0:000> !gcroot 2d61d164
Thread 20b0:
010fef80 6f85443a System.Windows.Forms.Application+ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr, Int32, Int32)
ebx: (interior)
-> 040e5568 System.Object[]
-> 031ced2c System.Windows.Forms.FormCollection
-> 031ced44 System.Collections.ArrayList
-> 1df9aaec System.Object[]
...
-> 144625fc DevComponents.DotNetBar.Controls.ComboBoxEx
-> 14462858 System.Windows.Forms.Timer
-> 2d61d164 System.Windows.Forms.Timer+TimerNativeWindow

从卦中的引用链来看,原来它是挂在 DevComponents.DotNetBar.Controls.ComboBoxEx 控件之下的,赶紧反向寻找源代码,截图如下:

尼玛居然是加密的,也是无语了,由于是 DevComponents 组件中的代码,赶紧看看组件的版本,结果发现是 2002 年的第一场雪,距今 23年,没有bug也是奇怪了。。。截图如下:

最后给到朋友的建议就是升级 DevComponents 或者寻找替代品。

三:总结

有人说bug分析就是一门法医学,不断的在绝望中寻找希望,千淘万漉虽辛苦,吹尽狂沙始到金!

记一次 .NET 某中医药附属医院门诊系统 崩溃分析的更多相关文章

  1. 记一次 .NET 某企业 ERP网站系统 崩溃分析

    一:背景 1. 讲故事 前段时间收到了一个朋友的求助,说他的ERP网站系统会出现偶发性崩溃,找了好久也没找到是什么原因,让我帮忙看下,其实崩溃好说,用 procdump 自动抓一个就好,拿到 dump ...

  2. 记一次 .NET 某医疗住院系统 崩溃分析

    一:背景 1. 讲故事 最近收到了两起程序崩溃的dump,查了下都是经典的 double free 造成的,蛮有意思,这里就抽一篇出来分享一下经验供后面的学习者避坑吧. 二:WinDbg 分析 1. ...

  3. 医院his系统数据库恢复

    医院IT系统的重要性堪比金融行业,“银行系统宕机,老百姓不能取钱:医院HIS系统宕机,老百姓不能看病”, 医院信息系统称得上是迄今为止企业级信息系统中最复杂的一类.  某医院HIS系统SQL2008数 ...

  4. 记一次 .NET 某市附属医院 Web程序 偶发性CPU爆高分析

    一:背景 1. 讲故事 这个月初,一位朋友加微信求助他的程序出现了 CPU 偶发性爆高,希望能有偿解决一下. 从描述看,这个问题应该困扰了很久,还是医院的朋友给力,开门就是 100块 红包 ,那既然是 ...

  5. 记一次 .NET 医院CIS系统 内存溢出分析

    一:背景 1. 讲故事 前几天有位朋友加wx求助说他的程序最近总是出现内存溢出,很崩溃,如下图: 和这位朋友聊下来,发现他也是搞医疗的,哈哈,.NET 在医疗方面还是很有市场的,不过对于内存方面出的问 ...

  6. 记一次 .NET 某医院HIS系统 CPU爆高分析

    一:背景 1. 讲故事 前几天有位朋友加 wx 抱怨他的程序在高峰期总是莫名其妙的cpu爆高,求助如何分析? 和这位朋友沟通下来,据说这问题困扰了他们几年,还请了微软的工程师过来解决,无疾而终,应该还 ...

  7. 记一次 .NET 某三甲医院HIS系统 内存暴涨分析

    一:背景 1. 讲故事 前几天有位朋友加wx说他的程序遭遇了内存暴涨,求助如何分析? 和这位朋友聊下来,这个dump也是取自一个HIS系统,如朋友所说我这真的是和医院杠上了,这样也好,给自己攒点资源, ...

  8. 记一次 .NET医疗布草API程序 内存暴涨分析

    一:背景 1. 讲故事 我在年前写过一篇关于CPU爆高的分析文章 再记一次 应用服务器 CPU 暴高事故分析 ,当时是给同济做项目升级,看过那篇文章的朋友应该知道,最后的结论是运维人员错误的将 IIS ...

  9. 记一次纠结Macbook 重装OS X的系统

    本文所有图片都是网上截图,不是实操环境.本文不具有教学意义. 起因:Macbook 白苹果了,无限菊花. 我的Macbook 只能装 OS X Mountain Lion 10.8,但是呢 MacBo ...

  10. 记一次kali和win8.1的双系统修复!!

    简要情况: 原来电脑存在的系统:win7和kali. 后来的系统:win8.1和原本的kali 情况描述:在我装完win8.1后就直接启动到win8.1了没有了grub2的选择启动界面,但是我还是想要 ...

随机推荐

  1. 3.Java SDK源码分析系列笔记-LinkedList

    目录 1. 是什么 2. 如何使用 3. 原理分析 3.1. uml 3.2. 构造方法 3.2.1. 队列的节点Node 3.3. add方法 3.3.1. 插入到链表尾部 3.3.2. 构造新节点 ...

  2. Web前端入门第 73 问:JavaScript DOM 常用事件那点小事

    网页上各种炫酷的交互效果离不开各种 DOM 事件 的支持,在写这篇文章之前,一度以为 JS 的事件绑定/取消方式就我知道的那几种,翻阅文档之后才发现,知识面还是有待提升,多翻翻文档,就像发现新大陆一样 ...

  3. .NET中全新的MongoDb ORM框架 - SqlSugar

    .NET中好用的MongoDb ORM很少,选择也很少,所以我打造了一款适合SQL习惯的MongoDb ORM,让用户多一个选择. 1. MongoDB ORM教程 1.1 NUGET 安装 SqlS ...

  4. Elastic学习之旅 (8) 深入词项和全文搜索

    大家好,我是Edison. 上一篇:Elastic学习之旅 (7) 聚合分析 相信很多童鞋和我一样,有点傻傻分不清Term查询和全文查询的区别,那么今天我们就来一起梳理一下. 基于Term的查询 Te ...

  5. INFINI Labs 产品更新 | Coco AI 0.5 发布 – 无缝集成 AI 搜索能力、支持插件扩展、支持快照版本更新等

    INFINI Labs 产品更新发布!此次更新涵盖 Coco AI 产品多项重要升级,重点提升 AI 搜索能力.易用性及企业级优化. Coco AI v0.5 无缝集成 AI 搜索能力,支持第三方插件 ...

  6. C# 对字符串进行UrlEncode/UrlDecode

    https://www.cnblogs.com/li150dan/p/13492280.html //对字符进行UrlEncode编码 string text= System.Web.HttpUtil ...

  7. 安装程序无法自动安装virtual machine

    安装VMware Tools 失败 发现在给过旧的系统安装 安装VMware Tools 的时候,会失败,比如 win7.win server2008等. 原因 官网的说明,在这里 看不懂的自行翻译: ...

  8. 前端开发系列055-基础篇之Vue项目实现多语言支持

    插件介绍 介绍:Vuei18n 是 Vue.js 的国际化插件.它可以轻松地将一些本地化功能集成到你的 Vue.js 应用程序中. 安装:npm install vue-i18n 或者 yarn ad ...

  9. 如何通过ETL进行数据抽取工作

    数据抽取作为数据集成过程中的核心环节,抽取速度直接决定了整个数据生命周期的质量与效率.在数字化转型加速的当下,企业需要从结构化数据库.非结构化文档.实时流数据.外部API接口等异构数据源中提取有价值的 ...

  10. OpenList挂载「迅雷」

    存储->添加 选择迅雷 填写挂载路径,其他的按默认的即可 填写用户名和密码 注意:第一次挂载迅雷的时候,这里填的手机号不要+86 例如,我的手机号是12345678,此时直接填12345678即 ...