基于ARM处理器的反汇编器软件简单设计及实现

分享到:

反汇编的目的:

缺乏某些必要的说明资料的情况下, 想获得某些软件系统的源代码、设计思想及理念, 以便复制, 改造、移植和发展;
从源码上对软件的可靠性和安全性进行验证,对那些直接与CPU 相关的目标代码进行安全性分析
流程分析

涉及的主要内容:

  • 分析ARM处理器指令的特点,以及编译以后可执行的二进制文件代码的特征;
  • 将二进制机器代码经过指令和数据分开模块的加工处理;
  • 分解标识出指令代码和数据代码;
  • 然后将指令代码反汇编并加工成易于阅读的汇编指令形式的文件


下面给出个示例,汇编源代码,对应的二进制代码,以及对应的反汇编后的结果
源代码:


二进制代码:


反汇编后的结果:


反汇编软件要完成的工作就是在指令和数据混淆的二进制BIN文件中,分解并标识出指令和数据,然后反汇编指令部分,得到易于阅读的汇编文件,如下图:


ARM体系结构及指令编码规则
分析略,请参考相关资料,如ARM Limited. ARM Architecture Reference Manual [EB/OL]. https://infocenter.arm.com/等;
主要可参考下图,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里的程序

 

 

  1. <font face="Helvetica" size="3">AREA Word, CODE, READONLY       ; name this block of code
  2. num     EQU     20                ; Set number of words to be copied
  3.         ENTRY                     ; mark the first instruction to call
  4. start
  5.         LDR     r0, =src            ; r0 = pointer to source block
  6.         LDR     r1, =dst            ; r1 = pointer to destination block
  7.         MOV     r2, #num            ; r2 = number of words to copy
  8. wordcopy
  9.         LDR     r3, [r0], #4            ; a word from the source
  10.         STR     r3, [r1], #4            ; store a word to the destination
  11.         SUBS    r2, r2, #1             ; decrement the counter
  12.         BNE     wordcopy             ; ... copy more
  13. stop
  14.         MOV     r0, #0x18           ; angel_SWIreason_ReportException
  15.         LDR     r1, =0x20026        ; ADP_Stopped_ApplicationExit
  16.         SWI     0x123456            ; ARM semihosting SWI
  17.         AREA BlockData, DATA, READWRITE
  18. src      DCD     1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8,1,2,3,4
  19. dst      DCD     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  20.         END</font>
复制代码


可以看出,该程序由两部分组成,CODE和DATA,即代码部分和数据部分。其中代码部分,READONLY,属于RO输出段;数据部分,READWRITE,属于RO输出段。

接下来再看看上述代码经过编译生成的BIN映像文件的二进制形式,及该映像文件反汇编后的汇编文件,如下图:


 从图中我们很容易发现,BIN文件分成了两部分,指令部分和数据部分。先看一下左图,从中我们发现,BIN文件的第一条指令编码是 0xe59f0020,即右图中的00000000h到00000003h,由于存储方式的原因,小端模式,指令的低字节存放在低地址部分,不过这不影响 我们的分析。在BIN文件中从00000000h开始一直到00000027h都是指令部分,即RO输出段,最后一条指令0xef123456存储在在 BIN文件的00000024h到00000027h。剩下的为数据部分,即RW输出段,有兴趣的读者可以对照源代码一一查找之间的对应关系。

ARM反汇编软件设计要解决的主要问题

一、指令与数据的分离
  冯·诺依曼机器中指令和数据是不加区别共同存储的,以 0、1 二进制编码形式存在的目标代码对于分析人员来说,很难读懂其含义。二进制程序中指令和数据混合存放,按地址寻址访问,反汇编如果采取线性扫描策略,将无法 判断读取的二进制编码是指令还是数据,从而无法实现指令和数据的分离。

  那么,怎样才能实现指令和数据的分离?
  众所周知,凡是指令,控制流是必经之处,凡是数据,数据流是必到之处,存取指令一定会访问,对于一般指令,控制流是按地址顺序递增而走向的,只有在出 现各种转移指令时,控制流才出现偏离。因此,抓住控制流这一线索,即跟踪程序的控制流[9]走向而遍历整个程序的每一条指令,从而达到指令与数据分开的目 的。

    怎样才能跟踪程序的控制流呢?
  一般来说控制流与控制转移指令有关,控制转移指令一般可分为两大类:

 

 

  • 单分支指令,即直接跳转,如B;BL;MOV PC,**;LDR PC,**等等;
  • 双分支指令,有条件的跳转,如BNE;MOVNE  PC,**等

 






 当该指令为双分支指令时,会有两个转向地址,我们把条件满足时的转向地址称为显示地址,条件不满足时的地址称为隐式地址。
     在跟踪控制流的过程中,还要设置三个表:
  (1)段表,将所有转移指令除条件转移的转移地址填入此表包括本指令地址和转向地址。其实可以不要这个表,但是加进去,会得到若干段的代码段,比较清晰明了。
  (2)返回表,用于记录程序调用时的返回地址。
  (3)显示表,碰到双分支指令时,将其显示地址和现场(程序各寄存器的值)填入该表中。
  以上都准备好之后,就可以开始跟踪程序控制流了具体步骤如下:
    (1)将程序的起始地址填入段表,且作为当前地址。
    (2)按当前地址逐条分析指令类型,若非无条件转移指令及二分支指令,则直至终结语句并转(7), 否则转(3)。
    (3)若为无条件转移指令(B指令,MOV PC,0x16等),则将此指令所在地址填段表,其显式地址填段表,且将显式地址作为当前地址,然后转(2),否则转(4)。
    (4)若为无条件转移指令子程序调用指令(BL指令),则将此指令所在地址填段表,返回地址和现场信息填入返回表,显式地址填段表,且将显式地址作为当前地址,然后转 (2), 否则转(5)。
    (5)若为无条件转移指令中的返回指令(MOV PC,LR),则在返回地址表中按“后进先出”原则找到返回地址,将此指令所在地址填段表,其返回地址填段表,且将返回地址作为当前地址,然后转(2),否则转(6)。
    (6)若为二叉点指令(BEQ,MOVEQ PC,0x16等等), 则将显式地址和现场信息填入显式表,然后将隐式地址作为当前地址转(2)。
    (7)判显式表空否,若空则算法终止,否则从显式表中按“先进先出”顺序取出一个显式地址作为当前地址,且恢复当时的现场信息转(2)。

  经过以上处理,可以遍历到所有的指令,且当访问到该条指令后,要把改地址处的指令标记为指令。接下来可以采用线性扫描策略,当遇到标记为指令的二进制代码时,把它反汇编成汇编指令即可。
  不过,在实现跟踪程序控制流过程中还有一个比较难处理的问题,就是间 接转移类指令的处理,因为这类指令的转移地址隐含在寄存器或内存单元中,无法由指令码本身判断其值,而且这些隐含在寄存器内或内存单元中的值往往在程序执 行时,被动态地进行设置或修改,因此很难判断这类指令的转移地址,从而难以完整的确定程序的指令区。
    本软件处理这个问题的方法是设置多个寄存器全局变量,在紧跟程序控制流的过程中,实时更新各寄存器的值,因此可以确定这类指令的转移地址。

二、代码部分的反汇编
  ARM指令集中的每天指令都有一个对应的二进制代码,如何从二进制代码中翻译出对应的指令,即代码部分反汇编所要完成的工作。
  ARM 指令的一般格式可以表示为如下形式:
  <opcode>{condition}{S}<operand0>{!},<operand1>{, <operand2>}
  指令格式中<·>符号内的项是必须的,{·}符号内的项 是可选的,/ 符号表示选其中之一,其中opcode 表示指令操作符部分,后缀 conditon、S 及!构成了指令的条件词,operand0、operand1、operand2 为操作数部分。指令反汇编就是将指令的各组成部分解析出来。
  为了使指令反汇编更加清晰、高效,可以采用分类的思想方法来解决该问题,把那些具有相同编码特征的指令分成同一种类型的指令,然后为每一类指令设计一个与之对应的处理函数。
  指令的反汇编的步骤,首先是判断哪条指令,可以由操作符及那些固定位来确定,然后是指令条件域的翻译,这个与二进制编码也有唯一的对应关系,然后操作数的翻译,在操作数的翻译过程中,可能涉及到各种操作数的计算方法,移位操作等情况。

 

更多Atmel及科技资讯请关注:  
Atmel中文官网:https://www.atmel.com/zh/cn/
Atmel技术论坛:https://atmel.eefocus.com/
Atmel中文博客:https://blog.sina.com.cn/u/2253031744
Atmel新浪微博:https://www.weibo.com/atmelcn

继续阅读
英特尔的芯片问题还没完,ARM又出安全漏洞了!

据VentureBeat报道,继承认不安全的内存漏洞会影响数以百万计的英特尔处理器后,ARM今天证实,许多Cortex系列处理器也存在漏洞。ARM的Cortex技术被用于各种各样的Android和iOS设备,以及部分Nvidia Tegra产品、高通骁龙芯片以及索尼的PlayStation Vita上。

ARM:人工智能学习的未来是分散式AI

人工智能(AI)现在以机器学习与深度学习技术,让性能提升到更高端段,但英国半导体设计大厂安谋(ARM)指出,由于人工智能的学习仍面临网路频宽、耗电、隐私、资安等种种课题待克服,解决这些课题的方式,就是分散式人工智能(Distributed Intelligance)。

中国首个商用量子通信专网投入使用,安全性已达设计目标

  国内首个商用量子保密通信专网——济南党政机关量子通信专网,昨天(12日)在济南通过专家评审,保密性、安全性、成码率的测试均达到设计目标,完成全网验收并正式投入使用。

ARM Cortex-A55,Cortex-A57, 从端到云实现高效能

ARM Cortex-A75 和Cortex-A55,即首批基于新近发布的DynamIQ 技术的Cortex-A系列处理器。本文我们讨论的就是 Cortex-A55:一款对为未来数字世界举足轻重的处理器。

ARM并入豪门软银之后,从幕后走到前台,积极开拓物联网市场

2016 年 7 月,日本软银集团以 243 亿英镑天价收购英国 IP 矽智财大厂 ARM,带给行业巨大的震惊。9个月之后,ARM都发生了哪些改变呢?其一,ARM 为了扩大生态圈,更积极从幕后走到台前和市场沟通。其二,内部不间断地组织改造,新建物联网事业群,将来ARM 要做的是提供一个快速进入物联网的管道,降低大家的门槛。

©2019 Microchip Corporation
facebook google plus twitter linkedin youku weibo rss