news 2026/4/16 15:12:19

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

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
记一次 .NET 某医联体管理系统 崩溃分析

一:背景

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 是一个类级别变量,看样子是多个方法在操控类级别变量时没有合理的控制好,为了一探究竟,再次分析源代码,果然是的,截图如下:

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/15 17:54:30

iOS功能开关革命:如何用动态配置重塑你的应用架构

iOS功能开关革命:如何用动态配置重塑你的应用架构 【免费下载链接】awesome-ios-architecture :japanese_castle: Better ways to structure iOS apps 项目地址: https://gitcode.com/gh_mirrors/aw/awesome-ios-architecture 还在为每次功能发布而提心吊胆吗…

作者头像 李华
网站建设 2026/4/15 22:52:20

JMeter分布式测试部署实战指南

随着现代应用架构日趋复杂,单机负载测试往往无法模拟真实的高并发场景。Apache JMeter的分布式测试功能通过多台机器协同工作,能够有效突破单机性能瓶颈,实现更真实的压力模拟。本文将深入探讨JMeter分布式测试的完整部署流程,为软…

作者头像 李华
网站建设 2026/4/16 9:02:52

腾讯混元图像3.0登顶全球:800亿参数重构开源生图格局

腾讯混元图像3.0登顶全球:800亿参数重构开源生图格局 【免费下载链接】HunyuanImage-3.0-Instruct HunyuanImage-3.0 通过自回归框架统一多模态理解与生成,文本生成图像表现媲美或超越顶尖闭源模型 项目地址: https://ai.gitcode.com/tencent_hunyuan/…

作者头像 李华
网站建设 2026/4/16 9:04:17

Nacos 2.4.2命名空间异常完整修复指南:从问题诊断到彻底解决

Nacos 2.4.2命名空间异常完整修复指南:从问题诊断到彻底解决 【免费下载链接】nacos Nacos是由阿里巴巴开源的服务治理中间件,集成了动态服务发现、配置管理和服务元数据管理功能,广泛应用于微服务架构中,简化服务治理过程。 项…

作者头像 李华
网站建设 2026/4/16 9:05:29

现代C++工程实践:简单的IniParser4——实现ini_parser

现代C工程实践:简单的IniParser4——实现ini_parser 前言 在上一篇博客中,我们已经完成了split的优化。现在我们即将开始我们工作的核心。这就是说,在项目工程的前期,我们把一些基建搞定了,由于IniParser很简单&#x…

作者头像 李华
网站建设 2026/4/16 9:02:07

Springboot简单二手车网站qs5ed(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。

系统程序文件列表项目功能:用户,商家,车辆品牌,车辆信息,定金支付,预约到店,评估报价,签订合同,通知公告,在线咨询开题报告内容一、研究背景与意义1.1 行业背景随着中国汽车保有量突破3亿辆,二手车交易市场规模持续扩大。2024年数据显示,全国…

作者头像 李华