`
izuoyan
  • 浏览: 9206002 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

调试经验谈-根据crash dump查找bug

 
阅读更多

很多时候,我们不知道如何重现一个crash问题,只有一些log或者dump,拿到一个这样的crash的问题,并不知道是什么原因,怎么样来慢慢分析,这篇文章就举了一个现实的例子,看看怎么查找一个crash问题的原因。

这个是我们软件发生的一次崩溃,只在客户的环境上发生,没有人知道在实验室里怎么重现,好在客户那边给出了windows的dump文件,这样就可以很容易的查看当时的案发现场了。

用windbg打开dump文件,打开汇编窗口,点击调用堆栈最上面的函数,就可以看到如下汇编代码

2e252013 51 push ecx
2e252014 53 push ebx
2e252015 57 push edi
2e252016 8bf9 mov edi,ecx
2e252018 33db xor ebx,ebx
2e25201a 395f04 cmp dword ptr [edi+4],ebx
2e25201d 7454 je nqp+0x22073 (2e252073)
2e25201f 66395f14 cmp word ptr [edi+14h],bx
2e252023 763c jbe nqp+0x22061 (2e252061)
2e252025 895dfc mov dword ptr [ebp-4],ebx
2e252028 56 push esi
2e252029 8da42400000000 lea esp,[esp]
2e252030 8b7704 mov esi,dword ptr [edi+4]
2e252033 0375fc add esi,dword ptr [ebp-4]
2e252036 837e0800 cmp dword ptr [esi+8],0 ds:0023:613d634e=???????? <<-----软件在这里就崩溃了

通过调用堆栈,我们可以找到对应的函数的源码

void HTMLelement:: ResetPriv()
{
if (i_pAttributeList) {
for (int i = 0; i < i_totAttrs; i++) {
GetAttributeEntry(i)->Reset();
}
}
}

可以看出来 是在cmp dword ptr [esi+8],0 的时候出了异常,这个指令能出的异常,也就是 [esi+8]不能读,这说明 esi+8这个地址错了,但是为啥会错呢,只能是esi的值不对。先看看esi是多少,在命令窗口 输入 r esi

0:036> r esi
Last set context:
esi=613d6346

这个613d6346 显然是不可访问的内存。所以,我们就需要看看esi是哪里来的。一行行的往上看:

add esi,dword ptr [ebp-4]

这句把ebp-4里面的数加到esi上,那我们需要看看ebp-4是多少了,在命令窗口里面输入 dd ebp-4

0:036> dd ebp-4
32e3cc10 00000000 32e3cc24 2e252966 32e47284
32e3cc20 32e47218 32e3cc44 2e252e24 32e47284
32e3cc30 00000000 00000001 32e47218 32e47218
32e3cc40 00000000 32e3e9fc 2e3abbd6 32e3e960
32e3cc50 00000000 00000000 00000001 32e3f8f0
32e3cc60 00000000 2e462e8c 00000000 32e3cc84
32e3cc70 00000001 016edda8 32e3cf5c 03434cf8
32e3cc80 034348f8 32e3cc90 60001780 016edda8

可见 ebp-4是0,这很正常,这个ebp-4是个局部变量i,其实就是个数组的下标,0不像是个越界的值,那么就需要继续往前看

mov esi,dword ptr [edi+4]

esi的值是来自edi+4,那我们来看看edi+4是啥

0:036> dd edi
32e3e960 32257974 613d6346 00000075 00000042
32e3e970 00000002 00000002 00000000 00000000
32e3e980 32e3e9a0 00000000 00000000 00000019
32e3e990 00000002 00000000 00000000 00000000
32e3e9a0 32e3e960 00000000 00000000 0000006e
可见这个值就是613d6346,就是esi的值,那就说明 这个内存里面的值有问题,出错的可能有两个,一种可能是这个内存的值不对,另一种可能是是edi的值不对,导致取值取错了地方。跟踪edi还是容易一点,所以我们继续往上看edi的值是哪里来的。

2e252016 8bf9 mov edi,ecx

这个是函数的开头,我们知道ecx放的就是对象的地址,也就是this,说明edi里面就是this,这就说明edi出错的可能比较小了,除非上面函数传值的时候就传错了,看了一下源码,这个HTMLelement的地址应该没啥太大机会出错。这里不是说完全排除,但是进一步跟踪的代价比较大了,所以我们先放一下,看另外一个可能。那就是这个对象里面的内容出错了。

越界的问题往往是数组越界,而字符串是最容易越界的,我们来看看这个会是啥字符,输入 dc edi 看看

:036> dc edi
32e3e960 32257974 613d6346 00000075 00000042 ty%2Fc=au...B...
32e3e970 00000002 00000002 00000000 00000000 ................
32e3e980 32e3e9a0 00000000 00000000 00000019 ...2............
32e3e990 00000002 00000000 00000000 00000000 ................
32e3e9a0 32e3e960 00000000 00000000 0000006e `..2........n...
32e3e9b0 00000002 00000000 00000000 00000000 ................
32e3e9c0 2e46beb4 00000000 3607274c 00000091 ..F.....L'.6....
32e3e9d0 32e3e9a0 00000000 00000000 00000033 ...2........3...

很明显这里应该是是个指针的地方,居然看起来像个字符串了,往前看看完整的字符串是啥

0:036> dc edi-128 edi+16
32e3e838 00000000 00000000 00000000 00000000 ................
32e3e848 00000000 00000001 00000001 ffffffff ................
32e3e858 2e2f2e2e 64242f2e 75616665 6976746c ../../$defaultvi
32e3e868 372f7765 45314243 43443944 43463944 ew/7CB1ED9DCD9FC
32e3e878 38424145 36353235 30334337 32453630 EAB852567C3006E2
32e3e888 2f454244 65704f3f 636f446e 6e656d75 DBE/?OpenDocumen
32e3e898 72502674 74655365 6c656946 683d7364 t&PreSetFields=h
32e3e8a8 7465535f 64616552 6e656353 5f683b65 _SetReadScene;h_
32e3e8b8 75636553 79746972 626d654d 6e497265 SecurityMemberIn
32e3e8c8 682c6f66 6d654d5f 4e726562 3b656d61 fo,h_MemberName;
32e3e8d8 4a3d6e63 61696c75 3032256e 73726143 cn=Julian%20Cars
32e3e8e8 32256e6f 3d756f46 69737542 7373656e on%2Fou=Business
32e3e8f8 50303225 6e6e616c 25676e69 6e613032 %20Planning%20an
32e3e908 30322564 6f736552 65637275 46322573 d%20Resources%2F
32e3e918 533d756f 65647574 3225746e 646e6130 ou=Student%20and
32e3e928 43303225 756d6d6f 7974696e 53303225 %20Community%20S
32e3e938 69767265 25736563 756f4632 6174533d ervices%2Fou=Sta
32e3e948 32256666 4d3d6f46 73616e6f 30322568 ff%2Fo=Monash%20
32e3e958 76696e55 69737265 32257974 613d6346 University%2Fc=a
32e3e968 00000075 00000042 00000002 00000002 u...B...........

看来前面是个很长的字符串,数数看,从字符串开始的地方 32e3e858 算,有270多个字符,估计有某个地方定义了个256的缓存区,然后没做检查,就把后面的栈上的内存给覆盖了,继续看stack,看看这个字符数组是属于哪个函数的栈帧。k可以看函数调用栈

0:036> k
*** Stack trace for last set context - .thread/.cxr resets it
ChildEBP RetAddr
WARNING: Stack unwind information not available. Following frames may be wrong.
32e3cc14 2e252966 nqp+0x22036
32e3cc24 2e252e24 nqp+0x22966
32e3cc44 2e3abbd6 nqp+0x22e24
32e3e9fc 2e3ae8d7 nqp+0x17bbd6
32e3eb40 2e3ace45 nqp+0x17e8d7
32e3eb84 2e3c9823 nqp+0x17ce45
32e3ebbc 2e2fb73b nqp+0x199823
32e3ebcc 2e301e22 nqp+0xcb73b
32e3ffe4 2e318255 nqp+0xd1e22
32e402a8 2e271b68 nqp+0xe8255
32e42c78 2e27236a nqp+0x41b68
32e42cc0 600bbf1a nqp+0x4236a

因为我现在没有当时那个版本的pdb,所以显示不了具体的函数,有pdb的话,可以看到函数名字,我们可以看出来32e3e858 是属于下面这个函数调用的栈上的

32e3e9fc 2e3ae8d7 nqp+0x17bbd6

在有symbol的情况下,就可以知道是哪个函数了,在这个函数里面,找到了这样的语句。

char memberDocURL[MAX_PATH+1] = "javascript:void(0);";

........

URLencodedString.Copy(dn);
huURL.URLencode(&URLencodedString);
strcat(memberDocURL, URLencodedString);

在栈上开了个MAX_PATH+1的数组,这里MAX_PATH是260,然后一系列操作,都是靠strcat来做的,dn这个字符串如果很长,就像上面显示的那样,URLencodedString也会很长,就会导致写越界了。把后面的对象给覆盖了。

到这里,原因就找到了。典型的字符串操作不小心导致缓存区溢出。

总结一下,对于这种不可重现的crash问题,就是要从crash的地方入手,看看哪个数据不对,顺藤摸瓜,一点点往前面排查。windbg是个很强大的调试工具,特别是分析这种只有dump,没法重现的问题,非常有用。

分享到:
评论

相关推荐

    flazx_panic-unix-system-crash-dump-analysis-handbook

    《flazx_panic-unix-system-crash-dump-analysis-handbook》是一本专注于Unix系统崩溃dump分析的专业指南。这本书深入探讨了如何在Unix系统遇到Panic(系统异常)时,通过分析系统崩溃dump文件来诊断问题,从而进行...

    嵌入式+Linux-Crash-Dump的设计与实现

    根据文中给出的表格,我们可以进一步分析这两种实现Crash-Dump方案的优缺点: | 实现方式 | 优点 | 缺点 | |----------|--------------------------------------------------------------|------------------------...

    Linux Crash Dump分析工具的设计与实现.pdf

    关键词:Linux Crash Dump、Crash Dump 分析工具、Linux 操作系统、系统调试、故障诊断。 Linux Crash Dump 的实现策略 Crash Dump 的生成是 Linux Crash Dump 分析工具的第一步。在 Crash Dump 生成过程中,...

    redis-check-dump.exe

    redis-check-dump.exe-

    canutils-4.0.6 candump.c源码 canutils-4.0.6 candump.c源码

    canutils-4.0.6 candump.c源码 canutils-4.0.6 candump.c源码

    Laravel开发-laravel-pretty-dump

    除了默认设置,`laravel-pretty-dump` 还允许开发者根据个人喜好进行配置。可以在 `config/debugbar.php` 文件中找到相关选项,如调整颜色方案、开启或关闭特定功能等。 6. **与其他工具的集成** `laravel-pretty...

    crashdump.dll

    crashdump.dll

    parallel-fastq-dump:并行fastq-dump包装器

    并行fastq转储并行fastq-dump包装器为什么和如何即使您已经拥有更快的资源(网络,IO,CPU),即使您已经下载了sra文件,NCBI fastq-dump有时也会非常慢。 该工具通过将工作划分为多个线程来加快过程。 这是可能的,...

    调试Release程序--Dump文件方式

    在Windows平台下用C++开发应用程序,最不想见到的情况恐怕就是程序崩溃,而要想解决引起问题的bug,最困难的应该就是调试release版本了。目前有一些方法可以解决:崩溃地址 + MAP文件;MAP文件;...

    Atom-atom-dicom-dump,用于检查dicom文件内容的atom编辑器包.zip

    Atom 提供了丰富的插件库,使得用户可以根据自己的需求定制编辑环境,而 Atom-atom-dicom-dump 正是这些插件之一,为处理 DICOM 数据提供了便利。 DICOM 文件通常包含元数据(如患者信息、设备信息、扫描参数等)和...

    class-dump-z全平台版本(linux、iPhone、Windows)

    《class-dump-z:全平台神器,探索iOS与跨平台逆向工程的得力助手》 在IT行业中,尤其是在移动应用开发和安全分析领域,逆向工程是一项至关重要的技能。它可以帮助开发者理解软件的工作原理,查找漏洞,或者优化...

    frida-ios-dump-master.zip

    frida-ios-dump-master.zip

    windbg-x64 dump分析工具

    Windbg是在windows平台下,强大的用户态和内核态调试工具。相比较于Visual Studio,它是一个轻量级的调试工具,所谓轻量级指的是它的安装文件大小较小,但是其调试功能,却比VS更为强大。它的另外一个用途是可以用来...

    Linux Crash Dump的设计与实现.pdf

    【Linux Crash Dump】是指在Linux操作系统中,当系统发生崩溃(Crash)时,能够将内存中的状态信息记录并保存下来的一种机制。这种机制对于系统开发者和维护者来说非常重要,因为它允许他们分析这些记录的信息,从而...

    前端开源库-adana-dump

    adana-dump就是为了弥补这一空白,它能在进程关闭前捕获并记录adana的相关信息,以便后续分析和调试。 adana-dump库的工作流程大致如下: 1. **集成到项目**:在你的前端项目中引入adana-dump,可以通过npm安装,...

    Unix System Crash Dump Analysis .chm

    Unix System Crash Dump Analysis Panic! UNIX® System Crash Dump Analysis &lt;br&gt;很好的一本分析Unix系统下Crash以后对dump文件的分析与实战技巧。想提高unix下的编程与调试水平,这本书相信有很大帮助。...

    class-dump, class-dump-z.exe,class-dump-z win版本

    class-dump, class-dump-z.exe,class-dump-z win版本

    MTK系统DUMP之Crash-8.0.1工具

    MTK(MediaTek)系统DUMP之Crash-8.0.1工具是专为基于MediaTek芯片的Android设备设计的故障排查和日志收集工具。这个工具主要用于当设备遇到崩溃或异常情况时,帮助开发者或者技术人员分析并解决系统问题。在Android...

    350-401_dump.zip

    【标题】"350-401_dump.zip" 是一个与Cisco认证考试相关的压缩文件,其中包含了关于350-401考试的重要资料。350-401是Cisco Certified Network Professional (CCNP) Enterprise认证考试的一个部分,全称为...

    Android-wechat-dump.zip

    Android-wechat-dump.zip,从android破解加密微信历史记录,安卓系统是谷歌在2008年设计和制造的。操作系统主要写在爪哇,C和C 的核心组件。它是在linux内核之上构建的,具有安全性优势。

Global site tag (gtag.js) - Google Analytics