一:背景

1. 讲故事

这段时间都在跑外卖,感觉好久都没写文章了,今天继续给大家带来一篇崩溃类的生产事故,这是微信上有位老朋友找到我的,让我帮忙看下为啥崩溃了,dump也在手,接下来就可以一顿分析。

二:崩溃分析

1. 为什么会崩溃

双击打开dump文件,会看到崩溃信息通览,参考如下:


Executable search path is:
Windows 10 Version 17763 MP (48 procs) Free x64
Product: Server, suite: TerminalServer DataCenter SingleUserTS
Edition build lab: 17763.1.amd64fre.rs5_release.180914-1434
Debug session time: Fri Oct 31 17:38:42.000 2025 (UTC + 8:00)
System Uptime: 14 days 2:42:29.643
Process Uptime: 0 days 0:00:58.000
................................................................
.......................................
Loading unloaded module list
.
This dump file has an exception of interest stored in it.
The stored exception information can be accessed via .ecxr.
(5a74.6250): Unknown exception - code c0000374 (first/second chance not available)
For analysis of this file, run !analyze -v
ntdll!NtWaitForMultipleObjects+0x14:
00007ffe`57baf0e4 c3 ret

从卦中看崩溃码是 c0000374,即 ntheap 损坏,哈哈,到这里一下子就把范围给缩小了。

2. 为什么ntheap 损坏

那为什么ntheap会损坏呢?可以使用 .ecxr 切到崩溃时的调用栈,观察崩溃行为。


0:032> .ecxr 0:032> k
*** Stack trace for last set context - .thread/.cxr resets it
# Child-SP RetAddr Call Site
00 000000b4`8503ede0 00007ffe`57c0b313 ntdll!RtlReportFatalFailure+0x9
01 000000b4`8503ee30 00007ffe`57c13b9e ntdll!RtlReportCriticalFailure+0x97
02 000000b4`8503ef20 00007ffe`57c13eaa ntdll!RtlpHeapHandleError+0x12
03 000000b4`8503ef50 00007ffe`57bae109 ntdll!RtlpHpHeapHandleError+0x7a
04 000000b4`8503ef80 00007ffe`57bbbb0e ntdll!RtlpLogHeapFailure+0x45
05 000000b4`8503efb0 00007ffe`17d17b3f ntdll!RtlFreeHeap+0x9d3ce
06 000000b4`8503f050 00007ffe`541392af AcLayers!NS_FaultTolerantHeap::APIHook_RtlFreeHeap+0x41f
07 000000b4`8503f0b0 00007ffe`3773b17e KERNELBASE!LocalFree+0x2f
08 000000b4`8503f0f0 00007ffe`37661d12 mscorlib_ni+0x58b17e
09 000000b4`8503f1a0 00007ffd`e49fe127 mscorlib_ni!System.Runtime.InteropServices.Marshal.FreeHGlobal+0x22 [f:\dd\ndp\clr\src\BCL\system\runtime\interopservices\marshal.cs @ 1212]
... 0:032> !clrstack
OS Thread Id: 0x6250 (32)
Child SP IP Call Site
000000b48503f118 00007ffe57baf0e4 [InlinedCallFrame: 000000b48503f118] Microsoft.Win32.Win32Native.LocalFree(IntPtr)
000000b48503f118 00007ffe3773b17e [InlinedCallFrame: 000000b48503f118] Microsoft.Win32.Win32Native.LocalFree(IntPtr)
000000b48503f0f0 00007ffe3773b17e DomainNeutralILStubClass.IL_STUB_PInvoke(IntPtr)
000000b48503f1a0 00007ffe37661d12 System.Runtime.InteropServices.Marshal.FreeHGlobal(IntPtr) [f:\dd\ndp\clr\src\BCL\system\runtime\interopservices\marshal.cs @ 1212]
000000b48503f1e0 00007ffde49fe127 b.B+A.MoveNext()
000000b48503f240 00007ffe376b3423 System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean) [f:\dd\ndp\clr\src\BCL\system\threading\executioncontext.cs @ 954]
000000b48503f310 00007ffe376b32b4 System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean) [f:\dd\ndp\clr\src\BCL\system\threading\executioncontext.cs @ 902]
...
000000b48503f5c0 00007ffde49fb04e DomainBoundILStubClass.IL_STUB_ReversePInvoke(Int32, Int32, Int64)

从卦中可以清晰的看到是 b.B+A.MoveNext 方法中调用了 FreeHGlobal 导致的NTHeap崩溃,如果你经验比较足的话,看到这个 FreeHGlobal 就应该想到 double free 问题,这是一个经典的问题。

3. 何为 double free

双释放即对一个 block 块进行二次释放,windows 的 RtlFreeHeap 方法会在业务逻辑中对这种情况直接判为异常,接下来你或许想知道这个 block 的地址是什么?这个可以用 !heap -s 观察,参考代码如下:


0:032> !heap -s ************************************************************************************************************************
NT HEAP STATS BELOW
************************************************************************************************************************ Details: Heap address: 0000028c75bb0000
Error address: 0000028c786018a0
Error type: HEAP_FAILURE_BLOCK_NOT_BUSY
Details: The caller performed an operation (such as a free
or a size check) that is illegal on a free block.
Follow-up: Check the error's stack trace to find the culprit. Stack trace:
Stack trace at 0x00007ffe57c72848
00007ffe57bae109: ntdll!RtlpLogHeapFailure+0x45
00007ffe57bbbb0e: ntdll!RtlFreeHeap+0x9d3ce
00007ffe17d17b3f: AcLayers!NS_FaultTolerantHeap::APIHook_RtlFreeHeap+0x41f
00007ffe541392af: KERNELBASE!LocalFree+0x2f
00007ffe3773b17e: mscorlib_ni+0x58b17e
00007ffe37661d12: mscorlib_ni!System.Runtime.InteropServices.Marshal.FreeHGlobal+0x22
00007ffde49fe127: +0xe49fe127 LFH Key : 0x765363a7204cf973
Termination on corruption : ENABLED
Heap Flags Reserv Commit Virt Free List UCR Virt Lock Fast
(k) (k) (k) (k) length blocks cont. heap
-------------------------------------------------------------------------------------
0000028c75bb0000 00000002 17920 9256 16364 2120 214 5 1 a LFH
External fragmentation 23 % (214 free blocks)
0000028c75b40000 00008000 64 4 64 2 1 1 0 0
0000028c75de0000 00001002 2636 132 1080 20 5 2 0 0 LFH
0000028c76190000 00001002 4680 2268 3124 1420 40 3 0 0 LFH
External fragmentation 62 % (40 free blocks)
0000028c76130000 00001002 2636 472 1080 5 27 2 0 0 LFH
0000028c767f0000 00041002 60 8 60 5 1 1 0 0
0000028c77020000 00041002 60 16 60 2 2 1 0 0
-------------------------------------------------------------------------------------

从卦中可以看到 Heap address: 0000028c75bb0000 即为 block 地址,接下来使用 !heap -x 0000028c786018a0 观察这个 block 块的状态,可以看到此时确实是 free 的。


0:032> !heap -x 0000028c786018a0
Entry User Heap Segment Size PrevSize Unused Flags
-------------------------------------------------------------------------------------------------------------
0000028c786018a0 0000028c786018b0 0000028c75bb0000 0000028c785c80d0 e0 - 0 LFH;free

到这里问题的成因我们是完全搞清楚了,接下来就是反推问题代码的时候了。

4. 问题代码在哪里

应该有朋友知道问题是在 b.B+A.MoveNext() 方法中,从名字上看这个项目应该是混淆的,有点搞哈。。。得要费点眼力,截图如下:

从卦中的 IntPtr intPtr = Interlocked.Exchange(ref b.A, IntPtr.Zero); 来看,这个 intPtr 是一个类级别变量,看样子是多个方法在操控类级别变量时没有合理的控制好,为了一探究竟,再次分析源代码,果然是的,截图如下:

到这里就真相大白了,让朋友修改源码自己控制好这个变量。

三:总结

这次生产事故是一个比较经典的 doublefree 问题,没接触过的话可能还是需要走一些弯路的,像我们这种老江湖,看到一二个特征这个问题就经注定解开!

记一次 .NET 某医联体管理系统 崩溃分析的更多相关文章

  1. 记一次 .NET 某医保平台 CPU 爆高分析

    一:背景 1. 讲故事 一直在追这个系列的朋友应该能感受到,我给这个行业中无数的陌生人分析过各种dump,终于在上周有位老同学找到我,还是个大妹子,必须有求必应 . 妹子公司的系统最近在某次升级之后, ...

  2. 记一次 .NET 某工控MES程序 崩溃分析

    一:背景 1.讲故事 前几天有位朋友找到我,说他的程序出现了偶发性崩溃,已经抓到了dump文件,Windows事件日志显示的崩溃点在 clr.dll 中,让我帮忙看下是怎么回事,那到底怎么回事呢? 上 ...

  3. 记一次 .NET 某教育系统API 异常崩溃分析

    一:背景 1. 讲故事 这篇文章起源于 搬砖队大佬 的精彩文章 WinDBg定位asp.net mvc项目异常崩溃源码位置 ,写的非常好,不过美中不足的是通览全文之后,总觉得有那么一点不过瘾,就是没有 ...

  4. 记一次 .NET 某自动化集采软件 崩溃分析

    一:背景 1.讲故事 前段时间有位朋友找到我,说他的程序在客户的机器上跑着跑着会出现偶发卡死,然后就崩掉了,但在本地怎么也没复现,dump也抓到了,让我帮忙看下到底怎么回事,其实崩溃类的dump也有简 ...

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

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

  6. 记一次常规的Mysql数据库访问的时间分析

    背景:记一次常规的数据访问的时间分析(插入操作) 1. TCP三次握手 SYN ---> <--- SYN,ACK ACK ---> 花费时间: 386.718-385.784=0. ...

  7. 记一次 Windows10 内存压缩模块 崩溃分析

    一:背景 1. 讲故事 在给各位朋友免费分析 .NET程序 各种故障的同时,往往也会收到各种其他类型的dump,比如:Windows 崩溃,C++ 崩溃,Mono 崩溃,真的是啥都有,由于基础知识的相 ...

  8. 记一次WMS的系统改造(1)-分析问题

    海外落地中的困境 目前面临主要的问题是"人",仓储系统主要辅助仓储人员进行生产,所以人变了其实一切就都已经变了,系统在海外面临最大的问题就是人变了. 这套软件是在国内的运营体系 ...

  9. 记一次bypass某场景GD库及拓展分析

    0x00 前言 gou楼兰师傅发来个站说是过不了gd库,问我有啥办法没有,给了他之前海贼师傅说的jpg_payload脚本,但是绕不过,问他拿了站点,写了个jpg_payload批量的fuzz脚本,f ...

  10. 记一次 .NET游戏站程序的 CPU 爆高分析

    一:背景 1. 讲故事 上个月有个老朋友找到我,说他的站点晚高峰 CPU 会突然爆高,发了两份 dump 文件过来,如下图: 又是经典的 CPU 爆高问题,到目前为止,对这种我还是有一些经验可循的. ...

随机推荐

  1. RENIX_Python_如何实现调速——网络测试仪实操

    1.Renix如何进行调速 Renix通过两种方式对流量进行调速一种是基于端口调速(Base On Port),一种是基于流调速(Base On Stream). 1.1Base On Port 基于 ...

  2. 西门子S7-200的VB、VW和VD

    西门子S7-200的VB.VW和VDs7-200中vd和VW有什么区别? VD是双字 VW是字 V表示变量储存区 字节.字或双字存取欲存取字节.字或双字,指定地址,地址包含区域标识符,指定数据大小的字 ...

  3. msys2 mingw64 ffmpeg 搭建最新ffmpeg编译环境 可用 ffmpeg 4.1 及更新版本

    介绍 最近需要编译Windows版本ffmpeg,各种折腾,最后从一个大神那找到了方案, 非常感谢 liaofeifly 这位大神. 不多说直接来说明怎么搭环境: 1. 下载msys2 https:/ ...

  4. GB28181流媒体服务LiveGBS前端源码(vue+webpack)

    各位,为了方便大家学习和使用LiveGBS,现已将 LiveGBS前端源码开源,https://github.com/livegbs/GB28181-Server ,欢迎大家前去下载,如果用帮助的话帮 ...

  5. 天梯赛 L2-018 多项式A除以B

    题目 这仍然是一道关于A/B的题,只不过A和B都换成了多项式.你需要计算两个多项式相除的商Q和余R,其中R的阶数必须小于B的阶数. 输入格式: 输入分两行,每行给出一个非零多项式,先给出A,再给出B. ...

  6. 域渗透靶场-vulntarget-a综合靶场

    nmap发现开放80端口 浏览器访问,是通达oa 可以搜索poc或者使用oa利用工具拿到shell 通过账号admin 密码滞空,进入后台 我们这里使用通达OA 11.2 后台getshell 点击系 ...

  7. AGC自动增益控制电路

    前言 本文章作为笔记分享出来,原内容出自: [AGC自动增益控制电路原理] AGC十分适用于单片机的ADC信号采样,可以限制输入信号的幅度变化,使得当输入信号变化的时候,后面信号处理的部分是不受影响. ...

  8. 无线电通信卡:9-基于DSP TMS320C6678+FPGA XC7V690T的6U VPX信号处理卡

    一.概述 本板卡基于标准6U VPX 架构,为通用高性能信号处理平台,系我公司自主研发.板卡采用一片TI DSP TMS320C6678和一片Xilinx公司Virtex 7系列的FPGA XC7V6 ...

  9. ORA-600 kzrini:!uprofile处理----惜分飞

    联系:手机/微信(+86 17813235971) QQ(107644445) 标题:ORA-600 kzrini:!uprofile处理 作者:惜分飞版权所有[未经本人同意,不得以任何形式转载,否则 ...

  10. Java源码:坦克大战+swing界面+大学生练手项目

    前言 学Java的朋友们,福利来了,今天小编给大家带来了一款 坦克大战 源码,看图: 演示视频 https://githubs.xyz/show/22.mp4 环境 JDK1.8 实现步骤 代码采用原 ...