arm ida 伪代码 安卓 符号表_ARM栈回溯——从理论到实践,开发IDAarmunwindplugin

本文详细介绍了ARM架构下的栈回溯原理,包括ELF文件中的.ARM.exidx和.ARM.extab段,以及如何使用python解析这些段来实现栈回溯。作者开发了一个IDA插件,用于在调试环境中进行栈回溯,通过字节码反汇编和解释执行,获取函数调用序列。
摘要由CSDN通过智能技术生成

39895d94f811c13884be4ae5bd1749da.png

本文为看雪论坛精华文章

看雪论坛作者ID:LeadroyaL

本文从栈回溯的原理开始,到 arm ehabi 的回溯方式,再到 elf 文件中的 unwind 信息,最后实现一款 IDA 里实时进行 arm 栈回溯的插件,覆盖了现代 arm 栈回溯的全部内容,希望能给大家带来帮助。   作品链接: https://github.com/LeadroyaL/IDA_ARM_Unwind   pyelftools的commit 链接: https://github.com/eliben/pyelftools/commit/ee0facee32ae5fc91709c93f9a57a9a7683a3315

一. 背景

起因

故事要从几个月前的一个 arm crash 说起,把 crash 交给新来的小朋友看,他说 IDA 里显示的栈回溯和logcat里显示的栈回溯是不一致的,问我为什么。   我说一直是logcat里看的,是正确的;那么 IDA 里只有一层栈回溯肯定是错的,但我却解释不来原因,于是有了本文和一系列研究。

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

从小老师就教育我们,函数开头一般是这三句话,用于保存堆栈,开辟新的栈空间:
push ebpmov ebp, espsub esp, 0x100
在这种设定下,栈回溯变得非常简单,ebp 就是栈帧,ebp 附近是上一个栈帧,再附近是返回地址。网上相关的文章一搜一大把,这里就不多讲了,找一张网图凑合一下。   82570da79f48b5d1d3a46826bbe5fbd3.png

arm 的栈结构

我们随便找个 /system/lib/libc.so,再随便编译一个 so,随便找几个函数看一下,发现和x86的不大一样。
.text:000233C0                 PUSH.W          {R4-R8,LR}.text:000233C4                 SUB             SP, SP, #8.text:000233C6                 LDR             R4, [SP,#0x20+arg_8].text:000233C8                 MOV             R5, R1....text:00023460                 MOV             R0, R4.text:00023462                 ADD             SP, SP, #8.text:00023464                 POP.W           {R4-R8,PC}
.text:00023A94                 PUSH.W          {R4-R9,LR}.text:00023A98                 SUB             SP, SP, #4.text:00023A9A                 MOV             R8, R1.text:00023A9C                 MOV             R5, R0....text:00023B12                 ADD             SP, SP, #4.text:00023B14                 POP.W           {R4-R9,PC}
.text:0003477C                 PUSH            {R7,LR}.text:0003477E                 MOV             R7, SP.text:00034780                 SUB             SP, SP, #0x28.text:00034782                 LDR             R2, =(__stack_chk_guard_ptr - 0x34788)....text:000347CE                 MOVS            R0, #0.text:000347D0                 ADD             SP, SP, #0x28.text:000347D2                 POP             {R7,PC}
.text:000138C4                 PUSH            {R4,R5,R7,LR}.text:000138C6                 ADD             R7, SP, #8.text:000138C8                 SUB             SP, SP, #0x20.text:000138CA                 LDR             R4, =(__stack_chk_guard_ptr - 0x138D0)....text:000138F4                 ADDEQ           SP, SP, #0x20.text:000138F6                 POPEQ           {R4,R5,R7,PC}
观察这几组汇编,前两段 sp 的内容并没有被保存到任意一个寄存器里,但它可以被正确栈回溯,暗示栈回溯信息不在这段汇编里;后两段,把 sp 放到 r7 里,把 sp+8 放到 r7 里,有点像栈帧的感觉,并且函数内也没有覆盖掉 r7 的内容,有点 x86 的感觉。   查阅资料,随着时代发展,arm 有两种 unwind 方式: 1. 一种是古老的,和 x86 类似的(目前没有找到样例,可能在某种编译选项下存在),使用专用的 fp 寄存器保存原先的 sp,fp 在函数内禁止被改写,thumb 模式下使用 r7 作为 fp,arm 模式下使用 r11 作为 fp。 2. 另一种是流行的, arm 特有的(目前绝大部分都使用这种方式),遵从 eabi 里的 ehabi 标准,即 exception handler abi,定义了一套专属的标准。简而言之就是对每个函数分配自己专用的字节码,解释执行,从而实现栈回溯。 使用readelf -
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值