C++疑难杂症定位之—IDA篇

我们日常在定位C++的Core问题时,经常会遇到Core位置并非真实问题点的情况,在release无符号偶发场景下定位会更加困难。今天就通过一个问题场景,来讲解下如何通过IDA来进行此类问题的定位。

一、问题场景

框架通过dlopen加载业务模块so文件时发生崩溃,由于版本升级前正常,升级后异常,故业务方怀疑为框架升级导致。

二、分析过程

1. 确定调用关系及崩溃调用链

如何确定崩溃点: 这里的基本原则是根据调用关系中逐级查看,如果系统模块中出现异常相关信息捕获、抛出前最近的自有模块调用位置就是触发点。

2. 取得崩溃点偏移信息

上图中我们可以看到这个日志信息中的每一级调用都有两个十六进制数值,其中位数较短的0x2d69e0为偏移地址,位数较长的0xfffdcf1fa9e0为虚拟地址。两者之差即为当前模块在内存中的基地址: base addr = 0xfffdcf1fa9e0 – 0x2d69e0 = 0xfffdcef24000

根据函数调用原理,我们知道无论Intel或是arm指令中,上面调用堆栈中地址其实就是函数调用后的返回地址,也就是被调用函数的下一条指令的位置,有了这个信息后面就可以在汇编指令中确定具体是哪个指令引发的崩溃。

3. 静态分析崩溃点

工具版本:IDA Pro 7.7 SP1。

由于是64bit平台下的模块,所以打开ida64后直接将libxxx.so文件拖拽到ida64主界面,然后一路确认下一步即可。

so相对较大时,IDA分析时间较长,耐心等待其分析完毕,分析完毕后会有提示,如下图所示:

在主界面上按字母g跳转到异常偏移0x2d69e0

跳转过去后按空格键,显示带地址的文本汇编界面

从这里可以看到引发异常的调用为0x2D69DC,被调函数为sub_2D6250,然后按F5(伪代码界面,这里的IDA支持ARM64指令的伪代码显示)。

可以看到,这里其实是进行了std::string对象的构造,将getenv所取得的环境变量指针传入std::string构造函数。若环境变量不存在v20将为nullptr,最终触发异常。

三、解决方案

将分析结果反馈给对应业务侧同学,其需要对getenv(“xxx_PATH”)的返回结果进行检查。

四、问题总结

这是一个典型的未校验空指针直接使用引发的异常,但是由于引发异常的时机是在框架执行dlopen加载业务模块时,所以被认为是框架自身的逻辑引发的异常。

无符号的release产出单纯通过coredump无法获得更详细的信息,因此定位较为困难,而借助IDA工具可以较为方便的定位问题的具体位置,确实是疑难杂症定位的利器。

 

欢迎关注下方“非著名资深码农“公众号进行交流~

发表评论

邮箱地址不会被公开。