ARM的栈回溯(一):函数调用栈的简介

本系列文章共三篇。本文是第一篇,讲一些栈回溯的背景,不涉及技术细节。关键词:arm unwind,ehabi,arm stacktrace。

# 起因

故事要从几个月前的一个 arm crash 说起,把 crash 交给新来的小朋友看,他说 IDA 里显示的栈回溯和logcat里显示的栈回溯是不一致的,问我为什么。

我说一直是logcat里看的,是正确的;那么 ida 里只有一层栈回溯肯定是错的,但我却解释不来原因,于是有了本文和一系列研究。

# 平时讨论的函数调用栈结构

从小老师就教育我们,函数开头一般是这三句话,用于保存堆栈,开辟新的栈空间:

在这种设定下,栈回溯变得非常简单,ebp 就是栈帧,ebp 附近是上一个栈帧,再附近是返回地址。网上相关的文章一搜一大把,这里就不多讲了,找一张网图凑合一下。

# arm 的栈结构

我们随便找个 /system/lib/libc.so,再随便编译一个 so,随便找几个函数看一下,发现和x86的不大一样。

 

观察这几组汇编,前两段 sp 的内容并没有被保存到任意一个寄存器里,但它可以被正确栈回溯,暗示栈回溯信息不在这段汇编里;后两段,把 sp 放到 r7 里,把 sp+8 放到 r7 里,有点像栈帧的感觉,并且函数内也没有覆盖掉 r7 的内容,有点 x86 的感觉。

查阅资料,随着时代发展,arm 有两种 unwind 方式:

1. 一种是古老的,和 x86 类似的(目前没有找到样例,可能在某种编译选项下存在),使用专用的 fp 寄存器保存原先的 spfp 在函数内禁止被改写,thumb 模式下使用 r7 作为 fp,arm 模式下使用 r11 作为 fp

2. 另一种是流行的, arm 特有的(目前绝大部分都使用这种方式),遵从 eabi 里的 ehabi 标准,即 exception handler abi,定义了一套专属的标准。简而言之就是对每个函数分配自己专用的字节码,解释执行,从而实现栈回溯。

使用

可以查看,字节码长这样:

# arm ehabi

讲了这么多,终于引出本系列的重点:arm ehabi

官方文档,复杂但权威:https://developer.arm.com/documentation/ihi0038/b/
看雪有篇不错的文档:[原创andorid native栈回溯原理分析与思考](https://bbs.pediy.com/thread-216447.htm)

– 使用 readelf -u 可以打印相关信息,也可以使用pyelftools里的 readelf.py -au 打印出来(而且这个功能是我写的)。
– 千万不要使用 llvm-readelf -u,因为它有 bug,只支持 .o 文件。

名词解释

| 名词 | 解释 |
|—–|—–|
| stack unwind | 意思就是栈回溯。|
| abi | (application binary interface)二进制应用接口,相当于标准和规范|
| arm eabi | arm 很多规范的合集,包括 AADWARF、AAELF等,也包括 CLIBABI、CPPABI、【EHABI】|
| arm ehabi | arm 的 exception handler abi |
| exception handler | 异常处理,既包括 crash 时的栈回溯,也包括 c++ 里的异常处理。|
| arm exception handler index table | 指 .ARM.exidx,存放函数offset、简单的handler 的数据、复杂handler的索引。|
| arm exception handler table | 指 .ARM.extab,存放复杂 handler 的数据。|

和平时逆向相关的,有两部分内容,有个大致认知就行:

1. 数据存放。在 ELF 文件里肯定存放了信息,指导如何进行栈回溯,.ARM.exidx.ARM.extab 就是做这件事情的;

2. 数据使用。每个函数 unwind 时需要解析 exception handler table,需要解释执行字节码,这个功能有时会由操作系统完成(例如 crash 的时候),有时会由应用程序自己完成(例如使用写代码主动进行栈回溯)。

# 总结

本文讲的是背景,没什么技术细节,第二篇讲文件格式。

 

第一篇指路:https://www.leadroyal.cn/?p=1125

第二篇指路:https://www.leadroyal.cn/?p=1131

第三篇指路:https://www.leadroyal.cn/?p=1135

 


=============================================================
随着访客的增多,LeadroyaL在本站流量的开支越来越多了,曾经1元能用1个月,现在1元只能用3天。如果觉得本文帮到了你,希望能够为服务器的流量稍微打赏一点,谢谢!

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*

code