arm的资料没有x86丰富,但搞安卓底层又绕不开这个。我作为一个初学者走了不少弯路,那么现在我用一个实际的例子来分析一个最简单的arm函数调用过程,希望能帮到大家,如果有理解不正确之处请高手指出。
注:这里的指令实际上是thumb(thumb2?),每个指令2字节
C源码:------------------------------------------------------------------
#include <stdio.h>
#include <dlfcn.h>
void (*func)();
void sub() {
void *p = dlopen("libxxx.so", RTLD_NOW);
if (!p) {
return;
}
else {
// myfn是libxxx.so的一个函数,作用是打印"call myfn...!"
func = (void (*)())dlsym(p,"myfn");
func();
}
}
int main()
{
printf("RTLD_NOW=%d\n", RTLD_NOW);
sub();
return 0;
}
运行结果---------------------------------------------------------------
反汇编分析-------------------------------------------------------------
sub:
1. 84a0: 4808 ldr r0, [pc, #32] ; (84c4 <printf@plt+0x6c>)
2. 84a2: 2100 movs r1, #0
3. 84a4: b510 push {r4, lr}
4. 84a6: 4c08 ldr r4, [pc, #32] ; (84c8 <printf@plt+0x70>)
5. 84a8: 4478 add r0, pc
6. 84aa: 447c add r4, pc
7. 84ac: f7ff efc8 blx 8440 <dlopen@plt>
8. 84b0: b138 cbz r0, 84c2 <printf@plt+0x6a>
9. 84b2: 4906 ldr r1, [pc, #24] ; (84cc <printf@plt+0x74>)
10. 84b4: 4479 add r1, pc
11. 84b6: f7ff efca blx 844c <dlsym@plt>
12. 84ba: 4905 ldr r1, [pc, #20] ; (84d0 <printf@plt+0x78>)
13. 84bc: 5863 ldr r3, [r4, r1]
14. 84be: 6018 str r0, [r3, #0]
15. 84c0: 4780 blx r0
16. 84c2: bd10 pop {r4, pc}
// 为5.做准备
1. r0 = [0x84a0+4+32] = [0x84c4] = 0x48
// dlopen的参数2
2. r1 = 0
// lr是sub的返回地址
3. r4,lr 入栈
// 为6.做准备
// 必须对齐到(0,4,8,c),所以0x84ca变成0x84c8
4. r4 = [0x84a6+4+32] = [0x84ca] = [0x84c8] = 0xc26
// dlopen的参数1 -> 0x84f4处存放字符串libxxx.so
5. r0 = 0x48+0x84a8+4 = 0x84f4
// 为13.做准备
6. r4 = 0xc26+0x84aa+4= 0x90D4
// 参数r0&r1,返回值r0
7. call dlopen
// 如果r0为0,则跳转到0x84c2
8. 条件跳转
// 为10.做准备
// ce对齐到cc
9. r1 = [0x84b2+4+24] = [0x84CE] = [0x84cc] = 0x46
// dlsym的参数2 -> 0x84FE处存放字符串myfn
10. r1 = 0x46+0x84b4+4 = 0x84FE
// 参数r0&r1,返回值r0,这个返回值就是myfn的地址
11. call dlsym
// 为13.做准备
// d2对齐到d0
12. r1 = [0x84ba+4+20] = [0x84D2] = [0x84d0] = 0xfffffffc
// r3是用来干嘛的呢,见14.
13. r3 = [0x90D4+0xfffffffc] = [0x90d0] = 0x90f0
// 将myfn的地址保存
14. [0x90f0] = r0
15. call myfn
16. 出栈,将lr放入pc,该sub返回
修改--------------------------------------------------------------------
从以上分析得知,12-14行的作用是将myfn的地址缓存以便加快以后重复的调用(该程序只调用了一次)
如果这个分析是正确的,那么将12-14行去掉应该不会影响程序的正常执行
下面是试验(将12-14行替换成nop,机器码0xc046):
修改后的运行结果:
程序执行正常。
[培训]《安卓高级研修班(网课)》月薪三万计划,掌
握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法