iOS采用Mach-O文件格式, 其中包含了很多原始数据.
Tweak指那些能够增强其他功能的工具, iOS中tweak指那些能够增强其他进程功能的dylib. 而tweak的编写一般用到C C++ Objective-C三种语言.
遇到我们想要实现的功能就需要定位目标文件, 方法如下:
-
固定位置
-
基于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格式文件
-
-
寄生在Settings应用里的App它的功能有些模糊, 可以作为单纯的配置文件, 由别的进程读取后执行.也可以含有实际功能, 自己来执行一些操作.
PreferenceBundle界面可以用代码编写, 也可以用plist文件构造.手机中的位置:
/System/Library/PreferenceBundles/
-
通过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中.
本章只是把一些自己认为是重点的地方简单的记录下来, 所以你可能感觉有些零散.