iOS逆向工程理论篇

iOS采用Mach-O文件格式, 其中包含了很多原始数据.

Tweak指那些能够增强其他功能的工具, iOS中tweak指那些能够增强其他进程功能的dylib. 而tweak的编写一般用到C C++ Objective-C三种语言.

遇到我们想要实现的功能就需要定位目标文件, 方法如下:

  1. 固定位置

    • 基于CydiaSubstrate的dylib位于 /Library/MobileSubstrate/DynamicLibraries/ 下.

    • .bundle主要分为App和framework.

      其中App Store App位于 /var/mobile/Containers/Bundle/Application/ 下.

      系统App位于/Application/ 下. framework位于/System/Library/Frameworks 或 /System/Library/

    • daemon的配置文件位于/System/Library/LaunchDaemons/ 或 /Library/Daemons 或 /Library/LaunchAgents/ 下, 是一个plist格式文件

  2. PreferenceBundle

    寄生在Settings应用里的App它的功能有些模糊, 可以作为单纯的配置文件, 由别的进程读取后执行.也可以含有实际功能, 自己来执行一些操作.

    PreferenceBundle界面可以用代码编写, 也可以用plist文件构造.手机中的位置:

    /System/Library/PreferenceBundles/

  3. 通过Cydia目标程序路径, 具体可到程序详情界面查找


在高级语言中, 操作的对象是变量. 在ARM汇编中, 操作的对象是寄存器 内存 栈. 一个名为stack pointer (SP)的寄存器保存栈底地址, 当变量入栈的时候保存它的值, 出栈的时候恢复它的值.实际操作中栈的地址不断变化, 但是在执行一块代码的前后确是不变的.

ARM中具有特殊用途的部分寄存器

寄存器 program counter(PC)用于存放下一条指令的地址. 指令的执行顺序取决于PC的值.

ARM中分支的条件一般有4种:

操作结果是否为0

操作结果为负数

操作结果有进位

运算溢出

复制代码

状态寄存器Program Status Register (PSR)保存这些条件(flag), 数据处理的相关指令会根据PSR 的条件做相应的事情.

ARM处理器用到的指令集分为ARM和THUMB.长度分别为32bit和16bit.所有的指令分为三类, 分别是数据操作指令 内存操作指令 分支指令.

1. 数据操作指令

数据操作指令有2条规则: 
复制代码
  • 所有操作数均为32bit

  • 所有结果也是32bit, 且只能存放在寄存器中.

      基本格式
      op{cond} {s} Rd, Rn, Op2
    复制代码

cond和s是两个可选后缀. cond作用指定指令op在什么条件下执行, 共有下面的17种条件:

  • cond用法:

比较R0和R1, 如果R0 > R1, R2 = R0. 否则R2 = R1.

  • s 的作用指定指令 op 是否设置 flag , 下面共有4种flag:

一般C flag表示无符号数运算结果是否溢出.而V flag反之.

数据操作指令分为以下4大类:

  • 算数操作

其中ADD和SUB为基础操作, 其他均为两者的变种.

以C结尾的变种代表有进位和借位的加减法, 产生进位或没有借位时, 将Carry flag置1.

  • 逻辑操作

C操作符里的移位操作并没有对应的逻辑操作指令, 因为ARM采用了桶式移位.

  • 比较操作

比较操作其实就是改变flag的算数操作或逻辑操作, 只是结果不保留在寄存器里.

  • 乘法操作

乘法操作数必须来自寄存器.

2. 内存操作指令

内存操作指令基本格式:

op{cond} {type} Rd, [Rn, ?Op2]
复制代码

Rn是基地址寄存器, 存放基地址. cond作用与数据操作指令相同.type指定指令 op 操作的数据类型.共有4种:

如果不知道type, 那么默认数据类型是word.

ARM内存操作基础指令只有两个: LDR (LoaD Register )将数据从内存中读出来, 存到寄存器中. STR (STore Register ) 将数据从寄存器中读出来, 存到内存中. 使用情况如下:

LDR

STR

此外LDR和STR的变种LDRD和STRD还可以操作双字, 即一次操作2个寄存器, 格式如下:

用法和原型类型:

STRD

LDRD

除了LDR和STR外, 还可以通过LDM (LoaD Multiple )和STM (STore Multiple )进行块传输, 一次性操作多个寄存器. 基本格式:

其中Rd是基地址寄存器, 可选的! 指定Rd变化后的值是否写回Rd. reglist是一系列寄存器, 用大括号括起来, 他们之间用 , 分割, 也可以用 - 表示一个范围, 如{R4 - R6, R8}表示寄存器R4 R5 R6 R8. 这些寄存器的顺序按照自身的编号由小到大排列的, 与大括号内的排列顺序无关.

还需要注意的是LDM和STM的操作方向与LDR和STR完全相反. LDM是把从Rd开始, 地址连续的内存数据存入reglist, STM是把reglist中的值存入从Rd开始, 地址连续的内存中. 这里容易混淆.

cond的作用与数据操作指令相同. mode指定Rd值的4种变化规律:

3. 分支指令

分为无条件分支和条件分支两种.

  • 无条件分支:

举个例子:

  • 条件分支

条件分支的cond是依照上面讲的4种flag来判断的,它们的对应关系如下:

在条件分支指令前会有一条数据操作指令来设置flag, 分支指令根据flag的值来决定代码走向如下:

4. THUMB指令

ARM指令集的一个子集, 每条指令均为16bit, 因此比ARM指令更节省空间.而且传输效率更高.但是, 除了b之外, 所有的THUMB指令均无法条件执行.桶式移位无法结合其它指令执行.大多数THUMB指令只能使用R0 - R7这8个寄存器等. 相对于ARM指令特点如下:

  • 指令数量减少

    THUMB指令的子集, 数量减少是必然的.如乘法指令只有MUL保留, 其他的都被精简了.

  • 没有条件执行

    除了分支指令外, 其它指令无法条件执行.

  • 所有指令默认附带 s

    所有THUMB指令都会设置flag

  • 桶式移位无法结合其它指令执行

    移位指令只能单独执行, 无法与其它指令结合执行.

    LSL R0 #2 可以

    ADD R0, R1, LSL #2 不可以

  • 寄存器使用受限

    除非显示声明, 否则THUMB指令只能使用R0 - R7寄存器. 但也有特殊情况可以使用.

  • 立即数和第二操作数使用受限

    大多数THUMB指令的形式是 op Rd, Rm, 只有移位指令 ADD SUB MOV CMP例外.

  • 不支持数据写回

    除了LDMIA和STMIA外, 其他THUMB指令均不支持数据写回, 即 ! 不可用.

以上指令是我们在逆向工程初级阶段经常遇到的, 如果想要系统的学习可以到ARM官方文档学习.

ARM调用规则

当一个函数调用另一个函数时, 常常需要传递参数和返回值. 如何传递这些数据, 称为ARM汇编的调用规则.

传递参数与返回值

我们可以看个例子:

clang -arch armv7 -isysroot `xcrun --sdk iphoneos --show-sdk-path` -o MainBinary main.m
复制代码

把这段代码用注释里面的命令编译:

然后把MainBinary拖进IDA, 生成Main.m汇编代码如下:

BLX_printf 执行printf函数.它的6个参数分别存放在R0 R1 R2 R3 [SP,#0x20+var_20] 和 [SP,#0x20+var_1C]中, 返回值存放在R0. 其中 var_20=-0x20, var_1C=-0x1C, 因此栈上的2个参数分别位于[SP] 和 [SP, #0x4].

一般情况记住一句话就好: 函数的前四个参数存放的在R0到R3中, 其他参数存放在栈中. 返回值存放在R0中.

本章只是把一些自己认为是重点的地方简单的记录下来, 所以你可能感觉有些零散.

转载于:https://juejin.im/post/5b2b4967f265da596b3d4127

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值