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

优采云 发布时间: 2022-11-21 10:26

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

  一:背景 1.讲故事

  前段时间有个朋友来找我,说他的程序在客户端机器上运行时偶尔会卡顿,然后死机,但是本地没有重现,dump也抓到了。让我帮忙看看是怎么回事。其实crash的转储可以很简单也可以很复杂,因为大部分都是非托管层面的各种故障,考验对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 scope

EXCEPTION_RECORD: (.exr -1)

ExceptionAddress: 0174ba6d

ExceptionCode: 00000000

ExceptionFlags: 00000000

NumberParameters: 0

PROCESS_NAME: xxx.exe

STACK_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+0x43

22dfe1e8 0174b525 00000000 00000000 00000000 mscorlib_ni!System.Runtime.CompilerServices.AsyncTaskMethodBuilder.Start+0x43

22dfe22c 0174b3bd 00000000 00000000 00000000 0x174b525

22dfe27c 0174b33b 00000000 00000000 00000000 0x174b3bd

22dfe2d0 0174b2d5 00000000 00000000 00000000 0x174b33b

...

SYMBOL_NAME: faultrep!WerpReportFaultInternal+59e

MODULE_NAME: Faultrep

IMAGE_NAME: Faultrep.dll

STACK_COMMAND: ~136s; .ecxr ; kb

...

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

  调试器。休息()

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

  

" />

  Faultrep!ReportFault()

  这就是WER 2.0,全称是Windows Error Reporting Service,用来捕捉崩溃转储。它的前身是Dr. Watson,可以在Windows服务列表中看到。

  还有一点,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 ; !clrstack

OS 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()来处理。

  一旦找到问题的根源,解决起来就很简单了。大概有两种方法。

  删除 Debugger.Break() 语句

  关闭 WER 2.0 服务

  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.

<p>

" />

// 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

</p>

  Note text: Else, this should invoke Watson 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

int isAttach = 0;

int main()

{

__try

{

__asm {

int 3

}

isAttach = 1;

}

__except(1)

{

isAttach = 0;

}

if (isAttach) {

printf("不好,发现有调试器 ...");

}

else {

printf("哈哈,一切正常!");

}

getchar();

}

  如果用WinDbg附加它,它会被程序检测到,截图如下:

  正常运行的话会是下面这个界面

  它可以通过 C# 中的 Pinvoke 导入。这种动态的方式,反反调试会相当困难。

  三:总结

  这个事故是因为有朋友在开发过程中使用了Debugger.Break()方法方便调试,但是在生产环境中没有删除,导致在部分客户端机器上Watson抓包导致的事故是因为开启了WER上。

  这次的教训是:在发给客户的版本中,必须关闭其中收录

的调试信息,才能避免这样的混乱。

  汇总:网站链接收录查询工具(百度隔天收录技巧)

  最近有很多站长朋友问我怎么查看网站收录了哪些链接,网站的关键词是多少,同行收录了多少链接,网站的排名是多少。另外,如何批量提取网站的死链接,以及哪些收录

的链接还没有更新。有没有免费的工具可以查询、统计和收录链接,支持多平台如:百度、搜狗、今日头条等搜索引擎。

  常用网站采集工具常见故障

  查询排名和收录可以使用爱站和SEO综合查询-站长工具。用过的都知道,只能查询一些通用的网站信息,比如:网站流量ip,百度权重,百度手机权重,360权重,搜狗权重等搜索引擎权重,还有域名注册信息,备案信息、网站信息(打开速度和响应时间等)。比如你不是该网站排名对应的关键词的会员,你只能查看关键词的一部分,你甚至不知道该网站的链接是哪些网站关键词 因为那些网站文章。

  

" />

  也许你会说可以用site命令来查询。但是一看就知道收录了哪些网站链接,收录的链接对应网站的哪个关键词。不可能对网站的关键词分布做一个详细的统计,你有吗?没有办法分析为什么竞争对手网站的SEO排名是基于什么样的关键词布局,关键词收录

链接。这样就没有准确的方法来判断下一步网站SEO优化的方向。不知道接下来网站的内容应该关注哪个关键词。

  免费好用的采集

链接查询工具

  答案是肯定的,这里我只谈自己的心得体会,对于工具我不做任何推荐。本工具可以查询不同搜索引擎(百度/搜狗/今日头条)的收录链接,您可以查询对应的搜索引擎收录了您的网站?哪个?友情链接,同时还提供标题和域名过滤功能。具体可以查询的字段:采集

排名/采集

标题/采集

链接/采集

时间/真实标题/真实链接/真实关键词等,重要的是它是免费的!自由的!自由的!,并且可以导出excel!

  

" />

  导出到excel后,可以用它按收录

时间进行过滤。对于那些长时间没有更新的快照,可以做批量反馈更新。这对于新奇的站长等对网站时效要求很高的站长来说可能非常有用。并且一眼就能知道网站是否被蜘蛛劫持。那些与网站无关的标题是指向你网站本身的链接,这就证明你的网站一定是木马。对小白站长来说非常方便。我第一次发现网站有问题。

  总之,一个好的SEO站长工具可以让你的网站有一个明确的优化方向。无论是SEO站内优化还是站外优化。如果SEO优化做得好,那么网​​站的访问量和排名,以及网站的收录都会越来越好。我是一名SEO从业者,SEO就是分享。今天的SEO分享就到这里了,希望能为大家的网站优化提供一些建设性的建议。

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线