记一次 .NET 某医联体管理系统 崩溃分析

news/2025/11/12 17:57:28/文章来源:https://www.cnblogs.com/huangxincheng/p/19214907

一:背景

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> .ecxr0: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 freeor 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 0x00007ffe57c7284800007ffe57bae109: ntdll!RtlpLogHeapFailure+0x4500007ffe57bbbb0e: ntdll!RtlFreeHeap+0x9d3ce00007ffe17d17b3f: AcLayers!NS_FaultTolerantHeap::APIHook_RtlFreeHeap+0x41f00007ffe541392af: KERNELBASE!LocalFree+0x2f00007ffe3773b17e: mscorlib_ni+0x58b17e00007ffe37661d12: mscorlib_ni!System.Runtime.InteropServices.Marshal.FreeHGlobal+0x2200007ffde49fe127: +0xe49fe127LFH Key                   : 0x765363a7204cf973
Termination on corruption : ENABLEDHeap     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   LFHExternal 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   LFHExternal 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 问题,没接触过的话可能还是需要走一些弯路的,像我们这种老江湖,看到一二个特征这个问题就经注定解开!
图片名称

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/963660.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何构建可信智能 Data Agent?推荐 Aloudata Agent 分析决策智能体

企业构建可信智能的 Data Agent 需以强大的数据底座为支撑,统一指标语义层和 NoETL 数据工程成为关键摘要: 在 AI 与大数据深度融合的当下,数据分析民主化日渐火热。Aloudata Agent 分析决策智能体依托于统一的指标…

Java 集合-Set

Java 集合 - Set 详解 集合(Set)是用于存储和处理无重复元素的高效数据结构,映射表(Map)则类似目录,支持通过键值快速查询和获取对应值。例如检验某人是否在论文答辩名单中,用 Set 实现比线性表更高效;若需存储…

#题解#牛客:牛牛的构造#DP#构造#

传送门 分析 1.容易发现的一件事,当n,n-1,n-2......2,1排列时是满足条件的(i,j)对最多的n排列 2.我们用递推的想法求每一个n的最大(i,j)对数ans[n] ans[0] = 0;int pre = 0;int x = 0;for (int i = 1; i <= …

Machine Learning - SVM Part 2: The Radial Kernel

Machine Learning - SVM Part 2: The Radial Kernel

2025-11-12 ZYZ28-NOIP-aoao round 2 hetao1733837的record

2025-11-12 ZYZ28-NOIP-aoao round 2 hetao1733837的record比赛链接:比赛详情 - ZYZ28-NOIP-aoao round 2 - ZYZOJ 比赛背景 昨天双十一,ZYZ著名NOI Cu选手@[TaoRan](用户详情 - TaoRan - ZYZOJ)爆出了惊天大瓜——…

2025/11/12

2025/11/12滑动窗口的核心是通过维护一个动态调整的 “窗口”(连续子区间),用 O (n) 时间复杂度替代暴力枚举的 O (n),避免重复计算。 其核心逻辑是用左右指针界定窗口范围,根据问题条件移动指针收缩或扩展窗口,…

redis stream介绍

介绍 redis stream是一种类似日志追加的数据结构。可用来记录和实时处理事件。适用场景:事件溯源 传感器监控 通知性能 新增 O(1) 访问单个节点是O(n),n是ID的长度 redis stream使用radix trees实现 基础 XADD 新增条…

Java 线性表、栈、队列和优先队列

Java 线性表、栈、队列和优先队列 选择合适的数据结构和算法是开发高性能软件的关键。数据结构是按特定形式组织数据的集合,不仅存储数据,还支持数据的访问与处理操作。 在面向对象思想中,数据结构被视为容器或容器…

2025/11/11

2025/11/11全流程开发逻辑 从前端表单设计、后端 Servlet 处理、DAO 层数据库操作,到 MySQL 表结构设计,完整覆盖了 “用户交互 -> 业务逻辑 -> 数据存储” 的 Web 应用开发流程。 问题排查方法 面对代码报错,…

植物大战僵尸修改器下载教程:图文详解与实用技巧

前言: 在塔防游戏还没有被各类快节奏手游占据之前,《植物大战僵尸》几乎是每位玩家电脑中必装的一款经典作品。即便十多年过去,它依然凭借简单的机制与极高的策略深度拥有极强的生命力。 对于不少老玩家来说,玩到中…

微服务——注册中心

常见的注册中心:eureka、nacos、zookeeper 服务注册和发现是什么意思?Spring Cloud是如何实现服务注册发现? 服务注册:服务提供者需要把自己的信息注册到eureka,由eureka来保存这些信息,比如服务名称、IP、端口等…

【深度学习计算机视觉】13:实战Kaggle比赛:图像分类 (CIFAR-10) - 指南

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

fabricjs 整合 vue3-sketch-ruler 实现标尺功能

版本信息 fabricjs版本为6.7.1 ------ vue3-sketch-ruler的版本为1.3.15 引入标尺的部分代码<!-- 画布区域 --><div id="workspace" style="width: 100%;height: 100%; position: relative; …

2025年真空耙式干燥机定做厂家权威推荐榜单:真空单锥螺带干燥机/沸腾床干燥机/闪蒸干燥机源头厂家精选

在精细化工与制药行业对热敏性物料干燥要求日益严格的背景下,一台高性能的真空耙式干燥机已成为保障产品质量、提升生产效率的关键装备。 据干燥设备行业数据显示,2024年中国真空干燥设备市场规模达到87亿元,年增长…

基础查找算法(三)二分查找

基础查找算法(三)二分查找一 定义 二分查找(Binary Search)是一种基于分治策略的高效查找算法,专用于有序数据集合。它通过不断将搜索范围减半来快速定位目标元素,具有对数时间复杂度,适合处理大规模静态数据。…

2025年软像套电缆订做厂家权威推荐榜单:补偿电缆/矿物质电缆/电力电缆源头厂家精选

在工业自动化与智能制造浪潮中,一根高品质的软像套电缆不仅是电力与信号的传输载体,更是保障设备稳定运行的关键。 据行业数据显示,全球工业电缆市场规模预计到2031年将达到千亿级别,年复合增长率稳定提升。软像套…

2025年济南统招专升本学校权威推荐榜单:专升本机构报名/全日制专升本/专升本考试培训学校精选

在山东省专升本录取率持续走低的背景下,选择一家优质的统招专升本培训机构已成为考生成功升本的关键因素。 根据山东省教育招生考试院公布的数据,2024年山东专升本报考人数已突破17万,而总招生计划仅为7.6万人左右,…

一些水题

https://www.luogu.com.cn/problem/CF374B点击查看代码 #include <bits/stdc++.h> using namespace std;/*CF374B - Inna and Nine思路:- 找到字符串中所有 maximal 的“相邻两位和为9”的连续段(段内任意相邻…

(3)Bug篇 - 详解

(3)Bug篇 - 详解2025-11-12 17:29 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-fam…

西林瓶灌装轧盖机:黔东南折旧年限与成本解析

在黔东南地区,随着生物医药、民族医药及大健康产业的快速发展,对西林瓶灌装设备的需求持续增长。无论是本地药企扩产,还是新兴诊断试剂企业建线,西林瓶灌装轧盖机作为核心装备之一,其采购决策不仅关乎生产效率,更…