糜娴雅 张怡 王宝生 国防科学技术大学
二进制软件防篡改技术研究
糜娴雅 张怡 王宝生 国防科学技术大学
随着软件安全性问题日益严重,软件防篡改技术作为软件保护的重要手段之一,越来越得到国内外研究者的重视。本文首先介绍软件破解与保护的基本概念,针对软件防篡改的主要目标,即能够准确地检测到正常功能之外的对程序进行的异常修改行为;对这种修改行为进行恰当的、有效的反应,重点介绍了几种基于“检测-响应”的二进制软件防篡改技术,对其具体实现方法进行分类和总结,详细分析和讨论各类方法的优劣和局限性,提出了一套评价体系,并展望了软件防篡改技术的发展前景,提出了自己的见解。
软件保护;防篡改;检测-响应
随着软件破解技术的发展,软件安全性问题日益突出,保护软件知识产权成为一个越来越艰巨的任务。攻击者获取软件副本后,借助一些工具,通过技术手段可以轻易地理解和修改二进制代码,从而达到破解软件、非法使用的目的。二进制软件防篡改技术作为软件保护的重要方法之一,越来越得到国内外研究者的重视。本文研究了防篡改技术的基本原理和实现方法,对当前主流的防篡改技术进行分析和评价,并就该技术的应用和发展前景提出见解。
1.1 软件篡改的实现方法
软件篡改通常发生在攻击者对代码进行有效分析之后,具体说来有三种实现方法:(1)在可执行文件运行之前,删掉其中的一些代码,同时/或者往其中加一些代码;(2)从正在运行的程序中,删掉一些代码,同时/或者往其中加入一些代码;(3)借助模拟器、调试器或修改过的操作系统等工具,影响程序运行时的行为。其中(1)属于静态篡改,即直接修改二进制代码,原代码不会进入内存。(2)、(3)属于动态篡改,即边运行边篡改,原代码要进入内存,与调试的原理比较相似。
1.2 防篡改技术的主要目标
图1 一个完整的防篡改系统示意图
防篡改技术的主要目标在于检测对程序的修改行为并做出相应的反应,因此其重要的技术原则有两条:(1)能够准确地检测到正常功能之外的对程序进行的异常修改行为;(2)对这种修改行为进行恰当的、有效的反应。目前常见的软件防篡改实现方法基本上都是基于这两条原则实现的,即“检测-响应”机制。从概念上来说,一个完整的防篡改系统应该是由CHECK和RESPOND两个函数组成,如图1所示,CHECK函数用来测试异常修改行为是否发生并返回结果,而RESPOND函数则根据CHECK函数的返回结果来判断是否触发对篡改行为的响应。
防篡改的具体实现方法有基于源代码和基于二进制代码两种,由于源代码方法有一定的局限性,本文主要研究基于二进制代码的软件防篡改技术。
根据CHECK和RESPOND函数的实现思想不同,当前主流的软件防篡改实现方法可以分为4种,分别是:(1)基于保护网络的防篡改方法,(2)基于Oblivious Hashing的防篡改方法,(3)远程防篡改方法,以及(4)基于监测运行环境的防篡改方法。
2.1 保护网络
Hoi Chang建立了一种由称之为guards的代码片段组成的保护网络[1],guards分为两类,一类是校验和代码,用来计算一段程序的校验和并验证完整性,即检查是否被篡改。一旦发现被篡改,校验和代码会做出反应,触发一定的行为,比如使软件无法继续使用、中断程序等等,即检查完整性功能。另一类是修复代码,用来将被破坏的代码和数据恢复到原来的样子,具体方法是在别处存放该段代码的原始备份,一旦被篡改则原样复制过来,即自治愈功能。
2.2 Oblivious Hashing
实际上Hoi Chang的保护网络所运用的是防篡改技术中非常普遍的一种方法:自监测原理,基本的思想就是计算某一代码区域的hash值,并根据这个值做出反应。可以把hash值作为程序中将要进行的算数运算中的一部分数据,或者把hash值用在其他变量地址的计算上。然而,上述自监测算法有两个根本性缺陷:(1)读取自己代码段的操作很容易被检测出来,即算法隐蔽性不高;(2)只检查代码正确性,攻击者可以修改运行时的数据来影响程序行为,比如使用调试器,在某个关键函数返回之前修改其返回值,即不能抗动态篡改。
由此产生了另一种防篡改思想:oblivious hashing[2],即“易遭忽视的hashing”,因为此方法中hash是作为软件的一部分在正常的计算过程中被计算出来的,攻击者很容易忽视它。图2显示了这种方法的基本原理,即通过结合源代码中的指令和内存中的指令来计算hash值。
Y.Chen提出了一种巧妙的方法[3],直接在源码中插入了hash计算代码,根据变量的值和控制流控制语句输出结果计算hash。它不记录程序trace,而是往程序中插入相关代码,计算trace的hash,来监测变量的改变和控制流执行情况。可以通过调整所插入的,用以计算hash的代码数量来调和性能开销和保护级别之间的矛盾。
图2 通过内存中的指令和源代码指令结合计算hash值
Mattias Jacob和Mariusz H.Jakubowski提出了另一种算法[3]。x86体系结构使用变长指令编码方式且指令无需对齐,可以利用这两个特性,把指令相互重叠,相互重叠的指令甚至可以属于两个不同的基本块。这个算法就是通过重叠基本块中的x86指令进行防篡改,当一个基本块执行的时候,另一个基本块的hash就被它“顺便”算了出来。这一技术的优点在于,计算hash不需要显式地读取代码,所以内存复制的攻击方法对这个是无效的。这个算法的缺点是,无法预计监测代码的及时性。
本节所阐述的方法的根本原理在于,运行时检查程序中使用的数据值是否在正常的取值范围之内,程序的控制流是否沿着一个合理的路径流动。
2.3 远程防篡改
远程防篡改的思想是,将想要保护的程序C运行在攻击者控制下的不可信主机(客户端)上,客户端必须和开发者的主机(服务器)上一个可信的程序S保持通信。除了向客户端提供服务,服务器还必须对C可能遭到的篡改进行监测和响应。
Xiangyu Zhang把程序拆成两个部分[4],一个是可以放在客户端中运行的公开部分,另一个是放在服务器里运行的隐藏部分。此算法通过只考虑标量数据(处理数组和链式结构数据的函数全部放在客户端中)和确保客户端和服务器处于同一个局域网中这两个方法来解决网络延迟和带宽这两个问题。
Christian Collberg将反分析和防篡改的方法相结合,具体说来是将反静态分析的自修改代码的思想运用在了这种远程防篡改的机制上。图3显示了这种远程防篡改方法的运行原理。通过经常变化客户端程序中的代码,使它难以分析。理想情况下,攻击者将会发现客户端程序中的代码变化太快,以至于在他完成分析并对当前的客户端程序进行修改之前,服务器又发了一个新的程序过来。然而,这个思路虽然很好,却还仅仅停留在理论上,目前还没有已知系统实现了这个通过不断改变代码进行防篡改的想法。
图3 Christian Collberg的远程防篡改方法示意图
2.4. 监测运行环境
对于使用了自监测原理的防篡改方法,攻击者早已形成了与之对应的攻击方法。攻击有两种方法:(1)想办法找到程序中的监测代码或相应代码,然后删掉;(2)从外部进行攻击,即修改程序执行的环境。
Glen Wurster提出了一种攻击自hash算法,该算法的关键点在于,基于hash的防篡改算法中,代码会被以两种形式访问:①当被执行时作为代码,②当计算hash时作为数据。当把代码当作数据读取的时候,应该获得未经修改的代码,这可以保证代码hash值不变;当执行代码时,应执行修改后的代码。此方法将同一个虚拟内存地址分别映射到两个不同的物理内存地址上:如果被访问的是代码,则映射其中一个地址;如果被访问的是数据,则映射到另一个地址上。对防篡改的攻击有以下三个步骤:i.把程序P复制一份,复制品称为;ii.对P进行修改,将其制成破解版;iii.修改操作系统的内核K,使计算机在读取数据时从中读取,而读取代码时则从中读取。这一攻击的具体实现方式有赖于具体的处理器型号和操作系统中内存管理模块的设计方式。
为了应对这种攻击,Jonathon Giffin提出了一种思路:向程序中加入新的代码,监测程序是否运行在一个可信的环境中。他使用自修改代码实现这种对抗攻击的保护方法,如果程序监测到自己运行在一个修改只会作用于数据而不会影响代码的系统中,它就会调用正常的篡改响应代码。
3.1 小结
综上所述,可以总结出5种能使程序变得难以修改的基本方法:
(1)向程序中加入新的代码,监测程序中的代码是否遭到了修改。Hoi Chang的保护网络算法使用了这种方法。
(2)向程序中加入新的代码,监测程序是否运行在一个可信的环境中。Jonathon Giffin的环境监测算法使用了这种思想。
(3)运行时检查程序中使用的数据值是否在正常的取值范围之内,程序的控制流是否沿着一个合理的路径流动。Oblivious Hashing一节中的两种算法使用了这种思想。
(4)远程防篡改:把程序割裂成两个部分,其中一个部分可以运行在服务器或者抗篡改硬件中,以避免被攻击者修改。Xiangyu Zhang的拆分函数方法使用了这种思想。
(5)使用代码混淆算法使攻击者难以理解程序,因而也就难以篡改程序。Christian Collberg的自修改代码机制使用了这种方法。
3.2 评价体系
在软件防篡改技术研究领域中,尚无被普遍接受的评价体系。本文借鉴ChristianCollberg提出的代码混淆的评价定义,建立了一套防篡改适用的评价标准,主要从防篡改强度、开销、隐蔽性三个方面对上述防篡改实现方法作定性分析。
防篡改强度 表示该算法对抗攻击者进行篡改的效果,可分为抗静态篡改和抗动态篡改两个方面。开销分为空间开销和性能开销两个方面,空间开销包括代码增加的大小、对于硬件和其他环境条件的需求等;性能开销主要关注增加保护代码之后程序运行时间的增加。隐蔽性表示该算法是否容易被攻击者发现并进行篡改攻击。
Hoi Chang的保护网络方法有一个非常好的特性就是其提供的安全性可以由我们自己随意调节,具体说来,就是通过调整保护代码的数量和防御图的复杂度来做到这一点。远程防篡改方法从理论上来说,对于动态篡改的抵抗效果是非常好的。然而,Xiangyu Zhang的拆分函数方法显然对服务器端的计算能力有很高的要求,对网络实时带宽的要求也比较高,因此实现成本是很高的。在性能开销方面,如果硬件条件不够好,会造成较大的延迟。此方法的性能开销往往依赖于有多少代码存放在服务器中。
监测运行环境的实现实际上是自修改代码的一种应用。对于以内存复制为主的动态篡改方式,这种方法效果还是比较明显的。据该算法的作者估计,在最坏的情况下将会导致一个与轻量级的系统调用近似的开销。
通过对当前主流软件防篡改技术的介绍,可以看出基本上没有突破“检测-响应”机制的框架。然而,响应部分往往是整个防篡改机制中的弱点,大部分攻击防篡改的破解技术以此作为突破口,一旦攻破,会使整个防篡改机制失去功效。另外,当前软件破解技术的主流倾向于将防篡改技术与其他软件反破解技术进行结合。如防篡改技术与代码混淆技术结合,增加“检测-响应”机制的隐蔽性;防篡改技术与软件水印技术结合,由于水印技术中的完整性验证要求软件遭到修改后水印即被破坏,实际上与防篡改技术的原理有相通之处,如何将二者结合亦是一项有意义的课题;总而言之,将防篡改技术与其他软件保护技术相结合能够大大增加软件保护的力度。
[1] Chang H,Atallah M J.Protecting software by guards[M]//Security and privacy in digital rights management.Springer Berlin Heidelberg,2002:160-175.
[2] Y.Chen,R.Venkatesan,M.Cary,R.Pang,S.Sinha,and M. Jakubowski.Oblivious hashing:A stealthy software integrity verification primitive.In 5th Information Hiding Workshop(IHW),pages 400-414,October 2002.Springer LNCS 2578.
[3] Mattias Jacob,Mariusz H.Jakubowski,and Ramarathnam Venkatesan.Towards integral binary execution:implementing oblivious hashing using overlapped instruction encodings.In Proceedings of the 9th workshop on Multimedia & Security,pages 129-140,New York,2007.ACM
[4] Xiangyu Zhang and Rajiv Gupta.Hiding program slices for software security.In CGO'03: Proceedings of the International Symposium on code Generation and Optimization, pages 325-336, Washington,DC,2003.IEEE.