针对目前软件在计算机系统中面临的两大威胁和目前软件防护存在的问题,本文提出了一种采用代码加密术的软件防护方法。依靠密码学算法实现对代码本身的保护,依靠硬件密码锁实现对密钥的保护,防止攻击者破解密码算法。下面从以下几个方面对防护原理进行阐释。
本文采用分块加密 [10] 对代码进行保护,按照运行逻辑顺序的先后以基本块为单位进行划分,将划分后的程序代码进行加密处理,并在每一个基本块前后插入哨兵代码,程序中的每一个基本块在被执行之前,全部处于加密状态。基本块运行前首先由哨兵代码对其进行解密,当前一个基本块解密运行完毕后,由哨兵将其加密,并获取下一基本块代码的解密密钥,依次执行直至程序执行完毕。
所谓基本块,非形式地讲,就是只有一个入口(块的第一条指令)和一个出口(块的最后一条指令)的代码段,即进入基本块必须且只能通过入口指令,退出基本块必须且只能通过出口指令。选择基本块作为分块粒度有两个好处:
(1)基本块包含指令数目较少,可以平衡保护强度和开销之间的关系。采用加密手段进行保护,在加解密时存在较大运算开销,因而不适用于对大段的程序代码直接进行加解密操作。
(2)基本块只有单个入口和单个出口的特点可以用来精确检测程序控制流的轨迹。
由于加密后的代码在反汇编时以乱码的形式呈现,如果在选择加密代码时全部选择涉及程序核心算法或者核心功能的关键代码无疑会将重要代码暴露给攻击者。为避免这个问题,文章在选择加密代码时将整个软件代码分成两部分,一般代码和关键代码。对于关键代码的划分和定位,文献[11~13]进行了较为详细的介绍,在此不再赘述。一般代码就是指除去关键代码外的部分。在选择要进行加密的代码块时,选择全部的关键代码,并按照比例,随机选择部分一般代码进行加密处理,以混淆攻击者的视线,降低加密代码中关键代码的比例。
对程序进行分块加密有以下几个优点:
(1)避免了大段代码同时加密时解密开销较大,等待时间长,造成不良用户体验的缺点,将等待时间分散化,使得保护对用户透明。
(2)同一时刻只有部分代码被解密置于内存中运行,即使遭受内存dump攻击,也不会将全部代码暴露给攻击者。
(3)可以采用不同的密钥对基本块进行加密,增加攻击者破解的难度。
对于加密算法的选择,本文在综合考虑加密算法强度和保护开销的基础上,选择SM4算法,对软件代码进行加密。因为SM4算法是在统一密钥控制下的分组密码算法,实现起来相比较公钥密码(SM2)和摘要算法(SM3)来说较为简单,适合使用软件实现,而且脱密速度较快,占用资源较低,不会造成过大的开销。
哨兵是指程序中一段实现保护功能且不易影响应用程序运行的代码,其本质是若干指令或者是一个字节序列 [14] ,哨兵一般不单独使用,而是与其他哨兵一起组成哨兵网络插入到程序中,一方面对程序进行全面的保护,另一方面可以实现哨兵之间的相互验证。本文的哨兵代码由于需要对被保护代码进行解密和再加密,所以必须插入被保护代码的前后必经点 [15] 上,即在运行被保护代码之前,首先执行加密代码;在运行被保护代码之后,必须运行加密代码。通过这种方式,结合被保护代码块的划分,实现在程序运行时只有一小部分关键代码处于明文状态,尽可能地增强软件代码的安全性。
哨兵实现如下功能:
(1)查询加密锁是否存在,当加密锁存在时,与其进行通信,获取相应代码块的加解密密钥。当加密锁不存在时,对用户进行提示软件正常运行需要加密锁,然后退出程序。
(2)使用获取的加解密密钥对响应代码块进行解密和加密。
其功能实现的伪代码如下:
加密锁是一种与程序绑定的硬件设备,通过将程序校验的关键数据写入加密锁或者直接将部分重要的程序内容写入加密锁并在加密锁中运行再返回运算结果的方式,利用硬件复制成本高,破解难度大的特点保护软件不被攻击 [16] 。但是,以上两种加密锁保护思路都存在一些缺陷。利用加密锁保存关键校验信息的方式,由于程序的关键代码仍然存在于软件中,攻击者仍可以对关键代码进行逆向分析;而且校验信息时往往存在明显的判断语句,攻击者可以通过打补丁的方式跳过验证机制。将程序关键代码写入加密锁运行的方式,由于具体的运算需要在加密锁内部运行,对加密锁运算能力需求较高,某些程序需要多次交互传递参数,严重影响了软件运行的效率;而且由于加密锁空间的限制,无法存放过多的代码,这也对被保护代码的大小造成了一定的限制。
基于以上问题,本文提出将硬件加密锁同代码加密技术相结合,充分利用加密锁硬件安全性较高的特点,将代码加密中的关键数据——密钥,保存在加密锁中。程序运行时,通过哨兵访问加密锁,并验证加密锁同软件的对应关系是否合法。通过验证后获取相应加密代码块的加解密密钥,解密运行程序。整个程序运行过程活动图如图1所示,其中左边泳道表示软件,右边泳道表示加密锁。
由图1可知,整个软件在运行过程中,大部分执行过程都是在软件中执行,也就是在计算机中完成,加密锁只参与通信和密钥的传递部分,由于计算机处理性能远远大于加密锁,所以相对于在加密锁中运行程序,本文提出的方法对于整个过程的开销影响较小。但加密锁中内容对于软件运行却又不可缺少,通过这种方式实现了软件保护强度和运行开销的平衡。
图1基于加密锁保护设计软件运行活动图