LDR load data to register
BL break with linker
寄存器和指令基本格式
- save Desktop 保存 opcode 长度,不用每次重新设置
- maps 中,内存地址前 1/4 给用户用,后 1/4 给内核用
- ARM 没有隐式内存操作指令,X86 直接通过栈操作,改变内存
- 0-3 个操作数,内存操作数和立即数操作数不能同时存在,内存操作数(中括号包含)至多出现 1 次,寄存器操作数总在最前
- 有=号,内存操作数,是伪指令,需要上下文,{Rx,Rx,Rx }寄存器操作数组,loc_xx 立即数操作数
- PSR 标志寄存器,常见位 N 正负数 Z 0 标志位 C 进位 V 溢出
读 PC 寄存器
- 读 arm PC,读出来的值就是 PC 值+8,不是严格的三级流水,预取指令,thumb+4 arm+8 ,典型反例(thumb 中一条指令 4 一条指令 2)
- F7 调试使用 CC 断点实现,UDF 异常,通过在要调试行下一行下异常,进行断点调试
- thumb 指令四字节对齐,PC 寻址,需要先四字节对其,如果没有对齐,向下取整
- MOV R0,PC MOV PC,R0 LDR R0,[PC,#4]
条件和标志位响应
N 当用两个补码表示的带符号数进行运算时,N=1表示运算的结果为负数;N=0表示运算的结果为正数或零.
Z Z=1表示运算的结果为零,Z=0表示运算的结果非零。
C 可以有4种方法设置C的值:
加法运算(包括CMN):当运算结果产生了进位时(无符号数溢出),C=1,否则C=0。
减法运算(包括CMP):当运算时产生了借位时(无符号数溢出),C=0,否则C=1。
对于包含移位操作的非加/减运算指令,C为移出值的最后一位。
对于其它的非加/减运算指令,C的值通常不会改变。
V 可以有2种方法设置V的值:
对于加减法运算指令,当操作数和运算结果为二进制的补码表示的带符号数时,V=1表示符号位溢出
对于其它的非加/减运算指令,V的值通常不会改变。
N 正负数 Z 0 标志位 C 进位 V 溢出
无符号 Higher lower
有符号 Greater less
cond | Mnemonic extension | integer | floating-point | conditional flags |
---|---|---|---|---|
0000 | EQ | Equal | Equal | Z == 1 |
0001 | NE | Not Equal | Not Equal,or unordered | Z == 0 |
0010 | CS^b | Carry set | Greater than,equal,or unordered | C == 1 |
0011 | CC^C | Carry clear | Less than | C == 0 |
0100 | MI | Minus,negative | Less than | N == 1 |
0101 | PL | Plus,positive or zero | Greater than,equal or unordered | N == 0 |
0110 | VS | Overflow | Unordered | V == 1 |
0111 | VC | No overflow | Not unordered | V == 0 |
1000 | HI | Unsigned higher | Greater than,or unordered | C == 1 and Z == 0 |
1001 | LS | Unsigned lower or same | Less than or equal | C == 0 or Z == 1 |
1010 | GE | Signed greater than or equal | Greater than or equal | N == V |
1011 | LT | Signed less than | Less than, or unordered | N != V |
1100 | GT | Signed greated than | Greater than | Z == 0 and N ==V |
1101 | LE | Signed less than or equal | Less than,equal,or unordered | Z == 1 or N != V |
1110 | None |
带s的指令 影响标志位
CMP CMN 只更新标志位
MOV 指令
MOV r0,0x40000000 01 01 A0 E3 0x10000000 = 0x01 ROR 2*01
MOV r0,0x80000000 02 01 A0 E3 0x10000000 = 0x02 ROR 2*01
MOV r0,0x10000000 02 02 A0 E3 0x10000000 = 0x02 ROR 2*02
movt 写寄存器的高16位 与mov一起操作,完成32位的数据写入
实际c语言中,ldr指向一个地址,地址是一个DCD数据,向寄存器赋值
mov 支持shift MOV R0,R1,LSL#4
可以理解成移位指令是MOV的宏
stype表示,逻辑左移,逻辑右移,算术右移,循环移位
LSL LSR ASR ROR
基本整形运算
ADD(ADR,ADRL),SUB(CMP),RSB(反减),AND(TST),BIC(反AND),ORR(或),EOR异或(TEQ),LSL,LSR,ASR
ADR R12,0x508 = ADD R12,PC,0
ADD 12位立即数
RSB 反减
访存指令
LDR R0,[R1,#4]! 从R1+4表示的地址取完数据之后,还要把R1更新为R1+4
LDR R0,[R1],#4 从R1表示的地址取完数据之后,还要把R1更新为R1+4
push r0: str r0,[sp,#-4]
pop r1 : ldr r1,[sp],#4
在0x5F4中
按Q键,可以将=(aHello-0x5FA),变为纯值,再加上PC,算偏移,可以得到真正的数据
aHello指向的是数据地址,因为下一句要相加PC,所以提前减掉PC+4,即0x5FA
在实际运行时,还是加上内存中的基址
块访存指令
向指定位置,批量保存寄存器
寄存器较小的放到低地址,寄存器较大的放到高地址
FD FullDescending
IA load memory increase after
IB increase before
LDMIA R0,{R1-R4}
push STMDB = STMFD 栈操作时指令一样,第一个参数为sp时,优先翻译为STMFD
pop LDMIA = LDMFD
IA:快速复制内存
分支和模式切换
1. 跳转目标
2. 模式切换
3. 写入LR
B imm
BL imm
BX reg
BLX imm
BLX reg
B的寻址范围 2^26
无限循环,跳转到自己,
可以在一个elf的_start函数起始地点改为FEFFFFEA,从而可以挂载上(如果没有while的情况)
BL 把当前指令的下一条指令的地址与T位做一个或,放到LR的最低位
BX 把寄存器的值的最低为写入T标志位,所以hook的时候,很多都是直接去地址+1
blx 立即数 一定会带有模式切换
根据函数的导出地址的最低一位判断是arm实现还是thumb实现
mov pc, reg和BX的区别:
不会根据寄存器最低一位判断指令模式
LDR PC,[R0]来跳转指令,也可以更改模式
Thumb模式,IT块
短指令一般不用r8-r12,
一般没有条件码和标志响应位,
运算指令优先对第一,第二操作数相同情况时有短指令编码
.w后缀,长编码,
STMFD thumb模式下直接简化为push
movs 短编码,mov长编码
IT指令会影响紧接着的1条指令
ITTTT指令会影响紧接着的4条指令
受影响的指令可能会加上条件 STRGE
ITTET ,if then if else
T块的长度取决于,opcode中最低0-3个bit中,最右边的1距离最左边的长度
PSR中IT,IT2取决于opcode中的bit,如果都为0,则代表已经出去IT块