0x00 用到的书籍
《Android软件安全与逆向分析》第六章
0x01 原生程序的生成过程
笔者是在Linux环境下测试的,详细过程见书中说明
需要编译的C语言代码
#include <stdio.h>
int main(int argc, char* argv[]){
printf("Hello ARM!\n");
return 0;
}
- 预处理,生成hello.i文件
gcc -E hello.c -o hello.i
- 编译
gcc -S hello.i -o hello.s
- 汇编,生成二进制目标文件
gcc -c hello.s -o hello.o
- 链接,生成hello可执行文件
gcc hello.o -o hello
0x02 完整ARM汇编结构
下面打开生成的.文件
.arch armv5te @处理器架构
.fpu softvfp @浮点协处理器类型
.eabi_attribute 20, 1 @接口属性
.eabi_attribute 21, 1
.eabi_attribute 23, 3
.eabi_attribute 24, 1
.eabi_attribute 25, 1
.eabi_attribute 26, 2
.eabi_attribute 30, 6
.eabi_attribute 18, 4
.file "hello.c" @源文件名
.section .rodata @声明只读数据
.align 2 @声明对齐方式2^2=4字节
.LC0: @标号LC0
.ascii "Hello ARM!\000"@声明字符串
.text @声明代码段
.align 2 @声明对齐方式4字节
.global main @全局符号main
.type main, %function @main类型为函数
main: @标号main
@ args = 0, pretend = 0, frame = 8
@ frame_needed = 1, uses_anonymous_args = 0
stmfd sp!, {fp, lr} @将fp,lr压入堆栈
add fp, sp, #4 @初始化fp寄存器,设置栈帧,用于访问局部变量
sub sp, sp, #8 @开辟栈空间
str r0, [fp, #-8] @保存第一个参数
str r1, [fp, #-12] @保存第二个参数
ldr r3, .L3 @取标号.L3处的内容,
.LPIC0:
add r3, pc, r3
mov r0, r3
bl puts(PLT)
mov r3, #0
mov r0, r3
sub sp, fp, #4
ldmfd sp!, {fp, pc}
.L4:
.align 2
.L3:
.word .LC0-(.LPIC0+8)
.size main, .-main
.ident "GCC: (GNU) 4.4.3"
.section .note.GNU-stack,"",%progbits
0x03 处理器架构定义
.arch armv5te @处理器架构
.fpu softvfp @浮点协处理器类型
.eabi_attribute 20, 1 @接口属性
.eabi_attribute 21, 1
.eabi_attribute 23, 3
.eabi_attribute 24, 1
.eabi_attribute 25, 1
.eabi_attribute 26, 2
.eabi_attribute 30, 6
.eabi_attribute 18, 4
0x04 段定义
本例子中定义了三个段
如下:
.section .rodata @声明只读数据
.text @定义了代码段
..section .note.GNU-stack,"",%progbits @保护代码,禁止生成可执行堆栈。
0x05 注释与标号
- 单行注释用@表示,例如
@声明只读数据
- 多行注释用/* */
0x06 汇编器指令
程序中所有以点开头的都是汇编器指令,就是给汇编器读的指令,不属于ARM指令集
.flie:指定了源文件名。手写可忽略
.align:指定了代码对齐方式你后面跟的是2的次方
.ascii:声明字符串
.global:声明全局符号。全局符号是指在本程序外可访问的符号。
.type:指定符号的类型,“.type main,%function”表示main为函数
.word: 用来存放地址。
.size:设定指定符号的大小。“.size main,.-main”中的”.”表示当前地址,减去main符号的地址为整个main函数的大小。
.ident:编译器标识,无实际意义。
0x07 子程序与参数传递
- 函数声明方法
.global 函数名
.type 函数名,“%function”
函数名:
<函数体>
- 实例
.global MyAdd
.type MyAdd,%function
MyAdd:
ADD r0,r0,r1 @两个数相加
MOV pc,lr @ 函数返回
- ARM参数传递规定(重要)
R0-R3这4个寄存器用来传递函数调用的第1到4个参数,超出的通过堆栈来传递,R0同时用来存放函数调用的返回值。由函数调用方来平衡堆栈。