🖨️
IOT 固件安全 All in One
  • 前言
  • WIKI
    • 固件分类
    • 固件获取
    • 固件解密
    • 固件解剖
    • 固件调试
    • 仿真分析
    • 固件FUZZ
    • 静态分析
    • 同源分析
    • 漏洞挖掘—Web接口
    • 漏洞挖掘—无线协议
    • 漏洞挖掘—APP应用
  • appendix
    • 附录1:信息收集
    • 附录2:工具列表
    • 附录3-1: 指令集分析-MIPS
    • 附录3-2: 指令集分析-PowerPC
    • 附录3-3: 指令集分析-ARM
    • 附录4: 基线
    • 附录5:Azure IOT SDLC Best Practice
    • 附录6: 论文
    • 附录7: 参考资料
Powered by GitBook
On this page
  • 一、ARM简介
  • 二、寄存器
  • 三、指令分析
  • 四、知识点图
  1. appendix

附录3-3: 指令集分析-ARM

一、ARM简介

ARM, Advanced RISC Machine, 是一个32位RISC处理器架构。ARM处理器广泛应用于嵌入式系统和物联网设备中,例如路由器,交换机,智能手机等。

ARM处理器支持7中运行模式,每种模式有自己的堆栈空间以及一组不同的寄存器子集。

  • 用户模式(user):正常程序执行模式;

  • 快速中断模式(FIQ):高优先级的中断产生会进入该种模式,用于高速通道传输;

  • 外部中断模式(IRQ):低优先级中断产生会进入该模式,用于普通的中断处理;

  • 特权模式(Supervisor):复位和软中断指令会进入该模式;

  • 数据访问中止模式(Abort):当存储异常时会进入该模式;

  • 未定义指令中止模式(Undefined):执行未定义指令会进入该模式;

  • 系统模式(System):用于运行特权级操作系统任务;

不过在Cortex系列中稍有不用,Cortex-A 和 Cortex-R 处理器有以上7中模式,而Cortex-M则只有两种模式,Thread 模式和 Handler 模式,Thread 模式没有特权,用于应用程序代码, Handler 模式有特权,用于异常处理程序(以下情况不适用于Cortex-M处理器)。

二、寄存器

ARM处理器有40个寄存器,32个通用寄存器,7个状态寄存器,一个PC寄存器,每一个模式对应有一种寄存器。

几个常用的寄存器: 1. R0-R3用户函数调用参数传递 2. R13,堆栈指针寄存器,也称为SP 3. R14,又称为LR,链接寄存器,用于保存函数调用时的返回地址 4. R15,又称为PC,程序计数器。在ARM状态下,位[1:0]为0,位[31:2]用于保存PC;在Thumb状态下,位[0]为0,位[31:1]用于保存PC。对于ARM指令集而言,PC总是指向当前指令的下两条指令的地址,即PC的值为当前指令的地址值加8个字节。

ARM寻址特点,如果汇编代码中使用 pc 间接寻址的话,实际得到的是 pc+偏移量+8 的地址中的内容,如:

pc = 0x1000
ldr  r0, [ pc, #12 ]

那么 r0 寄存器的结果是:

r0 = [0x1000+12+8] = [0x101a]

三、指令分析

ARM架构下的栈溢出利用跟x86,mips等架构下的利用过程差不多,只需要找到合适的gadgets即可,而我们照样可以用ROPGadget来寻找我们的gadgets。接下来记录下怎么一步一步来寻找我们的gadgets。

3.1 ARM指令概述

arm指令和x86有点相似之处,相比mips指令读起来更加容易理解。 ROP经常用到的指令如下:

arm架构下的函数返回时用LDMFD指令加BX指令,首先用LDMFD指令pop保存的寄存器的值以及LR的值,然后跳转至LR。在ROP的时候很多情况下可以利用LDMFD指令来减少ROP时用到的gadgets。

3.2 一步一步寻找gadgets

我们ROP的最终目的是执行system(cmd),cmd一般来说放到栈上,虽然针对未开地址随机化的情况,可以考虑放堆上,但还是会不稳定。所以绝大多数情况需要放到栈上面,这就需要找一个gadget来设置r0为一个栈地址,然后再寻找一个gadget跳到system即可。

ARM架构下的ROP有一个好处就是在函数返回时大多数情况会pop还原一些保存的寄存器的值,例如R4-R5,R4-R7等,这种情况可以利用函数本身的gadget来减少ROP的复杂程度。而如果函数返回时没有pop出lr以外的寄存器的话,这种情况就需要另外调整寻找gadgets的思路了。

  • 第一种情况

首先利用ROPGadget将libc中可利用的gadget找出来:

ROPgadget --binary libc.so > gadgets

ROPgadget --binary libc.so > gadgets

加入发生溢出的函数在返回时有以下指令操作:

LDMFD  SP!, {R4-R11,LR}
BX  LR

这里我们可以控制R4-R11和LR寄存器。 首先寻找类似

bx r5

的gadget,同时gadget也需要满足将栈地址赋值给一个通用寄存器。

grep "add r.*sp.*bx r5" gadgets

我们就随便选取第六个gadget即可。

gadget1:
    add r2, sp, #0x34
    mov lr, pc
    bx r5 

然后我们需要寻找一个类似mov r0, r2的gadget,但同时该gadget需要能控制程序流。 我们可以用如下命令寻找:

grep "mov r0, r2.*bx lr" gadgets

我们可以选取如下gadget:

gadget2:
    mov r0, r2
    pop {lr}
    bx lr

然后这两个gadgets结合程序本身的LDMFD指令即可完成ROP。 这个时候payload为:

payload = fill + gadget2 + fill + gadget1 + fill +  system + fill + cmd
  • 第二种情况

当函数返回时仅仅只有pop lr等操作时,这种情况下的ROP更加通用,跟MIPS架构下的ROP思路差不多。 这时我们只需要在上面的情况下找一个gadget来设置r5即可。满足条件的有很多,基很多函数返回时的最后两台指令都可以。

gadget3:
    LDMFD  SP!, {R4-R6,LR}
    BX   LR 

这个时候只需要在上述payload前面加上该gadget即可。

payload = fill + gadget3 + fill + gadget2 + fill + gadget1 + fill +  system + fill + cmd

四、知识点图

Previous附录3-2: 指令集分析-PowerPCNext附录4: 基线

Last updated 2 years ago

来源:

海特实验室
Page cover image