
技术摘要:
本发明公开一种Android加壳应用程序通用自动化脱壳方法及系统。本方法监控应用程序的运行,还原出应用程序的原始Dex文件。为了达到尽可能高的方法覆盖率,本方法使用虚假的参数强制反射调用应用程序定义的每一个方法,在方法执行时收集方法代码。尽管强制反射调用可能 全部
背景技术:
Android操作系统已远超其他手机操作系统,成为市场上所占份额最高的手机操 作系统。为了保护Android应用程序,使其免受篡改和逆向分析,市面上出现了一系列的加 壳服务。加壳服务在保护Android应用程序的同时,也可能会被恶意软件的作者用来隐藏恶 意行为。同时,研究人员难以发现被加壳的应用程序中是否存在漏洞和隐私泄露。因此,研 究者们提出了一系列的脱壳方案,这些脱壳方案可以分为两类: 第一类脱壳方案假定加壳服务存在一个确定的解密点,在解密点处,被加壳的应 用程序的Dex文件会被整体解密并释放到内存中。这类脱壳方案可以直接搜索或转储内存, 对应用程序脱壳。然而,目前的加壳服务采用分阶段解密的策略,这类脱壳方案不能保证得 到的Dex文件是完全解密的。 第二类脱壳方案监控应用程序的运行,并Hook住对应的系统函数,在应用程序运 行时收集应用程序被解密的代码,最终拼接成原始的Dex文件。由于加壳服务要确保被加壳 的应用程序能正常运行,因此在运行时收集的代码一定是可靠的。这类脱壳方案通常使用 辅助工具如强制执行或输入生成器提高方法覆盖率,但即便如此,他们也无法保证能收集 到应用程序的所有代码。 综上所述,加壳服务使得研究人员难以对应用程序进行有效的分析。现有的脱壳 方案也未能完美的脱壳。
技术实现要素:
针对现有脱壳方案中存在的缺陷,本发明的目的在于提供一种Android加壳应用 程序通用自动化脱壳方法及系统,可以在不具备专业逆向分析知识的前提下,完成自动化 的脱壳,覆盖尽可能多的方法,还原出程序的原始Dex文件。 为了实现上述目的,本发明采用以下技术方案: 一种Android加壳应用程序通用自动化脱壳方法,包括以下步骤: 1)对Android框架进行修改,在目标应用程序启动时创建一个新的线程,从虚拟机 的全局变量gDvm中获取已加载的Dex文件和相应的加载器ClassLoader,再使用 ClassLoader.LoadClass方法定义Dex文件中的所有Java类; 2)获取Java类中的所有方法,利用虚假的参数来强制反射调用上述方法; 3)在上述方法执行时收集被解密的代码,若一个方法为Java方法或被还原成Java 方法,其会由解释器解释执行,通过修改解释器完成代码的收集并保存到本地; 4)遍历Dex文件不同组成部分所在内存中的内容,并结合保存在本地的代码,重组 出脱壳后的Dex文件,写入外部存储介质中,完成脱壳。 4 CN 111581639 A 说 明 书 2/5 页 5)由于使用虚假的参数调用方法,方法在执行的过程中可能会抛出异常,某些异 常会使应用程序崩溃,如果方法在执行的过程中抛出异常,根据异常类型进行处理,对于可 捕获异常,使用try-catch捕获,对于不可捕获异常,重启目标应用程序并进行下一个方法 的脱壳。 进一步地 ,在目标应用程序启动时创建一个新的线程的方法是 :选取 ActivityThread类中的handleBindApplication函数添加新的逻辑,检查当前启动的应用 程序是否为目标脱壳应用程序,如果是,则创建一个新的线程,后续的脱壳操作都会在该线 程中完成。 进一步地,新线程通过虚拟机运行过程中的全局变量gDvm,访问DvmGlobals结构。 gDvm.userDexFiles保存着由自定义类加载器加载的Dex文件集,对于Dex文件集中的每个 Dex文件,访问gDvm.loadClasses,从中得到一个属于当前Dex文件的类,然后使用该类对应 的加载器ClassLoader作为当前Dex文件的ClassLoader。 进一步地,Java类中的所有方法分为两类:构造器方法和普通方法,该两类方法均 通过使用Java原生的反射机制获取,其中使用Class.getDeclaredConstructors获取构造 器方法,使用Class.getDeclaredMethods获取普通方法。 进一步地,利用虚假的参数来强制反射调用上述方法,采用的方法为:克隆使用 newInstance调用构造器方法和使用invoke调用普通方法这两条调用路径上的函数,使用 克隆的函数强制反射调用方法;其中,在克隆的函数上进行修改,使得调用时不检查参数是 否合法;调用时准备虚假的参数,如为boolean类型准备false,为int类型准备0,为类型引 用准备NULL,在反射调用方法前,使用setAccessible(true)函数以确保能强制反射调用私 有方法。 进一步地,步骤3)中,如果一个被加密的方法最终被解密成Java方法并执行,那么 无论其是被直接反射调用,被Java方法调用,还是被Native方法调用,它都会被解释器解释 执行。 进一步地,使用Portable解释器解释执行代码,在代码执行时选择了如下4种逻辑 记录方法的代码,方法执行时一定会触发其中的一个,这4种逻辑为:进入方法,从当前方法 返回,抛出异常,以及调用其他方法。在这四种逻辑中,方法都可能处于解密状态,即使Java 方法在执行时发生了动态的修改,上述的记录策略也能记录到被解密的代码,这是因为 Java解释器无法直接修改字节码,动态修改一定是发生在调用其他JNI方法的过程中。动态 修改完成后,被解密的Java方法仍旧会被Portable解释器解释执行,且至少触发上述四种 逻辑中的一种。因此,可以在方法执行时收集到被解密的代码。 进一步地,Dex文件由3个主要的段组成:头段,索引段和数据段;其中,索引段记录 了Dex文件的6个标识符列表:字符串列表、类型列表、方法原型列表、字段列表、方法列表和 类列表。重组时需要从索引段中索引多次才能得到正确的dex数据。比如,保存在头段里的 stringIdsOff记录着从Dex文件头到字符串列表的偏移。字符串列表保存着类型为 DexStringId的数据结构,通过DexStringId里面保存的stringDataOff,可以在数据段中得 到被MUTF-8编码过的字符串。类似地,可以从得到的Dex文件中提取出字符串信息、类型信 息、原型信息、字段信息、方法信息、类信息等。按照Dex文件标准规范重组出新的Dex文件; 重组时,需要计算数据信息在新Dex文件中的偏移,正确地将该偏移填入到新文件中的索引 5 CN 111581639 A 说 明 书 3/5 页 段,将数据填入到新文件的数据段;新文件头段的数据主要来源于得到的Dex文件的头段数 据,除了表示新Dex文件大小的fileSize,此数据通过计算新文件的大小得到;填入类代码 数据时,使用收集到的被解密代码。 进一步地,异常分为两种:可捕获异常和不可捕获异常,使用Java原生的try- catch机制捕获可捕获异常。对于不可捕获异常,在方法反射调用前记录相关的信息,目标 应用程序重启后,根据这些信息从下一个方法处开始脱壳。 进一步地,诸如NullPointerException和ArrayIndexOutOfBoundsException等可 捕获异常,可使用try-catch异常捕获机制捕获。如果方法强制执行时在Java层抛出了异 常,该异常可被捕获,避免应用程序崩溃。由于在虚拟机抛出异常前就收集了被解密的代 码,因此该处理策略不会影响脱壳的有效性。 进一步地,Java中的try-catch异常捕获机制只能捕获发生在Java层面的异常, Native层面的异常诸如内存访问异常等无法被捕获,且会导致应用程序崩溃。重启应用程 序时,如果从第一个方法开始脱壳流程,则已发生的崩溃仍会被触发。因此,在强制调用方 法前,记录下当前方法所属的类及Dex文件,保存在文件系统中。当应用程序重启时,根据保 存在文件系统内的信息,从下一个方法处继续脱壳,避免同一崩溃的二次触发。 一种Android加壳应用程序通用自动化脱壳系统,包括: 类获取单元,负责在目标应用程序启动时创建一个新的线程,从虚拟机的全局变 量 g D v m 中获取已 加载的 D e x 文件 和相应的 加载器 C l a s s L o a d e r ,再使 用 ClassLoader.LoadClass方法定义Dex文件中的每个Java类; 方法强制反射调用单元,负责获取Java类中的所有方法,并准备虚假的参数强制 反射调用方法; 监控单元,负责在方法执行时收集被解密的代码,若一个方法为Java方法或被还 原成Java方法,其会由解释器解释执行,通过修改解释器,在收集点处完成代码的收集并保 存到本地; Dex重组单元,负责遍历Dex文件不同组成部分所在内存中的内容,并结合保存在 本地的代码,重组出脱壳后的Dex文件; 异常处理单元,负责使用Java原生的try-catch机制捕获异常,或在方法反射调用 前记录相关信息,当目标应用程序重启后,根据所述信息从下一个方法处继续脱壳。 与现有技术相比,本发明的积极效果为: 本发明通过修改Android系统代码,强制反射调用应用程序中定义的所有方法,在 执行时收集被解密的真实代码,而后重组出脱壳后的Dex文件,实现了对加壳应用程序的通 用自动化脱壳。相比于第一类脱壳方案,本方案不直接从内存中获取Dex文件,可以保证得 到的Dex文件是完全解密的。相比于第二类脱壳方案,本方案无需借助辅助工具就能达到接 近96%的方法覆盖率,基本覆盖应用程序的所有代码。 附图说明 图1是本发明实施例中的Android加壳应用程序通用自动化脱壳方法整体流程图。 6 CN 111581639 A 说 明 书 4/5 页