附录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 的地址中的内容,如:
那么 r0 寄存器的结果是:
三、指令分析
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
加入发生溢出的函数在返回时有以下指令操作:
这里我们可以控制R4-R11和LR寄存器。 首先寻找类似
的gadget,同时gadget也需要满足将栈地址赋值给一个通用寄存器。
我们就随便选取第六个gadget即可。
然后我们需要寻找一个类似mov r0, r2
的gadget,但同时该gadget需要能控制程序流。 我们可以用如下命令寻找:
我们可以选取如下gadget:
然后这两个gadgets结合程序本身的LDMFD指令即可完成ROP。 这个时候payload为:
第二种情况
当函数返回时仅仅只有pop lr等操作时,这种情况下的ROP更加通用,跟MIPS架构下的ROP思路差不多。 这时我们只需要在上面的情况下找一个gadget来设置r5即可。满足条件的有很多,基很多函数返回时的最后两台指令都可以。
这个时候只需要在上述payload前面加上该gadget即可。
四、知识点图
来源: 海特实验室
Last updated