arm 反汇编
来源:互联网 发布:win7仿mac os x主题包 编辑:程序博客网 时间:2024/05/24 23:13
****************************************linux 下动态库函数调用反汇编问题。author: hjjdebugdate: 2016年 09月 07日 星期三 14:41:49 CST****************************************
#include <stdio.h>#include <string.h>void test_so(){ char buffer[256]; printf("---------- hello Android ------------\n"); FILE * fp=fopen("1.txt","rt"); if(fp) { memset(buffer,0,sizeof(buffer)); fread(buffer,sizeof(buffer),1,fp); printf("%s\n",buffer); fclose(fp); } else { printf("error open 1.txt\n"); }} cat Makefile #CC=gcc -march=i386 -m32CC=arm-linux-androideabi-gcc -mthumbCFLAG= -c -fPIC -g LDFLAG= -sharedall: hellohello: main.o libtest.so $(CC) -g -o $@ main.o -L . -ltest main.o: main.c $(CC) $(CFLAG) -o $@ $<libtest.so : testso.c $(CC) $(CFLAG) $(LDFLAG) -o $@ $<dump: arm-linux-androideabi-objdump -S -M force-thumb hello |tee 1.asmclean: rm hello main.o libtest.so 1.asm *~
以下分析代码为arm 指令, 由arm-Linux-androideabi-gcc 编译
1. c 函数框架。
c 函数会使用堆栈,故而会使用sp寄存器, 但函数执行完后要恢复sp寄存器,
所以框架通常会保留原来的寄存器,我们把它叫old-sp寄存器。 arm 用fp寄存器
充当这个角色。 下面是它的框架示意: frame pointer 在函数生命期内其值是不变的。
2b0: e92d4800 push {fp, lr} 2b4: e28db004 add fp, sp, #4 2b8: e24ddf42 sub sp, sp, #264 ; 0x108...... 34c: e24bd004 sub sp, fp, #4 350: e8bd8800 pop {fp, pc}
2.如何调用其它函数, 参数传递方法。
arm 的传参,小于4个的用寄存器, r0,r1,r2,r3. 大于4个用堆栈。 返回值用r0
3. 如何访问常量数据?例如: “hello android”
printf("hello android\n"); 2bc: e59f3090 ldr r3, [pc, #144] ; 354 <test_so+0xa4> 2c0: e08f3003 add r3, pc, r3 2c4: e1a00003 mov r0, r3 2c8: ebffffe9 bl 274 <test_so-0x3c>...... 354: 0000009c .word 0x0000009c 358: 000000b4 .word 0x000000b4 35c: 000000b0 .word 0x000000b0 360: 00000050 .word 0x00000050
在程序区造一个表,把它叫look-aside表吧, 就是手边的表。
表中存放数据地址,这个地址与当前pc值相加才是真实数据地址。
pc值2c0+9c = 36c 正好是”hello android”的的地址, 36c 位于rodata区
Contents of section .rodata: 0364 2d2d2d2d 2d2d2d2d 2d2d2068 656c6c6f ---------- hello 0374 20616e64 726f6964 202d2d2d 2d2d2d2d android ------- 0384 2d2d2d2d 2d000000 312e7478 74000000 -----...1.txt... 0394 72740000 6572726f 72206f70 656e2031 rt..error open 1 03a4 2e747874 00000000 .txt....
4. 如何访问局部变量?
局部变量是保存在堆栈中的,函数退出即丢弃。
例如: memset(buffer,0,sizeof(buffer)); 2f8: e24b3f42 sub r3, fp, #264 ; 0x108 2fc: e1a00003 mov r0, r3 300: e3a01000 mov r1, #0 304: e3a02c01 mov r2, #256 ; 0x100 308: ebffffdf bl 28c <test_so-0x24>
通过frame pointer 可以获得局部变量的地址。
5. 如何调用动态链接函数, 找到函数入口地址。
还以printf 为例, printf 是c 库函数, 编译期并不知道其地址。
看下面代码,关注bl 274 2bc: e59f3090 ldr r3, [pc, #144] ; 354 <test_so+0xa4> 2c0: e08f3003 add r3, pc, r3 2c4: e1a00003 mov r0, r3 2c8: ebffffe9 bl 274 <test_so-0x3c>....
274 处是另外一个表项,该表名称叫plt (procedure leakage table)
翻译为过程连接表
00000260 <.plt>: 260: e52de004 .word 0xe52de004 264: e59fe004 .word 0xe59fe004 268: e08fe00e .word 0xe08fe00e 26c: e5bef008 .word 0xe5bef008 270: 000011d4 .word 0x000011d4 274: e28fc600 .word 0xe28fc600 278: e28cca01 .word 0xe28cca01 27c: e5bcf1d4 .word 0xe5bcf1d4 280: e28fc600 .word 0xe28fc600 284: e28cca01 .word 0xe28cca01 288: e5bcf1cc .word 0xe5bcf1cc
这是小微代码区,用以完成向库函数跳转过程。 看274 对应的代码。(ida 中显示如下:)
.plt:00000274 ; =============== S U B R O U T I N E =======================================.plt:00000274.plt:00000274 ; Attributes: thunk.plt:00000274.plt:00000274 ; int puts(const char *s).plt:00000274 puts ; CODE XREF: test_so+18p.plt:00000274 ; test_so+7Cp ....plt:00000274 ADR R12, 0x27C.plt:00000278 ADD R12, R12, #0x1000.plt:0000027C LDR PC, [R12,#(puts_ptr - 0x127C)]! ; __imp_puts.plt:0000027C ; End of function puts
274处是一个三条指令组成的小代码区。
它首先取到一个立即数,以它为基址从一个内存中取数据, 转去执行。
这个内存地址在.got 表中.(global offset table). 显然,等价于pe 格式文件的导入地址表。
可以感受到,取到的地址就是动态连接库的函数地址。这个地址要由加载器把数值填充好。
extern:00001468 ; Segment type: Externsextern:00001468 ; int puts(const char *s)extern:00001468 IMPORT __imp_puts ; CODE XREF: puts+8jextern:00001468 ; DATA XREF: .got:puts_ptro
6.总结一下,动态跳转的过程是:
- 加载器把外部so文件的调用函数地址都填充好了, 这个导入地址表叫.got 全局偏移表。
- 有一个plt过程连接表,属于微代码区,用于从.got表中取得数据,并跳转执行。
7.扩展知识:
可重定位代码(windows->dll) 和 位置无关代码(linux->so)
1.可重定位代码:(windows)
生成动态库时假定它被加载在地址 0 处。加载时它会被加载到一个地址(base),
这时要根据代码重定位(relocation)信息,对代码进行定址,so 才能正确寻址。
缺点: 不同的进程会把so加载到不同的地址, 而这些地址是不同的,重定位后的代码也是不同的, 所以这些代码没有办法共享。内存中有多份。 这样失掉了共享库的优势,跟不共享没多少差别。
除非进程能把共享库加载到同一个地址(但这个要求是过分的).
2.位置无关代码:(linux)
linux so文件使用 -fPIC 来生成位置无关代码。这些代码可以被加载到内存的任何位置都可以运行。
怎样做到?
不管是程序地址还是数据地址,都是通过pc值加上一个偏移量来获得,就实现了位置无关。
例如访问外部函数,将外部函数地址全部放入.got table, 通过 [pc+offset] 获取。
优点:
虽然不同的进程会把so 映射到不同的地址空间,但操作系统将把它们映射到相同的物理地址, 节省了代码空间。
缺点:
代码执行效率上有一点损失。 但是,没有了重定位,加载也变快了。
8. 补充
1.arm thumb 编译及反汇编
arm thumb gcc 编译: 加上-mthumb 选项, 你可以用-S 生成汇编码arm thumb 反汇编objdump -d -M force-thumb xxx.so
2.b.n 是什么意思?
n 是正数, N 是负数, 在标志寄存器中CPSR 中占一位。运算结果是正数数跳转
要用ida-pro objdump 仅供参考,后者往往分不清arm,thumb 指令,只能强制一种。
3. 流水线与pc
add pc 指令由于有流水线需要额外添加2条指令。例如:4020D856 LDR R4, =(26284)4020D858 ADD R4, PC ;4020d858+26284+4=40233ae04020D85A LRD r3, [R4,4]
本来:
4020d858+26284 = 40233adc, 还需要再加两条指令(流水线)才构成40233ae0 赋值给r4
4. cmp 指令与 tst 指令,
ld r3, #1cmp r3, #1(status = src - dst)
两者相等,置位z标志
ld r3, #1
tst r3, #1
(status = src & dst)
相与不为0, 不置位z标志,即判定结果将沿着not-equ方向前进.
对应于c语言的相等判定和相与操作不为0判定
9. 添加几个例子
1.流程控制例:
- 能够分辨if-elseif-else 及其嵌套结构。
- 能够分辨switch-case 分支
- 能够分辨while循环及for循环
while (customer->id != 0) 87fc: ea000004 b 8814 <main+0x48> { print_customer(customer); 8800: e51b0014 ldr r0, [fp, #-20] 8804: ebffff39 bl 84f0 <print_customer> customer++; 8808: e51b3014 ldr r3, [fp, #-20] 880c: e2833028 add r3, r3, #40 ; 0x28 8810: e50b3014 str r3, [fp, #-20] // customer->id != 0 8814: e51b3014 ldr r3, [fp, #-20] 8818: e5933000 ldr r3, [r3] 881c: e3530000 cmp r3, #0 8820: 1afffff6 bne 8800 <main+0x34> }
2.结构变量例子
能够分辨结构变量,结构变量数组。 结构变量的成员变量
// insert our productsproducts[0].id = 1;8834: e51b3018 ldr r3, [fp, #-24]8838: e3a02001 mov r2, #1883c: e5832000 str r2, [r3]products[0].category = 0;8840: e51b3018 ldr r3, [fp, #-24]8844: e3a02000 mov r2, #08848: e5832004 str r2, [r3, #4]//注释: r3 是一个指针, 也许我们一开始翻译为 p->d0=1, p->d1=0//指针也可以用解引用翻译为引用. (*p).d0=1,(*p).d1=0;//...???products[0].p.book = ida_book;884c: e51b2018 ldr r2, [fp, #-24]8850: e59f3234 ldr r3, [pc, #564] ; 8a8c <main+0x2c0>8854: e7943003 ldr r3, [r4, r3]8858: e2821008 add r1, r2, #8885c: e1a02003 mov r2, r38860: e3a03080 mov r3, #128 ; 0x808864: e1a00001 mov r0, r18868: e1a01002 mov r1, r2886c: e1a02003 mov r2, r38870: ebfffeb3 bl 8344 <_start-0x1c> ; 这是微码区copy, 因为ida_book 是256个字符数组// 注释:struct book_t ida_book = { "IDA QuickStart Guide" };struct book_t { char title[128]; // an ASCII string};products[1].id = 2;8874: e51b3018 ldr r3, [fp, #-24]8878: e2833088 add r3, r3, #136 ; 0x88887c: e3a02002 mov r2, #28880: e5832000 str r2, [r3]products[1].category = SOFTWARE;8884: e51b3018 ldr r3, [fp, #-24]8888: e2833088 add r3, r3, #136 ; 0x88888c: e3a02001 mov r2, #18890: e5832004 str r2, [r3, #4]products[1].p.software = softwares.softs[0]; // we insert softwares from our variable length structure8894: e51b3018 ldr r3, [fp, #-24]8898: e2832088 add r2, r3, #136 ; 0x88889c: e59f31ec ldr r3, [pc, #492] ; 8a90 <main+0x2c4>88a0: e7943003 ldr r3, [r4, r3]88a4: e282c008 add ip, r2, #888a8: e283e004 add lr, r3, #488ac: e8be000f ldm lr!, {r0, r1, r2, r3}88b0: e8ac000f stmia ip!, {r0, r1, r2, r3}88b4: e8be000f ldm lr!, {r0, r1, r2, r3}88b8: e8ac000f stmia ip!, {r0, r1, r2, r3}88bc: e59e3000 ldr r3, [lr]88c0: e58c3000 str r3, [ip]
3.指针例子
能够分辨数据与指针,有很多函数调用用的就是指针
用指针访问结构中的成员变量
指针解耦合成为变量
看一下product->category 的汇编代码
product 是一个指针,
category 对应一个偏移量
取值对应解耦合。
bool print_product(struct product_t *product)....`if (!check_product(product->category))8734: e51b3008 ldr r3, [fp, #-8]8738: e5933004 ldr r3, [r3, #4]873c: e1a00003 mov r0, r38740: ebffff56 bl 84a0 <check_product>
4.全局与局部变量例子
能够分辨全局变量和局部变量, 全局变量是PIC的。
struct customer_t *customer = gCustomers;87f0: e59f3290 ldr r3, [pc, #656] ; 8a88 <main+0x2bc> // 从look-aside 表中取到偏移87f4: e7943003 ldr r3, [r4, r3] // r4 是全局变量表参考地址, 从里面拿到gCustomers87f8: e50b3014 str r3, [fp, #-20] // 存储到customer 局部变量......8a80: 00001648 .word 0x000016488a84: 0000037c .word 0x0000037c8a88: fffffff4 .word 0xfffffff48a8c: fffffff8 .word 0xfffffff88a90: fffffffc .word 0xfffffffc8a94: 00000204 .word 0x0000020j
- arm反汇编方法
- ARM反汇编学习
- arm反汇编方法
- arm 反汇编基础
- arm 反汇编
- ARM反汇编练习
- arm 反汇编
- ARM 反汇编的查看
- ARM反汇编基础(一)
- 一个ARM简单反汇编例子
- ARM的BIN文件反汇编方法
- ARM的BIN文件反汇编方法
- ARM的BIN文件反汇编方法
- 几种ARM反汇编器
- ARM的BIN文件反汇编方法
- ARM反汇编动态链接分析
- IDA分析HELLO ARM 程序的ARM 反汇编
- 基于arm的C++反汇编 qemu-arm环境搭建
- js 常见的日期时间
- Ubuntu下 ssh : connect to host localhost port 22:Connection refused
- EasyPusher如何推送纯音频RTSP流媒体数据
- hive全套安装过程,通吃环境。
- 动态规划-硬币问题
- arm 反汇编
- windows下C语言实现<读取>和<写入> *.ini文件。
- Hihocoder上java程序的提交格式
- [bigdata-078] python3 logging 的示例 TimedRotatingFileHandler和RotatingFileHandler 基于时间切分和基于文件大小切分
- 免费PM2.5数据如何获取之PM25.in网站API调用JSON数据处理方法
- 关于学习CSS flexbox的文章或网址链接
- 螺旋矩阵--由外向内旋转输出
- 配置多个tomcat的步骤
- ViewPager滑动效果加导航效果