Yk2eR0's Blog.

ARM汇编总结

字数统计: 2k阅读时长: 7 min
2021/03/23 Share

ARM简介

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

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

  1. 用户模式(user):正常程序执行模式;
  2. 快速中断模式(FIQ):高优先级的中断产生会进入该种模式,用于高速通道传输;
  3. 外部中断模式(IRQ):低优先级中断产生会进入该模式,用于普通的中断处理;
  4. 特权模式(Supervisor):复位和软中断指令会进入该模式;
  5. 数据访问中止模式(Abort):当存储异常时会进入该模式;
  6. 未定义指令中止模式(Undefined):执行未定义指令会进入该模式;
  7. 系统模式(System):用于运行特权级操作系统任务;

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

  • 由于大部分的嵌入式 IoT 设备的 ARM 指令集都是基于 32 位小端序的 armeabi 架构,因此在介绍时就会以此架构为例进行讲解,使用 file 命令查看到的信息如下:
1
bin/busybox: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-uClibc.so.0, stripped

寄存器介绍

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个字节。

函数参数传递

R0-R3 为用户函数调用参数传递的寄存器,分别用于传递函数的第一、第二、第三个参数,如当调用 test 函数时,汇编代码中会将 $R0、$R1、$R2 寄存器分别赋值为立即数 1、2、3,接着再去执行相关汇编指令去调用 test 函数。

1
2
3
4
MOV             R0, #1
MOV R1, #2
MOV R2, #3
BL test
  • 若函数调用所需要的参数数量大于 3 时,同样会借助栈进行剩下参数的传递。

指令集介绍

此处列举出在对 armeabi 指令集进行逆向过程中常使用的汇编指令类型。

Load/Store 类型指令

Load/Store 类型的指令的作用为从地址中读取数据和从地址中存入数据,Load 类型的指令有 LDR、LDRB 等,用法举例如下:

1
2
LDR R0, [addr, #10]                    // 将 addr 地址偏移10字节处的四字节内容存入 R0 寄存器中
LDRB R0, [addr, #10] // 将 addr 地址偏移10字节处的一字节内容存入 R0 寄存器中

Store 类型的指令有 STR、STRB 等,用法举例如下:

1
2
STR R0, [addr, #10]                    // 将 R0 寄存器的数据存储到 addr 地址偏移10字节内存地址处
STRB R0, [addr, #10] // 将 R0 寄存器最低字节的数据存储到 addr 地址偏移10字节内存地址处

算数运算类型指令

armeabi 指令集的算数运算类型指令名称与 x86 几乎完成相似,只是操作数的格式与 x86 指令架构不同。

  • 加法类型指令:
1
ADD R0, R1, #1								// 将 R1 寄存器的值加1之后存储到R0寄存器中
  • 减法类型指令:
1
SUB R3, R11, #10				// 将 R11 寄存器的值减去10之后存储到 R3 寄存器中

条件类型指令

ARM 指令集中的条件类型指令和x86完全一致,常见的条件比较类型的指令有:

1
2
BNE             0xC680				// 上一条 cmp 指令比较结果不相等时,跳转到 0xC680 地址处
BEQ 0xC680 // 上一条 cmp 指令比较结果相等时,跳转到 0xC680 地址处

跳转类型指令

常见的跳转指令有:

1
2
3
B             0xC680					// 直接跳转到 0xC680 地址处,即将 PC 寄存的值赋值为 0xC680
BL 0xC680 // 跳转到 0xC680 地址处,同时将待跳转的下一条地址存入到 LR 寄存器中
BLX //带返回和状态切换(ARM/THUMB)的跳转指令

寻址特点

  • pc 方式寻址

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

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

那么 r0 寄存器的结果是:r0 = [0x1000+12+8] = [0x101a]

堆栈结构

ARM 指令集对栈的操作和x86也几乎一致,在初始化函数栈时,会使用 PUSH 指令,将调用栈前的环境保存起来,在函数退出时,使用 POP 指令还原调用前的环境。

但是在 IDA 中查看函数的汇编代码,在开头部分可以看到 STMFD 这个指令,找不到 push 指令。

1
STMFD           SP!, {R4,R11,LR}

实际上 STMFD 指令可以看成是 push 指令的扩展,如针对于上述的指令可以扩展成如下指令:

1
2
3
4
5
6
7
8
9
PUSH R4
PUSH R5
PUSH R6
PUSH R7
PUSH R8
PUSH R9
PUSH R10
PUSH R11
PUSH LR

所以该指令的作用也就是将第二个操作数的寄存器依次压入到栈中(SP 指针指向的位置开始)。

同样在函数的末尾进行栈还原时,可以发现 LDMFD 指令,该指令的作用和 STMFD 指令相反,将从 SP 栈顶的数据开始依次 POP 到 R4-R11 以及 PC 寄存器中。

1
LDMFD           SP!, {R4,R11,PC}

因此也可以扩展为如下指令:

1
2
3
4
5
6
7
8
9
POP R4
POP R5
POP R6
POP R7
POP R8
POP R9
POP R10
POP R11
POP PC
  • 函数开头将 LR 寄存器压入到栈中,函数退出时将 LR 寄存器的值通过栈传递到 PC 寄存器中,可以说明 LR 寄存器存储的是函数返回地址。

逆向技巧

可能需要调整汇编模式:
在IDA中可以Edit->segments->change segment register value(快捷键ALT+G)中改变T的值来改变IDA对代码的解析方式。

  1. 0为ARM
  2. 1为thumb

ARMPwn

arm指令和X86有相似之处,相比mips指令更容易理解.
关于X86用到的ROP相关指令和ARM指令的对比:
6f4cc2fe323bf8a82b30c3d7e2c6e905.png
arm架构下的函数返回时,使用LDMFD指令和BX指令完成调用前环境还原和跳转.LDMFD指令pop保存的寄存器的值以及LR的值,然后跳转到LR.在ROP的时候很多情况下可以利用LDMFD指令来减少ROP时用到的gadgets.

寻找gadgets

ROP的最终目的是将可控的命令传入system函数并进行调用,cmd一般来说放到栈上,这就需要找一个gadget来设置R0为一个栈地址,然后再寻找一个gadget跳转并调用system函数即可.
ARM架构下的ROP再函数返回时大多数情况pop还原一些保存的寄存器的值.例如R4-R5,R4-R7等,这种情况可以利用函数本身的gadget来减少ROP的复杂程度.而如果函数返回时没有pop出lr以外的寄存器的话,这种情况就需要另外调整寻找gadgets的思路了.

函数推出时pop多个寄存器

首先利用ROPGadget将libc动态链接库中可利用的gadget找出来

参考链接

原文作者:Yk2eR0

原文链接:https://www.yk2er0.fun/2021/03/23/%C2%96arm/

发表日期:March 23rd 2021, 11:54:51 pm

更新日期:March 25th 2021, 11:04:49 am

版权声明:非商业用允许转载

CATALOG
  1. 1. ARM简介
  2. 2. 寄存器介绍
    1. 2.1. 函数参数传递
  3. 3. 指令集介绍
    1. 3.1. Load/Store 类型指令
    2. 3.2. 算数运算类型指令
    3. 3.3. 条件类型指令
    4. 3.4. 跳转类型指令
  4. 4. 寻址特点
  5. 5. 堆栈结构
  • 逆向技巧
  • ARMPwn
    1. 1. 寻找gadgets
      1. 1.1. 函数推出时pop多个寄存器
  • 参考链接