记一次 .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,一经查实,立即删除!

相关文章

onlyoffice修改字号

原文同步自作者博客&#xff1a;https://www.daxueyiwu.com/post/758 :/var/www/onlyoffice/documentserver/web-apps/apps/documenteditor/main/app.js 里找到{value:22,displayValue:"22"} 把displayValue对应的值换成汉字字体 小二等 其实中文数字&#xff08;字…

大数据

大数据技术的快速发展&#xff0c;对现如今人们的思维方式产生了巨大的改变。 首先&#xff0c;大数据的发展&#xff0c;改善了人们思维的局限性。在过去&#xff0c;数据流通速度慢&#xff0c;人们获取的数据资源有限&#xff0c;所以在看待事物方面&#xff0c;基于过去固有…

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

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

onlyOfice取消上传文件大小的限制

原文同步自作者博客&#xff1a;https://www.daxueyiwu.com/post/757 使用onlyOfice的时候&#xff0c;在打开的文件中&#xff0c;对文件的大小有限制的&#xff0c;可以在服务中修改被限制的大小&#xff0c;在服务上有/etc/onlyoffice/documentserver/default.json的文件&a…

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)组成…

win10下用docker安装onlyoffice服务

原文同步自作者博客&#xff1a;https://www.daxueyiwu.com/post/699 1. 使用DockerToolbox安装docker 1.1 DockerToolbox下载地址 DockerToolbox-19.03.1 GitHub上下载实在是太慢了。 我找了好久终于下载下来了&#xff0c;在这里分享一下&#xff01; 网盘下载&#xff1…

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…

速度和性能狂卷,.NET 7来了

.NET 作为一个免费的跨平台开放源代码开发人员平台&#xff0c;这些年在不断的升级完善。就在最近&#xff0c;史上最快最强的.net平台.NET 7于2022年11月8日正式发布, .NET 朝着更好的⾃⼰⼜迈进了⼀步&#xff01;那么&#xff0c;.NET 7 有什么新东西&#xff1f;.NET 7 建立…

前端JavaScript规范

摘要&#xff1a; JavaScript规范 目录 类型 对象 数组 字符串 函数 属性 变量 条件表达式和等号 块 注释 空白 逗号 分号 类型转换 命名约定 存取器 构造器 事件 模块 jQuery ES5 兼容性 HTML、CSS、JavaScript分离 使用jsHint 前端工具 类型 原始值: 相当于传值(JavaScript对…

修改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…

.Net 7 的 R2R,Crossgen2是什么?

楔子来下这些概念R22,Crossgen2这两个东西&#xff0c;跟前面讲的AOT和CLR有异曲同工之妙&#xff0c;到底什么呢&#xff1f;本篇来看下。R2RR2R(ReadyToRun),是一种结合了AOT和CLR编译模式&#xff0c;取其优点&#xff0c;抛其缺点的一种编译方式。具体的呢&#xff0c;R2R包…

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;但是已经创…

.NET Core统一参数校验、异常处理、结果返回

我们开发接口时&#xff0c;一般都会涉及到参数校验、异常处理、封装结果返回等处理。如果每个后端开发在参数校验、异常处理等都是各写各的&#xff0c;没有统一处理的话&#xff0c;代码就不优雅&#xff0c;也不容易维护。所以&#xff0c;我们需要统一校验参数&#xff0c;…