浙江大学学报(工学版), 2019, 53(3): 555-562 doi: 10.3785/j.issn.1008-973X.2019.03.017

计算机技术

函数Native化的Android APP加固方法

宋言言,, 罗森林, 尚海, 潘丽敏,, 张笈

Android APP reinforcement method with function Nativeization

SONG Yan-yan,, LUO Sen-lin, SHANG Hai, PAN Li-min,, ZHANG Ji

通讯作者: 潘丽敏,女,高级实验师. orcid.org/0000-0002-8850-8380. E-mail: panlimin@bit.edu.cn

收稿日期: 2018-05-16  

Received: 2018-05-16  

作者简介 About authors

宋言言(1989—),女,硕士生,从事信息安全研究.orcid.org/0000-0001-9133-904X.E-mail:songyanyan29@163.com , E-mail:songyanyan29@163.com

摘要

调研动态恢复攻击的逻辑思路和Android APP中函数调用执行流程. 通过对原DEX文件进行重构和加密,将其关键Java函数属性改为Native,并添加壳DEX文件;Android APP启动后首先执行壳DEX文件,然后对原DEX进行解密和动态加载,当调用被保护函数时,保持该函数在内存中的Native属性,通过Hook技术和反射机制隐式恢复并执行原Java函数. 实验和对比分析结果表明,该方法能够在较低资源损耗和无需反编译源码的前提下获取高强度的保护效果,可以有效抵御静态分析攻击、DEX动态恢复和动态脱壳攻击.

关键词: APP加固 ; 函数Native化 ; Hook技术 ; 动态加载 ; Android系统

Abstract

The logic of dynamic recovery attack and the function call execution flow in Android APP was investigated. The original DEX file was reconstructed and encrypted; its key Java function attribute was changed to Native, and the shell DEX file was added. When the Android APP was started, the shell DEX file was executed first, and then the original DEX was decrypted and loaded dynamically. When the protected function was called, the Native property of the function in memory was maintained, and the original Java function was implicitly restored and executed by the Hook technique and the reflection mechanism. The experimental results show that the method obtains high level of protection without Source decompilation at lower resource losses, and can effectively resist static analysis attacks, DEX dynamic recovery and dynamic shelling attacks.

Keywords: APP reinforcement ; function-Nativezation ; Hook technology ; dynamic loading ; Android System

PDF (878KB) 元数据 多维度评价 相关文章 导出 EndNote| Ris| Bibtex  收藏本文

本文引用格式

宋言言, 罗森林, 尚海, 潘丽敏, 张笈. 函数Native化的Android APP加固方法. 浙江大学学报(工学版)[J], 2019, 53(3): 555-562 doi:10.3785/j.issn.1008-973X.2019.03.017

SONG Yan-yan, LUO Sen-lin, SHANG Hai, PAN Li-min, ZHANG Ji. Android APP reinforcement method with function Nativeization. Journal of Zhejiang University(Engineering Science)[J], 2019, 53(3): 555-562 doi:10.3785/j.issn.1008-973X.2019.03.017

随着移动互联网的发展,移动APP数量呈爆炸式增长,黑色产业链从PC端转移到移动端. Android系统是目前市场占有率最高的移动操作系统,其APP安全问题也越来越得到业界的重视. Android系统的开放性使得攻击者可以通过定制只读内存镜像 (read only memory image,ROM),利用相对成熟的反编译工具和逆向方法对Android APP进行破解、分析、植入恶意代码、重打包等恶意攻击[1]. 阿里聚安全2016年报告[2]显示,89%的热门应用存在被重打包、仿冒等现象,恶意扣费、隐私窃取等攻击行为屡见不鲜,严重损害了应用开发者的经济利益和手机用户的隐私安全. 因此,如何通过Android APP加固技术来抵御攻击者的破解和逆向,维护开发者利益,保护用户手机安全,成为研究热点. 随着Android逆向攻击技术的发展,针对不同攻击方法的加固技术不断涌现,主要包括代码混淆技术和动态加载技术.

代码混淆技术[3]的原理是通过字符串混淆、控制流混淆来提高应用代码的复杂度,其中字符串混淆指的是将函数名、类名等字符串替换为无意义的字符,控制流混淆即隐藏或更改控制流结构中的执行路径和分支路径,或插入不会执行到的分支路径. 此方法仅在一定程度上提升了攻击者阅读反编译代码时的难度[4],无法彻底抵御逆向攻击行为.

动态加载技术[5]则以保护Dalvik虚拟机可执行文件(Dalvik VM executable,DEX)[6]的机密性为出发点,DEX文件是Android APP安装包(Android package,APK)中的核心文件. 该技术通过对DEX文件进行加密和添加壳DEX文件来抵御攻击者的静态分析,当APP启动时,首先执行壳DEX文件,进而对原DEX文件进行解密并动态加载[7]. 王泽华[8]提出了基于函数抽取和动态加载的加固方法,该方法抽取函数信息至DEX文件尾部,并在其类中添加静态代码段用以还原函数. 梆梆加固方法[9]首先抽取函数,然后通过Hook技术替换调用的加载函数,实现Java函数还原. 目前国内大部分商用Android APP加固工具均采用基于函数抽取的加固方法,包括梆梆加固[10]、360、爱加密等.

基于动态加载的DEX保护方法可有效抵御攻击者的静态分析,但是被保护后的应用在运行时,内存中依然存在完整的DEX文件,攻击者可以直接通过动态脱壳攻击方法获取完整的DEX源码. 基于此问题,函数抽取与恢复技术解决了DEX文件在内存中完整性的问题,但是抽取的函数在内存中最终仍会被还原成Java形式,攻击者可以依据函数在内存中的描述信息,动态恢复抽取的函数,最终实现动态脱壳. 为解决这个问题,本文提出一种基于函数Native化的Android APP加固方法,使得被抽取函数在APP运行的过程中始终为Native属性,对抗动态恢复和动态脱壳攻击,在较低的时间资源损耗情况下,获取高强度的保护效果.

1. 相关工作

APK文件本质上是一个带有签名信息的zip格式压缩文件,其结构中的classes.dex文件是Dalvik虚拟机平台运行环境下的可执行文件,是由Java代码编译成.class文件之后,再通过dx工具生成的字节码文件,Android APP的大部分逻辑功能实现均在该DEX文件中完成,因此保护APP不被逆向和攻击的重中之重便是保护DEX文件的机密性. 随着逆向脱壳技术的提升,DEX文件保护方法也由DEX级保护发展至函数级保护,更加细化的粒度和更加深入的保护方法提供了更好的保护效果. 近年来,研究人员开始使用代码翻译、虚拟化保护技术(virtual machine protection,VMP)等实现函数的隐藏.

Mulliner[11]实现了函数级保护的APP加固工具DDI,在APP运行过程中插入Native动态链接库,通过Hook技术将Java函数变成Native函数,每个Java函数均需生成对应的Native函数. 在函数被调用时首先执行对应的Native函数,然后调用并执行原Java函数. 该方法虽然在APP运行过程中将内存中的Java函数变成Native函数,但是在函数Hook执行之前,被保护的函数为Java属性,因此存在被攻击者通过动态恢复的方法获取完整DEX文件的风险. 此外,由于该方法对每一个被保护函数均进行Hook,不同的函数需定义特定的JNI(Java Native interface)接口,因此生成库文件的过程比较复杂.

刘惠明[12]实现了应用自动原生化及混淆系统,首先将应用中原DEX文件反编译为Smali文件,然后将其中关键的Smali代码自动转换成C/C++代码并编译、混淆,即采用自定义的翻译机制来实现Java函数的隐藏. 此方法兼具高强度和兼容性,但是该方法的实施需要满足APP可反编译的条件,而目前大部分APP成形后均无法直接进行反编译,这大大降低了该方法的可用性,同时在Smali语言翻译为C&C++语言的过程中,存在难以处理的语义问题,针对链表和哈希表等复杂的数据结构,翻译难度很大,可能无法支持使用了复杂数据结构的应用保护.

VMP保护方法是目前安全性较高的一种保护方法. VMP技术通过自定义指令集和解释器,将DEX中函数的字节码全部替换成自定义的指令,运行过程中由自定义的解释器进行解释执行,从而使得内存中不会出现原始的字节码. Zhou等[13]基于此思路,实现了VMP保护工具DIVILAR,通过Hook技术修改libdvm.so下的字节码解释器来完成虚拟机保护,应用启动后,首先按照自定义的转换规则还原指令,然后交由系统原解释器解释执行,虽然安全性高,但这种逐条指令的翻译机制导致应用执行效率降低.

综上所述,现有的APP加固方法能够使函数在内存中表现为Native形式,可在一定程度上提高APP的安全性,但存在无法有效抵御动态恢复攻击、通用性不高、时间资源消耗过大的问题.

2. 基于函数Native化的Android APP加固方法原理

2.1. 原理框架

基于函数Native化的Android APP加固方法原理框架如图1所示. 首先根据待保护函数列表,对待保护APK文件中的DEX文件进行函数抽取、函数Native化等操作,进而对DEX文件进行重构和加密,然后添加壳DEX文件,生成新的APK文件. APP启动时,首先执行壳DEX,完成对原DEX文件的解密和动态加载,并实现系统函数Hook,使得保护的函数被调用时,系统函数将重定向到自定义的代码,对函数信息进行隐式恢复,继而调用原始函数. 在此过程中,被保护函数自始至终均为Native属性.

图 1

图 1   函数Native化的Android APP加固方法原理图

Fig.1   Principle diagram of Android APP reinforcement method with function Nativeization


本方法的核心部分体现在以下两方面:一是在无需反编译原APK的前提下,将被保护的Java函数转换为Native函数;二是调用被保护函数时,在不造成较大额外时间损耗的前提下,通过Hook技术和反射机制对被保护函数进行隐式恢复和调用,同时保持函数的Native属性. 大致流程如图2所示.

图 2

图 2   函数Native化流程示意图

Fig.2   Flow chart of function Nativeization


2.2. DEX重构

应用加固的第一步需对DEX文件进行重构,即根据提供的待保护函数列表,对应用APK中的DEX文件进行函数Native化操作,并隐藏函数的代码内容,待保护函数列表中需提供关键函数的函数名和所属的类名. DEX文件中每个类均由一个class_def_item结构来描述,如图3中左侧结构体所示,该结构体中包含类序号class_idx和类信息数据偏移参数class_data_off等.

图 3

图 3   DEX文件中的类结构描述图

Fig.3   Description of class structure in DEX file


偏移参数class_data_off指向的地址内容是一个class_data_item结构体,用来描述类的关联信息包括静态成员变量、实例成员变量、成员变量和函数的定义等,如图3中间结构体所示,其中encoded_method即为函数定义,此字段内容格式如表1所示,其编码格式采用LEB128(Little-Endian Base 128)[6].

表 1   类结构中的encoded_method结构体格式描述

Tab.1  Description of encoded method in class structure

名称 格式 说明
method_idx_diff uleb128 函数ID
access_flags uleb128 访问权限
code_off uleb128 函数代码偏移位置

新窗口打开| 下载CSV


描述函数定义的encoded_method结构体中,包含3个参数,其中method_idx为函数编号,access_flags为函数属性,code_off为偏移参数,指向一个code_item结构体,即函数代码段. DEX重构的目标就是修改函数属性并隐藏函数代码段,因此接下来需修改encoded_method结构体中的参数,将Java函数属性改为Native属性,并对函数代码段code_item进行加密. 函数改为Native属性后,类加载时便不会对函数代码段进行验证,因此可以对函数代码段code_item进行原址加密. 通过class_idx和method_idx定位到相应的code_off偏移字段,即可根据此偏移位找到相应的函数代码段code_item,对code_item字段进行原址加密. 加密完成后进行函数属性修改操作,修改方法以如表2所示encoded_method结构为例进行说明.

表 2   类结构中的encoded_method示例

Tab.2  Example of encoded_method in class structure

名称 uleb128值 说明
method_idx_diff B2 6E(0x3732) 函数ID为0x3732
access_flags 01(0x01) 访问权限为ACC_PUBLIC
code_off C8 DB 22(0x8ADC8) 文件偏移为0x8ADC8

新窗口打开| 下载CSV


示例中access_flags参数为0x01,表示函数属性为Java,要将函数Java属性变为Native属性,只需将access_flags赋值为access_flags | ACC_NATIVE,即参数access_flags和ACC_NATIVE取“或”操作的值,其中ACC_NATIVE为0x100,因此本例中取“或”结果为0x101,转换为ule128值为81 02. 参数access_flags赋值为81 02,长度比赋值前的01增加1位,而类中多个函数的encoded_method结构体是按顺序排列的,其中一个结构体长度增加,将导致DEX错位问题. 此问题可通过调整code_off长度来解决,函数修改为Native属性后其code_off字段值应为0,而LEB128编码中00、80 00、80 80 00均表示0,因此总能找到合适的表示形式来抵消access_flags字段长度的变化. 显然此例中code_off字段选用80 00,比修改之前长度减少1位,即可抵消access_flags字段长度的增加,在保证DEX文件结构不错位的前提下完成函数的Native化. 需要注意的是,在修改此字段之前,应将字段原值及其函数名字符串偏移、类名字符串偏移和函数编号储存在DEX文件末尾,以备函数调用时恢复之用.

2.3. 应用加壳

为保证DEX文件的机密性,需对经过重构的DEX文件进行加密,基于解密时间损耗和安全性能的折中考虑,采用对称加密方法对DEX文件进行加密. DEX文件加密完成后,在APK文件中添加壳DEX. 壳DEX中包含解壳代码,在应用运行时,实现对原DEX文件的解密和动态加载. 应用加壳前、后APK文件结构对比如图4所示. 加壳前APK结构包含左侧方框中的文件,加壳过程中将原始的class.dex文件经过DEX重构、加密变成bfsproject.jar文件,并移动到/assets文件夹中,在原DEX文件位置插入壳DEX文件,在/libs下插入用于脱壳的动态库libbfsproject.so和libSound.so. 完成加壳后,对APK文件进行重新编译和签名,生成新的APK文件.

图 4

图 4   加壳前、后的APK结构对比

Fig.4   Comparison between original APK and shelled APK


2.4. 动态加载

启动APP后,首先加载壳DEX文件,并调用文件中重写了的attachBaseContext函数,在该函数中实现对原DEX文件的解密和动态加载. 具体实现方法是调用底层函数openDexFile,输入参数为已解密的原DEX文件内存地址,输出为一个cookie值,将此cookie值作为加载器DexClassLoader的输入,即可对原DEX文件进行加载和启动.

2.5. 函数隐式恢复

在APP运行过程中,当调用到被保护函数时,对这些函数进行信息恢复和调用,同时保持函数的Native属性以抵御攻击者的窃取,是所提方法的重中之重. 函数恢复的时机有3种选择. 1) DEX文件加载时,修复DEX文件,这将导致内存中的DEX是完整的;2) DEX文件加载后,利用Android Hook Java技术,修改函数在内存中的Method结构,这需要遍历DEX文件后的每一个保护函数信息,强制加载函数所在的类,造成不必要的预加载和更长的启动延时;3) 函数调用时恢复函数信息,在最小的时间消耗前提下实现应用运行过程中DEX文件的不完整性,此为最优解. 因此函数隐式恢复的核心包括:1) 在函数被调用时进行恢复;2) 保持函数Method结构体Native属性不变.

任何一个函数在内存中都由一个Method结构体描述,其中accessFlags字段表示函数的属性,即Java函数或Native函数,insns字段为Java函数指向的字节码地址,nativeFunc字段指向Native函数的地址,具体结构如图5所示.

图 5

图 5   内存中描述函数的Method结构体

Fig.5   Method structure for function description in memory


在Android系统中,第一次调用未注册的Native函数时将自动调用系统函数dvmResolveNativeMethod,此系统函数通过遍历所有动态库查找被调用函数,并将其地址写入Method->insns字段,然后将函数调用桥dvmCallJNIMethod函数地址写入Method->nativeFunc中,保证当第二次调用此函数时,函数调用桥可从insns参数读取位置信息并调用;接下来开始执行函数. 因此在本方法中,当调用某被保护函数时,需首先通过Hook技术拦截系统函数dvmResolveNativeMethod,使得当调用被保护函数时,首先执行函数的恢复操作. 具体恢复过程如下:

1)首先复制此Native函数的Method结构体,保存至insns字段中.

2)获取函数信息,即类名、函数名和函数编号3个特征值,获取方法如图6所示. 其中函数名和函数编号分别为Method结构体中的参数name和protoIdx,protoIdx是DexProto prototype字段中的一个参数;函数所属类名为Method结构体中clazz字段指向的ClassObject结构体中的descriptor字段.

图 6

图 6   函数特征值获取方法示意图

Fig.6   Diagram of function eigenvalue acquisition method


3)根据这3个特征值寻找DEX文件尾部被保护函数信息中相应原函数的code_off字段,继而根据此字段找到函数code_item在内存中的地址.

4)经解密,将code_item字段中的registers Size、insSize、outsSize、insns等参数赋值给insns(此insns为步骤1)中保存Method结构体副本的insns)字段中Method结构体的相应参数.

5)将nativeFunc参数赋值为自定义的函数调用桥的地址,第二次调用此函数时将直接调用函数调用桥.

6)调用函数调用桥,执行Java函数.

至此,内存中insns字段中的Method结构体即为原Java函数的Method结构体,完成函数恢复.

对于被保护的函数,内存中存在2个Method结构体,一个是其Native形式的Method结构体,另一个是Native形式Method中insns字段中的Java形式Method结构体. 此Java形式的Method结构体赋值完成后,即可由自定义的函数调用桥通过反射机制来调用被保护的Java函数.

3. 实验分析

分别从抗逆向分析和性能分析2个方面对提出的APP加固方法进行实验验证,并与其他APP加固方法进行对比分析. DEX文件保护无关于APP的具体业务逻辑,但是为了获取APP运行过程中的逆向结果、时延等相关参数用以评价论文方法的防护效果,被保护的APP中需要植入自定义的测试代码,因此实验对象采用自定义的APP样本TestAPP. 样本APP中包含2套代码相同的测试函数,函数信息如表3 所示. 其中一套作为被保护函数采用所提方法进行抽取加固运行,另一套则采用Android系统默认方式进行加载运行. APP启动后,按下界面中设置的“调用”按钮,将自动调用测试函数10 000次,在函数调用前、后均输出系统当前时间.

表 3   样本APP中的测试函数信息表

Tab.3  Test function information table in sample APP

函数编号 函数名 函数声明 字节码(Byte)
Method-1 testMethod (Z)Z 1 490
Method-2 testMethod (B)Z 192
Method-3 testMethod IZ 264
Method-4 testMethod (D)Z 108
Method-5 testMethod (F)Z 1 104
Method-6 testMethod (I)Z 768
Method-7 testMethod (S)Z 490
Method-8 testMethod (String;)Z 28

新窗口打开| 下载CSV


实验环境为不同型号和系统版本的Android手机,选用的设备型号分别为三星Galaxy GT9508、小米MI 3C和HTC M8SW,系统版本分别为4.4.2、4.4.4和4.4.4.

3.1. 抗逆向分析实验

实验目的为验证所提方法是否可抵御静态分析、动态脱壳和动态恢复等攻击. 通过是否可以直接反编译出源码来衡量方法对抗静态分析的能力;通过是否可以从内存中获取完整的DEX文件来衡量方法对抗动态脱壳攻击的能力;通过是否可以从内存中获取函数Java描述信息来衡量方法对抗动态恢复攻击的能力.

实验分为3个部分. 1)静态分析[14]实验,首先使用dex2jar[15]和Java decompliler[16]对目标APK进行反编译,然后使用010Editor编辑器打开反编译结果,从而完成静态分析实验. 2)动态脱壳实验,对被保护APK使用IDA调试工具进行调试,在dvmDexOpenPartial函数处添加断点. 3)动态恢复攻击实验,即从内存中获取被保护函数Method结构体的相关信息,用以恢复DEX文件中的函数信息,从而获取完整的DEX文件,实验将函数信息通过Android Log形式输出到控制台.

静态分析实验中利用反编译工具dex2jar和dexcompliler对classes.dex文件进行反编译,结果如图7所示;利用010Editor打开bfsprotect.jar文件,结果如图8所示.

图 7

图 7   反编译实验结果

Fig.7   Decompile experimental results


图 8

图 8   010Editor静态分析结果

Fig.8   010Editor static analysis results


从反编译实验结果可以看出,壳classes.dex文件是可以被反编译的,但是壳classes.dex文件中对原DEX文件的动态加载等逻辑功能均采用Native方式实现,无法被反编译,而从010Editor静态分析结果可以看出,原DEX文件经过重构变成了一个没有可读性的二进制jar文件,无法进行反编译.

动态脱壳实验结果如图9所示. 实验结果表明,从内存中获取脱壳后DEX文件,并对其进行反编译操作,仅可看到被保护函数的声明,而无法查看其具体的代码逻辑,且由于函数抽取,内存中DEX文件一直是不完整的,攻击者无法通过dump来获取被保护函数的信息.

图 9

图 9   动态脱壳实验结果

Fig.9   Experimental results of dynamic shelling


动态恢复实验中,函数Method-1的信息如图10所示. 从实验结果可以看出,参数method->accessFlag= 0x101,表示该函数的属性为Native,即在应用运行过程中,该函数始终为Native函数. 采用动态恢复的方法,通过系统函数获取内存信息,只能获取Native形式的函数声明,无法获取Java函数的真实描述信息,即无法对DEX文件中抽取的Java函数进行信息恢复,亦即无法获取完整DEX文件对APP进行破解.

图 10

图 10   动态恢复实验结果

Fig.10   Dynamic restore experiment results


3.2. 性能分析实验

实验目的为测试所提方法中函数Native化和函数恢复对函数执行过程中时间消耗的影响,以函数执行时的平均消耗时间为衡量标准,其计算方法如下:

$ t = \frac{1}{N}\sum {\left( {t_{\rm{start}}^i - t_{\rm{return}}^i} \right)} . $

式中:tstarti为函数第i次被运行函数调用时刻,treturni为函数第i次调用时函数返回时刻,N为函数被调用次数.

首先启动并运行TestAPP,按下“调用”按钮,将自动调用未保护函数和被保护函数各10 000次,通过函数System. nanoTime()获取系统当前时间,最后根据式(1)计算并输出各函数的平均消耗时间. 实验结果如图11所示. 由结果可知,时延的波动要远小于函数运行时间的波动,即无论函数运行时间长短,经保护后的函数执行时延均在一个较为集中的范围波动,最小为45.1 μs,最大为71.3 μs,即针对任何一被保护函数,所造成的时延均相等.

图 11

图 11   函数执行平均消耗时间

Fig.11   Average elapsed time of function execution


3.3. 对比分析

从是否实现函数抽取、是否实现函数Native化、加固处理对应用运行造成的时延和加固处理过程是否需要反编译4个方面,将本文方法与现有加固方法DDI、代码翻译方法、DIVILAR进行对比. 其中函数抽取表示将DEX中的Java函数抽取到DEX外部;Native化表示在运行过程中Java函数保持Native属性;时延表示加固方法对被保护函数执行时长的影响;是否需反编译表示加固过程是否需要反编译原DEX文件方法. 对比结果如表4所示.

表 4   所提方法与现有方法对比结果

Tab.4  Comparison of proposed method with existing methods

保护方法 是否函数抽取 是否Native化 时延 是否需反编译
DDI[11] 常量
代码翻译[12]
DIVILAR[13] 8.9%
所提方法 常量

新窗口打开| 下载CSV


表4可知,DDI[11]实现了函数抽取,但在被保护函数调用之前,其属性为Java,没有实现彻底的Native化,对函数执行造成的时延为一个常量;代码翻译方法实现了函数抽取和函数Native化,但加固过程需要对源码进行反编译;DIVILAR实现了函数抽取和函数Native化,但其导致函数执行时间增加了8.9%. 本文方法无需对DEX文件进行反编译,实现了函数抽取和函数Natvie化,对不同函数执行时间有一个微秒级的等量延长.

4. 讨 论

对比分析结果可知,DDI在函数执行过程中存在属性为Java的时间段,因此存在被通过动态恢复的方法获取完整DEX文件的风险;代码翻译方法的原理是将DEX文件反编译为Smali文件,然后对Smali代码中的每一条语句进行Native化转换,因此需要对DEX文件进行反编译,对于复杂的语义,容易出现难以理解与翻译的问题,这也限制了该方法的通用性;DIVILAR对每条指令均需单独处理,造成的时延与函数的执行时间成正比,导致应用执行效率降低.

所提方法采用直接修改DEX文件中相关参数和结构的方式将Java函数改为Native函数,无需对DEX文件进行反编译,并且只修改函数的描述,而不修改函数的指令代码. 对于不同的Java函数,函数的描述方式是相同的,因而所提方法适用于任意的函数,通用性更高;同时在函数调用时的恢复过程中保持函数的Native属性. 从加固过程造成的时间消耗角度来说,所提方法中每个被保护函数运行时所增加的时延,均由Native函数反射调用Java函数这个步骤造成,而不同被保护函数的反射调用过程是相同的,与Java函数本身的运行时间无关,这也与性能分析实验的结果相符. 对于执行时间较长的函数,所提方法时间损耗更小,更有优势.

5. 结 语

本文提出了一种基于函数Native化的Android应用加固方法,该方法将被保护Java函数转变为Native函数,同时保证函数在应用运行过程中始终保持Native属性,有效抵御DEX动态恢复和动态脱壳攻击,提高了DEX文件的安全防护能力. 被保护Java函数的Native化通过修改原DEX文件来实现,隐藏函数信息后对原DEX文件整体加密. 在APP启动阶段,利用动态加载技术解密、加载原DEX文件,并将被保护函数重定向到自定义的Native函数. 当被保护的Java函数被调用时,自定义的Native函数被执行,并通过Java反射机制调用原Java函数,完成对原Java函数的调用. 实验结果表明,本文方法无需对DEX文件进行反编译,实现了函数的Native化,函数调用时在内存中始终为Native形式,无需进行动态还原,在获取高强度的保护效果的同时,具备良好的通用性,且其对函数执行过程造成的时延为微秒级,影响较小.

参考文献

RASTOGI S, BHUSHAN K, GUPTA B B

Android applications repackaging detection techniques for smartphone devices

[J]. Procedia Computer Science, 2016, 78: 26- 32

[本文引用: 1]

阿里聚安全. 阿里聚安全2016年报[EB/OL]. (2017-03-09)[2017-08-23]. https://yq.aliyun.com/-articles/72037.

[本文引用: 1]

COLLBERG C. A taxonomy of obfuscating transformations [D]. New Zealand: University of Auckland, 1997.

[本文引用: 1]

LOW D. Java control flow obfuscation[D]. Auckland: University of Auckland, 1998.

[本文引用: 1]

TSAI K. Android APP copy protection mechanism with semi-trusted loader [C] // 17th International Conference on Advanced Communication Technology. Seoul: IEEE, 2015: 464–467.

[本文引用: 1]

Android Open Source. Dalvik可执行文件格式[EB/OL]. (2014-07-14)[2017-08-23]. https://sourc-e.android.google.cn/devices/tech/dalvik/dexformat?hl=zhcn.

[本文引用: 2]

SCHULZ P. Code protection in Android [R/OL]. Technical Report 110, Rheinische Friedrich-Wilhelms-Universitgt Bonn, Germany, 2012. http://net.cs.uni-bonn.de/fileadmin/user_upload/plohmann/2012-Schulz-Code_Protection_in_Android.pdf.

[本文引用: 1]

王泽华. Android软件安全加固技术研究与实现[D]. 成都: 电子科技大学, 2016.

[本文引用: 1]

WANG Ze-hua. Research and Implementation of the Android Software Security Reinforcement Technique[D]. Chengdu: University of Electronic Science and Technology of China, 2016.

[本文引用: 1]

加固脱壳及抽代码还原方法 [EB/OL]. (2016-04-15)[2018-02-15]. http://blog.csdn.net/justfwd/article/det-ails/51164281.

[本文引用: 1]

梆梆安全. 梆梆加固[EB/OL]. (2017-01-15)[2018-02-10]. http://www.bangcle.com/.

[本文引用: 1]

MULLINER C. Android DDI: Introduction to Dynamic Dalvik Instrumentation [EB/OL]. (2014-10-15)[2018-01-02]. https://github.com/crmulliner/ddi.

[本文引用: 3]

刘惠明

安卓应用自动原生化及混淆系统

[J]. 微电子学与计算机, 2016, 33 (10): 50- 62

[本文引用: 2]

LIU Hui-ming

Automatic Android APPs translation and obfuscation system

[J]. Microelectronics and Computers, 2016, 33 (10): 50- 62

[本文引用: 2]

ZHOU W, WANG Z, ZHOU Y Z. et al. DIVILAR: diversifying intermediate language for anti-repacking on Android platform [C] // Proceedings of the 4th ACM conference on Data and Application Security and Privacy, 2014: 199–210.

[本文引用: 2]

丰生强. Android软件安全与逆向方法[M]. 北京: 人民邮电出版社, 2014:152–156.

[本文引用: 1]

Sourceforge. dex2jar introduction [EB/OL]. (2016-10-11)[2017-12-20]. http://sourceforge.net/projects/dex2jar/

[本文引用: 1]

Emmanuel Dupuy. Java Decompiler [EB/OL]. (2014-03-01)[2017-12-25]. http://jd.benow.ca/.

[本文引用: 1]

/