记一次 .NET 某自动化采集软件 崩溃分析

一:背景

1.讲故事

前段时间有位朋友找到我,说他的程序在客户的机器上跑着跑着会出现偶发卡死,然后就崩掉了,但在本地怎么也没复现,dump也抓到了,让我帮忙看下到底怎么回事,其实崩溃类的dump也有简单的,也有非常复杂的,因为大多情况下都是非托管层面出现的各种故障,非常考验对 C, C++, Win32 API 以及 汇编 的理解,所以能不能解决看运气吧, 不管怎么说,先上 WinDbg。

二:WinDbg分析

1. 查找崩溃点

WinDbg 非常牛的地方在于它拥有一个自动化崩溃分析命令 !analyze -v,它的输出信息非常有参考价值,所以尝试一下看看。

0:136> !analyze -v
*******************************************************************************
*                                                                             *
*                        Exception Analysis                                   *
*                                                                             *
*******************************************************************************
CONTEXT:  (.ecxr)
eax=00000000 ebx=00000000 ecx=00000000 edx=00000000 esi=00000003 edi=00000003
eip=777cf04c esp=22dfd678 ebp=22dfd808 iopl=0         nv up ei pl nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000206
ntdll!NtWaitForMultipleObjects+0xc:
777cf04c c21400          ret     14h
Resetting default scopeEXCEPTION_RECORD:  (.exr -1)
ExceptionAddress: 0174ba6dExceptionCode: 00000000ExceptionFlags: 00000000
NumberParameters: 0PROCESS_NAME:  xxx.exeSTACK_TEXT:  
22dfd808 75b23b10     00000003 22dfdc68 00000001 ntdll!NtWaitForMultipleObjects+0xc
22dfd808 75b23a08     00000003 22dfdc68 00000000 KERNELBASE!WaitForMultipleObjectsEx+0xf0
22dfd824 672ff11a     00000003 22dfdc68 00000000 KERNELBASE!WaitForMultipleObjects+0x18
22dfdca4 672ff3ac     672dd150 672d0000 00000003 Faultrep!WerpReportFaultInternal+0x59e
22dfdcc4 672dd17d     22dfdcec 708d0479 22dfdd60 Faultrep!WerpReportFault+0x9e
22dfdccc 708d0479     22dfdd60 00000000 22dfdd60 Faultrep!ReportFault+0x2d
22dfdcec 708d07e9     ec030e28 1c8f7728 00000003 clr!DoReportFault+0x43
22dfdd44 709f3c7e     00000003 22dfe140 2e954594 clr!WatsonLastChance+0x19a
22dfe090 709f3d90     ec0333f0 22dfe140 2e954594 clr!DoWatsonForUserBreak+0xc2
22dfe120 6fdc690f     00000000 00000000 00000000 clr!DebugDebugger::Break+0xc9
22dfe148 0174ba6d     00000000 00000000 00000000 mscorlib_ni!System.Diagnostics.Debugger.Break+0x57
WARNING: Frame IP not in any known module. Following frames may be wrong.
22dfe194 0174b58b     00000000 00000000 00000000 0x174ba6d
22dfe1e8 0174b525     00000000 00000000 00000000 mscorlib_ni!System.Runtime.CompilerServices.AsyncTaskMethodBuilder.Start<<xxxAsync>d__10>+0x43
22dfe1e8 0174b525     00000000 00000000 00000000 mscorlib_ni!System.Runtime.CompilerServices.AsyncTaskMethodBuilder.Start<<xxxAsync>d__10>+0x43
22dfe22c 0174b3bd     00000000 00000000 00000000 0x174b525
22dfe27c 0174b33b     00000000 00000000 00000000 0x174b3bd
22dfe2d0 0174b2d5     00000000 00000000 00000000 0x174b33b
...SYMBOL_NAME:  faultrep!WerpReportFaultInternal+59eMODULE_NAME: FaultrepIMAGE_NAME:  Faultrep.dllSTACK_COMMAND:  ~136s; .ecxr ; kb...

从卦中的调用栈看,有二个非常重要的信息。

  1. Debugger.Break()

这个是 C# 对 int 3  的封装,即 断点中断异常,目的就是将程序的所有线程中断。

  1. Faultrep!ReportFault()

这个是 WER 2.0 ,全称为 Windows Error Reporting Service,用来抓崩溃dump的,前身是 Waston 医生,在 Windows 服务列表中可以看到。

786d910bc1989bacfca437508a615d1b.png

还有一点, Faultrep.dll 是 WER 的一个组件,会在抓取过程中自动加载,我们用 lm 观察进程中的 dll 列表。

0:136> lm
start    end        module name
00fe0000 01034000   xxx C (service symbols: CLR Symbols without PDB)        
0c100000 0c123000   WINMMBASE   (deferred)             
662d0000 662ef000   clrcompression   (deferred)                   
672d0000 67327000   Faultrep   (pdb symbols)          c:\mysymbols\FaultRep.pdb\E16126C7FB9849A8B9AC57D8D62CABB01\FaultRep.pdb
...

汇总以上信息,大概就能推测出代码中用了 Debugger.Break() 函数,因为无catch处理,Windows 启动了 WER 2.0,程序代码在 ntdll!NtWaitForMultipleObjects 处等待第三方组件处理完毕,因为各种原因出现了问题导致无法返回最后崩溃。

通过卦中的信息我们大概知道了前因后果,但代码中为什么会出现 Debugger.Break() 呢?这就需要我们继续深挖。

2. 为什么会有 Debugger.Break()

刚才的输出中有这么一段话: STACK_COMMAND: ~136s; .ecxr ; kb ,它可以让我们找到异常前的调用栈,为了能看到托管栈,这里将 kb 改成 !clrstack

0:136>  ~136s; .ecxr ; !clrstackOS Thread Id: 0x13ec (136)
Child SP       IP Call Site
22dfe0ac 777cf04c [HelperMethodFrame: 22dfe0ac] System.Diagnostics.Debugger.BreakInternal()
22dfe128 6fdc690f System.Diagnostics.Debugger.Break() [f:\dd\ndp\clr\src\BCL\system\diagnostics\debugger.cs @ 65]
22dfe150 0174ba6d xxx.xxx+d__10.MoveNext()
22dfe19c 0174b58b System.Runtime.CompilerServices.AsyncTaskMethodBuilder.Start[[xxx.xxx+d__10, xxx.Abstractions]](d__10 ByRef) [f:\dd\ndp\clr\src\BCL\system\runtime\compilerservices\AsyncMethodBuilder.cs @ 316]
22dfe1f0 0174b525 xxx.xxxAsync(System.String, System.String)
22dfe238 0174b3bd xxx.xxxProducer+d__7.MoveNext()
22dfe284 0174b33b System.Runtime.CompilerServices.AsyncTaskMethodBuilder.Start[[xxx.xxx+d__7, xxx.Abstractions]](d__7 ByRef)
22dfe2d8 0174b2d5 xxx.xxx.xxx(System.String, System.String)

从卦中看,貌似是在一个异步方法中手工调用了 Deubgger.Break() 方法,接下来我们观察下源码,由于比较隐私,这里就简化一下。

internal async Task xxxAsync(string x1, string x2)
{if (string.IsNullOrEmpty(x1)){Debugger.Break();return;}if (string.IsNullOrEmpty(x2)){Debugger.Break();return;}...
}

这代码果然有意思,在防御性编程中居然用 Debugger.Break() 来处理,比较少见。

找到了问题源头,解决方法就简单了,大概有两种做法。

  1. 去掉 Debugger.Break() 语句

  2. 关闭 WER 2.0 服务

32398e66b4dcf1283b171eb99bf75100.png

3. 对 Debugger.Break() 的题外话

在 clr 源码中有对 Debugger.Break() 非常详细的注释。

// This does a user break, triggered by System.Diagnostics.Debugger.Break, or the IL opcode for break.
//
// Notes:
//    If a managed debugger is attached, this should send the managed UserBreak event.
//    Else if a native debugger is attached, this should send a native break event (kernel32!DebugBreak)
//    Else, this should invoke Watson.
//
// Historical trivia:
// - In whidbey, this would still invoke Watson if a native-only debugger is attached.
// - In arrowhead, the managed debugging pipeline switched to be built on the native pipeline.
FCIMPL0(void, DebugDebugger::Break)
{...
}
FCIMPLEND

注释文本:Else, this should invoke Watson 中的 Watson 其实就是本篇聊到的 WER,观察反汇编其实就是对 int 3 的封装。

0:136> uf kernelBase!DebugBreak
KERNELBASE!DebugBreak:
75ba5e40 8bff            mov     edi,edi
75ba5e42 cc              int     3
75ba5e43 c3              ret

在很多反调试机制中,经常会用 int 3 来检测当前程序是否被附加了调试器,参考如下 C++ 代码。

#include <iostream>int isAttach = 0;int main()
{__try{__asm {int 3}isAttach = 1;}__except(1){isAttach = 0;}if (isAttach) {printf("不好,发现有调试器 ...");}else {printf("哈哈,一切正常!");}getchar();
}

如果你用 WinDbg 附加上去, 就会被程序检测到,截图如下:

e9b3f471a1afb433e57286d07330a2fc.png

如果是正常运行,会是如下界面

07e072e8fab69afbcb52e78ce11c1986.png

可以在 C# 中通过 Pinvoke 引入,这种动态方式,反反调试会有不小的难度。

三:总结

这次事故是朋友在开发过程中为了方便调试,使用了 Debugger.Break() 方法,但在生产环境下并没有删除,导致在某些客户机器上因为 WER 的开启,被 Waston 捕获导致的事故。

本次教训是:发给客户的版本,内含的调试信息该关闭的一定要关闭,以免生出此乱。

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

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

相关文章

如何在 .NET MAUI 中加载 json 文件?

引言:按.NET core传统方式添加 AddJsonFile("appsettings.json") 在windows平台和ssr工作正常,但是在 ios 和 android 无法用这种方式,因为资源生成方式不一样. 使用内置资源方式不够灵活而且 ios 平台会提示不能复制 json 文件到目录,于是进行了几天的研究,终于能正…

SSH整合注解版(Spring+Struts2+Hibernate)

整体架构&#xff1a; pom.xml 引入maven节点&#xff1a; <dependencies><!--单测--><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.3</version><scope>test</scope><…

定时插座动一下就断_使用插座定时器在某些时候自动将您的Amazon Echo静音

定时插座动一下就断The Amazon Echo is an always-listening voice-controlled virtual assistant, but if there are times you’d rather not listen (or be listened to) by the Echo, here’s how to automatically mute it at certain times of the day. Amazon Echo是一个…

周末读书:《红楼梦》

【周末读书】| 作者/Edison大家好&#xff0c;我是Edison。古人曾说“开谈不说红楼梦&#xff0c;读尽诗书也枉然”&#xff0c;刚好最近我爸开始在阅读《红楼梦》&#xff0c;我想起当年看了两遍《红楼梦》原著和一遍87版《红楼梦》电视剧的场景。本文是我首发于2018年的一篇读…

onlyoffice启用HTTPS

原文同步自作者博客&#xff1a;https://www.daxueyiwu.com/post/765 HTTPS需要使用SSL证书&#xff0c;可以自己签发也可以用ca机构签发的&#xff0c;加密效果相同。 生成证书&#xff1a; 创建私钥 openssl genrsa -out onlyoffice.key 2048 创建CSR openssl req -new -k…

Oracle-逻辑体系结构

这里指数据文件的逻辑体系结构&#xff0c;包括1.表空间(TABLESPACE) 2.段(SEGMENT) 3.区(EXTENT) 4.块(BLOCK) 数据库(Database)由若干表空间(TABLESPACE)组成&#xff0c;表空间由若干段(SEGMENT)组成&#xff0c;段由若干区(EXTENT)组成&#xff0c;区由若干块(BLOCK)组成…

chromebook刷机_如何从Chromebook上的APK侧面加载Android应用

chromebook刷机Chromebooks can now download and install Android apps from Google Play, and it works pretty well. But not every Android app is available in Google Play. Some apps are available from outside Google Play as APK files, and you can install them o…

修改onlyoffice存储为手动存储关闭浏览器时不进行保存

原文同步自作者博客&#xff1a;https://www.daxueyiwu.com/post/704 相关官方API地址&#xff1a; 文件保存 回调处理程序 配置-编辑-定制-自动保存 配置-编辑-定制-forcesave 需要将: config.editorConfig.customization.forcesave改为true, 并且config.editorConfig.…

如何使用NVIDIA ShadowPlay录制PC游戏

NVIDIA’s ShadowPlay, now known as NVIDIA Share, offers easy gameplay recording, live streaming, and even an FPS counter overlay. It can automatically record gameplay in the background–just on the PlayStation 4 and Xbox One–or only record gameplay when y…

Java流

流分类 字节流字符流输入流InputStreamReader输出流OutputStream WriterInputStream:BufferedInputStream、DataInputStream、ObjectInputStreamOutputStream:BufferedOutputStream、DataOutputStream、ObjectOutputStream、PrintStream 标准流: System.in 、Syst…

Win7安装OnlyOffice(不使用Docker)

原文同步自作者博客&#xff1a;https://www.daxueyiwu.com/post/741 1、安装准备 &#xff08;1&#xff09;安装Elang&#xff1a; 【注意事项】 a)Elang是为了给RabbitMQ使用的&#xff0c;因此在安装Elang之前应确定RabbitMQ的版本及其所需的Elang版本。RabbitMQ的地址…

geek_享受How-To Geek用户样式脚本的好处

geekMost people may not be aware of it but there are two user style scripts that have been created just for use with the How-To Geek website. If you are curious then join us as we look at these two scripts at work. 大多数人可能不知道它&#xff0c;但是已经创…

Memcached 在linux上安装笔记

第一种yum 方式安装 Memcached 支持许多平台&#xff1a;Linux、FreeBSD、Solaris、Mac OS&#xff0c;也可以安装在Windows上。 第一步 Linux系统安装memcached&#xff0c;首先要先安装libevent库 Ubuntu/Debian sudo apt-get install libevent libevent-deve 自动下…

onlyoffice回调函数controller方式实现

原文同步自作者博客&#xff1a;https://www.daxueyiwu.com/post/706 springboot实现的onlyoffice协同编辑网盘项目可以去作者博客。 上代码&#xff1a; //新建报告GetMapping("report/createReport")public String CreatReport(HttpServletRequest request,Stri…

读Bilgin Ibryam 新作 《Dapr 是一种10倍数 平台》

Bilgin Ibryam 最近加入了开发者软件初创公司Diagrid Inc&#xff0c;他是Apache Software Foundation 的 committer 和成员。他也是一个开源的布道师&#xff0c;并且是书籍 Kubernetes设计模式 和 Camel Design Patterns 的作者。早在2020年初 提出的Multi-Runtime Microserv…

如何在iPhone或iPad上使用Safari下载文件

Khamosh PathakKhamosh PathakIn your work or personal life, you’ll sometimes need to download a file on your iPhone or iPad. Using the new feature introduced in iOS 13 and iPadOS 13, you can now do this directly in Safari. No third-party app needed! 在工作…

java版左右手桌面盯盘软件dstock V1.0

V1.0功能比较简陋&#xff0c;先满足自己桌面盯盘需要 V1.0 版本功能介绍&#xff1a; 1. 1s实时刷新盯盘数据 主要市面上的&#xff0c;符合我要求的桌面应用要VIP,穷啊&#xff0c;还是月月付&#xff0c;年年付&#xff0c;还是自己搞吧&#xff01; 2. 配置文件配置股票…

放大倍数超5万倍的Memcached DDoS反射攻击,怎么破?

欢迎大家前往腾讯云社区&#xff0c;获取更多腾讯海量技术实践干货哦~ 作者&#xff1a;腾讯游戏云 背景&#xff1a;Memcached攻击创造DDoS攻击流量纪录 近日&#xff0c;利用Memcached服务器实施反射DDoS攻击的事件呈大幅上升趋势。DDoS攻击流量首次过T&#xff0c;引发业界热…

C# WPF TabControl控件用法详解

概述TabControl我之前有讲过一节&#xff0c;内容详见&#xff1a;C# WPF TabControl用法指南(精品)&#xff0c;上节主要讲解了tabcontrol控件的左右翻页&#xff0c;以及页面筛选&#xff0c;以及数据绑定等内容&#xff0c;这节内容继续接续上节内容进行扩展讲解&#xff0c…

pixel 解锁_如何在Google Pixel 4和Pixel 4 XL上禁用面部解锁

pixel 解锁Justin Duino贾斯汀杜伊诺(Justin Duino)Face Unlock is one of the Google Pixel 4 and Pixel 4 XL’s flagship features. But if the facial recognition is a form of biometric security you’re uncomfortable with, you can delete your face data right off …