记一次 .NET某股票交易软件 灵异崩溃分析
一:背景
1. 讲故事
在dump分析的旅程中也会碰到一些让我无法解释的灵异现象,追过这个系列的朋友应该知道,上一篇我聊过 宇宙射线
导致的程序崩溃,后来我又发现了一例,而这一例恰恰是高铁的 列控连锁一体化
程序,所以更加让我确定这是由于 电离辐射
干扰了计算机的 数字信号
导致程序的bit翻转,而这一篇也是一个我认为的 灵异现象
,拿出来给朋友们分享一下。
前段时间有位朋友找到我,说他的程序会偶发性崩溃,一直找不到原因很纠结,看我在这一块非常有经验让我帮忙看一下怎么回事,既然是有备而来自然dump也准备好了,接下来开始分析之旅吧。
二:WinDbg 分析
1. 为什么会崩溃
要想分析崩溃的原因还得windbg自带的自动化分析命令 !analyze -v
,输出如下:
0:117> !analyze -v
*******************************************************************************
* *
* Exception Analysis *
* *
*******************************************************************************
CONTEXT: (.ecxr)
rax=0000000000000001 rbx=0000000000000000 rcx=0000000000000002
rdx=000000000005001b rsi=000000000000000e rdi=00000161b1b8c718
rip=00007ffdd0961abd rsp=000000341547b370 rbp=000000341547b250
r8=0000000000000005 r9=000000000000003d r10=0000000000000000
r11=7007f0b8d350316a r12=0000000000000000 r13=0000000000000003
r14=000000341547b5c0 r15=0000000000000001
iopl=0 nv up ei pl nz na pe nc
cs=0033 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000202
clr!_report_gsfailure+0x1d:
00007ffd`d0961abd cd29 int 29h
Resetting default scope
EXCEPTION_RECORD: (.exr -1)
ExceptionAddress: 00007ffdd0961abd (clr!_report_gsfailure+0x000000000000001d)
ExceptionCode: c0000409 (Security check failure or stack buffer overrun)
ExceptionFlags: 00000001
NumberParameters: 1
Parameter[0]: 0000000000000002
Subcode: 0x2 FAST_FAIL_STACK_COOKIE_CHECK_FAILURE
SYMBOL_NAME: clr!_report_gsfailure+1d
...
卦中有一句话叫 Security check failure or stack buffer overrun
,浅层意思就是: 安全检查失败或缓冲区溢出
,行话就是:栈上的cookie遭到了破坏。
可能有些朋友对 cookie 不是很了解,这个cookie非web的cookie,而是在方法栈上藏的一个随时值,在方法的退出前会检查这个值有没有被破坏,目的就是防止有人无意或者恶意攻击线程栈,如果遭到破坏,会触发 int 29
即 nt!KiRaiseSecurityCheckFailure
函数让程序快速硬性崩溃。
如果有些朋友不明白,画个图如下:
2. cookie 被破坏了吗
既然说 cookie 被破坏了,说明有栈溢出的情况,那到底溢出了什么东西呢?这需要分析崩溃处附近的汇编代码才能知道,接下来使用 .ecxr ; k 3
切到崩溃前的上下文。
0:117> .ecxr ; k 3
rax=0000000000000001 rbx=0000000000000000 rcx=0000000000000002
rdx=000000000005001b rsi=000000000000000e rdi=00000161b1b8c718
rip=00007ffdd0961abd rsp=000000341547b370 rbp=000000341547b250
r8=0000000000000005 r9=000000000000003d r10=0000000000000000
r11=7007f0b8d350316a r12=0000000000000000 r13=0000000000000003
r14=000000341547b5c0 r15=0000000000000001
iopl=0 nv up ei pl nz na pe nc
cs=0033 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000202
clr!_report_gsfailure+0x1d:
00007ffd`d0961abd cd29 int 29h
# Child-SP RetAddr Call Site
00 00000034`1547b370 00007ffd`d0977900 clr!_report_gsfailure+0x1d
01 00000034`1547b3b0 00007ffd`d097816d clr!RtlAllocateLUnicodeString+0xe0
02 00000034`1547b420 00007ffd`d09e1d06 clr!RtlDuplicateLUnicodeString+0x8d
...
卦中的信息很丰富,说 clr 在 RtlAllocateLUnicodeString
函数退出阶段时检查 cookie 被破坏了,继而程序快速崩溃,接下来需要反编译 RtlAllocateLUnicodeString
函数,简化后如下:
0:117> uf clr!RtlAllocateLUnicodeString
clr!RtlAllocateLUnicodeString:
00007ffd`d0977820 48895c2418 mov qword ptr [rsp+18h],rbx
00007ffd`d0977825 55 push rbp
00007ffd`d0977826 56 push rsi
00007ffd`d0977827 57 push rdi
00007ffd`d0977828 488bec mov rbp,rsp
00007ffd`d097782b 4883ec50 sub rsp,50h
00007ffd`d097782f 488b05d2777600 mov rax,qword ptr [clr!_security_cookie (00007ffd`d10df008)]
00007ffd`d0977836 4833c4 xor rax,rsp
00007ffd`d0977839 488945f8 mov qword ptr [rbp-8],rax
00007ffd`d097783d 488bfa mov rdi,rdx
00007ffd`d0977840 488bf1 mov rsi,rcx
00007ffd`d0977843 c745f0e50000c0 mov dword ptr [rbp-10h],0C00000E5h
00007ffd`d097784a 33db xor ebx,ebx
00007ffd`d097784c 4885d2 test rdx,rdx
00007ffd`d097784f 745f je clr!RtlAllocateLUnicodeString+0x90 (00007ffd`d09778b0) Branch
...
00007ffd`d09778f2 8bc3 mov eax,ebx
00007ffd`d09778f4 488b4df8 mov rcx,qword ptr [rbp-8]
00007ffd`d09778f8 4833cc xor rcx,rsp
00007ffd`d09778fb e820a1feff call clr!_security_check_cookie (00007ffd`d0961a20)
00007ffd`d0977900 488b9c2480000000 mov rbx,qword ptr [rsp+80h]
00007ffd`d0977908 4883c450 add rsp,50h
00007ffd`d097790c 5f pop rdi
00007ffd`d097790d 5e pop rsi
00007ffd`d097790e 5d pop rbp
00007ffd`d097790f c3 ret
卦中的信息量还是非常大的,我们通读下汇编代码理解下 安全检查
中的一些基本元素以及逻辑是什么? 步骤大概如下:
- _security_cookie
这个是 cookie 种子,可以用 dp 给捞出来,即下面的 0000d9998c879750
。
0:117> dp clr!_security_cookie L1
00007ffd`d10df008 0000d999`8c879750
- xor rax,rsp
将 cookie 种子和当前方法的栈顶指针rsp异或一下,目的就是做一个和栈帧相关的随机值,当前的rsp即k上的000000341547b3b0
,用 windbg 计算之后为:
0:117> ? 00000034`1547b3b0 ^ 0000d999`8c879750
Evaluate expression: 239339632076000 = 0000d9ad`99c024e0
- qword ptr [rbp-8],rax
将异或后的 安全值
塞到 rbp-8
的栈位置,这里的 rbp 由上面的汇编语句 mov rbp,rsp
赋值的,因为上面有三个push加一个call,所以rbp应该退掉4个0x8,最后计算的结果为栈位置000000341547b3f8 存的就是安全值,下面的输出也可以确认。
0:117> ? 00000034`1547b420-0x8-0x8-0x8-0x8
Evaluate expression: 223695320064 = 00000034`1547b400
0:117> dp 00000034`1547b400-8 L1
00000034`1547b3f8 0000d9ad`99c024e0
- clr!_security_check_cookie
在方法退出时需要通过 _security_check_cookie
方法来检查cookie是否损坏,核心代码为:
clr!RtlAllocateLUnicodeString+0xd2:
00007ffd`d09778f4 488b4df8 mov rcx,qword ptr [rbp-8]
00007ffd`d09778f8 4833cc xor rcx,rsp
00007ffd`d09778fb e820a1feff call clr!_security_check_cookie (00007ffd`d0961a20)
经过 windbg 计算 rcx=0000d9998c879750
,即 _security_cookie
值。
0:117> dp 00000034`1547b400-8 L1
00000034`1547b3f8 0000d9ad`99c024e0
0:117> ? 0000d9ad`99c024e0 ^ 00000034`1547b3b0
Evaluate expression: 239253510920016 = 0000d999`8c879750
接下来拿着 rcx= 0000d9998c879750
去反汇编下 _security_check_cookie 函数,简化后如下:
0:117> uf clr!_security_check_cookie
00007ffd`d0961a20 483b0de1d57700 cmp rcx,qword ptr [clr!_security_cookie (00007ffd`d10df008)]
00007ffd`d0961a27 7510 jne clr!_security_check_cookie+0x19 (00007ffd`d0961a39)
00007ffd`d0961a29 48c1c110 rol rcx,10h
00007ffd`d0961a2d 66f7c1ffff test cx,0FFFFh
00007ffd`d0961a32 7501 jne clr!_security_check_cookie+0x15 (00007ffd`d0961a35)
00007ffd`d0961a34 c3 ret
00007ffd`d0961a35 48c1c910 ror rcx,10h
00007ffd`d0961a39 e962000000 jmp clr!_report_gsfailure (00007ffd`d0961aa0)
00007ffd`d0961aa0 48894c2408 mov qword ptr [rsp+8],rcx
00007ffd`d0961aa5 4883ec38 sub rsp,38h
00007ffd`d0961aa9 b917000000 mov ecx,17h
00007ffd`d0961aae ff15e4fa5a00 call qword ptr [clr!_imp_IsProcessorFeaturePresent (00007ffd`d0f11598)]
00007ffd`d0961ab4 85c0 test eax,eax
00007ffd`d0961ab6 7407 je clr!_report_gsfailure+0x1f (00007ffd`d0961abf)
00007ffd`d0961ab8 b902000000 mov ecx,2
00007ffd`d0961abd cd29 int 29h
代码逻辑非常简单,还原成 C 大概如下:
void __fastcall _security_check_cookie(uintptr_t stackcookie)
{
if ((stackcookie == __security_cookie) && (stackcookie高四位 == "0000")) {
return;
}
else {
_report_gsfailure()
}
}
从C的逻辑看我们的 stackcookie=0000d9998c879750
完全满足 if 条件,但不知道为什么会走到这个 else 里面去,无法想象。。。所以定性为 灵异事件!!!
4. 故事后续
把所有的值都推算完了之后,在不可能走到 else 的情况下还是走到了 else,这个真的很让人无语+费解,过了几天找朋友确认的时候,朋友又反馈了一个信息,说电脑上的其他程序也会遇到这种情况,让客户重装操作系统,目前还没遇到问题。
所以我觉得这个问题可能是 操作系统层面
的问题,或者是 硬件层面
的问题,而且程序的异常是在 clr 层面,用户代码是无法干涉的,程序中也没有做 Pinvoke。
三:总结
一个是辐射导致的bit位翻转,一个是不可能走到else的地方走了else,各个奇奇怪怪的事情,让我的高级调试之旅丰富多彩,大家觉得这个崩溃还有其他的可能性吗?期待大家的留言。
记一次 .NET某股票交易软件 灵异崩溃分析的更多相关文章
- 记一次 .NET 某教育系统API 异常崩溃分析
一:背景 1. 讲故事 这篇文章起源于 搬砖队大佬 的精彩文章 WinDBg定位asp.net mvc项目异常崩溃源码位置 ,写的非常好,不过美中不足的是通览全文之后,总觉得有那么一点不过瘾,就是没有 ...
- 记一次 .NET 某自动化集采软件 崩溃分析
一:背景 1.讲故事 前段时间有位朋友找到我,说他的程序在客户的机器上跑着跑着会出现偶发卡死,然后就崩掉了,但在本地怎么也没复现,dump也抓到了,让我帮忙看下到底怎么回事,其实崩溃类的dump也有简 ...
- 记一次 .NET 某工控MES程序 崩溃分析
一:背景 1.讲故事 前几天有位朋友找到我,说他的程序出现了偶发性崩溃,已经抓到了dump文件,Windows事件日志显示的崩溃点在 clr.dll 中,让我帮忙看下是怎么回事,那到底怎么回事呢? 上 ...
- 记一次 .NET 某企业 ERP网站系统 崩溃分析
一:背景 1. 讲故事 前段时间收到了一个朋友的求助,说他的ERP网站系统会出现偶发性崩溃,找了好久也没找到是什么原因,让我帮忙看下,其实崩溃好说,用 procdump 自动抓一个就好,拿到 dump ...
- AngularJS进阶(十四)AngularJS灵异代码事件
AngularJS灵异代码事件 注:请点击此处进行充电! 事情原委 router_sys.js源代码如下: 自己在html路由跳转的代码如下: 但是在实际路由过程中,却路由到了下面的状态,相应的页面中 ...
- 高效开发之SASS篇 灵异留白事件——图片下方无故留白 你会用::before、::after吗 link 与 @import之对比 学习前端前必知的——HTTP协议详解 深入了解——CSS3新增属性 菜鸟进阶——grunt $(#form :input)与$(#form input)的区别
高效开发之SASS篇 作为通往前端大神之路的普通的一只学鸟,最近接触了一样稍微高逼格一点的神器,特与大家分享~ 他是谁? 作为前端开发人员,你肯定对css很熟悉,但是你知道css可以自定义吗?大家 ...
- SWUST OJ 东6宿舍灵异事件(0322)
东6宿舍灵异事件(0322) Time limit(ms): 1000 Memory limit(kb): 65535 Submission: 88 Accepted: 31 Descriptio ...
- 记一次常规的Mysql数据库访问的时间分析
背景:记一次常规的数据访问的时间分析(插入操作) 1. TCP三次握手 SYN ---> <--- SYN,ACK ACK ---> 花费时间: 386.718-385.784=0. ...
- Python实战——基于股票的金融数据量化分析
说明:本文只是通过自己的已学知识对股票数据进行了一个简单的量化分析,只考虑了收盘情况,真实的量化交易中仅仅考虑收盘情况是不够的,还有很多的复杂因素,而且仅仅三年数据是不足以来指导真实的股票交易的,因此 ...
- 记一次 .NET WPF布草管理系统 挂死分析
一:背景 1. 讲故事 这几天看的 dump 有点多,有点伤神伤脑,晚上做梦都是dump,今天早上头晕晕的到公司就听到背后同事抱怨他负责的WPF程序挂死了,然后测试的小姑娘也跟着抱怨...嗨,也不知道 ...
随机推荐
- Windows安装、配置、卸载MySQL教程
MySQL是一个关系型数据库管理系统,目前为Oracle旗下产品,它具有开源.体积小.速度快的优点,许多网站使用的都是MySQL数据库. 简单而言,MySQL数据库核心功能就是用来存储数据的. MyS ...
- Java实践项目 - 购物车模块
Smiling & Weeping ----世界上美好的东西不太多,立秋傍晚从河对岸吹来的风, 加入购物车 1.数据创建--创建t_cart CREATE TABLE t_cart( cid ...
- 小知识:OCI实例的私钥文件权限
在OCI上创建新的实例时,会提示你保存私钥用于连接,而且该界面不会再次显示,所以一定要保存好这个私钥. 实例创建完成后,当使用保存的私钥进行连接时,却发现由于私钥文件的权限问题无法连接,查看当前私钥文 ...
- 《最新出炉》系列初窥篇-Python+Playwright自动化测试-17-处理鼠标悬停
1.简介 有些测试场景或者事件,playwright根本就没有直接提供方法去操作,而且也不可能把各种测试场景都全面覆盖提供方法去操作.比如:就像鼠标悬停,一般测试场景鼠标悬停分两种常见,一种是鼠标悬停 ...
- 2023-09-30:用go语言,给你一个整数数组 nums 和一个整数 k 。 nums 仅包含 0 和 1, 每一次移动,你可以选择 相邻 两个数字并将它们交换。 请你返回使 nums 中包含 k
2023-09-30:用go语言,给你一个整数数组 nums 和一个整数 k . nums 仅包含 0 和 1, 每一次移动,你可以选择 相邻 两个数字并将它们交换. 请你返回使 nums 中包含 k ...
- Linux 下 C语言 open() 和 fopen() 区别
Linux 下 C语言 open() 和 fopen() 区别 fopen() #include <stdio.h> FILE *fopen(const char *path, con ...
- Debian12安装.NET7 SDK
Debian,作为最受欢迎的 Linux 发行版之一,于 2023 年 6 月 10 日正式发布了其最新版本 Debian 12,代号"Bookworm".Debian 12 带来 ...
- C#堆排序算法
前言 堆排序是一种高效的排序算法,基于二叉堆数据结构实现.它具有稳定性.时间复杂度为O(nlogn)和空间复杂度为O(1)的特点. 堆排序实现原理 构建最大堆:将待排序数组构建成一个最大堆,即满足父节 ...
- Lucky Array 题解
Lucky Array 题目大意 维护一个序列,支持以下操作: 区间加一个大于 \(0\) 的数. 区间查询有多少个数位上只包含 \(4\) 或 \(7\) 的数. 思路分析 看起来很不可做,但考虑到 ...
- 下载kubernetes
前言 页面介绍了k8s的组件下载的方法 二进制文件 二进制文件的下载链接在CHANGELOG文件中,这里有一个技巧是直接下载Server Binaries,这个是包含了所有的二进制文件.下载后记得比对 ...