用于混淆虚拟机上的应用程序的执行的方法、装置以及计算机可读介质与流程

文档序号:11160874阅读:383来源:国知局
用于混淆虚拟机上的应用程序的执行的方法、装置以及计算机可读介质与制造工艺

软件应用程序常常要求某些适应性以便适合于在不同平台上的执行。修改软件以在不同平台上运行的过程称为“移植”并要求每个硬件平台的理解。CPU、操作系统、图形用户界面或标准库中的差别可能要求对软件代码的显著改变,并且可能要求编译器或链接器来生成用于每个不同平台的新的可执行代码。结果,保持应用程序在许多看起来接近的平台上的可移植性可能是困难的任务。

过程虚拟机(VM)使得软件开发者能够专注于单个“虚拟机”平台,从而使得开发者能够保持软件跨多个平台的可移植性,所述多个平台中的每一个可以运行虚拟机的一个版本。在图1A中图示出典型的VM开发流程。如图中所示,在生成应用程序二进制代码103的VM编译器上编译应用程序源代码101。应用程序二进制代码103可以被视为虚拟机代码,并且包含指令,所述指令然后如在104处所示被VM解释并执行。

某些众所周知的虚拟机是Java虚拟机(JVM)或公共语言运行时。在图1B中示出了用于Java虚拟机的虚拟机开发流程。源代码111被JVM编译器编译而生成在JVM上可执行的一组指令,也称为Java字节码113,因为可执行代码中的每个指令的尺寸是一个字节。然后在JVM 114上执行字节码,JVM114解释并执行字节码中的指令。

虚拟机应用程序有效地隐藏所有平台差异,因此仅单个应用程序(虚拟机本身)需要适应于所有平台。这对其中竞争导致大范围的计算平台差异的诸如移动电话和平台计算机之类的移动设备特别有用。VM还可以与数字TV内容相组合地使用,如在美国专利申请公开US 2004/0133794 A1和US 2008/0101604 A1中所述。

诸如JVM之类的许多虚拟机利用即时编译(JIT),其是在程序的执行期间——在运行时——而不是在执行之前完成的编译。JIT编译器可以分许多区段(或全部地)读取字节码,并动态地将其编译成机器语言,因此程序可以更快速地运行。代码可以在即将被执行时被编译(因此得名“即时”),并且然后被高速缓存且在稍后被再使用而不需要被重新编译。虽然虚拟机的使用可能导致性能损失,但即时编译器优化在大多数情况下使得VM与本地执行相比能够实现可接受的性能。JIT编译的一个实施方式是首先具有应用程序源代码到字节码(虚拟机代码)的提前(AOT)编译,称为字节码编译,并且然后具有到机器代码的JIT编译(动态编译)。

图1C示出了执行字节码121的JVM 122中功能组件中的某些。类加载器加载用于Java应用程序的特定类的Java字节码,并且在将控制转移给由VM解释器和JIT编译器形成的执行功能元件之前验证字节码完整性。存储器管理器模块控制对数据结构的访问并实现动态存储器功能。

Java API和运行时间库为Java应用程序提供了使用公共库函数并访问本地计算环境中的其它资源的能力。所有这些功能的集合常常称为Java运行时环境(JRE)。图1D示出了用于执行字节码131的JRE 132的示意图。

用JRE,Java应用程序可以实现本地应用程序可实现的任何功能。在某些情况下,仅使用在JRE中支持的特征来实现某些特征是困难或麻烦的。对于那些特征而言,Java本地接口(JNI)提供对接到本地应用程序(例如编译C或C++应用程序)的能力。图1E图示出用于JNI的示意图,其是执行字节码141并与操作系统144、硬件145以及本地应用程序143对接的JRE 142的一部分。

AndroidTM是主要针对诸如智能电话和平板计算机之类的触摸屏移动设备设计的众所周知的操作系统。Android应用程序包文件(APK)是用来将应用软件和中间件分发并安装到Android操作系统上的文件格式。为了产生APK文件,首先编译用于Android的程序,并且然后将其部分中的所有封装成一个文件。这保持该程序的字节码(诸如.dex文件)、资源、资产、证书以及清单文件中的所有,并且APK文件是基于Java档案文件(JAR)文件格式的ZIP文件格式化的包。

APK文件是通常包含以下文件和文件夹的档案文件:

• META-INF目录,包含:

○ MANIFEST.MF:清单文件,

○ CERT.RSA:应用程序的证书,

○ CERT.SF:MANIFEST.MF文件中的对应行的资源列表和SHA-1摘要,

• lib:包含处理器的软件层特定的编译代码的目录,该目录被分离成在其内部的更多目录:

○ armeabi:仅用于所有基于ARM的处理器的编译代码,

○ armeabi-v7a:仅用于所有基于ARMv7及以上的处理器的编译代码,

○ x86:仅用于x86处理器的编译代码,

○ mips:仅用于MIPS处理器的编译代码,

• res:包含未被编译成resources.arsc的资源的目录,

• assets:包含应用程序资产的目录,其可以被AssetManager检索,

• AndroidManifest.xml:附加Android清单文件,描述用于应用程序的名称、版本、访问权限、参考库文件。此文件可采取Android二进制XML,其可以被用诸如AXMLPrinter2、apktool或Androguard之类的工具转换成人类可读的明文XML,

• classes.dex:以可被Dalvik虚拟机理解的dex文件格式编译的类,以及

• resources.arsc:包含预编译资源(诸如例如,二进制XML)的文件。

“classes.dex”文件是APK中的最重要文件。每个APK正好具有一个“classes.dex”文件。上述列表显示整个程序的Java代码被包含在classes.dex文件中。由于可移植性原因,用于Android设备的程序通常用Java来编写并编译成字节码(其被包含在.class文件中)。该编译字节码然后被从Java虚拟机兼容的.class文件转换成Dalvik兼容的.dex(Dalvik可执行)文件以使得能够安装在移动设备上。

Java字节码(即.class文件)是表示Java虚拟机执行的指令的二进制格式。图1F图示出基于Java VM指令集且包括三个指令151、152和153的三行Java字节码150的示例。左侧的数字指示用于每个指令的字节地址。例如,第一指令151在字节号0处,第二指令152在字节号3处,并且第三指令153在字节号4处。某些指令可获取操作数。例如,第一指令“sipush”151将操作数150所指示的短值推送到栈上。由于该操作数占用两个字节(字节1和2),所以下一指令152在字节3处开始。

遗憾的是,存在于Java源代码文件中的大量信息常常将被包含在字节码中。这诸如通过将指令与特定行的源代码相关的“LineNumberTable”和用来验证变量类型的“StackMapTable”而包括关于类、方法、字段以及源代码的信息。诸如反编译器之类的逆向工程工具受益于此附加嵌入式信息而增加了反编译源代码的输出质量。

用于对抗逆向工程的一个技术是软件混淆。软件混淆技术可以使得对受保护的软件应用进行逆向工程非常难。然而,高度的混淆导致显著的性能损失。这特别地适用于在虚拟机(其本身引入性能损失)中操作的软件应用程序。由软件混淆和在虚拟机上的执行引起的组合的性能损失可能难以在诸如移动设备之类的资源有限平台中克服。因此,软件混淆保护的程度常常受限于实现可接受的性能。

如先前所述,期望应用程序可容易地移植到大范围的平台,诸如基于Android OS的移动设备。这可以通过虚拟机的使用来实现,这还简化了应用程序功能性的测试。然而,由于Android是基于开源软件的,所以其容易使攻击者基于VM源代码而产生已修改虚拟机并使用该已修改虚拟机来对应用程序进行逆向工程。

由于性能约束常常限制可用于防护Java应用程序(诸如移动游戏或应用)的混淆程度,所以这常常意味着受防护的应用程序不具有白盒攻击情形(即其中代码可用且可访问的情形)所需要的期望保护水平。此保护缺失使得从字节码对Java应用程序进行逆向工程比常常期望的更加可行。

仅仅对字节码加密并在其在JVM上执行之前将其解密是有问题的,因为攻击者可以用已修改JVM来替换JVM,并在加载阶段之后(在其已被解密之后)观察并拦截字节码。另外,任何受防护的外部应用程序也需要用标准JVM(或JRE)工作,攻击者可以对所述标准JVM(或JRE)进行修改以便获得用于Java应用程序的整个Java字节码的明码电文版本。

附图说明

图1A-1B图示出用于在虚拟机上执行应用程序的开发流程。

图1C-1E图示出Java虚拟机、Java运行时环境以及Java本地接口的组件。

图1F图示出Java字节码样本。

图1G图示出用于应用程序在Java虚拟机上的高级混淆和执行的开发流程。

图2图示出根据示例性实施例的用于混淆虚拟机上的应用程序的执行的流程图。

图3图示出根据示例性实施例的用于混淆虚拟机上的应用程序的执行的开发流程。

图4图示出根据示例性实施例的虚拟机编译器的组件。

图5图示出根据示例性实施例的虚拟机代码发生器的组件。

图6A图示出根据示例性实施例的高级混淆变换的示例。

图6B-6D图示出根据示例性实施例的对应于应用程序源代码的字节码的示例。

图7A-7B图示出根据示例性实施例的可以使用自定义虚拟机解释器和自定义应用程序字节码来实现的特殊指令的示例。

图8图示出根据示例性实施例的对应用程序字节码执行的加密变换。

图9图示出根据示例性实施例的对应用程序字节码执行的指令地址变换。

图10图示出根据示例性实施例的由自定义虚拟机实现的数据位置变换。

图11图示出根据示例性实施例的由自定义虚拟机实现的数据值变换。

图12图示出根据示例性实施例的可以用来实现用于混淆虚拟机上的应用程序的执行的方法的示例性计算环境。

具体实施方式

虽然在本文中以示例和实施例的方式描述了方法、装置以及计算机可读介质,但本领域技术人员认识到用于混淆虚拟机上的应用程序的执行的方法、装置以及计算机可读介质不限于所述的实施例或附图。应理解的是附图和描述并不意图局限于公开的特定形式。相反地,意图是涵盖落在所附权利要求的精神和范围内的所有修改、等价和替换。在本文中使用的任何标题仅仅用于组织的目的,而不意图限制本描述或权利要求的范围。如本文所使用的单词“可以”是在获准的意义上(即,意指具有...的潜力)而不是强制性意义上(即,意指必须)使用的。同样地,单词“包括”、“包含”和“含有”意指包括但不限于。

需要字节码混淆技术,其针对包含在字节码中的指令的观察进行保护,并且其并未对由虚拟机进行的应用程序执行设置显著的性能约束。

存在用来保护Java软件应用程序、使得攻击者难以获得或修改Java字节码的若干安全技术。例如,Java软件应用程序可以受到防护,或者可以使用软件混淆技术来使用源代码和/或编译时软件变换而保护Java软件应用程序。这些高级混淆技术在不依赖于一个或多个目标处理器的特性的情况下实现其混淆性质。

图1G示出了用于混淆源代码的过程流程的图。源代码160被提供给代码转换机161,其实现源代码160的高级混淆而产生混淆源代码162。此混淆源代码162在使得最终表示尽可能难理解的同时保持原始软件的语义。混淆源代码162然后被JVM编译器163编译而生成在JVM 165上执行的Java字节码164。

除高级代码的混淆之外,可以对字节码中的VM指令集进行加密或混淆,并且然后可以在应用程序(被字节码加载器)的加载期间或者在由VM执行指令期间将已加密指令解密。美国专利申请公开US 2012/0246487 A1(藉此将其内容通过引用并入)描述了使用JNI来建立到JVM的闭合链路的受防护的本地代码模块。受防护的应用程序实现特殊类加载器中的代码变换以及若干其它安全功能。

图1G中的图的工具链示出了将源代码转换成源代码的混淆版本的步骤,该混淆版本被编译并链接到Java虚拟机二进制中,亦即根据Java字节码指令集的混淆逻辑的表示。此步骤序列替换了此类的多个工具链,每个工具链将源代码变换成用于特定目标平台的混淆二进制(在本地指令集中)。

然而,如先前所讨论的,高度的源代码混淆导致显著的性能损失,并且不会针对经由结果得到的字节码(其可以通过已修改虚拟机而被观察和利用)中的指令进行的逆向工程而保护应用程序。此外,字节码的加密和在VM中的加载之前的解密也未充分地保护结果得到的字节码,其可以在加载之后被以解密形式观察。

申请人已经发现并开发了一种受防护(或混淆)的自定义虚拟机(自定义VM),诸如自定义Java VM,其通过包括针对字节码中的指令的观察进行保护的附加安全功能性而变得与Java VM应用程序的标准版本不兼容。

可以将混淆保护应用于整个VM应用程序或VM应用程序的一部分。遍及本公开,对Java VM进行参考,但本文所述的方法和系统也可以与其它类型的虚拟机一起利用。

自定义VM可以使用不同的(已变换)指令集,其要求已修改加载器和/或运行时字节码固定(fix-ups)以便执行,并且从而针对白盒逆向工程保护任何自定义应用程序字节码,因为自定义字节码将不会在非自定义VM上适当地执行。可以基于自定义VM定义对针对应用程序生成的字节码进行自定义。例如,自定义字节码格式可以被扩展,并且可以在由自定义VM执行期间将已扩展指令映射到未扩展字节码序列。已扩展指令还可以被受防护的JIT编译器处理以生成用以实现(一个或多个)期望操作的本地指令。

作为自定义VM的一部分的存储器管理器可以实现自定义应用程序字节码依赖于以便实现适当操作的非标准功能。另外,作为自定义VM的一部分的自定义VM解释器可以受到防护,并且可以支持非标准功能,诸如获取-执行循环的一部分的解密步骤。自定义VM解释器还可以向类加载器和/或指令验证器提供追踪信息以便检测异常程序执行痕迹。自定义应用程序字节码可以另外包含指令追踪,其触发自定义VM解释器内的隐藏功能性。

图2是示出根据示例性实施例的用于混淆VM上的应用程序的执行的方法的流程图。在步骤201处,接收对应于自定义VM的自定义VM定义。自定义VM定义可以是描述特定虚拟机或现有虚拟机的变体的文件。例如,自定义VM定义可以指定唯一自定义VM。该自定义VM定义将被用来创建自定义VM,包括解释针对自定义VM设计的自定义应用程序字节码的自定义VM解释器以及将把应用程序源代码编译成自定义应用程序字节码的自定义VM编译器。

在步骤202处,至少部分地基于自定义VM定义而生成自定义VM源代码。在步骤203处,可以诸如通过使用先前描述的高级混淆和/或安全技术来可选地混淆或防护自定义VM源代码。例如,混淆技术包括简单的关键字替换、用以创建艺术效果的白空间的使用或不使用以及自动生成的或严重压缩的程序。

可以使用的其它高级混淆和/或安全技术包括控制流程变换、分支保护、例程内联、控制流程展平、白盒密码术、完整性验证修改、防调试修改和/或安全打包/加载。下面更详细地对这些进行描述。

控制流程变换。控制流程指的是随着程序运行且控制被转移到语句的各种块而遵循的执行路径。控制流程变换通过将目标源代码的块体随机化来防护程序。这导致极难追踪的代码,并且因此大大地增加了尝试对应用程序的流程进行逆向工程的攻击者的成本。

分支保护。在软件中,将潜在地将控制转移到另一指令的指令称为“分支”。条件分支是其目的地由其(一个或多个)输入值确定的分支,并且包括IF语句、SWITCH语句以及条件算子。攻击者通常尝试堵塞或绕过代码中的重要分支以便回避安全检查或尝试修改程序的原始流程。分支保护通过添加引起程序在分支被堵塞的情况下不正确地表现的代码来防止分支堵塞。

例程内联。在此技术中,在应用变换之前对文件内的代码的单独逻辑段进行合并。这种方法不同于编译器内联选项,其是在预处理之后执行的。目标是将操作组合并混淆程序的逻辑。

控制流程展平。编译器使用目标指令集的固定的一组跳跃和条件分支指令来实现程序语言的控制流程。一般地,使用系统或规则驱动方法用机器代码来实现控制流程。控制结构被转换成密封且可预测的指令序列。因此,诸如反编译器和程序切片机之类的逆向工程工具常常可以成功地再现原始程序的控制流程。控制流程展平将控制流程变成SWITCH语句,这防止静态控制流程分析。

白盒密码术。当存在攻击者可能能够监视应用程序并提取由应用程序嵌入或生成的一个或多个密码密钥的担心时使用白盒密码功能。在传统密码术中,黑盒攻击描述其中攻击者通过知道算法并监视输入和输出来获得密钥的情况,但是在执行不可见的情况下。白盒密码术提出了其中攻击者可以观察到一切的内容保护系统的更加严重的威胁模型。仍要求加密和解密,但并不暴露密码密钥。用适当的设计,应用程序可以保持敏感数据被加密或变换或二者,使得原始数据从不被暴露。所有数据操作都将在已变换状态下发生。

完整性验证修改。完整性验证是在不可信主机上确保信任的代码签名的更安全变体。其提供了确认应用程序的完整性的安全方法,并且还可以确保与该应用程序相交互的外部模块(包括操作系统的组件)的完整性。完整性验证确保软件不能在没有检测到的情况下被篡改——无论是静态地还是动态地。这显著地提高了篡改抵抗中的障碍,因为攻击者必须不仅对程序进行逆向工程和对二进制进行修改,而且必须也战胜完整性检查。

防调试修改。在应用程序的环境中运行的任何调试或诊断功能性都帮助其意图是对所部署的应用程序的正常功能性进行逆向工程或将其搅乱的最终用户。防调试技术允许检测到与应用程序在同一环境中运行的调试程序。如果检测到,则应用程序可以采取行动以将该调试程序去激活或停止运行。

安全打包器/加载器。在这种技术中,称为安全打包器/加载器的小型应用程序拦截在运行时期间对目标文件的用户或应用程序调用。安全打包器/加载器必须在其将所调用的目标文件拆开并执行之前首先对触发事件进行确认。将目标可执行指令或DLL加密也使得攻击者难以静态地分析存储中的文件。

当然,可以使用任何已知的高级混淆和/或安全技术来混淆和/或防护本文所述的高级源代码。

在步骤204处,用一个或多个目标系统编译器来编译自定义VM源代码(其可选地已被以已知方式混淆)以生成自定义VM的一个或多个实例。自定义VM的这些实例中的每一个被配置成在一个或多个目标系统中的一个上运行。例如,如果存在两个目标系统,则可以用两个不同的目标系统编译器来编译自定义VM源代码以生成自定义VM的两个实例,每个目标系统一个。

在步骤205处,可选地诸如通过先前所述的高级混淆技术来混淆应用程序源代码。在步骤206处,至少部分地基于自定义VM定义,从应用程序源代码或应用程序源代码的一部分生成自定义应用程序字节码。自定义应用程序字节码是被配置成在自定义VM上运行的字节码。例如,自定义应用程序字节码可以包含一个或多个指令,其只能被作为自定义VM的一部分的自定义解释器而不是标准Java VM的解释器解释。

在步骤207处,自定义应用程序字节码和自定义VM的一个或多个实例被打包到可安装应用程序中。这可以采取包文件的形式,诸如Android应用程序包文件(APK)。

图3图示出用于生成可安装应用程序的过程流程图,所述可安装应用程序包括自定义应用程序字节码和自定义VM的一个或多个实例。如图中所示,代码转换机301可以使用自定义VM定义和应用程序源代码来生成混淆应用程序源代码。代码转换机301可以使用自定义VM定义来生成适当的高级结构以便在由自定义VM定义指定的自定义VM上执行。替换地,可以仅基于应用程序源代码而在没有自定义VM定义的情况下生成混淆应用程序源代码。此步骤也可以省略,使得应用程序源不被混淆。

VM目标描述发生器302也接收自定义VM定义并将其转换成适合于在VM编译器303的后端中使用的自定义VM目标描述。例如,自定义VM定义可以是包括定义自定义VM的一组性质的文件。所述性质可以涉及自定义VM的任何方面,诸如容量、OS、启动选项、磁盘、存储器、网络、输入/输出、约束、要求、表达语法、类、指令集、指令语法、规范等。然后可以使用自定义VM定义中的性质来调整、选择或者映射在VM编译器303的后端中使用的自定义VM目标描述中的设置。

例如,自定义VM定义可定义并非标准JVM指令集的一部分的自定义字节码指令。VM目标描述发生器可以接收该自定义VM定义并将其转换成自定义VM目标描述,其将自定义字节码指令包括在自定义VM目标描述的指令集部分中。

VM编译器303处理(可选地混淆的)应用程序源代码或应用程序源代码的一部分,以生成被配置成用于在由自定义VM定义指定的自定义VM上执行的自定义应用程序字节码。VM编译器303可以至少部分地基于从VM目标描述发生器302接收到的自定义VM目标描述而生成自定义应用程序字节码。

自定义VM定义另外被输入到VM代码发生器304,其生成对应于自定义VM(其包括自定义VM解释器)的自定义VM源代码。

为了针对白盒攻击保护自定义VM源代码,代码转换机305可以可选地对自定义VM源代码或自定义VM源代码的各部分执行高级混淆。

(可选地混淆的)自定义VM源代码被发送到对应于两个不同目标平台的目标编译器306A和306B。针对每个目标平台,目标编译器306A和306B处理自定义VM源代码以生成自定义VM的两个实例,每个目标平台对应一个。图3图示出两个目标平台,但在实践中目标平台的数目可更大或更小。这意味着保护方案解决了自定义VM到所有目标平台的可移植性,并且应用程序源代码开发者不需要这样做。

打包器307将用于目标平台1的自定义VM、用于目标平台2的自定义VM以及自定义应用程序字节码打包到可安装应用程序中。如先前所讨论的,该包可以采取标准格式,诸如APK。

参考图4,现在将描述VM编译器的架构。VM编译器403接收应用程序源代码401并使用自定义VM目标描述402来控制VM后端,其将在公共优化器中使用的中间表示转换成自定义应用程序字节码404。

此架构允许可以容易地支持大范围的目标虚拟机的编译器。替换地,VM编译器可以利用自定义VM目标描述来修改现有VM编译器组件(例如,宏预处理器、编译器和/或链接器)的一部分。这种方法就潜在的自定义而言不那么灵活,但要求较少的实现努力以便执行对现有VM的特定改变。

生成的自定义应用程序字节码要求对应于自定义VM定义的自定义VM(包括自定义VM解释器)。如先前所述,用以实现此自定义VM的源代码由VM代码发生器生成。在图5中示出了VM代码发生器的示意图。

VM代码发生器502的代码选择器502A使用自定义VM定义501来从VM源代码储存库502C中选择VM源代码。所选代码被代码适配器502B修改以生成自定义VM源代码。这使得VM代码发生器502能够选择、组合和/或修改现有的源代码片段。自定义VM定义501还可以指定VM代码发生器502在生成自定义VM源代码503时使用的用于自定义VM的附加功能性。由于自定义VM定义还被VM编译器在编译应用程序源代码时使用,所以对应的自定义应用程序字节码能够利用该附加功能性。将相对于可以由自定义VM实现的特定变换来更详细地描述附加功能性的示例。

由于自定义VM组件中的每一个(包括自定义解释器组件)可以实现生成的自定义应用程序字节码被配置成使用的附加功能,所以自定义应用程序字节码和自定义VM被有效地链接。攻击者因此将必须对自定义VM和自定义应用程序字节码镜像两者进行逆向工程以便修改用于在具有不同VM解释器的不同VM上执行的字节码。

以下小节提供了用于将构成自定义VM且使用选自源代码储存库502C的源代码生成的自定义VM组件中的每一个的附加功能性的示例。

类加载器组件处理应用程序字节码的加载。用于类加载器的附加功能可以包括已变换应用程序字节码(对应于自定义应用程序字节码)的加载、已变换应用程序字节码的按需加载以及指令地址变换。下面更详细地描述这些功能中的每一个。

已变换应用程序字节码的加载。在这种情况下,自定义应用程序字节码是已被变换以针对逆向工程进行保护的字节码。在加载期间,应用逆变换。结果是原始应用程序字节码到自定义VM存储器中的加载。字节码变换的示例是加密,在这种情况下自定义VM的类加载器将在加载时将字节码解密。

已变换应用程序字节码的按需加载。在这种情况下只有自定义应用程序字节码的一部分被加载。当执行传递至尚未被加载的自定义应用程序字节码时,自定义VM使用类加载器来加载自定义应用程序字节码的下一部分,因此执行可以继续。由于自定义应用程序字节码的加载集合取决于程序执行,所以使攻击者难以观察自定义VM存储器中的整个自定义应用程序字节码镜像。此运行时保护扩展了由已变换应用程序字节码的加载提供的静态保护。

指令地址变换。在这种情况下,类加载器将自定义应用程序字节码存储在不同的位置处。在编译时,对自定义应用程序字节码被存储在不同位置处的事实进行修正。可以仅对应用程序字节码的选定部分应用地址变换。

存储器管理器组件分配并管理存储在自定义VM存储器中的数据结构。下面列出了用于此组件的附加功能。

存储器管理器可以将数据移动至不同的位置。只有了解此附加特征的应用程序字节码可以在使用数据结构之前正确地计算数据结构的实例的位置。

存储器管理器可以对存储器中的数据进行变换。只有了解此附加特征的应用程序字节码将能够对此类已变换数据进行操作。

存储器管理器还可以验证存储器结构如从由适当编译器生成的应用程序字节码预期的那样被访问。在正常地址范围之外或者具有不正确访问模式的任何存储器访问可以导致存储器管理器触发某些防御措施。可以使用特殊数据结构来控制存储器管理器中的访问模式验证器。

自定义VM解释器组件对自定义应用程序字节码指令实行获取-执行环路。自定义VM解释器可以被适配成支持附加功能性,诸如并非标准指令集的一部分的附加指令。

现在将参考附图来描述混淆技术、应用程序字节码生成以及可以由自定义VM和自定义应用程序字节码实现的变换的某些示例。

图6A示出了用Java记法表达的应用程序源代码被如何转换成混淆形式。应用程序源代码包括主函数601A和增量函数602A。603所指示的变换被应用于源代码并根据第一等式的所有输入流值(在主函数601A中为“5”)、根据第二等式的所有输出流值(在主函数601A中为“6”)进行变换,并且基于对主函数中的值的改变而修改增量函数中的返回值以保持相同的执行流程。结果得到的混淆应用程序源代码包括混淆主函数601B和混淆增量函数602B。为了提供变换的示例,由于主函数601A中的“5”是输入流值,所以结果得到的变换是((5*4) + 5)*6=150。

图6B图示出混淆应用程序源代码到应用程序字节码的变换。具体地,当混淆主函数601B被VM编译器604编译时,产生应用程序字节码601C。另外,当混淆增量函数602B被VM编译器编译时,产生应用程序字节码602C。

图6C图示出对应于混淆主函数的应用程序字节码以及关于由字节码601D中的每个指令执行的动作的注释。例如,字节12处的指令比较栈上的两个整数。如果其不相等,则执行分叉到指令中的分支偏移(+11)所指示的字节,导致地址23处的字节的执行。还示出了对应于混淆增量函数的应用程序字节码以及关于由字节码602D中的每个指令执行的动作的注释。

图7A-7B图示出可以使用自定义VM解释器和自定义应用程序字节码来实现的特殊指令的示例。图7A图示出对应于先前讨论的混淆增量函数的字节码701。如图中所示,字节地址1、2、3和5处的字节码指令中的每一个(对应于将恒定值“3”初始化并将其推送到栈上、将栈上的前两个数相除并将结果存储在栈上、将值10推送到栈上、以及将栈上的前两个数相加的步骤)必须被JVM解释器解释并被JVM映射到本地指令,导致执行这些步骤所需的四个指令。

转到图7B,示出了对应于同一混淆增量函数的自定义应用程序字节码702。在自定义应用程序字节码中,被用来除以3并向值加10的四个指令已被单个复杂指令“xc_obfuscated_inc_operation”替换,其具体地被确定目标以表示本示例特定的变换域中的增量函数。该复杂指令可以取栈上的第一个值,将其除以3,并向结果加10,将结果存储在栈上。这通过去除从和向自定义VM的虚拟栈读和写中间值的需要而减少了所需指令的总数。

对应于自定义应用程序字节码的自定义VM中的自定义VM解释器可以在其指令集中包括复杂指令“xc_obfuscated_inc_operation”,使得当其在自定义应用程序字节码中被遇到时,可以适当地执行该指令。相反地,如果此指令集是在标准JVM上运行的,则标准JVM解释器将不能解释该复杂指令,并且应用程序将不会正确地执行。

自定义VM与自定义应用程序字节码之间的此协调可以基于自定义VM定义和先前所述的过程来实现。通过将自定义VM中的非标准功能性和混淆特征与混淆自定义应用程序字节码配对,大大地增强了应用程序字节码的安全性,因为自定义VM和对应的自定义应用程序字节码两者都将必须被逆向工程以复制应用程序。

自定义VM解释器还可以验证指令序列如从自定义VM字节码执行预期的一样。在正常范围之外的任何指令模式都可以导致自定义VM解释器触发某些防御措施。可以使用特殊字节码指令或指令序列来控制自定义VM解释器中的指令模式验证器。此控制可以作为正常字节码处理的副效应发生。

可以使用的另一技术是自定义VM解释器的获取-执行循环中的应用程序字节码变换的实现。此变换可以独立于自定义VM类加载器组件中的类似功能性。

自定义VM解释器还可以支持特殊字节码指令以处理由自定义VM的其它部分(例如,在存储器管理器或自定义VM类加载器中)实现的附加功能。

自定义VM的另一组件是JIT编译器组件,其提供了用以增加用于处理自定义应用程序字节码的性能的方式。下面列出了用于此组件的附加功能。

JIT编译器可以支持存在于加载代码中的扩展的一组字节码。这类似于如先前所述的自定义VM解释器中的新指令的支持。

JIT编译器可以生成本地指令以验证自定义应用程序字节码指令序列是否如针对自定义应用程序字节码执行所预期的那样。在正常范围之外的任何指令模式可以导致自定义VM触发某些防御措施。编译代码可以与自定义VM的其它部分交换指令追踪信息以便高效地记录执行进展,并检测在预期范围之外的任何执行模式。

可以扩展JIT编译器以处理自定义应用程序字节码,其在将其编译成本地指令序列时已被变换。该变换可以独立于自定义VM类加载器或存储器管理器中的类似功能性。

JIT编译器还可以以利用由自定义VM的其它部分(例如,在存储器管理器或自定义VM类加载器中)实现的附加功能的方式生成本地代码。

自定义VM的附加组件包括自定义VM API和运行时间库模块,其是自定义VM用来以优化方式提供对公共高级操作的访问的标准的一组功能。这些操作通常与I/O任务有关。下面列出了用于这些类似组件的附加功能。

VM API和/或运行时间库可以支持扩展的一组功能以支持应用程序。

VM API和/或运行时间库可以支持变换的一组功能以支持应用程序。已变换意味着作为调用的一部分而提供的入口点(库例程名或API函数名)或参数被映射到另一域。应用程序需要了解这些变换以便激活预定函数。例如,可以使用自定义VM定义来编译自定义应用程序字节码以利用已变换函数。

VM API和/或运行时间库还可以修改将支持函数的适当操作锁定到特定硬件平台的库中的参数。该锁定可以在安装时、在第一次执行期间或者作为从应用程序商店的获取过程的一部分而配置。

现在将描述自定义VM可以利用的自定义应用程序字节码变换的某些附加示例。

图8图示出在对应于先前讨论的增量函数的应用程序字节码上执行的加密变换。该变换可以由VM编译器在应用程序源代码的编译期间执行,并且可以是基于自定义VM定义文件中的信息。原始应用程序字节码801对应于如802处所示的一组相关操作码。操作码是字节码中的指令的两数位十六进制表示,每个操作码对应于一字节且表示唯一指令。可以执行变换以用恒定值来调整用于每个指令的操作码(具有例外情况,即任何已变换操作码不能超过一个字节尺寸极限,并且将替代地变成第一操作码,因此ff将变成00)。

在图8中,用于每个指令的操作码被增加1,导致已变换的一组操作码803。在804处示出了对应于这些已变换操作码的指令。此指令集804可以被视为自定义应用程序字节码,并且将仅在知道该变换的自定义VM上执行,使得其可以在执行之前执行逆变换。如前所述,自定义VM与自定义应用程序字节码之间的协调可以基于自定义VM定义文件,并且可以使用先前关于图2-3所述的过程来促进。

在本示例中,逆变换将是在解释并执行指令之前从用于每个指令的每个操作码减去一。如果自定义应用程序字节码将在不知道该变换的VM上运行,则将执行不正确的指令,可能导致应用程序的错误和/或崩溃。

图9图示出在对应于先前所讨论的主函数的应用程序字节码上执行的指令地址变换。应用程序字节码900在地址12处包括if_icmpne指令,其在未满足条件的情况下分叉到地址23。地址23包含结束主函数的返回指令。

可以对此指令执行变换901以将if_icmpne的分支偏移参数修改成分叉到不正确的指令地址。如图9中所示,变换901之后的自定义应用程序字节码902在地址12处包括if_icmpne指令,其在未满足条件的情况下分叉到地址25。

自定义应用程序字节码902将仅在知道该变换的自定义VM上执行,使得其可以在执行之前执行逆变换。如前所述,自定义VM与自定义应用程序字节码之间的协调可以基于自定义VM定义文件,并且可以使用先前关于图2-3所述的过程来促进。

在本示例中,逆变换将是在解释并执行指令之前从用于if_icmpne指令的分支偏移减去二。如果自定义应用程序字节码将在不知道该变换的VM上运行,则执行将转移到不正确的分支地址,并且应用程序将可能冻结,因为主函数不能被结束。

图10图示出可以由自定义VM的存储器管理器实现的数据位置变换的示例。

左列对应于标准VM,诸如JVM,并且图示出用于分别地将值存储到变量1中和从变量1加载值的指令“istore_1”和“iload_1”的处理流程。如在1001A处所指示的,栈中的第一个值是整数X,并且指令istore_1和iload_1两者都与地址1相关联。

当istore_1指令被执行1002A时,栈中的第一个值(在这种情况为X)被存储在存储器地址1处,如在1003A处所指示的。当iload_1指令被执行1004A时,地址1处的值被推送到栈上。这导致X被推送到栈上,如在1005A处所指示的。

在自定义VM中,存储器管理器可以实现数据位置变换1010,其切换与istore_1和istore_2命令相关联的地址,导致istore_1命令与地址2相关联且istore_2命令与地址1相关联。此数据位置变换只能影响istore命令,iload命令不受影响。

参考图10,右列对应于已实现上述数据位置变换的自定义VM。如在1001B处所指示的,栈中的第一个值仍是整数X,并且与iload_1相关联的地址仍是地址1,但是与istore_1相关联的地址现在是地址2。

当istore_1指令被执行1002B时,栈中的第一个值(在这种情况为X)被存储在存储器地址2处,如在1003B处所指示的。当iload_1指令被执行1004B时,地址1处的值被推送到栈上。如在1005B处所指示的,这是不正确的值,因为用于变量1的值被存储在地址2处而不是地址1处。由于应用程序字节码不知道数据位置变换,所以未改变的应用程序字节码将不会在自定义VM上适当地执行。

为了在此自定义VM上适当地执行应用程序,自定义应用程序字节码将必须知道该变换且被相应地修改。例如,当VM编译器正在编译应用程序源代码时,可以使用自定义VM定义来切换iload_1和iload_2指令,使得当运行那些指令时正确的值被加载。在这种情况下,那将意味着用iload_2来替换应用程序字节码中的指令iload_1以生成自定义应用程序字节码。自定义VM与自定义应用程序字节码之间的此协调可以是基于自定义VM定义文件,并且可以使用先前关于图2-3所述的过程来促进。

图11图示出可以由自定义VM的存储器管理器实现的数据值变换的示例。由于VM中的每个变量的存储器地址与本示例无关,所以将在不参考特定存储器地址的情况下讨论istore和iload指令。

左列对应于标准VM,诸如JVM,并且图示出用于分别地将值存储到变量1中和从变量1加载值的指令“istore_1”和“iload_1”的处理流程。如在1101A处所指示的,栈中的第一个值是整数X。

当istore_1指令被执行1102A时,变量1被设置成栈中的第一个值(在这种情况为X),如在1103A处所示。当iload_1指令被执行1104A时,变量1的值被推送到栈上。这导致X被推送到栈上,如在1005A处所指示的。

在自定义VM中,存储器管理器可以实现数据值变换1110,其在执行存储指令时自动地向存储在变量中的所有值加上值Y。

参考图11,右列对应于已实现上述数据值变换的自定义VM。如在1101B处所指示的,栈中的第一个值仍是整数X。

当istore_1指令被执行1102B时,变量1被设置成值X+Y,如在1103B处所指示的。当iload_1指令被执行1104B时,值X+Y被推送到栈上。如在1105B处所指示的,这是不正确的值,因为最初在栈的顶部处的值正是X。由于应用程序字节码不知道数据值变换,所以未改变的应用程序字节码将不会在自定义VM上适当地执行。

为了在此自定义VM上适当地执行应用程序,自定义应用程序字节码将必须知道该变换且被相应地修改。例如,当VM编译器正在编译应用程序源代码时,可以使用自定义VM定义来添加指令以补偿Y到所有变量的存储值的相加。这些指令可以有效地从已从变量加载的所有值减去Y。例如,在值被从变量加载到栈之后,可以向栈添加常数Y,并且然后指令可以从先前加载的值减去Y并将该结果存储在栈上。在这种情况下,栈上的最终值将与添加Y的数据值变换未发生的情况下是相同的。

自定义VM与自定义应用程序字节码之间的此协调可以是基于自定义VM定义文件,并且可以使用先前关于图2-3所述的过程来促进。

如在以上示例中所述,从应用程序源代码生成自定义应用程序字节码可以包括从应用程序源代码生成应用程序字节码并对应用程序字节码执行第一变换以生成自定义应用程序字节码。另外,自定义VM定义可以指定将应用于在自定义VM上执行的字节码的第二变换,该第二变换是基于第一变换。此第二变换可以由根据自定义VM定义生成的自定义VM执行。

如示例中所示,变换的许多变化是可能的。第一变换可以是字节码中的指令的加密,并且第二变换可以是字节码中的指令的解密。第一变换可以是与字节码中的指令相关联的指令地址的调整,并且第二变换可以是与字节码中的指令相关联的指令地址的逆向调整。第一变换可以是用第二指令替换字节码中的第一指令,并且第二变换可以是其中存储了与字节码中的第一指令相关联的数据的存储器位置的变换,使得与第二指令相关联的数据被存储在先前对应于与第一指令相关联的数据的存储器位置处。第一变换可以是向字节码添加一个或多个新指令,并且第二变换可以是在字节码中的指令的执行期间存储在存储器中的数据值的变换。在这些示例中的每一个中,可以使用第二变换来补偿第一变换的效果。当然,这些示例仅仅是为了例证而提供的,并且其它变换变化是可能的。

返回图2的流程图,在该过程结束时,生成自定义VM的一个或多个实例,并且其可以作为可安装应用程序的一部分分发给用户。这些自定义VM中的每一个可以实现在本文中讨论的自定义,并且可以在用户的目标平台上执行。下面描述一种根据示例性实施例的用于在自定义VM上执行应用程序的方法。

在应用程序的执行期间,可以将对应于应用程序的自定义应用程序字节码加载到自定义VM的存储器中,自定义应用程序字节码和自定义VM两者都是至少部分地基于对应于该自定义VM的自定义VM定义而生成的。

可以在自定义VM上执行针对自定义VM配置的字节码指令。另外,可以至少部分地基于一个或多个字节码指令将一个或多个数据值存储在自定义VM的存储器中。

自定义应用程序字节码可以是已被至少部分地基于自定义VM定义的第一变换所变换的字节码。在那种情况下,可以通过基于第一变换对自定义应用程序字节码应用第二变换以生成已变换应用程序字节码(第二变换也至少部分地基于自定义VM定义)并将已变换应用程序字节码加载到自定义VM的存储器中来加载自定义应用程序字节码。

第一变换可以是字节码中的指令的加密,并且第二变换可以是自定义应用程序字节码中的对应指令的解密。第一变换可以是与字节码中的指令相关联的指令地址的调整,并且第二变换可以是与自定义应用程序字节码中的对应指令相关联的指令地址的逆向调整。

还可以通过加载自定义应用程序字节码的第一部分并至少部分地基于确定了应用程序的执行已被转移到在第一部分之外的自定义应用程序字节码的一部分的而加载自定义应用程序字节码的第二部分来加载自定义应用程序字节码。

可以通过解释字节码指令中的某些或所有以识别运行时间库中的一个或多个对应例程并执行一个或多个对应例程来执行自定义应用程序中的字节码指令。

字节码指令可以是已被至少部分地基于自定义VM定义的第一变换所变换的字节码。可以通过基于第一变换对字节码指令应用第二变换以生成已变换字节码指令(第二变换至少部分地基于自定义VM定义)并解释已变换字节码指令以识别运行时间库中的一个或多个对应例程来执行解释字节码指令。字节码指令可以是在自定义VM定义中指定的自定义指令,如先前所讨论的。

解释字节码指令还可以包括确定所述多个字节码指令中的字节码指令序列,并且至少部分地基于确定了所述字节码指令序列与已接受的字节码指令序列(诸如指示正常操作的字节码指令序列)不匹配而触发防御措施。

还可以通过将一个或多个字节码指令中的至少一个字节码指令转换成本地机器代码并执行本地机器代码来执行自定义应用程序字节码中的字节码指令。

字节码指令可以包括已被至少部分地基于自定义VM定义的第一变换所变换的字节码。在这种情况下,可以通过基于第一变换对字节码指令应用第二变换以生成已变换字节码指令来转换字节码指令,第二变换至少部分地基于自定义VM定义。然后可以将已变换字节码指令转换成本地机器代码。

可以至少部分地基于确定了本地机器代码序列与已接受的本地机器代码序列不匹配来触发本地机器代码序列和防御措施。

如前所述,字节码指令可以包括已被至少部分地基于自定义VM定义的第一变换所变换的字节码。在这种情况下,可以通过对其中存储了与所述至少一个字节码指令相关联的数据的存储器位置应用第二变换来将一个或多个数据值存储在自定义VM的存储器中,第二变换至少部分地基于自定义VM定义。

字节码指令可以包括已基于第一变换生成的字节码,该第一变换本身至少部分地基于自定义VM定义。在这种情况下,可以对存储在自定义VM存储器中的一个或多个数据值中的至少一个数据值应用第二变换,其中第二变换也至少部分地基于自定义VM定义。

当将数据值存储在自定义VM的存储器中时,可以确定对应于所述多个数据值的VM存储器地址序列。如果此VM存储器地址序列与已接受的VM存储器地址序列不匹配,则可以触发防御措施。

上述技术中的一个或多个可以在一个或多个计算机系统中实现或涉及到一个或多个计算机系统。图12图示出计算环境1200的一般化示例。计算环境1200并不意图暗示关于所述实施例的使用或功能性的范围的任何限制。

参考图12,计算环境1200包括存储器1220和至少一个处理单元1210。处理单元1210执行计算机可执行指令,并且可以是实际或虚拟处理器。在多处理系统中,多个处理单元执行计算机可执行指令以增加处理能力。存储器1220可以是易失性存储器(例如,寄存器、高速缓存、RAM)、非易失性存储器(例如,ROM、EEPROM、闪存等)或两者的某种组合。存储器1220可存储用于在被一个或多个处理器执行时实现所述技术的软件指令1280。存储器1220可以是一个存储器设备或多个存储器设备。

计算环境可具有附加特征。例如,计算环境1200包括储存器1240、一个或多个输入设备1250、一个或多个输出设备1260以及一个或多个通信连接1290。诸如总线、控制器或网络之类的互连机制1270将计算环境1200的组件互连。通常,操作系统软件或固件(未示出)为在计算环境1200中执行的其它软件提供操作环境,并且协调计算环境1200的组件的活动。

储存器1240可以是可移除或不可移除的,并且包括磁盘、磁带或磁带盒、CD-ROM、CD-RW、DVD或可以用来存储信息且可以在计算环境1200内被访问的任何其它介质。储存器1240可存储用于软件1280的指令。

(一个或多个)输入设备1250可以是诸如键盘、鼠标、笔、轨迹球、触摸屏或游戏控制器之类的触摸输入设备、语音输入设备、扫描设备、数字式相机、远程控制或向计算环境1200提供输入的另一设备。(一个或多个)输出设备1260可以是显示器、电视、监视器、打印机、扬声器或从计算环境1200提供输出的另一设备。

(一个或多个)通信连接1290使实现通过通信介质到另一计算实体的通信。通信介质在已调制数据信号中传送信息,诸如计算机可执行指令、音频或视频信息或其它数据。已调制数据信号是其特性中的一个或多个被以从而对信号中的信息进行编码的这样的方式设定或改变的信号。以示例而非限制的方式,通信介质包括用电、光学、RF、红外、声学或其它载体实现的有线或无线技术。

可以在计算机可读介质的一般上下文下描述实施方式。计算机可读介质是可以在计算环境内被访问的任何可用介质。以示例而非限制的方式,在计算环境1200内,计算机可读介质包括存储器1220、储存器1240、通信介质以及上述各项中的任何的组合。

当然,图12仅仅为了便于识别而将计算环境1200、显示设备1260以及输入设备1250图示为单独设备。计算环境1200、显示设备1260以及输入设备1250可以是单独设备(例如,通过导线连接到监视器和鼠标的个人计算机)、可被集成在单个设备中(例如,具有触摸显示器的移动设备,诸如智能电话或平板电脑)或者可以是设备的任何组合(例如,被操作耦合到触摸屏显示设备的计算设备、被附着到单个显示设备和输入设备的多个计算设备等)。计算环境1200可以是机顶盒、移动设备、个人计算机或一个或多个服务器,例如联网服务器农场、集群服务器环境或计算设备的云网络。

已参考所述实施例描述并例证了我们的发明的原理,将认识到的是可以在布置和细节方面修改所述实施例而不脱离这样的原理。应理解的是本文所述的程序、过程或方法并非关于或局限于任何特定类型的计算环境,除非另外指明。各种类型的通用或专用计算环境可被用于或执行根据本文所述的教导的操作。可用硬件来实现用软件示出的所述实施例的元件,并且反之亦然。

鉴于可应用我们的发明的原理的许多可能实施例,我们将如可落在以下权利要求及其等价物的精神和范围内的所有此类实施例作为我们的发明要求保护。

当前第1页1 2 3 
网友询问留言 已有0条留言
  • 还没有人留言评论。精彩留言会获得点赞!
1