news 2026/5/28 12:54:34

记一次 .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/5/28 0:44:30

5个高效调试技巧:如何实现API开发效率倍增

5个高效调试技巧:如何实现API开发效率倍增 【免费下载链接】swagger-ui Swagger UI is a collection of HTML, JavaScript, and CSS assets that dynamically generate beautiful documentation from a Swagger-compliant API. 项目地址: https://gitcode.com/Git…

作者头像 李华
网站建设 2026/5/24 22:13:44

归并排序:3步拆解,从困惑到精通的实战指南

归并排序:3步拆解,从困惑到精通的实战指南 【免费下载链接】algorithm-base 一位酷爱做饭的程序员,立志用动画将算法说的通俗易懂。我的面试网站 www.chengxuchu.com 项目地址: https://gitcode.com/gh_mirrors/al/algorithm-base 还在…

作者头像 李华
网站建设 2026/5/27 9:26:40

LookingGlass与OBS深度整合:打造专业级直播录屏体验的终极指南

想要实现零延迟的游戏直播效果吗?LookingGlass与OBS的完美结合为您提供了理想的解决方案。作为一款专为VGA PCI直通虚拟机设计的极低延迟KVMFR实现,LookingGlass通过共享内存技术彻底改变了传统录屏方式,让您的直播画面更加流畅自然。&#x…

作者头像 李华
网站建设 2026/5/28 2:36:15

Redisson与Spring Boot版本兼容性问题的完整解决方案

在Java开发领域,Redisson作为功能强大的Redis客户端,与Spring Boot的集成使用非常普遍。然而,版本兼容性问题常常成为开发者的绊脚石。本文将深入分析Redisson与Spring Boot版本冲突的技术原理,并提供切实可行的解决方案。 【免费…

作者头像 李华
网站建设 2026/5/22 19:58:22

如何快速掌握C语言编程?谭浩强第五版PPT完整资源助你轻松入门

如何快速掌握C语言编程?谭浩强第五版PPT完整资源助你轻松入门 【免费下载链接】C程序设计第五版谭浩强著PPT资源下载 - **标题**: C程序设计(第五版)谭浩强 著PPT- **内容**: 本课件共有十章,涵盖了C语言的基础知识和高级应用。每…

作者头像 李华