记一次 .NET某工控 宇宙射线 导致程序崩溃分析
一:背景
1. 讲故事
为什么要提 宇宙射线, 太阳耀斑 导致的程序崩溃呢?主要是昨天在知乎上看了这篇文章:莫非我遇到了传说中的bug? ,由于 rip 中的0x41变成了0x61出现了bit位翻转导致程序崩溃,截图如下:


下面的评论大多是说由于 宇宙射线,这个太玄乎了,说实话看到这个 传说bug 的提法,我还是挺兴奋的,毕竟在我的分析旅程中,我也是真的遇到过,这篇就拿出来给大家分享吧,当时百思不得其解,真的是无语死了。
这位朋友找到我的时候,说程序会出现偶发性崩溃,自己在网上也发了很多帖子来寻找答案,最后都不了了之,问题确实太玄乎了,这一篇我们就开始这个奇妙之旅吧。
二:Windbg 分析
1. 为什么会崩溃
找崩溃点比较简单,使用windbg 自带的 !analyze -v 命令去挖那个 EXCEPTION_POINTERS 结构体即可。
0:083> !analyze -v
CONTEXT: (.ecxr)
rax=0000024f82c77341 rbx=000000f275dfe7f0 rcx=00007ffb05e55658
rdx=7ffb083d8c582d89 rsi=0000000000000000 rdi=000000f275dfe300
rip=00007ffb64be082f rsp=000000f275dfeaa0 rbp=000000007ffb05ee
r8=0000024ff9bc0810 r9=deb6f5c6f59b3377 r10=1441a86c71655650
r11=ebbed78e94800000 r12=00007ffb05e55640 r13=0000000000000020
r14=0000024b26a3d9e0 r15=0000024f82c77340
iopl=0 ov up ei ng nz na po cy
cs=0033 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010a85
clr!WKS::gc_heap::background_mark_simple1+0x516:
00007ffb`64be082f 4c8b02 mov r8,qword ptr [rdx] ds:7ffb083d`8c582d89=????????????????
Resetting default scope
EXCEPTION_RECORD: (.exr -1)
ExceptionAddress: 00007ffb64be082f (clr!WKS::gc_heap::background_mark_simple1+0x0000000000000516)
ExceptionCode: c0000005 (Access violation)
ExceptionFlags: 00000001
NumberParameters: 2
Parameter[0]: 0000000000000000
Parameter[1]: ffffffffffffffff
Attempt to read from address ffffffffffffffff
STACK_TEXT:
000000f2`75dfeaa0 00007ffb`64be03a0 : clr!WKS::gc_heap::background_mark_simple1+0x516
000000f2`75dfeb00 00007ffb`64be074e : clr!WKS::gc_heap::background_mark_simple+0x6d
000000f2`75dfeb30 00007ffb`64a45fc7 : clr!WKS::gc_heap::background_promote+0x98
...
从卦中数据看,当前触发了后台GC,并且处于标记阶段,在标记托管堆上的对象时发现了有坏对象,无奈只能触发 CLR执行引擎异常,这也说明当前的托管堆是处于损坏状态,可以用 !verifyheap 命令验证一下。
0:083> !verifyheap
object 0000024f82c76b18: bad member 0000024F82C77F40 at 0000024F82C76B70
Last good object: 0000024F82C76AA0.
object 0000024f82c76ca8: bad member 0000024F82C77340 at 0000024F82C76CB0
Last good object: 0000024F82C76C58.
object 0000024f82c76fa8: bad member 0000024F82C77050 at 0000024F82C76FD0
Last good object: 0000024F82C76F88.
Could not request method table data for object 0000024F82C77050 (MethodTable: 00007FFB3C032138).
Last good object: 0000024F82C76FA8.
果然卦中的数据也验证了这一点,托管堆上有三个坏对象,接下来抽一个用 !do 命令来验证下。
0:083> !do 0000024f82c76b18
Name: System.Windows.Forms.TreeNode
MethodTable: 00007ffb3c431af8
EEClass: 00007ffb3c488500
Size: 168(0xa8) bytes
File: C:\xxxx\System.Windows.Forms.dll
Fields:
MT Field Offset Type VT Attr Value Name
...
00007ffb3c431ed8 400263f 58 ....Forms.TreeNode[] 0 instance 0000024f82c77f40 children
...
0:083> !do 0000024f82c77f40
<Note: this object has an invalid CLASS field>
Invalid object
从错误信息以及刚才卦中的数据表明 TreeNode.children 内存布局被破坏了,这种情况大多是因为 MethodTable 不对了导致CLR识别不出这块内存的对象,可以用 dp 验证下。
0:083> dp 0000024f82c77f40 L4
0000024f`82c77f40 00007ffb`3c411ed8 00000000`00400008
0000024f`82c77f50 0000024f`82c56fa8 0000024f`82c57378
0:083> !dumpmt 00007ffb`3c411ed8
00007ffb3c411ed8 is not a MethodTable
从卦中的 00007ffb3c411ed8 is not a MethodTable 可以看到这个地址是错误的,那正确地址是什么呢?如果有心细的朋友会看到 !do 的时候已经显示了正确的方法表,即 00007ffb3c431ed8。
接下来仔细观察 00007ffb3c411ed8 和 00007ffb3c431ed8 这两个地址,会发现一个是 3c41 一个是 3c43,真的是无语了,截图如下:

一般来说,这种单bit位的翻转也不像是用 PInvoke 的方式让 C++ 破坏了 C# 的托管堆,也不像是什么 hook 注入导致的,反正很神奇,为了拿更多证据可以在抽一个 坏对象 观察下。
0:083> !do 0000024f82c76fa8
Name: System.Windows.Forms.TreeNode
MethodTable: 00007ffb3c431af8
EEClass: 00007ffb3c488500
Size: 168(0xa8) bytes
Fields:
MT Field Offset Type VT Attr Value Name
...
00007ffb3c432138 4002636 28 ...eNodeImageIndexer 0 instance 0000024f82c77050 imageIndexer
...
0:083> !do 00007ffb`3c032138
<Note: this object has an invalid CLASS field>
Invalid object
0:083> dp 0000024f82c77050 L1
0000024f`82c77050 00007ffb`3c032138
从卦中数据看:方法表 00007ffb3c032138 和 00007ffb3c432138 也是差了一个bit位,即 3c03 和 3c43 的差别。

2. 为什么会翻转
有些朋友可能说,你这数据是不是网络数据,比如有什么 纠错码,海明码 之类的,其实 mt 的数据是嵌入到 image 中的,这块数据一般在初始化的时候由 clr 构建好,后期不会有人去改写的,可以用 !address 看下。
0:083> !address 00007ffb3c432138
Usage: Image
Base Address: 00007ffb`3c431000
End Address: 00007ffb`3c434000
Region Size: 00000000`00003000 ( 12.000 kB)
State: 00001000 MEM_COMMIT
Protect: 00000004 PAGE_READWRITE
Type: 01000000 MEM_IMAGE
Allocation Base: 00007ffb`3c400000
Allocation Protect: 00000080 PAGE_EXECUTE_WRITECOPY
Image Path: C:\Windows\assembly\NativeImages_v4.0.30319_64\System.Windows.Forms\1534a59650e0fd08da0ed8931d9f6d5f\System.Windows.Forms.ni.dll
Module Name: System_Windows_Forms_ni
Loaded Image Name:
Mapped Image Name:
More info: lmv m System_Windows_Forms_ni
More info: !lmi System_Windows_Forms_ni
More info: ln 0x7ffb3c432138
More info: !dh 0x7ffb3c400000
Content source: 1 (target), length: 1ec8
后来计划让朋友开启 MDA 托管调试助手去验证,结果朋友给我反馈说开启后,程序运行特别慢,这个很好理解,如果你的程序 PInvoke 过多,确实容易引发过高的 GC,所以能不能适应到各位的程序,还需要实际测试。
遗憾的这条路朋友没有走通,所以寻找答案就遥遥无期了,最后也就不了了之,因为那时候我认为所有的用户态异常都是软件造成的。。。
三:总结
直到昨天看了这篇 莫非我遇到了传说中的bug? 我现在有想法了,在下面可能的七种选项中:
- 宇宙射线
- 太阳耀斑
- 地磁暴
- 电离辐射
- 硬件故障
- 杀毒软件
- 内存超频
我觉得 内存超频 引发的程序不稳定概率是最大的,不知道大家可有不同的看法?

记一次 .NET某工控 宇宙射线 导致程序崩溃分析的更多相关文章
- 记一次 .NET 某工控软件 内存泄露分析
一:背景 1.讲故事 上个月 .NET调试训练营 里的一位老朋友给我发了一个 8G 的dump文件,说他的程序内存泄露了,一时也没找出来是哪里的问题,让我帮忙看下到底是怎么回事,毕竟有了一些调试功底也 ...
- 记一次 .NET 某工控数据采集平台 线程数 爆高分析
一:背景 1. 讲故事 前几天有位朋友在 B站 加到我,说他的程序出现了 线程数 爆高的问题,让我帮忙看一下怎么回事,截图如下: 说来也奇怪,这些天碰到了好几起关于线程数无缘无故的爆高,不过那几个问题 ...
- 记一次 .NET 某工控自动化控制系统 卡死分析
一:背景 1. 讲故事 前段时间遇到了好几起关于窗体程序的 进程加载锁 引发的 程序卡死 和 线程暴涨 问题,这种 dump 分析难度较大,主要涉及到 Windows操作系统 和 C++ 的基础知识, ...
- 记一次 .NET 某工控视觉软件 非托管泄漏分析
一:背景 1.讲故事 最近分享了好几篇关于 非托管内存泄漏 的文章,有时候就是这么神奇,来求助的都是这类型的dump,一饮一啄,莫非前定.让我被迫加深对 NT堆, 页堆 的理解,这一篇就给大家再带来一 ...
- 记一次 .NET 某工控MES程序 崩溃分析
一:背景 1.讲故事 前几天有位朋友找到我,说他的程序出现了偶发性崩溃,已经抓到了dump文件,Windows事件日志显示的崩溃点在 clr.dll 中,让我帮忙看下是怎么回事,那到底怎么回事呢? 上 ...
- 记一次 .NET 某医疗器械 程序崩溃分析
一:背景 1.讲故事 前段时间有位朋友在微信上找到我,说他的程序偶发性崩溃,让我帮忙看下怎么回事,上面给的压力比较大,对于这种偶发性崩溃,比较好的办法就是利用 AEDebug 在程序崩溃的时候自动抽一 ...
- 开源纯C#工控网关+组态软件(十)移植到.NET Core
一. 引子 写这个开源系列已经十来篇了.自从十年前注册博客园以来,关注了张善友.老赵.xiaotie.深蓝色右手等一众大牛,也围观了逗比的吉日嘎啦.精密顽石等形形色色的园友.然而整整十年一篇文章都 ...
- Wireshark工控协议
Wireshark是一个强大开源流量与协议分析工具,除了传统网络协议解码外,还支持众多主流和标准工控协议的分析与解码. 序号 协议类型 源码下载 简介 1 Siemens S7 https://git ...
- 【转】工控老鬼】西门子S7200入门&精通【1】S7200硬件大全
转载地址:http://blog.sina.com.cn/s/blog_669692a601016i5f.html 工控老鬼提醒以下的信息和资料可能不全或者不准确,如有疑问可以查阅西门子中国网 ...
- 基于HTML5的Web SCADA工控移动应用
在电力.油田燃气.供水管网等工业自动化领域Web SCADA的概念已经提出了多年,早先年的Web SCADA前端技术大部分还是基于Flex.Silverlight甚至Applet这样的重客户端方案,在 ...
随机推荐
- role
角色权限管理改造方案 # 为什么需要角色 现有的权限方案 .net后台权限管理 在后台类中配置,权限 = 一级菜单:二级菜单:三级菜单: 通过在view模板中判断是否有权限显示菜单 后端通过权限配 ...
- Vue-基本语法及事件绑定
一.基本语法 v-bind绑定: 双大括号不能在 HTML attributes 中使用.想要响应式地绑定一个 attribute,应该使用 v-bind 指令 代码展示: <div id=&q ...
- 算法打卡|Day5 哈希表part01
哈希表 part01 今日任务 ● 哈希表理论基础 ● 242.有效的字母异位词 ● 349. 两个数组的交集 ● 202. 快乐数 ● 1. 两数之和 目录 哈希表 part01 链表理论基础 Pr ...
- 其它——Apache-ab压力测试工具使用
文章目录 一 介绍 二 安装 2.1 windows安装 2.2 Linux安装 三 使用 四 参数介绍 一 介绍 Apache Benchmark(简称ab) 是Apache安装包中自带的压力测试工 ...
- 用MMCls训练手势模型
import os import json import mmcv import time from mmcv import Config from mmdet.apis import inferen ...
- 它让你1小时精通RabbitMQ消息队列、且能扛高并发
支持.Net Core(2.0及以上)与.Net Framework(4.5及以上) 本文所述方案近期被江苏省某亿级数据量+高并发的政府"物联网"项目采用,获得圆满成功!! [目录 ...
- Python 利用pymysql和openpyxl操作MySQL数据库并插入Excel数据
1. 需求分析 本文将介绍如何使用Python连接MySQL数据库,并从Excel文件中读取数据,将其插入到MySQL数据库中. 2. 环境准备 在开始本文之前,请确保您已经安装好了以下环境: Pyt ...
- 前后端分离,前端发送过来的请求是服务器的ip还是用户的ip
前后端分离部署时,服务器A用于部署前端项目,称为前端服务器,服务器B用于部署后端项目,称为后端服务器.后端服务器通过开放API的方式,向前端服务器中的前端项目提供数据或数据操作接口,以此实现前端与后端 ...
- java 处理常量字符串过长 & springboot 项目读取 resouces 文件夹下的文件内容
长字符串起因 项目里面有一长串的加密字符串(最长的万多个字符),需要拼接作为参数发送给第三方. 如果我们使用 枚举 定义的话,idea 编译的时候就会出现编译报错 Error: java:常量字符串过 ...
- spring---反射(java.lang.reflect)
反射简介 反射是Java的高级特性之一,但是在实际的开发中,使用Java反射的案例却非常的少,但是反射确实在底层框架中被频繁的使用. 比如:JDBC中的加载数据库驱动程序,Spring框架中加载bea ...