调试实战——使用windbg调试崩溃在ole32!CStdMarshal::DisconnectSrvIPIDs

简介: 使用windbg调试崩溃在ole32!CStdMarshal::DisconnectSrvIPIDs

前言

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

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

初识问题

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调试TerminateThread导致的死锁
本文记录了调试 TerminateThread 导致的死锁问题
|
SQL Java 测试技术
再也不需要手写 SQL 造数据了
DBeaver 是一个功能非常完善的数据库客户端,它有 开源免费版本:https://github.com/dbeaver/dbeaver, 企业版:https://dbeaver.com/
再也不需要手写 SQL 造数据了
|
Web App开发 弹性计算 关系型数据库
【MySQL数据库进阶实战】如何在云端创建MySQL数据库
冬季实战营第三期:MySQL数据库进阶实战 2月15日 动手实战-如何在云端创建MySQL数据库
2522 0
【MySQL数据库进阶实战】如何在云端创建MySQL数据库
|
10月前
|
关系型数据库 MySQL 数据库
Docker Compose V2 安装常用数据库MySQL+Mongo
以上内容涵盖了使用 Docker Compose 安装和管理 MySQL 和 MongoDB 的详细步骤,希望对您有所帮助。
900 42
|
11月前
|
数据建模 网络安全
阿里云SSL证书不同类型DV、OV和EV如何收费?单域名和通配符SSL价格整理
阿里云SSL证书提供免费和收费版本,涵盖DV、OV、EV多种类型。收费证书品牌包括DigiCert、GlobalSign等,价格从238元/年起。免费SSL证书由Digicert提供,单域名有效3个月,每个实名主体每年可领取20个。具体价格和详情见阿里云SSL官方页面。
|
机器学习/深度学习 运维 安全
图神经网络在欺诈检测与蛋白质功能预测中的应用概述
金融交易网络与蛋白质结构的共同特点是它们无法通过简单的欧几里得空间模型来准确描述,而是需要复杂的图结构来捕捉实体间的交互模式。传统深度学习方法在处理这类数据时效果不佳,图神经网络(GNNs)因此成为解决此类问题的关键技术。GNNs通过消息传递机制,能有效提取图结构中的深层特征,适用于欺诈检测和蛋白质功能预测等复杂网络建模任务。
474 2
图神经网络在欺诈检测与蛋白质功能预测中的应用概述
|
开发框架 Android开发 iOS开发
安卓与iOS开发中的跨平台策略:一次编码,多平台部署
在移动应用开发的广阔天地中,安卓和iOS两大阵营各占一方。随着技术的发展,跨平台开发框架应运而生,它们承诺着“一次编码,到处运行”的便捷。本文将深入探讨跨平台开发的现状、挑战以及未来趋势,同时通过代码示例揭示跨平台工具的实际运用。
355 3
|
Ubuntu Linux 数据库
在Linux中,如何进行软件包升级?
在Linux中,如何进行软件包升级?
|
监控 安全 Windows
逆向学习Windows篇:lab的使用和生成过程,以及“dell”的导出函数和作用
逆向学习Windows篇:lab的使用和生成过程,以及“dell”的导出函数和作用
306 0
|
人工智能 编解码 算法
【MATLAB】史上最全的9种频谱分析算法全家桶
【MATLAB】史上最全的9种频谱分析算法全家桶
1275 0
【MATLAB】史上最全的9种频谱分析算法全家桶