iOS逆向学习笔记之--ARM处理器的寄存器学习

ARM 160浏览


iOS逆向学习笔记之–ARM处理器的寄存器学习

对于逆向过程中需要分析目标APP某个方法实现的时候,需要了解一些汇编指令。下面就来了解一些常用汇编指令的用法。

ARM官方文档地址http://infocenter.arm.com

ARM32

R0 - R3 传递参数与返回值
R7      帧指针,指向母函数与被调用子函数在栈中的交界
R9      iOS 3.0以前被系统保留
R12     内部调用寄存器,dynamic linker会用到它
R13     SP寄存器
R14     LR寄存器,保存函数地址
R15     PC寄存器

// 比较
EQ      结果为零
NE     结果不为零
// 算术操作
ADD R0, R1, R2R0=R1+R2
ADC R0, R1, R2R0=R1+R2 + C(array)
SUB R0, R1, R2R0=R1-R2
SBC R0, R1, R2R0=R1-R2 - !C
RSB R0, R1, R2R0=R2-R1
RSC R0, R1, R2R0=R2-R1 - !C


CMP r1r2;  // r1 - r2并依结果设置flag

LDR 将数据从内存中读取出来,放到寄存器中
STR 将数据从寄存器取出来放到内存中

LDM 把Rd开始,地址连续的内存数据存入寄存器中
STM 是把寄存器中的值存入从Rd开始,地址连续的内存中

// 金句
函数前4个参数存放在R0R3中,其他参数存放在栈中,返回值在R0

AArch64

  • 常用寄存器
寄存器 位数 描述
X0-X30 64bit 通用寄存器,如果有需要可以当做32位是使用W0-W30
FP(X29) 64bit 保存栈帧地址(栈底指针)
LP(X30) 64bit 通常称X30为程序链接寄存器,保存跳转返回信息地址
SP 64bit 保存栈指针
PC 64bit 程序计数器,PC指针,总是指向即将要执行的下一条指令
  • 通用寄存器32位位于64位名称
位数
64bit Xn(通用) XZR(0寄存器) SP(堆栈指针)
32bit Wn(通用) WZR(0寄存器) WSP(栈指针)
  • 通用寄存器用法
    x0…x7 用于子程序调用时的参数,x0还用于返回值传递
    x8 间接寻址结果
    x29 通常用作FP
    x30 通常用作LR

  • 常用汇编指令

// 算术指令
ADD    X0,X1,X2   // 寄存器X1和X2的值相加后传送到X0
SUB    X0,X1,X2   // 寄存器X1和X2的值相减后传送到X0
CMP    w0, #0x0     // w0 - 0 比较指令,相当于SUBS,影响程序状态寄存器CPSR 
CMN    w0, #0x10     // w0 + 0x10 并影响条件标志位

// 逻辑指令
AND    X0,X0,#0xF   // x0 = x0 & 0xF  X0的值与0xF相位与后的值传送到X0 ADNS表示影响条件标志位
ORR    X0,X0,#9     // x0 = x0 | 9    X0的值与9相位或后的值传送到X0
EOR    X0,X0,#0xF   // x0 = x0 ^ 0xF  X0的值与0xF相异或后的值传送到X0

// 数据传输指令
MOV X1, X0 // x1 = x0 将寄存器x0的值存到x1

// 地址偏移指令
ADR

// 移位运算指令
ASR xd,xn, #uimm // 算术右移,移位过程中符号位不变
LSL xd,xn, #uimm // 逻辑左移,移位后寄存器空出的低位补0
LSR xd,xn, #uimm // 逻辑右移,移位后寄存器空出的高位补0
ROR xd,xn, #uimm // 循环右移,从右端移出的位将被插入左侧空出的位

// 加载存储指令
LDR    X5,[X6,#0x08]    // X6寄存器加0x08的和的地址值内的数据传送到X5
STR    X0, [SP, #0x8]    // X0寄存器的数据传送到SP+0x8地址值指向的存储空间
STUR   w0, [x29, #0xfffffff8] // w0的值写入x29 +0xfffffff8指向的内存
LDUR   w9, [x29, #0xffffffec] // 将x29 + 0xffffffec地址内存处的值,写入w9寄存器
STP    x29, x30, [sp, #0x10]   // 入栈指令
LDP    x29, x30, [sp, #0x10]   // 出栈指令

// 条件跳转指令
B.cond 0x100007f70  // cond为真 跳转到0x100007f70
CBZ x8, 0x100007f70  // x8=0 跳转到0x100007f70  比较(Compare),如果结果为零(Zero)就转移(只能跳到后面的指令)
CBNZ x8, 0x100007f70 // x8!=0 跳转到0x100007f70  比较,如果结果非零(Non Zero)就转移(只能跳到后面的指令)

// 无条件跳转指令
B/BL 0x100007f70 // 绝对跳转0x100007f70, 返回地址保存到LR(X30)
RET   // 子程序返回指令,返回地址默认保存在LR(X30
BR xn // 无条件跳转到xn寄存器地址

// 其他寄存器
PC 寄存器:记录当前代码执行的地址
SP 寄存器:指向栈帧指针,在内存指令中通过x31寄存器来访问
LR 寄存器:指向返回地址,对应于寄存器x30
FP 寄存器:指向栈帧的底部对应于寄存器x29
  • 条件码标志
    N、Z、C、V均为条件标志位。它们的内容可被算术或逻辑运算的结果所改变,并且可以决定某条指令是否被执行。条件码标志各位的具体含义如下表所示:
标志位 含义
N 当两个有符号额整数运算时: N=1:表示运算的结果为负数 N=0:表示运算结果为正数或零
Z Z=1表示运算的结果为零,Z=0表示结果非零。对于CMP指令,Z=1表示进行比较的两个数相等
C 可以有4种方法设置C的值: 1、在加法指令中(包括比较指令CMP),当结果产生了进位,则C=1,表示无符号运算发生上溢出,其他情况C=0。 2、在减法指令(包括减法指令CMP),当运算中发生了借位,则C=0,表示无符号运算数发生下溢出;其他情况下C=1。 3、对于包含移位操作的非加减运算指令,C中包含最后一次溢出位的数值。 4、对于其他非加减运算指令,C位的值通常不受影响
V 对于加减运算指令,当操作数和运算结果为二进制的补码表示的带符号数时,V=1表示符号位溢出;通常其他指令不影响V位
  • 常见的指令的条件码
条件码助记符 标志 含义
NE Z清零 不相等
EQ Z置位 相等
LE Z清零或N不等于V 带符号数小于或等于
GE N等于V 带符号数大于或等于
LT N不等于V 带符号数小于
GT Z清零且N等于V 带符号数大于
Hl C置位Z清零 无符号数大于
LS Z置位C清零 无符号数小于或等于
CC(LO) C清零 无符号数小于
CS(HS) C置位 无符号数大于或等于

如何编写代码,编译成汇编指令

有时候我们需要将自己编写的代码,编译然后查看对应的汇编代码

将c代码编译成.m文件,然后将.m文件拖入IDA查看汇编代码
clang -O0 -arch arm64 -isysroot xcrun --sdk iphoneos --show-sdk-path test.c -o test.m
// xcrun –sdk iphoneos –show-sdk-path 是获取xcode环境中iPhoneOS sdk的目录

还有一种方法就是直接在Xcode下断点,设置Debug->Debug workflow->Awayls show Disassembly 查看对应的汇编代码