ARM背景知识

学习ARM首先要了解下CPU是什么

分不清ARM和X86架构,别跟我说你懂CPU

  • Central Processing Unit,
  • cpu的组成部分
  1. 运算器(ALU- arithmetic logic unit 算术逻辑单元,马达)
  2. 控制器(Control 负责分配指定运算)
  3. 寄存器(Register ARM汇编就是操作寄存器和内存的指令集)
  4. cpu内部总线(物理)地址线路,数据线路 控制线路(内存读写命令)
    地址总线 限制CPU内存地址空间的大小,地址总线宽度为32,2的32次方=4GB.个内存单元,一个内存单元可以存放8位数据也就是一个字的数据。cpu访问内存单元时,要给出内存单元的地址,所有的内存单元构成的存储空间是一个一维的线性空间。每一个内存丹云在这个空间中都有唯一的地址,我们将这个唯一的地址称为物理地址。
    N位结构。比如64位(位机,字长与结构含义相同),描述了一个cpu具有下面几方面的结构特性
    • 运算器一次最多可以处理64位的数据 8个byte
    • 寄存器的最大宽度为64位
    • 寄存器和运算器之间的通路为64位。
    • 对于65位cpu,能一次性处理,传输,暂时存储64位的地址
总结:从字面意思看运算器就是起着运算的作用
控制器就是负责发出CPU每条指令所需要的信息
寄存器就是保存运算或者指令的一些临时文件,这样可以保证更高的速度。
  • CPU有着处理指令、执行操作、控制时间、处理数据四大作用,打个比喻来说,CPU就像我们的大脑,帮我们完成各种各样的生理活动。因此如果没有CPU,那么电脑就是一堆废物,无法工作。移动设备其实很复杂,这些CPU需要执行数以百万计的指示,才能使它向我们期待的方向运行,而CPU的速度和功率效率是至关重要的。速度影响用户体验,而效率影响电池寿命。最完美的移动设备是高性能和低功耗相结合。

#cpu处理器模式
cpu的模式切换,模式和模式间相对独立。说白了就是切换状态
cpu要读取一个内存单元的时候,必须先给出这个内存单元的地址

#段的概念

  • 错误认识
    • 内存被划分成了一个一个的段,每一个段有一个段地址
  • 其实:
    • 内存并没有分段,段的划分来自于CPU,由于cpu用 段地址*16 + 偏移地址 = 物理地址 的方式给出内存单元的物理地址,使得我们可以用分段的方式来管理内存。
  • 以后,在编程时可以根据需要,将若干地址连续的内存单元看作一个段。
  • 偏移地址为16位,16位地址的寻址能力为64k,所以一个段的长度最大64KB。

#为什么需要寄存器

  • cpu切换状态时,比如funA -> funB,实际上操作的是内存地址,把这些操作内存地址的指令或者内存地址直接放在cpu里,可以更好的控制和提高效率,cpu就需要寄存器来存放这些指令。

#寄存器常用术语

  • SP(stack point)栈指针,存储栈地址,指向栈顶
  • LR(link register)链接寄存器
  • PC(program count)程序技术器
  • A\C PSR(program status register)程序状态寄存器
  • SPSR(saved program status register)已保存程序状态寄存器
  • user模式没有SPSR

#cpu怎么处理指令 指令处理过程

  1. 先从某个地方去取指令(一般是芯片上的寄存器)(F)
  2. 对指令进行译码成机器码(D)
  3. 取完指令之后要译码然后在执行(E)
  • 也就是基于FDE,那么这个就是我们在某一个时刻它应该做的三步操作,就这三步操作我们才能完成CPU正在进行运算,因为它必须要取指令,然后这些指令是ARM指令,CPU默认的情况下不一定认可,所以就要进行一个翻译,翻译成最简单的然后再去执行,那么这个就是第一个时刻“F-D-E”,然后马上它又转到另外一个任务里面,那么就会有一段时间的延后,那么又是一个“F-D-E”的过程,后面同样的延后又会是同样的过程,这样看来就会像一个流水线,所以我们就称为流水线,这就是CPU运转的一个机制,而这样三步就称为三级流水。后来我们在这个过程中又增加一些步骤,我们可以有多级流水,所以这个就知道这是CPU在去读取指令和运行的一个机制。

#要了解X86和ARM,就得先了解复杂指令集(CISC)和精简指令集(RISC)

  • Complex Instruction Set Computing - CISC
  • reduced instruction set computing
  • 从CPU发明到现在,有非常多种架构,从我们熟悉的X86,ARM,到不太熟悉的MIPS,IA64,它们之间的差距都非常大。但是如果从最基本的逻辑角度来分类的话,它们可以被分为两大类,即所谓的“复杂指令集”与“精简指令集”系统,也就是经常看到的“CISC”与“RISC”。 Intel和ARM处理器的第一个区别是,前者使用复杂指令集(CISC),而后者使用精简指令集(RISC)。属于这两种类中的各种架构之间最大的区别,在于它们的设计者考虑问题方式的不同。
  • 我们可以继续举个例子,比如说我们要命令一个人吃饭,那么我们应该怎么命令呢?我们可以直接对他下达“吃饭”的命令,也可以命令他“先拿勺子,然后舀起一勺饭,然后张嘴,然后送到嘴里,最后咽下去”。从这里可以看到,对于命令别人做事这样一件事情,不同的人有不同的理解,有人认为,如果我首先给接受命令的人以足够的训练,让他掌握各种复杂技能(即在硬件中实现对应的复杂功能),那么以后就可以用非常简单的命令让他去做很复杂的事情——比如只要说一句“吃饭”,他就会吃饭。但是也有人认为这样会让事情变的太复杂,毕竟接受命令的人要做的事情很复杂,如果你这时候想让他吃菜怎么办?难道继续训练他吃菜的方法?我们为什么不可以把事情分为许多非常基本的步骤,这样只需要接受命令的人懂得很少的基本技能,就可以完成同样的工作,无非是下达命令的人稍微累一点——比如现在我要他吃菜,只需要把刚刚吃饭命令里的“舀起一勺饭”改成“舀起一勺菜”,问题就解决了,多么简单。这就是“复杂指令集”和“精简指令集”的逻辑区别。
  • x86多用于电脑,ARM多用于手机

程序是什么

  • 程序 = 数据结构 + 算法

机器语言

  • 机器语言是机器指令的集合。机器指令展开来讲就是一台机器可以正确执行的命令。计算机折机器指令是一列二进制数字。计算机将之转变为一列高低电平,以使计算机的器件受到驱动,进行运算。

了解Application是怎么运行在端上的

  • 我们写的代码被编译转换成c语言或者被直接编译成汇编指令集(汇编程序)。
  • cpu的ALU单元通过FDE(fetch-decode-excut)流水线,运行这些汇编指令,这些指令最后会被编译工具链中的as程序以及ld链接程序汇编成机器码,这个过程叫译码decode
  • 核心原理就是把我们写的代码编译成机器码
  • 见上面的 "cpu怎么处理指令 指令处理过程"

为什么我们需要ARM汇编呢

ARM汇编以及汇编语言基础介绍

  • 在开始用ARM汇编做漏洞利用开发之前,还是需要学习下基础的汇编语言知识的。如果我们想做逆向工程,或者理性相关二进制程序的执行流程,构建我们自己的ARM架构的shellcode, ROP链,以及调试ARM应用,这些都要求先懂得ARM汇编。当然也不需要学习的太过深入,足够做逆向工作,以及漏洞的利用开发刚刚好。
  • ARM汇编,是一种更容易被人们接受的汇编语言。当然我们的计算机也不能直接运行汇编代码,还是需要编译成机器码的。通过编译工具链中as程序来将文件后缀为".s"的汇编码编译成机器码。写完汇编代码后,一般保存后缀为".s"的文件。然后用as编译以及用ld链接程序:
liangze $ as program.s -o program.o
liangze $ ld program.o -o program

#汇编语言本质

  • 在最底层,只有电路的电信号。信号被格式化成可以变化的高低电平0V(off)或者5V(on)。但是通过电压变化来表述电路状态是繁琐的,所以用0和1来代替高低电平,也就有了二进制格式。由二进制序列组成的组合便是最小的计算机处理器工作单元了,比如下面的这句机器码序列就是例子。
1110 0001 1010 0000 0010 0000 0000 0001
  • 看上去不错,但是我们还是不能记住这些组合的含义。所以,我们需要用助记符和缩写来帮助我们记住这些二进制组合。这些助记符一般是连续的三个字母,我们可以用这些助记符作为指令来编写程序。这种程序就叫做汇编语言程序。用以代表一种计算机的机器码的助记符集合就叫做这种计算机汇编语言。因此,汇编语言是人们用来编写程序的最底层语言。同时指令的操作符也有对应的助记符,比如:
MOV R2, R1
  • 现在我们知道了汇编程序是助记符的文本信息集合,我们需要将其转换成机器码。就像之前的,在GNU Binutils工程中提供了叫做as的工具。使用汇编工具去将汇编语言转换成机器码的过程叫做汇编(assembling)。
  • 总结一下,计算机是通过由0101代表高低电平的机器码序列来进行运算的。我们可以使用机器码去让计算机做我们想让它做的事情。不过因为我们不能记住机器码,我们使用了缩写助记符来代表有相关功能的机器码,这些助记符的集合就是汇编语言。最后我们使用汇编器将汇编语言转换成机器可以理解的机器码。当然,在更高级别的语言编译生成机器码过程中,核心原理也是这个。

  • 栈有两个基本操作:入栈和出栈
    • 入栈:将一个新的元素放到栈顶
    • 出栈:从栈顶取出一个元素
  • 栈顶的元素总是最后入栈的,需要出栈时,又是最先被从栈中取出的
  • 栈的操作规则 (LIFO) last in first out 后进先出
  • cpu中都有栈的设计,ARM提供相关的指令以栈的方式来访问内存空间,这意味着汇编时,可以将一段内存当作栈来使用
  • ARM的栈是满递减的,向下增长,也就是开口向下。新的变量被存放到栈底的位置,越靠近栈底,内存地址越小
  • 一个名为“stack pointer” SP.的寄存器保存栈顶地址,称为栈地址,在实际操作中,栈地址会不断变化;但是在执行一块代码前后,栈地址应该不变。

iOS汇编精讲