前言
对于应用层开发人员而言,仅仅掌握Objective-C和系统框架即可较好的完成开发,但在涉及到应用加固、逆向分析等内容时仅有应用层开发技能就会显得非常的无力,因此掌握汇编对于突破iOS开发水平的瓶颈十分有效。
一个例子
以反调试为例,我们知道,通过调用ptrace函数可以阻止调试器依附。
ptrace(31, 0, 0, 0)
这种方式能够被函数hook轻易破解,例如使用facebook的fishhook。
为了防止函数被hook,我们可以将函数调用转为通过汇编发起系统调用,即使用下面的代码。
mov x0, #31
mov x1, #0
mov x2, #0
mov x3, #0
mov x16, #26
svc #0x80
其中x0-x3存储的为函数入参,x16存储的为函数编号,通过Apple提供的System Call Table 可以查出ptrace的编号为26,最后一句指令发起了系统调用。
通过使用__asm__指令能够将汇编代码嵌入我们的函数中,构成反调试方法。
// 使用inline方式将函数在调用处强制展开,防止被hook和追踪符号
static __attribute__((always_inline)) void anti_debug() {
// 判断是否是ARM64处理器指令集
#ifdef __arm64__
// volatile修饰符能够防止汇编指令被编译器忽略
__asm__ __volatile__(
"mov x0, #31\n"
"mov x1, #0\n"
"mov x2, #0\n"
"mov x3, #0\n"
"mov x16, #26\n"
"svc #0x80\n"
);
#endif
}
虽然上面的反调试机制并不完善,但是比直接调用ptrace要好上很多倍,从这一点来看,掌握汇编技能对于iOS应用安全和底层研究非常有利。
入门攻略
iOS设备主要使用的为ARM64汇编,因此本文主要介绍ARM64汇编的入门技巧。
汇编入门最难的地方在于对栈的理解,汇编的所有指令操作都是围绕栈实现的,在汇编中,没有变量的概念,只有寄存器和内存。
栈
汇编中的栈是由高地址向低地址生长的数据结构,sp指针永远指向栈顶,需要记住的是,在某位置进行存储时,是向高地址进行的,下面以一个简单的例子讲解汇编的栈操作。
我们以一段简单的C代码为例。
// hello.c
#inc