ARM 汇编学习

1、取出libc函数文件库

 adb pull /system/lib/libc.so ./

2、IDA下 alt + g 可以修改thumb 或 arrm指令集

3、arm下 R0~R12 寄存器都是普通的寄存器,R13寄存器就是SP寄存器,相当于esp,LR寄存器是用来保存返回地址的(调用函数时) PSR处理机寄存器,相当于Eflag寄存器

4、arm的用户地址空间为 0 ~ 0xc0000000

5、arm无隐式操作内存的指令(如push , pop),所以其调用函数的时候不能把返回地址写在内存里,故其使用了LR寄存器保存返回地址

6、arm的每一条指令,内存操作最多出现一次,这也是为什么设计者设计了adr str两条用于访存的指令

7、读取arm指令集的pc值的时候,实际上会显示 pc + 8的大小, thumb模式下,实际上会显示 pc + 4

8、arm指令集 = 后面一定跟内存操作数

如LDR r0,=0x10086 意思就是读取其读取的地址对应的值是0x10086 , 这是ida的伪指令,ida优化后的
MOV R6,R6,LSL R2 # 其中 LSL 是左移命令,左移R2位
 

9、arm 指令下的断点为 UND #0x10 即F0 01 F0 E7 ,相当于cc断点

thumb 是UND #0x10 => 10 de
利用这一点我们可以实现反调试
通过使用 LDR pc , [pc , #-4] (arm模式) 汇编来实现反调试
arm模式下,我们在使用LDR pc , [pc,#-4]读取下一个地址所对应的值的时候,由于程序处于调试状态,我们使用f7或f8的时候,下一个地址对应的值是断点,这就导致我们读取的值是断点的值,但f9可以绕过该反调试

10、arm 和 thumb 都是四字节对齐

这导致thumb读取指令的数据时会存在四字节对齐的问题
 
 
条件和标志位响应

11、arm指令集的条件一般是指令后缀的形式 , 如BEQ指令就是B指令加上EQ条件的产物

 
0
arm模式下,条件被体现在指令的第四字节的前四位上如:
BXEQ => EQ是0,对应了2F 01的0
0
thumb模式下,被体现在了指令的第二个字节的后四位上
 

12、ADDS 与 ADD指令的区别,带s的指令运算会影响标志位

 

13、mov 指令后跟操作数

因为arm 指令是四字节的,所以其表示立即数是比较有讲究的
当立即数比较小的时候,mov指令为A2类型:
立即数的硬编码存储也有讲究:
0
指令的第0~11位与第12~15位拼接成立即数
如 mov r0 , 0x1234
其硬编码为: 34 02 01 e3
 
当立即数比较大,但能通过循环移位的方式得到
则mov指令采用A1类型
Mov 指令的A1类型:
0
如Mov ,#0x40000000
=> 01 01 A0 E3
而其他大的,不能通过循环移位得到的立即数,则是不合法的Mov指令,
一般的处理方法就是借助MOVT指令
movt指令是把立即数写入到寄存器的高16位中

14、mov , r0, r1,LSL#4 # 把r1左移四位给r0

mov ,r0, r1,lsl r2 # r1 左移r2位给r0
0
A1类型,stype两位代表四种情况:
逻辑左移,逻辑右移,算术右移,循环移位
 

15、add

arm模式下add只有A1一种形式
0
这也是把低12位拆成一个8位和一个四位,然后进行循环移位
add ,r0 ,pc,4
在ida中汇编变成: adr r0 , xxx
所以,当我们逆向分析的时候,要明白 adr 指令后面的值是要被重定位的,而不应该是固定的值
 

16、RSB

反减
RSB R0, R1,#8 代表 r0 = 8-r1
 

17、tst

tst是and操作,但只影响标志位,不影响结果

18、bic

反and
BIC R0, R1, #8
把r1和第8 取反之后做and运算并放入r0
 

19、LDR后续附加行为

LDR指令后加 !
如: ldr r0,[r1, #4]!
相当于把 r1 + 4地址对应内容的值加载到r0 , 同时把r1 的值进行加4
ldr r0,[r1],#4
相当于把 r1地址对应的内容加载到r0,再把r1的值加4 (r1 += 4
利用!我们们可以实现压栈或出栈
str r0 , [sp, #-4]!
相当于实现了 push r0的功能
ldr r0,[sp], #4
相当于 pop r0功能
 

20、理解ida的 =() 指令

如下:
.text:B4408EC8 18 01 9F E5                       LDR             R0, =(dword_B440C0AC - 0xB4408EDC)
.text:B4408ECC 07 10 A0 E1                       MOV             R1, R7  ; buf
.text:B4408ED0 06 20 A0 E1                       MOV             R2, R6  ; n
.text:B4408ED4 00 00 9F E7                       LDR             R0, [PC,R0] ; dword_B
代码中 (dword_B440C0AC - 0xB4408EDC) 的0xB4408EDC 是ida自动分析的结果,因为R0需要在0xB4408ED4的地址上执行 LDR r0,[pc,r0] 操作,而0xB4408EDC正好是pc + 8的值,那么 dword_B440C0AC 其实就是 LDR R0, [PC,R0] 指令执行后的R0的值
arm之所以把该操作表示的这么麻烦,就是为了方便重定位
 

21、LDRB

LDRB读取8位的数据宽度
LDRH读取16位的数据宽度
 

22、块访存指令

读内存:LDM** (LDMIA,LDMIB,LDMDA,LDMDB) //从寄存器到内存
写内存:STM** (LDMIA,LDMIB,LDMDA,LDMDB) // 从内存到寄存器 //不要记方向..
一般用法:
LDMIA R0 , {R1-R4}
IA: increase After ,即向地址高的方向读取内存
IA!: 读取地址后把指针跟到最后读完的位置
读取之后,按地址由低到高分别放入R1~R4中
0
IB: increase before
DA:decrease after
DB: decrease before
 
函数调用时,堆栈保存寄存器的操作:
堆栈使用的是DB!(push) 和 IA!(pop)
push : stmdb,sp!,{r0-r3} , 但ida上的汇编是stmfd sp!,{r0-r3},这是因为当第一个操作数为sp时,ida会有限翻译为stmfd
fd的意思是:full down ,即满栈,反向增长 满栈说明sp指向的数据是有用的(反之,空栈说明sp的数据是无效的,sp+4的位置是有用的) down,代表地址向低地址增长
故LDMFD==LDMIA ; STMFD==STMDB
STMFD==push
LDMFD==pop
 

23、分支跳转和模式切换

模式切换看标志寄存器的T位,0为arm,1为thumb
B指令
0
24位扩展,但实际寻址大小为 4**24大小,因为他的单位是指令长度(即4字节)
BL指令
arm模式下,其跳转的时候,会把当前指令的下一条指令的地址写入LR寄存器中
thumb模型下,其跳转的时候,会把当前指令的下一条地址+1 写入LR寄存器中
加的这个1实际上就是标志寄存器的T位
 
BX指令
若目标地址的bit[0]为1,则跳转时自动将CPSR中的标志位T置位,即把目标地址的代码解释为Thumb代码
BLX指令
BLX + 立即数 一定带有状态切换
BLX + 寄存器 不一定有状态切换
 
通过 ldr pc , [r0] 也可以实现跳转,并且自带模式切换!!
arm指令在定位导入函数的时候经常使用此方法
 

24、thumb指令集

thumb 模式下,短指令一般不使用r8-r12寄存器,使用r8-r12寄存器会带来指令扩展
如 mov r4,#0 是两字节的 而mov r8,#0,是四字节的

25、.w后缀的thumb指令

带表示.w的表示四字节长编码

26、IT指令块

格式: IT***
用法:
ITTET EQ
指令1 :movs r0,#1
指令2 :movs r1,#2
指令3 :movs r2,#3
指令4 :movs r3,#4
TET中的T代表then,E代表else
在运行的时候指令一会被附加EQ条件 T (这是固定不变的
指令二会被附加EQ条件 T
指令三会被附加EQ的反条件(NE) E
指令四会被附加EQ条件 T
执行完之后,只有r2的值被赋值为3,其他寄存器值不变
 

27、调用约定

使用r0-r3四个寄存器传参,其他参数栈传递
非易变寄存器: r4-r11
r11:栈帧指针 类似于x86的ebp , 其值保存上个函数的栈指针
r12:导入表寻址
 
posted @ 2022-12-06 23:14  TLSN  阅读(310)  评论(0编辑  收藏  举报