基于AVR单片机的反汇编及仿真设计与实现

分享到:

1 引 言


计算机软件仿真技术凭其有效性、可重复性、经济性受到各行各业的青睐。大到航空航
天系统,小到单片机程序的开发,仿真技术都成为不可或缺的研究手段。在单片机应用开发
过程中,一般是由源文件(*.inc、*.asm、*.tab等)经编译生成目标单片机的特殊代码,
也就是所谓的目标码,然后就再进行相关的仿真调试工作。仿真调试可分为两大类--芯片级
仿真和代码级仿真。芯片级仿真是指使用仿真软件和ICE硬件工具相配合,在实际硬件上进
[1]

汇编及仿真,则是在知道编译后的目标代码而不知道其程序源代码时较为适用的研究手段。
在这里,反汇编是指由目标代码生成源代码的过程;仿真则是用生成的源代码在PC机上进行
代码级仿真;整个过程与开发单片机程序的过程是互逆的。在单片机的开发应用中我们会经
常碰到这种问题:将功能代码写好并通过仿真器写入单片机的程序区后,在无法获得源代码
的情况下,这将会对单片机功能改进和研发造成不便,这就需要一种工具能将编译后的目标
文件反汇编成源文件,并希望能看到这个源文件在单片机正常工作时是怎样发挥其功能的,
即将反汇编出的程序用软件仿真执行,这就用到上述所说的反汇编及仿真。这种反汇编及仿
真也可以应用在对单片机的破解和攻击上,该技术通常使用处理器通信接口并利用协议、加
密算法或这些算法中的安全漏洞来进行攻击。但作为一种开发手段,我们可以通过这种方法
来寻回丢失的源文件、检测单片机程序的可执行性、单片机的安全性,并可以快速通过软件
环境在PC机上进行仿真,达到缩短研发周期,降低研究经费等比较不错的效果。
综上所述,本文设计了一种简易算法来实现AVR系列单片机的反汇编及仿真,而且针对
 

AVR系列单片机支持C语言编译这一功能,将该算法用标准C语言实现,这样一来,即可载入
AVR硬件仿真器中应用,也可在PC机中单独执行。最后,我们分析了算法的复杂度,并通过
与其它反汇编系统的比较证明了本算法的实用性和价值。

 

2.2 实现从机器码到 AVR 指令系统的反汇编


精简指令集RISC是为了提高CPU运行的速度而设计的指令体系,它的关键技术在于流水
线操作和采用等长指令体系结构,使一条指令可以在一个单独操作中完成。这使得对AVR的
反汇编工程及仿真,变得简洁明了。以ATmega128 为例,设计算法实现从机器码到AVR指令
[3]

中,共有 133 条指令,其中只有 4 条是 32 位,其余均为 16 位。因此,我们的基本思想是:
1. 从程序区一次读入一个字(16 位);
2. 从中取出操作码并判断该字是哪条指令,如果是 16 位的指令,转 3;如果是 32 位的指
令则转 4;否则将该字节当作数据或伪指令处理;
3. 将此字转换成相应的汇编指令,再从程序区中取下一个字,直到结束。
4. 将此字以及下一个字一并转换成相应的汇编指令,再从程序区中取下一个字,直到结束
关键技术:
思想虽简洁明了,对单片机指令系统较熟悉的人可能在实现上也并不困难,但本文提供
的算法可使复杂度达到最低。对于步骤 2,我们首先定义一个名词 mask。对于一条 16 比特
的指令机器码,即 16 比特全部由 0 或 1 组成,其操作码就包含在这 16 比特之中;而对于一
条 32 比特的指令字,其操作码包含在其前 16 比特中。 AVR 单片机指令系统的每条指令都
有其固定的比特组成该指令的操作码,因此无法统一取出。mask 的作用就是取出每条指令
的操作码,因此每条指令都配有自己的 mask。因此,mask 也是一串 16 比特的 0、1 码,在
这 16 比特中,如果某比特被置 1,说明该比特在指令中为操作码;如果某比特被清 0,说明
该比特在指令中为操作数。例如:对于指令 BREQ k (指令功能:如果状态寄存器的零标志

2 算法设计与实现


2.1 AVR 系列单片机
AVR单片机属于精简指令集(RISC)单片机。这种结构使得AVR单片机具有接近
1MIPS/MHz的高速处理能力。快速存取RISC寄存器文件由 32 个通用工作寄存器组成。传统的
基于累加器的结构需要大量的程序代码,以实现累计器和存储器之间的数据传输,而 32 个
通用工作寄存器代替累加器,可以避免传统累加器和存储器之间的数据传输造成的瓶颈现
象。而且,由于快速访问寄存器文件包含 32 个 8 位可单周期访问的通用寄存器,所以在一
个时钟周期内,AVR内核应完成如下操作:读取寄存器文件中的 2 个操作数,执行操作,将
结果存回到寄存器文件。此外,AVR采用了Harvard结构,具有独立的数据和程序总线。程序
[2]

指令的单时钟周期运行。在对AVR系列单片机进行反汇编及仿真时除了要熟知单片机的指令
系统,还要对其结构有足够的认识,这样才能了解反汇编出的源程序是如何在单片机内部协
调工作的并将其用软件方法展示出来。要做到这一点,我们必须将单片机的硬件构成全部用
软件方法来重新定义。因此,为了更好的理解这篇文章中的算法及程序,以下给出了,AVR
的内存映像、通用器存器的图示(以ATmage128 Normal Mode为例)。
 

 

位被置位,则相对 PC 值转移 k 个字),机器码为:1111 00kk kkkk k001,由此我们可以定
义该指令的 mask 为:0xFC07。
有了 mask 之后,我们首先做一张指令列表,指令系统中每一条指令对应列表中的一项,
该项包括指令名称,为指令取出操作码的 mask,以及为指令取出操作数的 mask。这样我们
就可以根据列表方便的判断从程序区读出的机器码属于哪条指令。具体方法:从程序区读出
两字节,跟列表第一项的 Mask 进行按位与操作,若结果恰好与该列表相的操作码相同,那
么,这两个字节就属于该列表项的指令。例如:读入的两字节为 0xF0A1,当从列表中查询到
BREQ 时,由于 0xF0A1 跟 0xFC07(BREQ 的 Mask)按位与的结果是 0xF001,即 BREQ 的操作
码,所以 0xF0A1 应反汇编为指令 BREQ。同理,我们类似的取出指令的源操作数和目的操作
数。最终的列表形式如下:
 

其中,“mask”,“op[0]”,“op[1]”分别为该条指令的操作码掩码、源操作数掩码和
目的操作数掩码。
因此,设计算法一如下:
1. 从程序区一次读入一个字(16 位);
2. 将取出的字跟 Mask 做按位与操作以取出操作码;
3. 根据操作码判断该字是哪条指令,如果是 16 位的指令,转 3;如果是 32 位的指令则转
4;否则将该字节当作数据或伪指令处理;
4. 将此字跟 op[0]做按位与操作以取出源操作数(假设指令存在源操作数),跟 op[1]做按
位与操作以取出目的操作数(假设指令存在目的操作数),从而转换成相应的汇编指令,
再从程序区中取下一个字,直到结束。
5. 将此字以及下一个字一并跟 op[0]做按位与操作以取出源操作数(假设指令存在源操作
数),跟 op[1]做按位与操作以取出目的操作数(假设指令存在目的操作数),从而转换
成相应的汇编指令,再从程序区中取下一个字,直到结束

 


2.3 各指令功能的实现


在完成了机器码到汇编指令的反汇编之后,我们还要将每条指令的功能进行仿真。AVR
系列单片机的指令系统主要功能有数值运算、比较和调转、数据传送、位操作和位测试、MCU程序控制器等各部件以配合完成上述功能。为了提高程序的效率和可读性,我们将Flash、成了单片机构件之间的数据交换。
之后,我们对每一条反汇编出来的指令都作以下判断(假定单片机程序处在正常运行状
态并开始运行):
数值操作的结果是否保留
操作结果是否会影响状态寄存器
该指令是否与外部设备之间进行数值交换
是否根据条件进行跳转
MCU 如何控制指令的执行顺序
然后,我再根据以上的判断结果来完善每条指令的具体操作和功能,进而从程序入口开
始整体上把握指令的执行顺序。例如:对于指令 IN 指令,其功能是从 I/O 口读数,可用 C
语言实现如下:
 

 

2.4 仿真过程中应注意的问题及交互技术


按前述步骤只要将各指令功能分别以小函数形式实现,再用主程序对整体程序指针 PC
进行控制,依程序的执行过程分别调用各指令小函数,便可将整个程序在单片机种的执行过
程再现。我们采用算法如下(以 ATmage128 为例):
1) 设整体程序计数指针 PC-mage128,其初始值赋为程序入口地址并为每个指令函数
定义一个函数指针;
2) 以字为单位取机器码,调用算法一;
3) 链接函数指针,实现该指令功能;
4) 判断该指令是否为双字指令、跳转指令、自程序调用指令、或返回指令。若属于上
述情况指令,在该指令函数中将 PC-mage128 作适当修改,否则不进行任何修改;
5) PC-mage128++,转步骤 2);
6) 执行到程序出口时,结束。
这样我们就可以将单片机 Flash 中的机器码读出,并在 PC 机上反汇编及仿真该 Flash
中的程序。但在整个反汇编及仿真过程中需注意以下几个问题:
程序控制指针一定要正确无误;
在小函数中要先将反汇编出的指令代码打印出来,再完成指令功能,否则在功能执
行完后可能会影响打印结果;
 

 

对 I/O 寄存器的操作中,需对原来的目标码中取出的地址加上$20,以便与通用寄存
器分开;
地址跳转出现负值或者大于 Flash 地址时,应对 Flash 地址进行取模操作;
堆栈大小要适当,避免指令执行过程中误改了堆栈中的内容;
LPM 指令对程序存储器进行取数操作,利用 Z 寄存器的高 15 为做地址进行寻址,
末尾一位用来决定取高为字节(为 1)还是地位字节(为 0)。
此外,还有一些细节问题,我们可以在每个指令小函数中加以注意,就不再一一列举了。
为了使用方便我们在程序中可加入一些交互技术,交互菜单如图所示:

 

2.5 算法复杂度分析及改进


由于该算法采用了函数指针,所以从取机器码完成反汇编后到调用相应指令子函数的复
杂度为 O(1),所以该算法的复杂度关键在于算法一的复杂度,即将机器码查表转换为相应
指令码的复杂度。
我们知道折半查找的复杂度是目前各查找算法中最好的一个,对于n个数进行查找的复
n

首先我们将二进制的操作码转换为大家熟悉的十进制数,以ATmega128 为例,共有 133 个不
同的数值,再对这 133 个数值进行排序,并将每一数值对应到一条指令,加入查找表;然后,
再利用此查找表用折半查找对每条机器码进行反汇编。可问题是,各条指令的Mask不尽相同,
无法统一取出操作码,在ATmega128 指令系统中,共有 16 种Mask,因此对每一个待反汇编
的机器字,我们要做:
1) 用任意一个 Mask 取出该机器码的操作数,并转换为十进制数值;
2) 用折半查找查看该数值是否在表中,若在,转 4),否则转 3);
3) 另选一个 Mask,转 2);
 

4) 找到该数对应的指令,结束;
假设需要反仿真的程序包含h条指令,单片机指令系统的指令条数为n,Mask的种类数为
在这用折半查找并不是一个好方法。实际上,在相同假设下,我们可以采用顺序查找,复杂明了,预处理少,我们就采用了这用方法用标准C语言进行了实现。


当然,针对某一个或某一类程序,我们可以提出一些改进方法。例如方法一:在每个指
令函数中加入计数器来记录该指令在整个程序中的执行次数,然后根据每条指令出现的频率
高低对指令表进行排序以缩短顺序查找的查询时间;方法二:程序执行过程中一般会有好多
代码段重复率很高,比如从内存中读数、被调用的子程序段等,我们可将这类代码直接用高
级语言编写相应的子函数以提高仿真效率。


3 结论与应用


从研究单片机的角度看,我们的算法及实现不但可以通过目标文件寻回丢失的源文件、
检测单片机的安全性,还可以快速通过软件环境在 PC 机上进行仿真,达到缩短研发周期,
降低研究经费的目的。例如:在研究机顶盒加密电视节目时,对媒体流解密程序相当复杂,
用硬件仿真一次程序执行过程需要大量时间,而且如须改动程序,就得对原芯片的 Flash
进行重写。所以,我们可以先实时抓取媒体流信号,再利用这个简单的反编译器在 PC 机上
进行仿真调试,结果较为满意时,再写进芯片。并且,由于 AVR 系列单片机支持标准 C 语言
编译功能,我们可以直接将修改后较为满意的程序直接载入 Flash 中,进而大大提高了开发
效率。并且,我们若想此基础上增加新的功能,只需修改一下算法及程序即可,而不必拘泥
于目前一些仿真软件的功能。
目前,IDA,AVRstudio 等仿真软件也可以完成这种反汇编或仿真,但都有一些不便的
地方,并且只能应用,无法在细节上对其改进。例如,IDA 反汇编功能比较强,而且反汇编
的程序代码清晰,框架层次明了,但无法模拟运行;而 AVRstudio 能够模拟运行,但运行后
的程序不连贯,无法看到前边已经运行过的程序代码。因此,我们在实现上兼顾了这两个方
面,即能很好的完成反汇编,又可使运行后的程序连贯起来,使得阅读,修改都比较方便。
以下是,本文的实现与 AVRstudio 的对比。反汇编结果和模拟运行结果对比如图 3.1、3.2、
3.3 所示。图 3.1 是 AVRstudio 的反汇编结果,各指令按照在程序区中的地址顺序排列,黄
色箭头表示程序当前执行此指令,当继续用 AVRstudio 模拟程序运行时,黄色箭头会指示到
 

下一条指令。这样,如果碰到跳转或子程序调用、返回等指令时,就无法再与前边的篇幅连
贯起来,降低了可读性;图中第一条指令就要跳转到地址 0x00AB 处,但在 AVRstudio 界面
上却无法一下看到 0x00AB 处究竟是何指令。图 3.2 是我们的反汇编结果,可见,我们的简
单仿真模型与 AVRstudio 在反汇编结果上是一致的。图 3.3,是我们的仿真结果,可以看出
我们解决了 AVRstudio 在这方面的不足。我们可以很连贯地看到由地址 0x0000 跳转到
0x00AB 后的执行顺序。
 

 

 

随着单片机应用广度的提高,单片机的反汇编及仿真的应用也会逐渐变得广泛。本文
提供的方法只是一个简单模型,读者也可根据自己的具体需要做出相应改动以完善其功能。
 

继续阅读
基于AVR单片机的可充电电池的放电监测

本文介绍AVR单片机ATtiny12的主要性能特点,并利用它实现了可充电电池放电的自动监测。单片机;可充电电池;自动监测AVR是增强型RISC、内置Flash的高性能8位单片机。

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

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

AVR单片机及其特点

AVR单片机是1997年由ATMEL公司研发出的增强型内置Flash的RISC(Reduced Instruction Set CPU) 精简指令集高速8位单片机。AVR的单片机可以广泛应用于计算机外部设备、工业实时控制、仪器仪表、通讯设备、家用电器等各个领域。

基于AVR单片机的嵌入式“瘦服务器”

本文的主要内容为:以AVR单片机为主控CPU芯片,提供“瘦服务器”的软件、硬件的组成框图。该“瘦服务器”的应用前途广泛,可以应用于各行各业的Internet远端监控系统中。主要应用于:(1)网络家电产品,通过该系统把数字化家电直接接入Internet网络,组成intelligentizedhome;(2)城市网络自动售货机;(3)城市交通Internet监控;(4)楼宇防火防盗Internet监控;(5)工厂生产设备Internet监控。

基于AVR单片机的电冰箱控制系统的设计

随着电冰箱在日常生活中的普及,人们对电冰葙的性能和控制功能的要求越来越高,为了满足人们实际生活中电冰箱的需要,以AVR单片机为核心,通过硬件和软件设计了电冰箱的控制系统,试验结果表明,该系统性能指标和功能达到了预期目的,具有功能齐全、操作简单、使用方便等优点。该系统在同类产品中处于较高水平,具有较高的实用价值。

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