原调试debugwindbg崩溃crash

前言

最近程序会不定期崩溃,很是头疼!今晚终于忍无可忍,下决心要干掉它!从之前的几个相关的dump可以猜到是有接口未释放导致的问题,但没有确认到底是哪个接口。本篇总结记录了找到这个接口的过程。

{% note info %}

这是几年前在项目中遇到的一个问题。我对之前的笔记进行了整理重新发布于此。

{% endnote %}

初识问题

windbg打开dump文件,显示如下:


startup

从图中可以很明显的看出来是访问违例(因为红框标识的地址5bbc97f8的内容是????????),而且这是一条call指令,call调用的地址存储在ecx+8 (0x5bbc97f8) 处。我们可以用!address address来查看某个地址的信息,输入!address 5bbc97f8


address info

从图中得知,地址5bbc97f8对应的内存已经被释放了(StateMEM_FREE)。windbg还贴心的给出了和此地址相关的一些模块信息。其中有几个是我们自己的模块,从Unloaded可以看出这几个模块曾经被卸载过。很有可能跟我们的崩溃相关。

至此,我们可以大胆猜测崩溃的原因是模块被卸载后,还要执行其中的代码!:bomb:

下面让我们继续分析,为什么模块卸载后还会执行其中的代码!

寻根溯源

先用.ecxr切换到发生异常时的上下文,然后用kpnk显示调用栈,p显示函数的参数,n显示栈帧编号)查看调用栈,如下图:


ecxr-kpn

从上图可知,11号线程在调用CoUninitialize()执行COM的线程清理工作,frame 0在调用ole32!CStdMarshal::DisconnectSrvIPIDs()时崩溃了!从Disconnect猜测是要断开连接!使用ub 76f8bbe776f8bbe7是由76f8bbe4 + 3得到的,在上一篇文章里介绍过了)查看崩溃前的几条指令:


ub-76f8bbe7

红框内的指令非常像是虚函数的调用(调用约定是stdcall,不是thiscalleax是调用类对象的指针(通过入栈方式传递), ecx指向虚函数表(vtable),dword ptr[ecx+8]是虚函数表中的第三项(32位下指针占4字节,第一项的偏移是+0,第二项的偏移是+4,第三项的偏移是+8)。回想IUnkown的前三个函数分别是QueryInterface(), AddRef()Release(),可以大胆猜测这里是在调用Release(),跟上下文也很搭(从CoUninitialize()推断当前线程正在做COM清理工作)!我们的猜测很有可能是正确的!

我们先小小总结一下:整个过程应该是这样的,我们使用了一个COM接口,但是由于某些原因并没有释放,线程在退出的时候,调用CoUninitialize()COM清理工作。当清理到我们的接口的时候,由于接口代码所在的dll已经被卸载了,从而导致了访问违例!下面我们的任务是找出到底是哪个接口没释放,然后对照代码验证我们的猜测是否正确!

验证

先用lm a 5bbc97f8确认下该地址属于哪个模块。


lma-5bbc97f8

看来,地址5bbc97f8落在AccIME.dll中,由于AccIME.dll已经被卸载了,我们需要使用命令.reload /f AccIME.dll=5bbb0000,5bbd8000-5bbb0000来重新加载已经被卸载的模块,我们可以使用lm vm AccIME来确认加载成功与否。


reload-and-lmvm

从上图可知,我们成功的加载了AccIME模块,符号也加载成功了。

**友情提示:**如果遇到如下错误,说明我们成功加载了被卸载的dll,但是加载符号的时候遇到了问题。


reload-failed

可以使用!sym noisy开启嘈杂模式,然后再次执行.reload命令,通过输出日志来排查具体原因。排查完毕后可以使用!sym quiet来关闭嘈杂模式。具体使用方法可通过.hh !sym查看windbg帮助文档。

接下来我们用ln 5bbc97f8查一下该地址附近函数。


ln-5bbc97f8

至此,我们可以看到是与AccIME!CCfgDpyScheme类相关的问题,接下来我们可以把重点放到对此类的引用计数的使用上了!

本篇总结暂时写到这,还需要弄明白几个问题:

  1. 涉及引用计数的相关代码是否有问题。
  2. 为什么有时候会崩溃,有时候不崩溃。

有结果后会再发一篇总结,敬请期待!(能力有限,没能查出来:cry:)

解决方案

由于没能查出代码哪里有问题。使用临时解决方案先绕过去了:在退出的时候,没有使用FreeLibrary()显示卸载该模块,交由操作系统来做模块清理工作)。

未弄明白的问题的可能原因:

  1. 涉及引用计数的相关代码是否有问题。

    Oops, 没查出代码哪里有问题。无法确定问题的根本原因。:sob:

  2. 为什么有时候会崩溃,有时候不崩溃。

    有时候崩溃应该是还没断开连接,对应的dll就被卸载了。有时候不崩溃应该是在卸载dll之前,已经成功的断开了连接。

命令总结

  • !address address可以查看对应地址的信息,如果一个地址不可访问,那么显示的内容会是????????

  • .ecxr可以让windbg使用发生异常时的上下文,这样再使用k等命令时就是发生异常时的相关信息了。

  • u可以反汇编某个地址对应的代码,ub可以向前反汇编,b应该是backward的缩写。

  • lm a address可以查看address所属的模块。

  • ln可以查看某个地址附近的符号名。

  • .reload /f <image.ext>=<base>,<size>可以加载模块(甚至是已卸载的)到base指定的位置,并为之加载符号。

  • 关于各个windbg命令的用法,可以使用.hh command进行查看!非常方便,而且非常重要!

参考资料

  • 《格蠹汇编》
  • windbg帮助文档

[原]调试实战——使用windbg调试崩溃在ole32!CStdMarshal::DisconnectSrvIPIDs的更多相关文章

  1. [原]崩溃在ole32!CStdMarshal::DisconnectSrvIPIDs

    最近项目里遇到一个崩溃,不定期出现,很是头疼!今晚终于忍无可忍,下决心要干掉它!(于是用凉水洗了把脸,开始分析dump)希望凌晨的这篇总结对有相似经历的朋友有所启发!(看之前相关的几个dump可以猜到 ...

  2. [原]调试实战——使用windbg调试崩溃在ComFriendlyWaitMtaThreadProc

    原调试debugwindbgcrash崩溃COM 前言 这是几年前在项目中遇到的一个崩溃问题,崩溃在了ComFriendlyWaitMtaThreadProc()里,没有源码.耗费了我很大精力,最终通 ...

  3. [原]调试实战——使用windbg调试DLL卸载时的死锁

    原调试debugwindbg死锁deadlock 前言 最近我们的程序在退出时会卡住,调查发现是在卸载dll时死锁了.大概流程是这样的:我们的dll在加载的时候会创建一个工作线程,在卸载的时候,会设置 ...

  4. [原]调试实战——使用windbg调试TerminateThread导致的死锁

    原调试debugwindbg死锁deadlock 前言 项目里的一个升级程序偶尔会死锁,查看dump后发现是死在了ShellExecuteExW里.经验少,不知道为什么,于是在高端调试论坛里发帖求助, ...

  5. [原]调试实战——使用windbg调试excel启动时死锁

    原调试debugwindbg死锁deadlock 前言 这是几年前在项目中遇到的一个死锁问题,在博客园发布过.我对之前的笔记进行了整理重新发布于此. 本文假设小伙伴们知道一些基本概念,比如什么是.du ...

  6. .NET高级调试系列-Windbg调试入门篇

    Windbg是.NET高级调试领域中不可或缺的一个工具和利器,也是日常我们分析解决问题的必备.准备近期写2篇精华文章,集中给大家分享一下如果通过Windbg进行.NET高级调试. 今天我们来一篇入门的 ...

  7. Windbg调试命令详解

    作者:张佩][原文:http://www.yiiyee.cn/Blog] 1. 概述 用户成功安装微软Windows调试工具集后,能够在安装目录下发现四个调试器程序,分别是:cdb.exe.ntsd. ...

  8. Windbg调试命令详解(1)

    转载注明>> [作者:张佩][镜像:http://www.yiiyee.cn/Blog] 1. 概述 用户成功安装微软Windows调试工具集后,能够在安装目录下发现四个调试器程序,分别是 ...

  9. windbg调试.net程序

    1. 解决线上.NET应用程序的如下问题: 崩溃 CPU高 程序异常 程序Hang死 2. 安装WinDbg: http://msdn.microsoft.com/en-us/windows/hard ...

随机推荐

  1. HTTP协议、时间戳

    1.什么是HTTP协议 超文本传输协议(英文:HyperText Transfer Protocol,缩写:HTTP)是一种用于分布式.协作式和超媒体信息系统的应用层协议.HTTP是万维网的数据通信的 ...

  2. 基于云开发开发 Web 应用(四):引入统计及 Crash 收集

    在完成了产品的基础开发以后,接下来需要进行一些周边的工作,这些周边工具将会帮助下一步优化产品. 为什么要加应用统计和 Crash 收集 不少开发者在开发的时候,很少会意识到需要添加应用统计和 Cras ...

  3. ACM&OI 基础数论算法专题

    ACM&OI 基础数学算法专题 一.数论基础 质数及其判法 (已完结) 质数的两种筛法 (已完结) 算数基本定理与质因数分解 (已完结) 约数与整除 (已完结) 整除分块 (已完结) 最大公约 ...

  4. VS Code 配置vue开发环境

    一.插件 网上搜索vscode插件的文章,动辄十几个,其实根本用不了那么多,很多插件的作用还有重叠,电脑性能还被白白浪费.这里精简为主,每一个插件都发挥它最大的作用,并尽量说明它们的作用 Vetur ...

  5. Day 7:TreeSet

    补充上一日:HashCode方法默认返回的是内存地址,String类已经重写了对象的HashCode方法 方法细节:取出数组中的值或字符串的值按照规定计算返回一个值,如果两个字符串内容一致就会返回相同 ...

  6. 尝试用kotlin做一个app(写在前面)

    学kotlin的目的好像就是做一个app,不一定有什么想做的项目,只是单纯想掌握这一门技术,确切地说只是单纯想学会做app.对于概念的东西,我也没兴趣深究,用得到的学一下,用不到的,就算了.我也不知道 ...

  7. python类(3)感悟

    1.关于类属性attribute和实例(对象)特性property思考 为什么特性会出现,类属性不能完全替代它吗? 属性: python在为属性赋值时,只会搜索对象本身的__dict__,如果找不到对 ...

  8. 读书笔记 - js高级程序设计 - 第七章 函数表达式

      闭包 有权访问另一个函数作用域中的变量的函数 匿名函数 函数没有名字 少用闭包 由于闭包会携带包含它的函数的作用域,因此会比其它函数占用更多的内存.过度使用闭包可能会导致内存占用过多,我们建议读者 ...

  9. 合并两个word文档,保持样式不变

    一.需求说明 例如将封面插入到word正文上方 二.导入依赖 <dependency> <groupId>org.apache.poi</groupId> < ...

  10. MySQL数据库索引常见问题

    笔者看过很多数据库相关方面的面试题,但大多数答案都不太准确,因此决定在自己blog进行一个总结. Q1:数据库有哪些索引?优缺点是什么? 1.B树索引:大多数数据库采用的索引(innoDB采用的是b+ ...