博客导航戳这里
练习资源戳这里
IDA 是反汇编工具,Android Killer 是反编译工具
1.ARM基础知识
2.so文件基础知识
可以直接对ARM汇编进行直接修改
ARM是ARM公司的32位处理器。ARM汇编指令的机器码就是32位。
学会了ARM,就会了主流的嵌入式开发。
还可以进行硬件编程,可以从事机器人或机械制造。
Thumb 是16位的ARM汇编。
如同样的beq,bne这两个汇编指令,用ARM的4个HEX数表示时,
其HEX值为0A,1A,而当用2个HEX数表示时,其HEX值为D0,D1。
在动态调试的时候,IDA无法分辨ARM和Thumb指令。所以需要人工去进行纠正和调整。
ARM机器码的一般格式。
举一个实例:
movne r2,r1
0001 00 0 1101 0 0000 0010 000000000001
首先来说说 31-28字段,cond是条件码,就是表明这条语句里是否有大于、等于、非零等的条件判断。
再来一张图片
这张图片就能更好的说明了。
指令与条件码可以有多重组合,比如MOV指令可以有MOVEQ、MOBLT等多种形式。
27-26位为保留位,恒为00
25位,shifter_operand段存放的是立即数还是寄存器,若为寄存器则为0,如果是立即数则为1
24-21 位为opcode
20位:表明指令是否会影响程序状态寄存器,如果是就是1,否则为0。
19-16位,表示第一个源操作数寄存器。
11-0 目的寄存器
R0-R7: 通用寄存器
R8-R10:不常用的通用寄存器
R11:基质寄存器(FP)
R12:暂时寄存器(IP)
R13:堆栈制作(SP)
R14:链接寄存器(LR)
CPSR:状态寄存器
B 无条件跳转
BL 带链接的无条件跳转
BLX 带状态的无条件跳转
BNE 不相等跳转
BEQ 相等跳转
LDR 从存储器中加载数据到寄存器。
LDR R1,[R2],把R2指向的位置的数据给R1
STR:把寄存器的数据存储到存储器
STR R1,[R2],在R2指向的地址,存储R1
LDM :将存储器的数据加载到一个寄存器列表。
LDM R0,{R1,R2,R3},把R0中的数据一次加载到R1,R2,R3
SDM: 将一个寄存器列表的数据存储到指定的存储器
SDM R0,{R1,R2,R3},把R1,R2,R3加载到R0单元
PUSH:入栈
POP:出栈
MOV 将立即数或寄存器的数据传送到目标寄存器
ADD : 加法
(Addition)
ADD{条件}{S} , , dest = op_1 + op_2
ADD 将把两个操作数加起来,把结果放置到目的寄存器中。操作数 1 是一个寄存器,操作数 2 可以是一个寄存器,被移位的寄存器,或一个立即值:
ADD R0, R1, R2 ; R0 = R1 + R2 ADD R0, R1, #256 ; R0 = R1 + 256 ADD R0, R2, R3,LSL#1 ; R0 = R2 + (R3 << 1)
加法可以在有符号和无符号数上进行。
ps:带进位的加法ADC
SUB : 减法
(Subtraction)
SUB{条件}{S} , , dest = op_1 - op_2
SUB 用操作数 one 减去操作数 two,把结果放置到目的寄存器中。操作数 1 是一个寄存器,操作数 2 可以是一个寄存器,被移位的寄存器,或一个立即值:
SUB R0, R1, R2 ; R0 = R1 - R2 SUB R0, R1, #256 ; R0 = R1 - 256 SUB R0, R2, R3,LSL#1 ; R0 = R2 - (R3 << 1)
减法可以在有符号和无符号数上进行。
ps:带进位的减法SBC
MUL : 乘法
这两个指令与普通算术指令在对操作数的限制上有所不同:
给出的所有操作数、和目的寄存器必须为简单的寄存器。
你不能对操作数 2 使用立即值或被移位的寄存器。
目的寄存器和操作数 1 必须是不同的寄存器。
最后,你不能指定 R15 为目的寄存器
(Multiplication)
ps:带累加的乘法MLA
MUL{条件}{S} , , dest = op_1 * op_2
MUL 提供 32 位整数乘法。如果操作数是有符号的,可以假定结果也是有符号的。
DIV除法
SDIV 带符号除法
UDIV 不带符号位除法
与:AND
或:ORR
异或:EOR
LSL:逻辑左移
LSR:逻辑右移
CMP:比较指令
SWT:切换用户模式
伪指令:DCB
恩,其实和8086挺像的
7种,但是是分享常用的
立即寻址:MOV R0,#1234 R0=0X1234
寄存器寻址:MOV R0,R1 R0=R1
寄存器移位寻址:MOV R0,R1,LSL #2 R0=R1*4
寄存器间接寻址:LDR R0,[R1] 将R1寄存器中的值作为地址,取出地址中的值赋予R0
寄存器间接基址偏移寻址:LDR R0,[R1,#-4]将R1寄存器的值-0x4的值作为地址,取出地址中的值给R0
1.IDA自身的缺陷
2.函数库与类有时无法识别
3.自身对ARM汇编的熟练度
.so文件实际上是Linux文件里的动态链接库。
还有一些其他文件,比如说静态可执行文件,,没有后缀名。
如果在linux下编写用过gcc文件。那么就要生成可执行文件。
so文件主要是通过NDK编程来源。因为是程序猿,所有通过Android Studio就可以编译了。具体请看之前的文章。
so文件的文件格式是ELF文件。有自己的文件格式。一般的文件都分为静态下的状态和动态下的状态,当然之后要对ELF文件进行一个分析,之前姜大佬分析过了,不过这个是人家分析的,只有自己过一遍才能对ELF进行一个更深的了解。当然这个会在10中进行说明。
readelf命令用来显示一个或者多个elf格式的目标文件的信息,可以通过它的选项来控制显示哪些信息。这里的elf-file(s)就表示那些被检查的文件。可以支持32位,64位的elf格式文件,也支持包含elf文件的文档(这里一般指的是使用ar命令将一些elf文件打包之后生成的例如lib*.a之类的“静态库”文件)。
部分指令:
-a
--all 显示全部信息,等价于 -h -l -S -s -r -d -V -A -I.
-h
--file-header 显示elf文件开始的文件头信息.
-l
--program-headers
--segments 显示程序头(段头)信息(如果有的话)。
-S
--section-headers
--sections 显示节头信息(如果有的话)。
-s
--syms
--symbols 显示符号表段中的项(如果有的话)。
-d
--dynamic 显示动态段的信息。
-V
--version-info 显示版本段的信息。
-A
--arch-specific 显示CPU构架信息。
-I
--histogram 显示符号的时候,显示bucket list长度的柱状图。
objdump命令是用查看目标文件或者可执行的目标文件的构成的gcc工具。
一些常用命令
-a
显示档案库的成员信息,类似ls -l将lib*.a的信息列出。
-V
--version
版本信息
--debugging
-g
显示调试信息。企图解析保存在文件中的调试信息并以C语言的语法显示出来。仅仅支持某些类型的调试信息。有些其他的格式被readelf -w支持。
--disassemble
-d
从objfile中反汇编那些特定指令机器码的section。
-f
--file-headers
显示objfile中每个文件的整体头部摘要信息。
-h
--section-headers
--headers
显示目标文件各个section的头部摘要信息。
-H
--help
简短的帮助信息。
开虚拟是可以的,但是呢却非常占用内容,那么我们想在Windows下使用Linux的命令应该怎么办呢。
使用cygwin即可。安装或者其他,自行Google or 百度。
当然还有很多其他的方法。