反汇编的目的
缺乏某些必要的说明资料的情况下, 想获得某些软件系统的源代码、设计思想及理念, 以便复制, 改造、移植和发展;
从源码上对软件的可靠性和安全性进行验证,对那些直接与CPU 相关的目标代码进行安全性分析;
涉及的主要内容
- 分析ARM处理器指令的特点,以及编译以后可执行的二进制文件代码的特征;
- 将二进制机器代码经过指令和数据分开模块的加工处理;
- 分解标识出指令代码和数据代码;
- 然后将指令代码反汇编并加工成易于阅读的汇编指令形式的文件;
下面给出个示例,汇编源代码,对应的二进制代码,以及对应的反汇编后的结果
源代码:
二进制代码:
反汇编后的结果:
反汇编软件要完成的工作就是在指令和数据混淆的二进制BIN文件中,分解并标识出指令和数据,然后反汇编指令部分,得到易于阅读的汇编文件,如下图:
ARM体系结构及指令编码规则分析
主要可参考下图,ARM指令集的编码:
ARM可执行二进制BIN文件分析
目前主要的ARM可执行文件种类:
ELF文件格式:Linux系统下的一种常用、可移植目标文件格式;
BIN文件:直接的二进制文件,内部没有地址标记,里面包括了纯粹的二进制数据;一般用编程器烧写时,从0开始,而如果下载运行,则下载到编译时的地址即可;
HEX格式:Intel HEX文件是记录文本行的ASCII文本文件;
本文主要研究BIN文件的反汇编;
BIN映像文件的结构
ARM程序运行时包含RO,RW,ZI三部分内容,RO(READONLY),是代码部分,即一条条指令,RW(READWRITE),是数据部分,ZI,是未初始化变量。其中RO和RW会包含在映像文件中,因为一个程序的运行是需要指令和数据的,而ZI是不会包含在映像文件的,因为其中数据都为零,程序运行前会将这部分数据初始化为零。
ARM映像文件是一个层次性结构的文件,包括了域(region),输出段(output section)和输入段(input section)。一个映像文件由一个或者多个域组成,每个域最多由三个输出段(RO,RW,IZ)组成,每个输出段又包含一个或者多个输入段,各个输入段包含了目标文件中的代码和数据。
- 域(region):一个映像文件由一个或多个域组成。是组成映象文件的最大结构。所谓域指的就是整个bin映像文件所在的区域,又分为加载域和运行域,一般简单的程序只有一个加载域。
- 输出段(output section):有两个输出段,RO和RW。
- 输入段(input section):两个输入段,CODE和DATA部分,CODE部分是代码部分,只读的属于RO输出段,DATA部分,可读可写,属于RW输出段。
ARM的BIN映像文件的结构图
举一个例子,ADS1.2自带的examples里的程序
AREA Word, CODE, READONLY ; name this block of code
num EQU 20 ; Set number of words to be copied
ENTRY ; mark the first instruction to call
start
LDR r0, =src ; r0 = pointer to source block
LDR r1, =dst ; r1 = pointer to destination block
MOV r2, #num ; r2 = number of words to copy
wordcopy
LDR r3, [r0], #4 ; a word from the source
STR r3, [r1], #4 ; store a word to the destination
SUBS r2, r2, #1 ; decrement the counter
BNE wordcopy ; ... copy more
stop
MOV r0, #0x18 ; angel_SWIreason_ReportException
LDR r1, =0x20026 ; ADP_Stopped_ApplicationExit
SWI 0x123456 ; ARM semihosting SWI
AREA BlockData, DATA, READWRITE
src DCD 1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8,1,2,3,4
dst DCD 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
END
可以看出,该程序由两部分组成,CODE和DATA,即代码部分和数据部分。其中代码部分,READONLY,属于RO输出段;数据部分,READWRITE,属于RO输出段。
接下来再看看上述代码经过编译生成的BIN映像文件的二进制形式,及该映像文件反汇编后的汇编文件,如下图:
从图中我们很容易发现,BIN文件分成了两部分,指令部分和数据部分。先看一下左图,从中我们发现,BIN文件的第一条指令编码是0xe59f0020,即右图中的00000000h到00000003h,由于存储方式的原因,小端模式,指令的低字节存放在低地址部分,不过这不影响我们的分析。在BIN文件中从00000000h开始一直到00000027h都是指令部分,即RO输出段,最后一条指令0xef123456存储在在BIN文件的00000024h到00000027h。剩下的为数据部分,即RW输出段,有兴趣的读者可以对照源代码一一查找之间的对应关系。
【文章福利】小编在群文件上传了一些个人觉得比较好得学习书籍、视频资料,有需要的可以进群【977878001】领取!!!额外赠送一份价值699的内核资料包(含视频教程、电子书、实战项目及代码)
内核资料直通车:Linux内核源码技术学习路线+视频教程代码资料
学习直通车:Linux内核源码/内存调优/文件系统/进程管理/设备驱动/网络协议栈
ARM反汇编软件设计要解决的主要问题
一、指令与数据的分离
冯·诺依曼机器中指令和数据是不加区别共同存储的,以 0、1 二进制编码形式存在的目标代码对于分析人员来说,很难读懂其含义。二进制程序中指令和数据混合存放,按地址寻址访问,反汇编如果采取线性扫描策略,将无法判断读取的二进制编码是指令还是数据,从而无法实现指令和数据的分离。
那么,怎样才能实现指令和数据的分离?
众所周知,凡是指令,控制流是必经之处,凡是数据,数据流是必到之处,存取指令一定会访问,对于一般指令,控制流是按地址顺序递增而走向的,只有在出现各种转移指令时,控制流才出现偏离。因此,抓住控制流这一线索,即跟踪程序的控制流[9]走向而遍历整个程序的每一条指令,从而达到指令与数据分开的目的。
怎样才能跟踪程序的控制流呢?
一般来说控制流与控制转移指令有关,控制转移指令一般可分为两大类:
- 单分支指令,即直接跳转,如B;BL;MOV PC&#