找回密码
 立即注册
首页 业界区 业界 记一次 .NET 某中医药附属医院门诊系统 崩溃分析 ...

记一次 .NET 某中医药附属医院门诊系统 崩溃分析

撙仿 昨天 14:29
一:背景

1. 讲故事

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

1. 为什么会崩溃

关于怎么分析崩溃dump,这个在训练营里面早已整出来了套路,先用 !analyze -v 自动化分析崩溃原因,简化后如下:
  1. 0:000> !analyze -v
  2. *******************************************************************************
  3. *                                                                             *
  4. *                        Exception Analysis                                   *
  5. *                                                                             *
  6. *******************************************************************************
  7. CONTEXT:  (.ecxr)
  8. eax=15c96638 ebx=010fecb0 ecx=00000000 edx=000109a8 esi=000109a8 edi=0000001c
  9. eip=02f1d218 esp=010fec7c ebp=010feca8 iopl=0         nv up ei pl nz na pe nc
  10. cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010206
  11. 02f1d218 8b410c          mov     eax,dword ptr [ecx+0Ch] ds:002b:0000000c=????????
  12. Resetting default scope
  13. EXCEPTION_RECORD:  (.exr -1)
  14. ExceptionAddress: 02f1d218
  15.    ExceptionCode: c0000005 (Access violation)
  16.   ExceptionFlags: 00000000
  17. NumberParameters: 2
  18.    Parameter[0]: 00000000
  19.    Parameter[1]: 0000000c
  20. Attempt to read from address 0000000c
  21. STACK_TEXT:  
  22. WARNING: Frame IP not in any known module. Following frames may be wrong.
  23. 010feca8 758d139b     000109a8 0000001c 00000000 0x2f1d218
  24. 010fecd4 758c836a     15c9664e 000109a8 0000001c user32!_InternalCallWinProc+0x2b
  25. 010fedb8 758c7f6a     15c9664e 00000000 0000001c user32!UserCallWinProcCheckWow+0x33a
  26. 010fee1c 758cbb2f     01aef180 00000000 0000001c user32!DispatchClientMessage+0xea
  27. 010fee58 77a64f5d     010fee74 00000020 010ff110 user32!__fnDWORD+0x3f
  28. 010feee0 758cbdca     010fefb8 00000000 00000000 ntdll!KiUserCallbackDispatcher+0x4d
  29. 010feee0 758cbd3e     00000000 00000000 00000000 user32!_PeekMessage+0x2a
  30. 010fef1c 6f8a707c     010fefb8 00000000 00000000 user32!PeekMessageW+0x16e
  31. 010fef68 6f85443a     00000000 00000000 00000000 System_Windows_Forms_ni+0x22707c
  32. 010feffc 6f8540d1     00000000 ffffffff 00000000 System_Windows_Forms_ni!System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop+0x1b6
  33. 010ff050 6f853f23     00000000 00000000 00000000 System_Windows_Forms_ni!System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner+0x175
  34. 010ff07c 6f82c83d     00000000 00000000 00000000 System_Windows_Forms_ni!System.Windows.Forms.Application.ThreadContext.RunMessageLoop+0x4f
  35. 010ff094 02fa0b04     00000000 00000000 00000000 System_Windows_Forms_ni!System.Windows.Forms.Application.Run+0x35
  36. 010ff0f8 7337f066     00000000 00000000 00000000 xxx!xxx.Program.Main+0x2bc
  37. ...
复制代码
从卦中的 DispatchClientMessage 来看,这是提取到了消息队列中的消息,在 0x2f1d218 处出现了访问违例,接下来的问题是寻找到底在处理啥消息?
2. 到底在处理什么消息

要想找到这个问题的答案,可以通过 !dso 在调用栈上寻找 MSG 结构体,简化后的输出如下:
  1. 0:000> !dso
  2. OS Thread Id: 0x20b0 (0)
  3. ESP/REG  Object   Name
  4. 010FEF9C 175ea6ec System.Windows.Forms.NativeMethods+MSG[]
  5. 0:000> !mdt -e:2 175ea6ec
  6. 175ea6ec (System.Windows.Forms.NativeMethods+MSG[], Elements: 1, ElementMT=6f688e60)
  7. [0] (System.Windows.Forms.NativeMethods+MSG) VALTYPE (MT=6f688e60, ADDR=175ea6f4)
  8.     hwnd:00140488 (System.IntPtr)
  9.     message:0x113 (System.Int32)
  10.     wParam:00000531 (System.IntPtr)
  11.     lParam:00000000 (System.IntPtr)
  12.     time:0xfbf4f32 (System.Int32)
  13.     pt_x:0x118 (System.Int32)
  14.     pt_y:0x42d (System.Int32)
复制代码
从卦中的 message:0x113 来看,这是经典的 WM_TIMER 消息,即定时器事件,用 C# 的话术就是窗体的 Timer 控件,参考MSDN截图:
1.png

接下来的关注点就是分析崩溃处的汇编代码了,使用 ub 命令反编译,输出如下:
  1. 0:000> .ecxr
  2. eax=15c96638 ebx=010fecb0 ecx=00000000 edx=000109a8 esi=000109a8 edi=0000001c
  3. eip=02f1d218 esp=010fec7c ebp=010feca8 iopl=0         nv up ei pl nz na pe nc
  4. cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010206
  5. 02f1d218 8b410c          mov     eax,dword ptr [ecx+0Ch] ds:002b:0000000c=????????
  6. 0:000> ub 02f1d218 La
  7. 02f1d200 50              push    eax
  8. 02f1d201 107567          adc     byte ptr [ebp+67h],dh
  9. 02f1d204 51              push    ecx
  10. 02f1d205 83ec04          sub     esp,4
  11. 02f1d208 ff7304          push    dword ptr [ebx+4]
  12. 02f1d20b ff7308          push    dword ptr [ebx+8]
  13. 02f1d20e ff730c          push    dword ptr [ebx+0Ch]
  14. 02f1d211 8b13            mov     edx,dword ptr [ebx]
  15. 02f1d213 8b4808          mov     ecx,dword ptr [eax+8]
  16. 02f1d216 8b09            mov     ecx,dword ptr [ecx]
复制代码
由于 02f1d218 处没有显示函数名,根据经验猜测,这个应该是 JIT 动态生成的小函数,并且 02f1d204 是函数的入口点,程序崩溃是因为执行了 ecx=0 导致的,接下来根据 ecx 的来源进行反推看看有没有新的发现,输出如下:
  1. 0:000> dp 15c96638+0x8 L1
  2. 15c96640  015a8658
  3. 0:000> dp 015a8658 L1
  4. 015a8658  00000000
  5. 0:000> !do 015a8658
  6. <Note: this object has an invalid CLASS field>
  7. Invalid object
  8. 0:000> !dumpmd 015a8658
  9. 015a8658 is not a MethodDesc
  10. 0:000> !dumpmt 015a8658
  11. 015a8658 is not a MethodTable
复制代码
从卦中看没有任何发现,015a8658 既不是 obj,也不是 mt,也不是 md ,这一下子就把我打入了黑暗之渊。。。
3. 在绝望中寻找希望

一时也没想到好办法,到门口边抽烟边思考, message:0x113 是一个 Win32 的 Timer,应该是 Timer 的定时回调在JIT的函数中意外崩掉了,按道理说在崩溃处的内存附近应该能找到与之对应的C# Timer,有了这个想法之后就在 015a8658 附近内存查找,还真给找到了,参考如下:
  1. 0:000> dp 015a8658 L4
  2. 015a8658  00000000 2d61d1a8 2d4ef48c 00000000
  3. 0:000> !do 2d61d1a8
  4. Name:        System.Windows.Forms.NativeMethods+WndProc
  5. MethodTable: 6f687200
  6. EEClass:     6f681458
  7. Size:        32(0x20) bytes
  8. File:        C:\windows\Microsoft.Net\assembly\GAC_MSIL\System.Windows.Forms\v4.0_4.0.0.0__b77a5c561934e089\System.Windows.Forms.dll
  9. Fields:
  10.       MT    Field   Offset                 Type VT     Attr    Value Name
  11. 71ec2734  40002f3        4        System.Object  0 instance 2d61d164 _target
  12. 71ec2734  40002f4        8        System.Object  0 instance 00000000 _methodBase
  13. 71ec7b18  40002f5        c        System.IntPtr  1 instance  5b73c34 _methodPtr
  14. 71ec7b18  40002f6       10        System.IntPtr  1 instance        0 _methodPtrAux
  15. 71ec2734  4000300       14        System.Object  0 instance 00000000 _invocationList
  16. 71ec7b18  4000301       18        System.IntPtr  1 instance        0 _invocationCount
  17. 0:000> !do 2d61d164
  18. Name:        System.Windows.Forms.Timer+TimerNativeWindow
  19. MethodTable: 6f6995e4
  20. EEClass:     6f6ede04
  21. Size:        56(0x38) bytes
  22. File:        C:\windows\Microsoft.Net\assembly\GAC_MSIL\System.Windows.Forms\v4.0_4.0.0.0__b77a5c561934e089\System.Windows.Forms.dll
  23. Fields:
  24.       MT    Field   Offset                 Type VT     Attr    Value Name
  25. 71ec2734  40005ba        4        System.Object  0 instance 00000000 __identity
  26. 71ec7b18  4001cf9       18        System.IntPtr  1 instance        0 handle
  27. 6f687200  4001cfa        8 ...veMethods+WndProc  0 instance 2d61d1a8 windowProc
  28. 71ec7b18  4001cfb       1c        System.IntPtr  1 instance 15ca1bee windowProcPtr
  29. 71ec7b18  4001cfc       20        System.IntPtr  1 instance 77a77f70 defWindowProc
  30. 71ec878c  4001cfd       28       System.Boolean  1 instance        1 suppressedGC
  31. 71ec878c  4001cfe       29       System.Boolean  1 instance        0 ownHandle
  32. 6f685da8  4001cff        c ...orms.NativeWindow  0 instance 00000000 previousWindow
  33. 6f685da8  4001d00       10 ...orms.NativeWindow  0 instance 00000000 nextWindow
  34. 71ec6018  4001d01       14 System.WeakReference  0 instance 2d61d19c weakThisPtr
  35. 70229854  4001d02       24         System.Int32  1 instance        0 windowDpiAwarenessContext
  36. 713fe7cc  4001ce3      b88 ...stics.TraceSwitch  0   static 00000000 WndProcChoice
  37. 71ec426c  4001ce4      b8c       System.Int32[]  0   static 03111988 primes
  38. 71ec878c  4001ceb     1312       System.Boolean  1   static        1 anyHandleCreatedInApp
  39. 71ec42a8  4001ced     1304         System.Int32  1   static     1786 handleCount
  40. 71ec42a8  4001cee     1308         System.Int32  1   static     2915 hashLoadSize
  41. 6f685e9c  4001cef      b90 ...ow+HandleBucket[]  0   static 2c7b5f14 hashBuckets
  42. 71ec7b18  4001cf0     130c        System.IntPtr  1   static 77a77f70 userDefWindowProc
  43. 71ec3a08  4001cf3     1313          System.Byte  1   static        0 userSetProcFlagsForApp
  44. 71ec882c  4001cf4     1310         System.Int16  1   static        1 globalID
  45. 71f1c594  4001cf5      b94 ...ntPtr, mscorlib]]  0   static 03111bc8 hashForIdHandle
  46. 71f1c6d0  4001cf6      b98 ...Int16, mscorlib]]  0   static 03111c3c hashForHandleId
  47. 71ec2734  4001cf7      b9c        System.Object  0   static 03111b90 internalSyncObject
  48. 71ec2734  4001cf8      ba0        System.Object  0   static 03111b9c createWindowSyncObject
  49. 71ec878c  4001cea      979       System.Boolean  1 TLstatic  anyHandleCreated
  50.     >> Thread:Value 20b0:1 <<
  51. 71ec3a08  4001cf1      97a          System.Byte  1 TLstatic  wndProcFlags
  52.     >> Thread:Value 20b0:1 <<
  53. 71ec3a08  4001cf2      97b          System.Byte  1 TLstatic  userSetProcFlags
  54.     >> Thread:Value 20b0:1 <<
  55. 6f69ad98  400415e       2c ...ndows.Forms.Timer  0 instance 14462858 _owner
  56. 71ec42a8  400415f       30         System.Int32  1 instance        0 _timerID
  57. 71ec878c  4004161       2a       System.Boolean  1 instance        0 _stoppingTimer
  58. 71ec42a8  4004160     190c         System.Int32  1   static     2462 TimerID
复制代码
从卦中的引用链来看,原来它是挂在 DevComponents.DotNetBar.Controls.ComboBoxEx 控件之下的,赶紧反向寻找源代码,截图如下:
2.png

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

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

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

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册