ARM的栈回溯(三):在 ida 里实时进行 arm 栈回溯
本系列文章共三篇。本文是第三篇,使用已有的知识,实现 arm stack unwind,给本系列完美地画上句号。
ida arm unwind plugin
IDA 里有一个不常用的功能,叫打印栈回溯,使用的是常见的 ebp/esp 栈帧技术,没有对 ARM 进行适配,导致调试安卓 so 时完完全全是错的。本文编写一个 ida 插件,正确展示实时的 arm 栈回溯。
代码在:https://github.com/LeadroyaL/IDA_ARM_Unwind ,欢迎 star。
设计思路:
- 总目标,对当前断点进行栈回溯,得到 pc 序列,进一步可以得到 crash-log 一样的栈回溯展示
- 检查运行环境,需要是 ARM 架构,需要处于调试中的状态
- 将当前 pc 加入序列
- 初始化
VRSStatus
状态,将各个寄存器的值设置正确,为 unwind 做准备 - 递归 unwind
- 根据当前 pc 找到当前 ELF 头部的大概位置,解析头部的一些字节,使用 pyelftools 得到第一个 PT_LOAD
.ARM.exidx
和.ARM.extab
一定在第一个PT_LAOD
里,使用 pyelftools 解析它们的数据- 根据当前 pc、
List[EHABIEntry]
,找到对应的 EHABIEntry - 解释执行对应的字节码,得到最终状态
- 最终状态的 LR 就是返回地址,判断 ARM 还是 THUMB,再决定是 -2 还是 -4,修正为上一条指令的地址
- 将计算好的 pc 加入序列
- 使用 pc 序列,寻找对应的 module、funcion,计算相对偏移,构造为
List[Frame]
7: 绑定快捷键,画 GUI,抄的https://github.com/ChiChou/IDA-ObjCExplorer
的代码
效果图,个人感觉还是非常好用的哈:
具体用途看仓库里的 readme 哈。
总结
三篇文章,虽然是按照开发的时间顺序写的,但发生顺序其实是反的,这个流程拖得挺长:
- 先发现 IDA 失效,于是准备写个插件;
- 写插件,研究栈回溯,发现 ARM 的栈回溯跟人不一样 (参考 原创andorid native栈回溯原理分析与思考 )
- pyelftools 不提供 arm ehabi 的解析,于是自己实现数据解析(参考 https://github.com/llvm/llvm-project/blob/master/llvm/tools/llvm-readobj/ARMEHABIPrinter.h )
- libunwind 接入成本太高,于是自己用 python 写字节码的解释执行和 unwind(参考 https://github.com/llvm/llvm-project/blob/master/libunwind/src/Unwind-EHABI.cpp )
把大量的规范从 c 移植为 python,整个下来花了我大量时间,但对 unwind 本身有了非常深刻的理解,希望 elftools.ehabi
和 ida-arm-unwind-plugin
这两个轮子能为行业做贡献吧。
作品链接:https://github.com/LeadroyaL/IDA_ARM_Unwind
pyelftools的commit 链接:https://github.com/eliben/pyelftools/commit/ee0facee32ae5fc91709c93f9a57a9a7683a3315
总结
本文讲了 ELF 里 arm ehabi 的存放和使用。
第一篇指路:https://leadroyal.cn/p/1125
第二篇指路:https://leadroyal.cn/p/1131
第三篇指路:https://leadroyal.cn/p/1135