逆向工程简介

iOS 逆向工程,是指从目标应用的界面以及功能表现入手,使用不同工具和理论知识去分析其实现原理,得出应用的代码结构、整体设计、功能实现、执行流程等,然后利用iOS的系统知识和语言特性,借鉴或修改原有实现流程的技术。

前置基础知识

学习逆向工程我们需要先了解设备知识,下面我们先介绍一下设备相关的基础知识。

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的速度和功率效率是至关重要的。速度影响用户体验,而效率影响电池寿命。最完美的移动设备是高性能和低功耗相结合。

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

段的概念

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

为什么需要寄存器

cup切换状态时,比如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

指令集

要了解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多用于手机。

参考文章
ARM汇编以及汇编语言基础介绍

汇编基础

模拟器32位处理器是i386架构,
模拟器64位处理器是x86_64架构,
真机32位处理器是armv7,或者armv7s架构,(armv7s 是iPhone5C、armv7是iphone4之前的手机版本)
真机64位处理器是arm64架构。(iPhone5s之后的手机)【接下来主要学习的】

ARM64下的寄存器

功能:

  • 进行数据的临时存储
  • 数据执行算术及逻辑运算
  • 操作内存(寻址)

寄存器分类:

  1. 通用寄存器(用来存放一般性的数据)

    • x0~x30(64位)
    • x29 又名fp(用于保存栈底的地址)
    • x30 又名 lr(bl 跳转后就会把下一条指令地址写到lr中)
    • w0w30(32位)这些就是x0x30的低32位
  2. 浮点寄存器(CPU中专门提供浮点数寄存器来处理浮点数)

    • D0~D31(64位)
    • S0S31 (32位)这些就是D0D31的低32位
  3. 向量寄存器
    (现在的CPU支持向量运算.(向量运算在图形处理相关的领域用得非常的多)为了支持向量计算系统了也提供了众多的向量寄存器.)

    • V0-V31(128位)
  4. 状态寄存器(又称 CPSR【current program status register】寄存器)

    • CPSR寄存器是32位的,每一位的功能如下
      31 30 29 28 27~8 7 6 5 4 3 2 1 0
      N Z C V 保留 I F T M4 M3 M2 M1 M0
    • CPSR的低8位(包括I、F、T和M[4:0])称为控制位,程序无法修改,除非CPU运行于特权模式下,程序才能修改控制位!
    • N【负数标志】、Z【0标志】、C【进位标志】、V【溢出标志】均为条件码标志位。
  5. 栈寄存器

    • SP (任意时刻会保存我们栈顶的地址)
    • FP (用于保存栈底的地址)

ARM64下常用的汇编指令(重要)

基础指令

  • MOV - MOV X1,X0 ; 将寄存器X0的值传送到寄存器X1
  • ADD - ADD X0,X1,X2 ; 寄存器X1和X2的值相加后传送到X0
  • SUB - SUB X0,X1,X2 ; 寄存器X1和X2的值相减后传送到X0
  • AND - AND X0,X0,#0xF ; X0的值与0xF相位与后的值传送到X0
  • ORR - ORR X0,X0,#9 ; X0的值与9相或后的值传送到X0
  • EOR - EOR X0,X0,#0xF ; X0的值与0xF相异或后的值传送到X0

堆栈操作

  • STR - 将数据从寄存器中读出来,存到内存中.
    STR - STR X0, [SP, #0x8] ;X0寄存器的数据传送到SP+0x8地址值指向的存储空间
  • STP - STR 的变种指令,可以同时操作两个寄存器
    STP x29, x30, [sp, #0x10] ; 将x29,x30存入栈中
  • LDR - 将数据从内存中读出来,存到寄存器中
    LDR X5,[X6,#0x08] ;X6寄存器加0x08的和的地址值内的数据传送到X5
  • LDP - LDR 的变种指令,可以同时操作两个寄存器
    LDP x29, x30, [sp, #0x10] ; 将栈中的值取出存放到x29, x30

跳转操作

  • BL 将下一条指令的地址放入lr(x30)寄存器
  • RET 默认使用lr(x30)寄存器的值,通过底层指令提示CPU此处作为下条指令地址!
  • CMP 比较指令,相当于SUBS,影响程序状态寄存器
    • B.GT 比较结果是大于,执行标号,否则不跳转
    • B.GE 比较结果是大于等于,执行标号,否则不跳转
    • B.EQ 比较结果是等于,执行标号,否则不跳转
    • B.HI 比较结果是无符号大于,执行标号,否则不跳转
  • CBZ - CBZ ; 比较(Compare),如果结果为零(Zero)就转移(只能跳到后面的指令)
  • CBNZ - CBNZ ; 比较,如果结果非零(Non Zero)就转移(只能跳到后面的指令)

逆向工具

对任何平台进行逆向分析时都会借助很多工具,iOS逆向也不例外。以逆向的流程为例,会使用解密工具、class-dump、Cycript、Reveal、Charles、Hopper、IDA、Xcode、Theos等,这些工具都是必须了解的。

除了使用工具,还需要了解每个工具的实现原理,有哪些值得借鉴的地方。

效率工具

  • iTerm2
  • oh-my-zsh
  • Go2Shell
  • autojump
  • Alfred

实用工具

效率提升后,需要一些实用工具来帮助完成某些复杂的操作

  • Homebrew
  • Cakebrew
  • libimobiledevice
  • tree
  • 010 Editor

逆向工具

逆向工具很重要,需要介绍一下

  • jtool: 查看文件结构,代码签名
  • capstone: 多平台、多架构支持的反汇编框架
  • keystone: 将汇编指令转换为 Hex 机器码
  • radare2: 开放源代码的逆向工程平台
  • mobiledevice: 安装 app 或 ipa 包

最后的总结

这些只是我们接触逆向时,必要的准备工作,还有进阶的知识,后面会慢慢讲解。