由于固化在片外eprom里的单片机程序容易复制,所以,如不在技术上采取保护措施,则程序中所采用的处理方法易被他人分析仿制。对单片机程序进行加密是一种有效的保护措施,也是一项实用的技术。虽然本身带有eprom的单片机可做到程序保密,但由于价格和存储容量方面的原因,用户仍常常采用外接eprom的单片机来开发产品。
本文以mcs-51单片机为例介绍一种对片外e2prom里的程序进行软件加密和硬件解密的方法。这种方法不增加用户应用程序开销。
1 基本原理
我们知道,异或运算有这样的特点:aýbýb=a,亦即当用变量b对变量a作偶数次异或运算后,其结果恢复为变量a。例如a=32h,b=5eh,则aýb的结果为6ch,该结果再与变量b作异或运算,即6chý5eh就得到变量a的值32h。因此,我们可以利用这一特点给单片机程序加密和解密。
51系列单片机在对外部程序存储器rom和外部数据存储器ram操作时采用两套不同的指令,在对ram操作时用movx指令,并产生相应的读(rd)和写(wr)信号,而当对外部rom进行读操作时不用rd信号,而是有一条专给外部rom使用的“读”数控制信号(psen)线。亦即外部ram和rom的控制信号是严格分开的。这就为利用异或运算给外部rom里的程序进行加密后固化、解密后执行提供了条件。
这种方法的思路是:首先对欲固化到外部rom里的目的代码(原代码)进行第一次异或运算(加密),再把加密后的代码固化到rom里,程序运行时由硬件对从rom读出的加密代码进行第二次异或运算(解密)变为原代码后送到数据总线。这样,外部rom
里固化的是加密代码,即便该代码被复制也反汇编不出原程序。另外该程序的执行还需相应的解密电路支持。
图1是可以在实际中应用的单片机解密电路。当cpu对片外eprom(u04)进行“读”操作时,控制信号psen为低电平,这时u04送出八位加密代码(rd0~rd7)并和“密钥”经由u05、u06组成的异或运算电路作第二次异或运算(解密)得到原代码,该代码经三
态缓冲器(u07)由psen信号控制送入数据总线。由于电路中已将单片机的ea脚接地,故片外eprom的最低地址为0。另外,与rd0~rd7一起参与异或运算的另一个数据(“密钥”)取自当前待解密代码在外部eprom所在存储单元的低八位地址,并从高位到低位按a0a2a4a6a1a3a5a7的顺序组合成新的数据。例如,原地址分别为35h和36h,组合后的地址则分别为e2h和6ah。采用这样的方法确定“密钥”,一是可使一页中的代码中“密钥”不重复,二是由于同页中的代码字节的“密钥”都不同,故很难找到加密规律,可增加破译难度。
2 操作过程
现以sice通用单片机仿真器为例说明制作加密程序并固化到片外eprom里的操作过程。设程序一是一个待固化到片外eprom里执行的用户应用程序。为简便起见,它对外部ram的前256个单元赋于相应的低地址后转入死循环。因为仿真器的出借ram为从8000h开始的24k空间,故应根据程序大小用伪指令把最低地址定位在8000h~dfffh的24k空间里(如程序一中的org8000h),否则,无法直接对该程序的目的码进行第一次异或运算。
程序二是对程序一的目的代码(存放于仿真ram的8000h~804ah中共4bh个字节)进行第一次异或加密运算的。要加密的总代码字节数由程序一经汇编后得知。该程序中“密钥”的计算应与硬件电路中送到解密电路的低八位地址线的连接关系相一致。
程序一:main.asm
org8000h
sjmpmain
org8003h
reti
org800bh
reti
org8013h
reti
org801bh
reti
org8023h
reti
org8030h
main:clrea
clrrs0
clrrs1
mova,#0
movdptr,#0
movb,#0
acallsubr
loop:nop
sjmploop
subr:movx@dptr,a
inca
incdptr
djnzb,subr
nop
ret
end
程序二:xorm.asm
xorm:movr0,#4bh;置欲加密代码字节数
movdptr,#8000h;置程序一首地址
lop1:movxa,@dptr
pushacc
mova,dpl;取代码单元的低地址
movb,a
movc,b.0;组合新数据开始加密
movacc.7,c
movc,b.2
movacc.6,c
movc,b.4
movacc.5,c
movc,b.6
movacc.4,c
movc,b.1
movacc.3,c
movc,b.3
movacc.2,c
movc,b.5
movacc.1,c
movc,b.7
movacc.0,c
popb
xrla,b;“异或”产生加密代码
movx@dptr,a;加密代码存入原单元
incdptr
djnzr0,lop1
nop
stop:nop
首先把程序一调入仿真器汇编,目的是得到总的代码字节数。即键入如下内容(带下划线的为键入内容,否则为显示内容)。
>asm51|
fdasm251v3.0
copyright1989microcomputerlab.fudanuniversity
noerror
displaylist?(y/n)n|
nextadr:804b;记下程序一的末地址为804bh,由此可知总代码字节数为4bh。再把程序二添加到程序一的末尾(ret指令后,end伪指令前),调入仿真器后再汇编。即:
>asm51|
fdasm251v3.0
copyright1989microcomputerlab.fudanuniversity
noerror
displaylist?(y/n)n|
nextadr:8081
>exit|;退到监控状态
3map3|;仿真ram出借(8000h~dfffh)
3dx8000|;显示未加密代码(原代码)
8000:802e5b32cd900798a4c05c32c994039c
8010:80e47832edb027b884e56f32e9b729b8
8020:40224f32724f188f52cf83c31292f483
8030:c2afc2d3c2d4740090000075f0001143
8040:0080fdf004a3d5f0fa0022784b908000
8050:e0c0e0e582f5f0a2f092e7a2f292e6a2
8060:f492e5a2f692e4a2f192e3a2f392e2a2
8070:f592e1a2f792e0d0f065f0f0a3d8d100
8080:0000000000a041ac4450488d434a4e45
这里应该注意的是如果在程序一中使用了长转移(ljmp)或长调用(lcall)指令,就应列表显示或打印汇编结果,查找这些指令涉及的标号地址的高八位,并把高八位地址减去80h,使其与外部eprom的地址相符。
3goxorm,stop|;执行程序二,对程序一的目的码进行异或加密运算
3dx8000|;显示加密的代码,804bh以后的代码不变
8000:80ae53ba8d504f50a04450be8d504f50
8010:a044509a8d504f50a041439e8d534554
8020:42a045b830d8534554498d4d5454ba4d
8030:e00de879a0361eeab6a62edb96e67fad
8040:1010e56854738d28ee943e784b908000
8050:0ec0e0e582f5f0a2f092e7a2f292e6a2
8060:f492e5a2f692e4a2f192e3a2f392e2a2
8070:f592e1a2f792e0d0f065f0f0a3d8d100
8080:0000000000a041ac4450488d434a4e45
3meck0,3fff| ;检查待固化rom
ok
3mep8000,804b,0,5| ;将仿真ram中8000h~804bh的加密代码
ok固化到外部rom的0地址开始的单元里
3map0| ;使用片外rom,取消仿真ram出借
3ex0|;执行片外rom里的程序
3dx0|;显示外部ram从0地址开始的单元内容可见程序执行无误(显示略)对于大的用户应用程序,其操作过程仍如上述,但需改变程序二的加密字节数,并注意不要把程序二的代码固化到eprom里,否则,加密方法会暴露。
3 讨论
由于单片机程序是固化在eprom里的,所以不能象个人计算机那样利用类似磁盘防复制等这一类的方法对单片机程序防复制(带保密位的单片机除外),而只能在程序本身和相应的硬件上做文章。
本文虽然以mcs-51单片机为例介绍了一种用异或运算对片外eprom里的单片机程序进行软件加密和硬件解密的方法,但本方法也适用于其它外接e2prom的单片机,此法一直应用在笔者于1993年研制成功并生产了20余套的一种分布式数控测井系统中。
使用上面介绍的方法,如果解密电路做得隐蔽,使非设计者不知道加密方法,则要破译片外eprom里的程序具有一定的难度。实际使用中还可采用更为复杂的方法产生“密钥”,“密钥”周期还可进一步加长;在硬件上也应做得隐蔽,解密电路亦可用编程器件实现,以进一步增加破译难度。
screen.width-333)this.width=screen.width-333 dypop=按此在新窗口浏览图片>