分析问题中会涉及到看反汇编代码,通过反汇编code推断代码逻辑,从而更快更准确定位问题点,所以学会看反汇编代码是必要的。
下面将我工作中用到的一些常用汇编知识分享给大家,欢迎交流补充!
注意:汇编指令对大小写不敏感
LDR(load register) 字数据加载指令
STR(store register) 字数据存储指令
此ldr 和 str 的变种ldp(pair) 和 stp(pair) 还可以操作2个寄存器
ldp指令
LDR 字数据加载指令(4bytes)
LDRB 字节数据加载指令(1bytes)
LDRH 半字数据加载指令(2bytes)
STR 字数据存储指令(4bytes)
STRB 字节数据存储指令(1byte)
STRH 半字数据存储指令(2bytes)
SUB指令 减法指令
ADD 加法指令
MOV 指令将源操作数复制到目的操作数。作为数据传送(data transfer)指令,它几乎用在所有程序中。在它的基本格式中,第一个操作数是目的操作数,第二个操作数是源操作数:
movk
EOR 逻辑异或
ORR
LSL(Logic Shift Left) 逻辑左移指令,也就是向左移位
#0xfffe, lsl #16
0xfffe左移16位
rsb 指令(逆向减法指令)
RSB{条件}{S} 目的[寄存器],操作数1,操作数2
RSB指令称为逆向减法指令,用于把操作数2减去操作数1,并将结果存放到目的寄存器中。
操作数1应是一个寄存器,操作数2可以是一个寄存器,被移位的寄存器
CMP指令(比较):
CMP{条件} 操作数1, 操作数2
CMP指令用于把一个寄存器的内容和另一个寄存器的内容或立即数进行比较,同时更新CPSR中条件标志位的值。
该指令进行一次减法(cmp r0, r1 等价于 sub r2, r0, r1 (r2 = r0 - r1))运算,但不存储结果,只更改条件标志位。
标志位表示的是操作数1与操作数2的关系(大、小、相等),例如,当操作数1大于操作数2,则此后的有GT后缀的指令将可以执行。
cbz w8, 0x100c96694
b.eq b.ne
B{条件} 目标地址
BL{条件} 目标地址
跳转之前,会在寄存器R14 中保存PC 的当前内容,因此,可以通过将R14 的内容重新加载到PC 中,来返回到跳转指令之后的那个指令处执行。该指令是实现子程序调用的一个基本但常用的手段。以下指令:
BL Label ;当程序无条件跳转到标号 Label 处执行时,同时将当前的 PC 值保存到 R14 中
bx
指令跳转到指定的目标地址中, 目标地址处指令即可是ARM指令也可以是Thumb指令
bx lr
返回子程序
int main() {
return 0;
}
00000000 <main>:
0: e3a00000 mov r0, #0 // r0 = 0; r0为函数返回值寄存器
4: e12fff1e bx lr // lr别名r14,保存函数返回地址寄存器
00000000 <main>:
0: e52db004 push {fp} ; (str fp, [sp, #-4]!) // 压栈,保存main函数上一个func的栈帧地址fp到sp -4, sp -= 4
4: e28db000 add fp, sp, #0 // fp = sp + 0
8: e3a03000 mov r3, #0 // r3 = 0
c: e1a00003 mov r0, r3 // r0 = r3
10: e24bd000 sub sp, fp, #0 // sp = fp - 0
14: e49db004 pop {fp} ; (ldr fp, [sp], #4) // 出栈,fp = sp + 4
18: e12fff1e bx lr // 跳转到函数返回地址寄存器
code
int main() {
int a = 2;
return 0;
}
反汇编 code not with -O2
00000000 <main>:
0: e52db004 push {fp} ; (str fp, [sp, #-4]!) //压栈,保存main函数上一个func的栈帧地址fp到sp -4, sp -= 4
4: e28db000 add fp, sp, #0 // 栈帧指针指向栈顶地址,fp = sp
8: e24dd00c sub sp, sp, #12 // sp -= 12
c: e3a03002 mov r3, #2 // r3 = 2
10: e50b3008 str r3, [fp, #-8] // 保存r3到(fp - 8)寄存器,局部变量a放到栈内存中
14: e3a03000 mov r3, #0 // r3 = 0
18: e1a00003 mov r0, r3 // r0 = r3, r0 函数返回值寄存器,即return 0
1c: e24bd000 sub sp, fp, #0 // sp = fp, 栈顶指针指向栈帧指针,销毁掉局部变量a
20: e49db004 pop {fp} ; (ldr fp, [sp], #4) // fp = [sp], sp += 4,栈帧指针指向main函数上一个func的栈帧,栈顶指针指向main函数上一个func的栈顶
24: e12fff1e bx lr // 跳转到目标地址lr,即r14(函数返回地址)
int main(void) {
int a = 2;
char b = 3;
a = b;
return 0;
}
00000000 <main>:
0: e52db004 push {fp} ; (str fp, [sp, #-4]!)
4: e28db000 add fp, sp, #0
8: e24dd00c sub sp, sp, #12
c: e3a03002 mov r3, #2
10: e50b3008 str r3, [fp, #-8]
14: e3a03003 mov r3, #3 // r3 = 3,对应代码中b = 3
18: e54b3009 strb r3, [fp, #-9] // 3存入一个bytes到fp-9中
1c: e55b3009 ldrb r3, [fp, #-9] // 加载[fp-9]的一个bytes到r3中
20: e50b3008 str r3, [fp, #-8] // 将r3存入[fp-8]中,即a = b
24: e3a03000 mov r3, #0
28: e1a00003 mov r0, r3
2c: e24bd000 sub sp, fp, #0
30: e49db004 pop {fp} ; (ldr fp, [sp], #4)
34: e12fff1e bx lr
void test(void) {
}
int main(void) {
int a = 2;
char b = 3;
a = b;
test();
return 0;
}
00000000 <test>:
0: e52db004 push {fp} ; (str fp, [sp, #-4]!) // 压栈帧
4: e28db000 add fp, sp, #0
8: e24bd000 sub sp, fp, #0
c: e49db004 pop {fp} ; (ldr fp, [sp], #4) // 弹栈帧
10: e12fff1e bx lr
00000014 <main>:
14: e92d4800 push {fp, lr}
18: e28db004 add fp, sp, #4
1c: e24dd008 sub sp, sp, #8
20: e3a03002 mov r3, #2
24: e50b3008 str r3, [fp, #-8]
28: e3a03003 mov r3, #3
2c: e54b3009 strb r3, [fp, #-9]
30: e55b3009 ldrb r3, [fp, #-9]
34: e50b3008 str r3, [fp, #-8]
38: ebfffffe bl 0 <test> // 跳转到test func
3c: e3a03000 mov r3, #0
40: e1a00003 mov r0, r3
44: e24bd004 sub sp, fp, #4
48: e8bd8800 pop {fp, pc}
void test(int p1, int p2, int p3, int p4) {
}
int main(void) {
int a = 2;
char b = 3;
a = b;
test(a, a, a, a);
return 0;
}
00000000 <test>:
0: e52db004 push {fp} ; (str fp, [sp, #-4]!)
4: e28db000 add fp, sp, #0
8: e24dd014 sub sp, sp, #20 // 栈顶指针开辟空间 20个
c: e50b0008 str r0, [fp, #-8] // 第一个形参拷贝第一个实参
10: e50b100c str r1, [fp, #-12] // 第2个形参拷贝第2个实参
14: e50b2010 str r2, [fp, #-16] // 第3个形参拷贝第3个实参
18: e50b3014 str r3, [fp, #-20] ; 0xffffffec // 第4个形参拷贝第4个实参
1c: e24bd000 sub sp, fp, #0
20: e49db004 pop {fp} ; (ldr fp, [sp], #4)
24: e12fff1e bx lr
00000028 <main>:
28: e92d4800 push {fp, lr}
2c: e28db004 add fp, sp, #4
30: e24dd008 sub sp, sp, #8
34: e3a03002 mov r3, #2
38: e50b3008 str r3, [fp, #-8]
3c: e3a03003 mov r3, #3
40: e54b3009 strb r3, [fp, #-9]
44: e55b3009 ldrb r3, [fp, #-9]
48: e50b3008 str r3, [fp, #-8]
4c: e51b0008 ldr r0, [fp, #-8] // 函数入参1,赋值为a
50: e51b1008 ldr r1, [fp, #-8] // 函数入参2,赋值为a
54: e51b2008 ldr r2, [fp, #-8] // 函数入参3,赋值为a
58: e51b3008 ldr r3, [fp, #-8] // 函数入参4,赋值为a
5c: ebfffffe bl 0 <test>
60: e3a03000 mov r3, #0
64: e1a00003 mov r0, r3
68: e24bd004 sub sp, fp, #4
6c: e8bd8800 pop {fp, pc}
int test(int p1, int p2, int p3, int p4) {
int p = 0;
p = p1 + p2 + p3 - p4;
return p;
}
int main(void) {
int a = 2;
char b = 3;
a = b;
a = test(a, a, a, a);
return 0;
}
00000000 <test>:
0: e52db004 push {fp} ; (str fp, [sp, #-4]!)
4: e28db000 add fp, sp, #0
8: e24dd01c sub sp, sp, #28 // 栈顶指针开辟空间 28个
c: e50b0010 str r0, [fp, #-16]
10: e50b1014 str r1, [fp, #-20] ; 0xffffffec
14: e50b2018 str r2, [fp, #-24] ; 0xffffffe8
18: e50b301c str r3, [fp, #-28] ; 0xffffffe4
1c: e3a03000 mov r3, #0 // p = 0
20: e50b3008 str r3, [fp, #-8] // p ---> [fp - 8]
24: e51b2010 ldr r2, [fp, #-16]
28: e51b3014 ldr r3, [fp, #-20] ; 0xffffffec
2c: e0822003 add r2, r2, r3 // p1 += p2
30: e51b3018 ldr r3, [fp, #-24] ; 0xffffffe8
34: e0822003 add r2, r2, r3 // p1 += p3
38: e51b301c ldr r3, [fp, #-28] ; 0xffffffe4
3c: e0633002 rsb r3, r3, r2 // p4 = p1 - p4
40: e50b3008 str r3, [fp, #-8] // p = p4
44: e51b3008 ldr r3, [fp, #-8]
48: e1a00003 mov r0, r3 // 函数返回值r0 = p
4c: e24bd000 sub sp, fp, #0
50: e49db004 pop {fp} ; (ldr fp, [sp], #4)
54: e12fff1e bx lr
00000058 <main>:
58: e92d4800 push {fp, lr}
5c: e28db004 add fp, sp, #4
60: e24dd008 sub sp, sp, #8
64: e3a03002 mov r3, #2
68: e50b3008 str r3, [fp, #-8]
6c: e3a03003 mov r3, #3
70: e54b3009 strb r3, [fp, #-9]
74: e55b3009 ldrb r3, [fp, #-9]
78: e50b3008 str r3, [fp, #-8]
7c: e51b0008 ldr r0, [fp, #-8]
80: e51b1008 ldr r1, [fp, #-8]
84: e51b2008 ldr r2, [fp, #-8]
88: e51b3008 ldr r3, [fp, #-8]
8c: ebfffffe bl 0 <test>
90: e50b0008 str r0, [fp, #-8] // a = test函数返回值r0
94: e3a03000 mov r3, #0
98: e1a00003 mov r0, r3
9c: e24bd004 sub sp, fp, #4
a0: e8bd8800 pop {fp, pc}
int test(int p1, int p2, int p3, int p4) {
int p = 0;
p = p1 + p2 + p3 - p4;
return p;
}
int main(void) {
int a = 2;
char b = 3;
a = b;
a = test(a, a, a, a);
for (int i = 0; i < 4; i++) {
a = a+ i;
}
if (a > 100) {
a = 200;
} else {
a = 1;
}
return 0;
}
00000000 <test>:
0: e52db004 push {fp} ; (str fp, [sp, #-4]!)
4: e28db000 add fp, sp, #0
8: e24dd01c sub sp, sp, #28
c: e50b0010 str r0, [fp, #-16]
10: e50b1014 str r1, [fp, #-20] ; 0xffffffec
14: e50b2018 str r2, [fp, #-24] ; 0xffffffe8
18: e50b301c str r3, [fp, #-28] ; 0xffffffe4
1c: e3a03000 mov r3, #0
20: e50b3008 str r3, [fp, #-8]
24: e51b2010 ldr r2, [fp, #-16]
28: e51b3014 ldr r3, [fp, #-20] ; 0xffffffec
2c: e0822003 add r2, r2, r3
30: e51b3018 ldr r3, [fp, #-24] ; 0xffffffe8
34: e0822003 add r2, r2, r3
38: e51b301c ldr r3, [fp, #-28] ; 0xffffffe4
3c: e0633002 rsb r3, r3, r2
40: e50b3008 str r3, [fp, #-8]
44: e51b3008 ldr r3, [fp, #-8]
48: e1a00003 mov r0, r3
4c: e24bd000 sub sp, fp, #0
50: e49db004 pop {fp} ; (ldr fp, [sp], #4)
54: e12fff1e bx lr
00000058 <main>:
58: e92d4800 push {fp, lr}
5c: e28db004 add fp, sp, #4
60: e24dd010 sub sp, sp, #16 // 栈顶指针开辟空间 16个
64: e3a03002 mov r3, #2
68: e50b3008 str r3, [fp, #-8]
6c: e3a03003 mov r3, #3
70: e54b300d strb r3, [fp, #-13]
74: e55b300d ldrb r3, [fp, #-13]
78: e50b3008 str r3, [fp, #-8]
7c: e51b0008 ldr r0, [fp, #-8]
80: e51b1008 ldr r1, [fp, #-8]
84: e51b2008 ldr r2, [fp, #-8]
88: e51b3008 ldr r3, [fp, #-8]
8c: ebfffffe bl 0 <test>
90: e50b0008 str r0, [fp, #-8]
94: e3a03000 mov r3, #0 // i = 0
98: e50b300c str r3, [fp, #-12] // i ----> [fp - 12](i)
9c: ea000006 b bc <main+0x64> // 跳转到 main的bc地址处
a0: e51b2008 ldr r2, [fp, #-8] //-------a0 --------
a4: e51b300c ldr r3, [fp, #-12]
a8: e0823003 add r3, r2, r3 // i = a +i
ac: e50b3008 str r3, [fp, #-8] // i ----> [fp - 8](a),即a = i
b0: e51b300c ldr r3, [fp, #-12]
b4: e2833001 add r3, r3, #1 // i += 1
b8: e50b300c str r3, [fp, #-12]
bc: e51b300c ldr r3, [fp, #-12] //------bc ----------
c0: e3530003 cmp r3, #3 // i - 3,根据结果置标志寄存器 Z C
c4: dafffff5 ble a0 <main+0x48> // if(i <= 3),则跳转到 main的a0地址处
c8: e51b3008 ldr r3, [fp, #-8]
cc: e3530064 cmp r3, #100 ; 0x64 // a - 100
d0: da000002 ble e0 <main+0x88> // if (a <= 100),则跳转到main的e0地址处
d4: e3a030c8 mov r3, #200 ; 0xc8 // else { a = 200 }
d8: e50b3008 str r3, [fp, #-8]
dc: ea000001 b e8 <main+0x90> // 跳转到main的e8处,不再对a进行赋值操作
e0: e3a03001 mov r3, #1 // ------- e0 --------
e4: e50b3008 str r3, [fp, #-8] // a = 1
e8: e3a03000 mov r3, #0 // ------- e8 --------
ec: e1a00003 mov r0, r3 // 函数返回值r0 = 0
f0: e24bd004 sub sp, fp, #4
f4: e8bd8800 pop {fp, pc}