Android逆向系列之ARM概述篇

Android逆向系列之ARM概述篇

ARM简介

ARM 即Advanced RISC Machines的缩写,既可以认为是一个公司的名字,也可以认为是对一类微处理器的通称,还可以认为是一种技术的名字。

ARM处理器的三大特点是:耗电少功能强、16位/32位双指令集和众多合作伙伴。

ARM商品模式的强大之处在于它在世界范围有超过100个的合作伙伴(Partners)。ARM 是设计公司,本身不生产芯片。采用转让许可证制度,由合作伙伴生产芯片。

当前ARM体系结构的扩充包括:

  • Thumb 16位指令集,为了改善代码密度;
  • DSP DSP应用的算术运算指令集;
  • Jazeller 允许直接执行Java字节码。

ARM处理器系列提供的解决方案有:

  • 无线、消费类电子和图像应用的开放平台;
  • 存储、自动化、工业和网络应用的嵌入式实时系统;
  • 智能卡和SIM卡的安全应用。

ARM处理器和Intel处理器

ARM处理器和Intel处理器之间有很多的差异,其中最大的不同点就是它们的指令集。Intel处理器是一个CISC(Complex Instruction Set Computing,复杂指令集)处理器。因此它具有更庞大,功能更丰富的指令集,并且允许指令进行一些复杂的访存操作。它也因此具有支持更多的复杂操作和寻址方式,并且寄存器的数量比ARM要少的多。CISC处理器一般用在通用PC,工作站和服务器中。

ARM是一个RISC(Reduced Instruction Set Computing,精简指令集)处理器。因此它拥有一套精简的指令集(100个左右,甚至更少的指令)以及比CISC处理器更多的通用寄存器。与Intel处理器不同,ARM指令只处理寄存器中的数据,并使用了load/store结构访问存储器,也就是说只有load/store指令可以访问存储器。

RISC也有它的优势和劣势。其中一个重要的优势是指令可以被更快的执行(RISC处理器通过引入流水线机制,减少每个指令的占用的CPU的时钟周期来缩短执行时间)。它的劣势也很明显,较少的指令增加了软件的复杂性。另一个重要的事实是,ARM具有两种运行模式,ARM模式和Thumb模式。Thumb指令可以是2或4个字节的。

ARM和x86/x64之间更多的区别还包括:

  • 在ARM中大多数指令可以用于分支跳转的条件判断
  • Intel的x86/x64系列CPU是小端序的
  • ARM架构在ARMv3之前是小端序的,之后版本,ARM处理器可以通过配置在大端和小端之间切换

下表简单的表示ARM指令集版本和处理器版本之间的映射关系:

ARM处理器家族 ARM指令集架构
ARM7 ARM v4
ARM9 ARM v5
ARM11 ARM v6
Cortex-A ARM v7-A
Cortex-R ARM v7-R
Cortex-M ARM v7-M

ARM7没有MMU(内存管理单元),只能叫做MCU(微控制器),不能运行诸如Linux、WinCE等这些现代的多用户多进程操作系统,因为运行这些系统需要MMU,才能给每个用户进程分配进程自己独立的地址空间。ucOS、ucLinux这些精简实时的RTOS不需要MMU,当然可以在ARM7上运行。

到了ARMv7架构的时候开始以Cortex来命名,并分成Cortex-A、Cortex-R、Cortex-M三个系列。三大系列分工明确:“A”系列面向尖端的基于虚拟内存的操作系统和用户应用;“R”系列针对实时系统;“M”系列对微控制器。简单的说Cortex-A系列是用于移动领域的CPU,Cortex-R和Cortex-M系列是用于实时控制领域的MCU

流水线技术

ARM内核采用相对简单的流水线,这使得芯片结构变得简单。另外,ARM内核革命性地采用了16位Thumb指令集。这种指令集大大提高了系统的运行效率,使得在相同的内存和缓存中可以存放更多的指令,从而简化了指令解码系统。为了进一步简化系统结构,ARM处理器把浮点运算单元(FPU)、内存管理单元(MMU)的配置作为ARM内核的选项而不是标准配置。

简单的3级流水线:

取指级:取指级完成程序存储器中指令的读取,并放入指令流水线中

译码级:对指令进行译码,为下一周期准备数据路径需要的控制信号

执行级:指令”占有”数据路径,寄存器堆栈被读取,操作数在桶形移位器中被移位,ALU产生相应的运算结果并写回到目的寄存器中,ALU结果根据指令需求更改状态寄存器的条件位。

CPU模式

除M-profile外,32位ARM体系结构指定了几种CPU模式,具体取决于实现的体系结构功能。在任何时候,CPU可以只处于一种模式,但它可以由于外部事件(中断)或以编程方式切换模式。

  • 用户模式(usr):唯一的非特权模式。
  • 快速中断模式(fiq):只要处理器接受快速中断请求,就进入特权模式。
  • 外部中断模式(irq):处理器接受中断时进入的特权模式。
  • 管理模式(svc):每当CPU复位或执行SVC指令时进入特权模式。
  • 中止模式(abt):每当发生预取中止或数据中止异常时输入的特权模式。
  • 未定义模式(und):每当发生未定义的指令异常时输入的特权模式。
  • 系统模式(ARMv4及更高版本)(sys):异常未输入的唯一特权模式。只能通过执行从另一个特权模式(而非用户模式)明确写入当前程序状态寄存器(CPSR)的模式位的指令来输入它。
  • 监控模式(ARMv6和ARMv7安全扩展,ARMv8 EL3):引入了监控模式以支持ARM内核中的TrustZone扩展。
  • Hyp模式(ARMv7虚拟化扩展,ARMv8 EL2):一种管理程序模式,支持Popek和Goldberg虚拟化对CPU的非安全操作的要求。
  • 线程模式(用于ARMv6-M,用于ARMv7-M,ARMv8-M):其可以被指定为特权和非特权A模式,而是否使用主堆栈指针(MSP)或进程堆栈指针(PSP)也可以在指定CONTROL具有特权访问权限。此模式专为RTOS环境中的用户任务而设计,但通常在裸机中用于超级循环。
  • 处理程序模式(用于ARMv6-M,用于ARMv7-M,ARMv8-M):专用于异常处理的模式(除了其在线程模式处理的RESET)。处理程序模式始终使用MSP并在特权级别工作。

详细介绍

(1)用户模式:

用户模式是用户程序的工作模式,它运行在操作系统的用户态,它没有权限去操作其它硬件资源,只能执行处理自己的数据,也不能切换到其它模式下,要想访问硬件资源或切换到其它模式只能通过软中断或产生异常。

(2)系统模式:

系统模式是特权模式,不受用户模式的限制。用户模式和系统模式共用一套寄存器,操作系统在该模式下可以方便的访问用户模式的寄存器,而且操作系统的一些特权任务可以使用这个模式访问一些受控的资源。

说明:用户模式与系统模式两者使用相同的寄存器,都没有SPSR(Saved Program Statement Register,已保存程序状态寄存器),但系统模式比用户模式有更高的权限,可以访问所有系统资源。

(3)一般中断模式:

一般中断模式也叫普通中断模式,用于处理一般的中断请求,通常在硬件产生中断信号之后自动进入该模式,该模式为特权模式,可以自由访问系统硬件资源。

(4)快速中断模式:

快速中断模式是相对一般中断模式而言的,它是用来处理对时间要求比较紧急的中断请求,主要用于高速数据传输及通道处理中。

(5)管理模式(Supervisor,SVC) :

管理模式是CPU上电后默认模式,因此在该模式下主要用来做系统的初始化,软中断处理也在该模式下。当用户模式下的用户程序请求使用硬件资源时,通过软件中断进入该模式。

说明:系统复位或开机、软中断时进入到SVC模式下。

(6)终止模式:

中止模式用于支持虚拟内存或存储器保护,当用户程序访问非法地址,没有权限读取的内存地址时,会进入该模式,linux下编程时经常出现的segment fault通常都是在该模式下抛出返回的。

(7)未定义模式:

未定义模式用于支持硬件协处理器的软件仿真,CPU在指令的译码阶段不能识别该指令操作时,会进入未定义模式

指令结构

ARM微处理器的在较新的体系结构中支持两种指令集:ARM指令集和Thumb指令集 其中,ARM指令为32位的长度,Thumb指令为16位长度。Thumb指令集为ARM指令集的功能子集,但与等价的ARM代码相比较,可节省30%~40%以上的存储空间,同时具备32位代码的所有优点。

寄存器结构

ARM处理器共有37个寄存器,被分为若干个组(BANK),这些寄存器包括:

  1. 31个通用寄存器,包括程序计数器(PC指针),均为32位的寄存器。
  2. 6个状态寄存器,用以标识CPU的工作状态及程序的运行状态,均为32位,只使用了其中的一部分。

寄存器

R0~R12(R12的使用要慎重):R0~R12是通用寄存器(R12已经不完全是了),它们可以在常规操作中使用,来存储临时变量或地址。习惯上,

R0常在算数运算中作为累加器,或者存储函数的返回值

R7常用于存储系统调用号。

R11常作为栈帧指针来标记函数栈帧的边界。

ARM的函数调用约定规定,函数的前四个参数存储在寄存器r0~r3中。

R13:R13是堆栈指针(SP,Stack Point)。它指向堆栈的顶部。堆栈是用来存储函数局部存储的一段内存,在函数返回时回收。堆栈指针通过减去我们要分配的空间大小,来分配堆栈上的空间。比如,我们要分配一个32 bit的空间,那么就令R13减4。

R14:R14是链接寄存器(LR,Link Register)。当进行函数调用时,链接寄存器被更新为调用函数指令的下一条指令的地址。这样做可以使程序在执行完子函数之后得以返回父函数。

R15:R15是程序计数器(PC,Program Counter)。在执行指令时,PC总是自动的增加,增加的大小等于正在执行指令的长度。这个长度在ARM架构下是固定的,ARM模式是4字节,Thumb模式是2字节。当执行分支指令时,PC被更新为目的地址。需要注意的是,由于RISC CPU流水线优化的原因,在执行期间,ARM模式下PC等于当前指令地址加8,Thumb模式下等于当前指令地址加4,也就是后移两条指令。这不同于x86的EIP寄存器,总是指向当前指令的下一条指令。

除FIQ模式外,寄存器R8至R12在所有CPU模式下都相同。FIQ模式有自己独特的R8到R12寄存器。

除系统模式外,R13和R14在所有特权CPU模式下进行存储。也就是说,由于异常而可以输入的每种模式都有自己的R13和R14。这些寄存器通常分别包含堆栈指针和函数调用的返回地址。

别名:

  • R13也称为SP,堆栈指针。
  • R14也称为LR,即链路寄存器。
  • R15也称为PC,即程序计数器。
寄存器 别名 作用
R0 通用
R1 通用
R2 通用
R3 通用
R4 通用
R5 通用
R6 通用
R7 常用于保存系统调用号
R8 通用
R9 通用
R10 通用
R11 FP 用于保存栈帧
专用寄存器
R12 IP 内部调用暂存寄存器
R13 SP 栈顶指针
R14 LR 用于保存函数返回地址
R15 PC 用于保存下一条指令的地址
CPSR 当前程序状态寄存器

当前程序状态寄存器(CPSR)具有以下32位(条件码/控制位):

  • M(位0-4)是处理器模式位。
  • T(第5位)是Thumb状态位。
  • F(第6位)是FIQ禁用位。
  • I(第7位)是IRQ禁用位。
  • A(位8)是不精确的数据中止禁用位。
  • E(第9位)是数据字节顺序位。
  • IT(位10-15和25-26)是if-then状态位。
  • GE(比特16-19)是比特大于或等于的比特。
  • DNM(位20-23)是不修改位。
  • J(第24位)是Java状态位。
  • Q(第27位)是粘滞溢出位。
  • V(第28位)是溢出位。
  • C(第29位)是进位/借位/扩展位。
  • Z(第30位)是零位。
  • N(第31位)是负数/小于比特

数据类型

和高级语言一样,ARM汇编语言支持对不同数据类型的操作。我们可以load(或store)的数据类型包括signed/unsigned words,halfwords或者bytes。我们用“-h”或“-sh”后缀表示half words,用“-b”或“-sb”表示bytes,无后缀默认表示words。(LDR/STR)有符号和无符号数据类型之间的区别有:

§ 有符号数可以表示正直和负值,所以范围较小;

§ 无符号数只能表示正值,所以范围更大。

字节序

在内存中有两种存储多字节数据的方式,大端序和小端序。这两种方式的差异是数据存储时的字节顺序不同。在以小端序存储数据的设备中(如x86),位权低(个位的位权比十位低)的字节存储在低地址(地址值小的地址)。在以大端序存储数据的设备上,位权高的字节存储在低地址。上一篇我们提到过,ARM架构在ARMv3之前是小端序的,在那之后,ARM处理器可以通过硬件配置在大小端之间切换。以ARMv6为例,指令是固定的以小端序存储的,而内存数据的读取方式可以通过控制程序状态寄存器CPSR的第9位实现在大端和小端之间切换。

参考

Arm Wikipedia

ARM 命名规则——指令架构、CPU的历史回顾

Arm Technologies

Arm Documents

Arm/Thumb-2 指令集快速参考卡

Thumb 指令集快速参考卡

The Thumb Instructions Set

The Arm Instructions Set

Arm Instruction Set Reference Guide Version 1.0

发表评论

电子邮件地址不会被公开。

You must enable javascript to see captcha here!