记一次 .NET 某企业审批系统 崩溃分析

记一次 .NET 某企业审批系统 崩溃分析

    正在检查是否收录...

一:背景

1. 讲故事

今年年初有位朋友在微信上找到我,说他们的系统在客户这边崩掉了,在代码中也加了全局异常处理但还是崩,不知道咋回事,让朋友在客户那边拿程序dump,拿到dump之后开始分析。

二:崩溃分析

1. 为什么会崩溃

既然是崩溃,那就用 !analyze -v 命令观察下windbg给我们整理的崩溃信息,看看可有蛛丝马迹。

 0:000> !analyze -v ******************************************************************************* * * * Exception Analysis * * * ******************************************************************************* CONTEXT: (.ecxr) eax=006fdb40 ebx=00000005 ecx=00000005 edx=00000000 esi=006fdc04 edi=00000001 eip=768f9132 esp=006fdb40 ebp=006fdb9c iopl=0 nv up ei pl nz ac po nc cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000212 KERNELBASE!RaiseException+0x62: 768f9132 8b4c2454 mov ecx,dword ptr [esp+54h] ss:002b:006fdb94=005b1570 Resetting default scope EXCEPTION_RECORD: (.exr -1) ExceptionAddress: 768f9132 (KERNELBASE!RaiseException+0x00000062) ExceptionCode: e0434352 (CLR exception) ExceptionFlags: 00000001 NumberParameters: 5 Parameter[0]: 80131604 Parameter[1]: 00000000 Parameter[2]: 00000000 Parameter[3]: 00000000 Parameter[4]: 72e90000 PROCESS_NAME: xxx.exe EXCEPTION_CODE_STR: 8007000e FAULTING_THREAD: ffffffff STACK_TEXT: 006fde30 07a0941c System_Drawing!System.Drawing.Graphics.FromHdcInternal+0x4c 006fde40 1173bbdb System_Drawing!System.Drawing.Font.GetHeight+0x5b 006fde70 1173bb4b System_Drawing!System.Drawing.Font.get_Height+0xb 006fde80 178658d4 DevExpress_Utils_v13_1!DevExpress.Utils.Frames.NotePanel.CalcSizes+0x304 006fdf4c 17864f4f DevExpress_Utils_v13_1!DevExpress.Utils.Frames.NotePanel.OnPaint+0x9f 006fe0b0 0705ab89 System_Windows_Forms!System.Windows.Forms.Control.PaintWithErrorHandling+0x89 006fe0e0 07058d75 System_Windows_Forms!System.Windows.Forms.Control.WmPaint+0x47d 006fe1d8 07a003db System_Windows_Forms!System.Windows.Forms.Control.WndProc+0x39b 006fe218 0707f821 System_Windows_Forms!System.Windows.Forms.Control+ControlNativeWindow.OnMessage+0x11 006fe220 0707f7f8 System_Windows_Forms!System.Windows.Forms.Control+ControlNativeWindow.WndProc+0xa0 006fe234 0707f227 System_Windows_Forms!System.Windows.Forms.NativeWindow.Callback+0x5f 

从卦中可以看到 ExceptionCode: e0434352,这很明显是一个 托管异常,既然是 托管异常 那为什么朋友的代码拦截不到呢?这就比较有意思了,那到底是什么类型的托管异常,用 !t 观察一下。

 0:000> !t ThreadCount: 13 UnstartedThread: 0 BackgroundThread: 11 PendingThread: 0 DeadThread: 1 Hosted Runtime: no Lock ID OSID ThreadOBJ State GC Mode GC Alloc Context Domain Count Apt Exception 0 1 68b4 00970248 26020 Preemptive 2BB06608:00000000 0096ad08 1 STA System.Reflection.TargetInvocationException 2baf5884 (nested exceptions) 2 2 8b90 0098a220 2b220 Preemptive 00000000:00000000 0096ad08 0 MTA (Finalizer) 5 4 1cc 05e3f308 202b220 Preemptive 00000000:00000000 0096ad08 0 MTA ... 

从卦中的 System.Reflection.TargetInvocationException 可以看到这是一个 调用目标异常,由于卦象上有 (nested exceptions) 标记,使用 !pe -nested 命令观察异常链走势。

 0:000> !pe -nested Exception object: 2baf5884 Exception type: System.Reflection.TargetInvocationException Message: 调用的目标发生了异常。 InnerException: System.ComponentModel.Win32Exception, Use !PrintException 96e70c07 to see more. StackTrace (generated): SP IP Function 00000000 00000001 mscorlib_ni!System.RuntimeMethodHandle.SerializationInvoke(System.IRuntimeMethodInfo, System.Object, System.Runtime.Serialization.SerializationInfo, System.Runtime.Serialization.StreamingContext ByRef)+0xffffffff8d074f41 xxx 006FDFF4 71891968 mscorlib_ni!System.Resources.RuntimeResourceSet.GetObject(System.String, Boolean, Boolean)+0x1e8 006FE074 7189B263 mscorlib_ni!System.Resources.RuntimeResourceSet.GetObject(System.String, Boolean)+0x13 006FE07C 7189331B mscorlib_ni!System.Resources.ResourceManager.GetObject(System.String, System.Globalization.CultureInfo, Boolean)+0x22b 006FE0DC 7194FD5B mscorlib_ni!System.Resources.ResourceManager.GetObject(System.String)+0xf 006FE0E0 07CB92F8 xxx.frmBase.InitializeComponent()+0x68 006FE0F0 0707308A xxx.frmBase..ctor()+0x42 006FE100 05202B3D xxx.frmErrorMessage..ctor()+0xd 006FE10C 05202A03 xxx.ExceptionHandler.HandlerErr(System.Exception)+0x23 006FE11C 052029C9 xxx.UnhandledExceptionManager.Application_ThreadException(System.Object, System.Threading.ThreadExceptionEventArgs)+0x9 006FE120 052027E8 System_Windows_Forms!System.Windows.Forms.Application+ThreadContext.OnThreadException(System.Exception)+0x88 006FE15C 05202746 System_Windows_Forms!System.Windows.Forms.Control.WndProcException(System.Exception)+0x16 006FE168 0520271A System_Windows_Forms!System.Windows.Forms.Control+ControlNativeWindow.OnThreadException(System.Exception)+0xa 006FE16C 0707F256 System_Windows_Forms!System.Windows.Forms.NativeWindow.Callback(IntPtr, Int32, IntPtr, IntPtr)+0x8e StackTraceString: <none> HResult: 80131604 Nested exception ------------------------------------------------------------- Exception object: 2baeb3b0 Exception type: System.OutOfMemoryException Message: 内存不足。 InnerException: <none> StackTrace (generated): SP IP Function 006FDE30 07A0941C System_Drawing!System.Drawing.Graphics.FromHdcInternal(IntPtr)+0x4c 006FDE40 1173BBDB System_Drawing!System.Drawing.Font.GetHeight()+0x5b 006FDE70 1173BB4B System_Drawing!System.Drawing.Font.get_Height()+0xb 006FDE80 178658D4 DevExpress_Utils_v13_1!DevExpress.Utils.Frames.NotePanel.CalcSizes(System.Drawing.Graphics)+0x304 006FDF4C 17864F4F DevExpress_Utils_v13_1!DevExpress.Utils.Frames.NotePanel.OnPaint(System.Windows.Forms.PaintEventArgs)+0x9f 006FE0B0 0705AB89 System_Windows_Forms!System.Windows.Forms.Control.PaintWithErrorHandling(System.Windows.Forms.PaintEventArgs, Int16)+0x89 006FE0E0 07058D75 System_Windows_Forms!System.Windows.Forms.Control.WmPaint(System.Windows.Forms.Message ByRef)+0x47d 006FE1D8 07A003DB System_Windows_Forms!System.Windows.Forms.Control.WndProc(System.Windows.Forms.Message ByRef)+0x39b 006FE218 0707F821 System_Windows_Forms!System.Windows.Forms.Control+ControlNativeWindow.OnMessage(System.Windows.Forms.Message ByRef)+0x11 006FE220 0707F7F8 System_Windows_Forms!System.Windows.Forms.Control+ControlNativeWindow.WndProc(System.Windows.Forms.Message ByRef)+0xa0 006FE234 0707F227 System_Windows_Forms!System.Windows.Forms.NativeWindow.Callback(IntPtr, Int32, IntPtr, IntPtr)+0x5f StackTraceString: <none> HResult: 8007000e 

从卦象看,程序是先抛出了 OutOfMemoryException 异常,在全局异常处理中再次抛出 TargetInvocationException 引发程序崩溃,接下来看下为什么会抛 OutOfMemoryException 异常呢?导出源代码观察,简化后如下:

 public float GetHeight() { IntPtr dC = UnsafeNativeMethods.GetDC(NativeMethods.NullHandleRef); float num = 0f; try { using Graphics graphics = Graphics.FromHdcInternal(dC); return GetHeight(graphics); } finally { UnsafeNativeMethods.ReleaseDC(NativeMethods.NullHandleRef, new HandleRef(null, dC)); } } public static Graphics FromHdcInternal(IntPtr hdc) { IntPtr graphics = IntPtr.Zero; int num = SafeNativeMethods.Gdip.GdipCreateFromHDC(new HandleRef(null, hdc), out graphics); if (num != 0) { throw SafeNativeMethods.Gdip.StatusException(num); } return new Graphics(graphics); } internal static Exception StatusException(int status) { return status switch { 2 => new ArgumentException(SR.GetString("GdiplusInvalidParameter")), 3 => new OutOfMemoryException(SR.GetString("GdiplusOutOfMemory")), ... }; } 

从卦象看,应该就是 GdipCreateFromHDC 方法返回 num=3,继而代码上手工 throw OutOfMemoryException,这里不是引发程序崩溃的直接原因,所以暂时就不深究了,转头关注核心的 HandlerErr 方法。

2. 全局异常处理崩溃探究

接下来回头看为什么 Application_ThreadException -> HandlerErr 全局异常处理中会再次抛异常?观察源代码发现是在初始化 frmErrorMessage 的时候抛错的。。。无语了。。。难怪拦截不到,截图如下:

记一次 .NET 某企业审批系统 崩溃分析

细心的朋友会发现上面还有一句话 System.ComponentModel.Win32Exception, Use !PrintException 96e70c07 to see more.,即 TargetInvocationException 的内部还有一个异常 Win32Exception,可以用 !pe 显示出来。

 0:000> !PrintException /d 2baf5360 Exception object: 2baf5360 Exception type: System.ComponentModel.Win32Exception Message: 操作成功完成。 InnerException: <none> StackTrace (generated): SP IP Function 006FDA9C 07CBA3BA System_Drawing!System.Drawing.Icon.Initialize(Int32, Int32)+0x83a 006FDB6C 07CB9B49 System_Drawing!System.Drawing.Icon..ctor(System.Runtime.Serialization.SerializationInfo, System.Runtime.Serialization.StreamingContext)+0xc1 StackTraceString: <none> HResult: 80004005 There are nested exceptions on this thread. Run with -nested for details 

到这里逻辑基本就搞清楚了。

  1. 业务代码在 System.Drawing.Graphics.FromHdcInternal 处抛了一个 OutOfMemoryException 进入全局异常拦截。
  2. 在全局异常拦截中,又不幸在 new frmErrorMessage()System.Drawing.Icon.Initialize 处抛出了 Win32Exception 异常。

最后就是 Icon.Initialize 函数为什么会抛异常?说实话我也搞不清楚,在 stackoverflow https://stackoverflow.com/questions/2356580/system-drawing-icon-constructor-throwing-operation-completed-successfully-exce 上找到了这样的解读,截图如下:

记一次 .NET 某企业审批系统 崩溃分析

最后给到朋友的建议:

  1. 设置多尺寸的 icon 图片,再观察效果。
  2. 修改 frmErrorMessage,避免双异常。

三:总结

本次事故是 多异常的联合作战 成功在高压的全局异常拦截方法Application_ThreadException中逃逸,是不是非常的有意思,示警大家,警惕被偷家!

记一次 .NET 某企业审批系统 崩溃分析
  • 本文作者:WAP站长网
  • 本文链接: https://wapzz.net/post-27518.html
  • 版权声明:本博客所有文章除特别声明外,均默认采用 CC BY-NC-SA 4.0 许可协议。
本站部分内容来源于网络转载,仅供学习交流使用。如涉及版权问题,请及时联系我们,我们将第一时间处理。
文章很赞!支持一下吧 还没有人为TA充电
为TA充电
还没有人为TA充电
0
0
  • 支付宝打赏
    支付宝扫一扫
  • 微信打赏
    微信扫一扫
感谢支持
文章很赞!支持一下吧
关于作者
2.8W+
9
1
2
WAP站长官方

《刚刚问世》系列初窥篇

上一篇

【渲染流水线】[逐片元阶段]

下一篇
评论区
内容为空

这一切,似未曾拥有

  • 复制图片
按住ctrl可打开默认菜单