APP下载

基于自修改字节码的Android软件保护技术研究

2016-05-09刘克胜邱世万

计算机应用与软件 2016年4期
关键词:调用字节逆向

高 琦 刘克胜 常 超 邱世万

基于自修改字节码的Android软件保护技术研究

高 琦 刘克胜 常 超 邱世万

(合肥电子工程学院 安徽 合肥 230037)

随着侵权现象的不断发生,加强Android软件的保护已成为一个研究热点。对软件逆向工程及其对抗措施进行分析和评价,指出重点的研究领域;针对Android软件逆向工程,在研究APK安装原理及dex文件格式的基础上,采取软件运行时自修改dalvik字节码的方案有效改变了代码的执行流程,增加了代码的迷惑性。通过实验实现对软件关键模块的隐藏,使分析者无法得到正确的代码流程,证明了该方法在软件保护领域具有可行性,为软件保护提供了新的思路。

Android 软件保护 字节码 dex文件 代码自修改

0 引 言

Android软件市场发展十分迅猛,根据360公司2014年的统计数据[1],仅国内37个大型市场中,软件数达50万以上的就有6个,其中3个市场的软件数超百万。但市场繁荣的背后隐藏着严重的版权保护问题,如游戏厂商“Dead Trigge”因软件盗版而被迫免费出售软件的案例曾引起广泛热议[2],给开发商带来巨大损失。更为严重的问题是,软件破解的方法被大量用于恶意代码的编写,如伪装成合法应用窃取用户敏感信息的恶意软件[3],不但侵犯了开发者的版权,更损害了用户的利益和个人隐私。文献[4]详细说明了这种恶意软件从合法逆向、代码分析、恶意篡改到重打包生成APK并发布的整个过程。

程序自修改(SMC)是一种允许代码在运行时对自身进行修改的技术手段,最早由日本研究者于2003年提出[5],现在已比较成熟[6],相关文献[7,8]将此方法进行改进以应对动态分析技术的发展,取得了理想效果。2013年,Bluebox Scurity网站的一篇文章[9]为自修改技术在Android移动端的应用提供了启示。本文在分析Android软件静态分析技术的基础上,重点研究了APK在系统中的安装及APK的可执行文件格式,掌握了dalvik字节码在系统中的存放形式,并将SMC技术原理与Android系统架构和软件格式相结合,提出了一种基于自修改dalvik字节码的Android软件保护方案,并编写实例进行了测试。一方面,将SMC技术用于Android系统,扩展了其应用范围,另一方面,本文实现的方法可以有效地提高Android平台软件对抗逆向工程的能力。

1 Android软件逆向及对抗方法

1.1 Android软件逆向工程

逆向工程,通常也称之为Android静态分析,指的是采用词法分析、语法分析等手段生成软件的反汇编代码,分析员通过阅读代码掌握程序功能的一类技术。在实际操作中,分析员通常会采用动静结合的方法开展分析,但静态分析仍在其中起主要作用。静态分析的基本方法是代码的反汇编和语法分析,通过分析代码获取目标软件各功能模块及其实现方法。

Android平台软件通常基于Java语言编写,经.class文件转化成.dex文件,并被dalvik虚拟机所解释。反汇编程序基于dex文件格式编写,将Java代码反汇编生成一种smali格式的语言文件,该文件分别为程序的每一个抽象类、普通类、内部类或接口生成一个对应的smali文件,按原代码的组织形式呈现在用户面前。常用的反汇编工具是baksmali、apktool和dex2jar。

1.2 对抗逆向工程的Android软件保护技术

如何有效保护软件版权一直是开发商关注的重点,围绕该问题业界提出了大量解决方案。目前,对抗逆向分析的方法大致可以归为以下几类:

(1) 核心模块隐藏:修改dex文件特殊字段的值可以实现关键方法的隐藏,但字段值的改变很容易被有经验的分析者发现;动态加载函数也允许将部分代码以资源形式隐藏在本地或云端,但与云端的交互受网络条件和用户资费承受能力的制约;利用Java语言的反射机制[10]实现函数功能也能隐藏代码意图,但通常仍不可避免地需要将相关参数存储于云端。

(2) 软件完整性校验:对dex文件或整个APK计算hash值,结果存储于云端或资源文件中,每次运行时都计算该hash值,与存储的值进行比较。但是这种方法可以通过修改代码逻辑使之失效。

(3) 破坏代码可读性: “append”函数允许逐个字符地产生字符串数组,以增大分析者提取关键字段的难度;也可以通过使用goto指令实现代码的乱序;dexguard或proguard等工具对软件进行的处理,隐藏了类和方法的名称,使分析者无法直接判断代码作用。

(4) 使用NDK:原生代码的逆向分析难度远远大于Java层代码,因此软件的核心功能通过C代码实现可以增强保护。

(5) 加壳:对关键代码进行加密处理。

(6) 逆向工具对抗:对逆向工具进行分析,寻找其缺陷,有针对性地破坏其功能。Manifest欺骗通过在AndroidManifest文件的节点加入未知id,破坏apktool工具的重打包过程;伪加密则利用Android系统解压缩zip文件的缺陷,将general purpose bit flags字段的第0位置1,干扰apktool工具对文件的解析。

综合对上述六种方法的分析,目前逆向工程的对抗技术主要存在两点不足:

一是代码阅读的难度虽然增大,但执行流程没有改变,有经验的分析者完全有能力克服阅读上的障碍,因此,需要在提高代码不可读性、改变代码执行流程方面加以研究;

二是针对逆向工具对抗的方法具有时效性,随着分析技术的不断发展,对抗方法也需要不断改进,因此,软件保护的重点应当是对代码本身的保护。

基于此分析,本文主要研究通过软件运行时修改代码执行流程的方法保护代码。

2 APK安装及其在系统中的运行

APK是Android平台的软件安装包,DEX文件是可执行的Android程序。本节结合Android4.0版本源代码研究了系统对APK安装包进行的处理过程,并分析了dex文件格式,为自修改dalvik字节码提供了理论基础。

2.1 APK的安装过程

分析APK文件的安装过程,重点研究APK安装后代码及数据的存放,梳理软件在系统中的运行模式,为正确定位dalvik字节码的内存地址提供理论支撑。

系统软件包packageinstaller.apk接收到系统的Intent后开始软件的安装。分析源码发现这一过程的最终落脚点是frameworksasecmdinstalldcommands.c中的方法install(),该方法执行完毕后通过socket向系统上层报告软件安装信息。

APK文件本质是一个压缩包,包含META-INF(签名信息)、res(资源文件)、AndroidManifest.xml(配置文件)、classes.dex(Dalvik字节码)、resources.arsc(二进制资源文件)、lib(原生库)等内容。APK安装时,系统首先将APK复制于/data/app目录下,然后分别将APK的数据部分和dex可执行程序文件部分存于/data/data和/data/ dalvik-cache目录,其中数据部分包括databases数据库目录、cache缓存数据目录、file应用程序控制的文件目录、lib库目录。Android程序首次启动时,Dalvik虚拟机通过依存关系树优化程序代码,包括将APK中dex格式优化为odex格式,并删除原dex文件。odex文件是Android平台的可运行文件,比dex文件体积小。这种优化可以加快软件启动速度,减少对RAM的占用。

2.2 dex文件与odex文件的格式

Dex文件是软件的可执行程序在内存中的存放形式,修改dalvik字节码的本质是对dex文件的修改,研究该文件格式,重点是研究函数的字节码在文件中的存放位置和存放格式,为自修改dalvik字节码的实现提供框架支撑。

Android4.1以前版本的源码的文档dex-format.html记录了dex的文件格式,本文主要结合Android4.0版本源码对相关内容进行分析和梳理。

Odex文件被视为dex文件的超集,其文件结构如图1所示。

图1 Odex文件结构

综合代码中对odex文件的叙述,可以用如下的结构对其进行定义,其中header是文件头,dexfile是dex文件。

struct ODEXFile{

DexOptHeader header;

//文件头

DEXFile dexfile ;

//dex文件

Dependences dependlib ;

//库

ChunkDexClassLookup classlook;

//辅助数据

ChunkRegisterMapPool Registerpool;

//辅助数据

ChundEnd end;

//文件结束

}

源码中的dalvik/libdex/DexFile.h文件对该结构体的各个要素在dalvik虚拟机中的映射作了定义。文件头结构DexOptHeader中,dexOffset代表dex文件头偏移,dexLength代表dex文件总长度。

struct DexOptHeader {

//odex文件头

u1 magic[8];

/* includes version number */

u4 dexOffset;

/* file offset of DEX header */

u4 dexLength;

u4 depsOffset;

/* offset of optimized DEX dependency table */

u4 depsLength;

u4 optOffset;

/* file offset of optimized data tables */

u4 optLength;

u4 flags;

/* some info flags */

u4 checksum;

/* adler32 checksum covering deps/opt */

};

结构体的dexOffset字段记录了dex的基地址偏移。

Android系统对dex文件结构的定义如图2所示。

图2 Dex文件结构

Dalvik虚拟机在源码中将文件映射为DexFile结构体:

struct DexFile {

/* directly-mapped ″opt″ header */

const DexOptHeader* pOptHeader;

/* pointers to directly-mapped structs and arrays in base DEX */

const DexHeader* pHeader;

const DexStringId* pStringIds;

const DexTypeId* pTypeIds;

const DexFieldId* pFieldIds;

const DexMethodId* pMethodIds;

const DexProtoId* pProtoIds;

const DexClassDef* pClassDefs;

const DexLink* pLinkData;

……

}

其中DexHeader是文件头,它的methodIdsSize、mehtodIdsOff、classDefsSize、classDefsOff指针分别代表DexMethodId(方法结构体)及DexClassDef(类结构体)字段的大小和偏移。

struct DexHeader {

//dex文件头

u1 magic[8];

/* includes version number */

u4 checksum;

/* adler32 checksum */

u1 signature[kSHA1DigestLen];

/* SHA-1 hash */

u4 fileSize;

/* length of entire file */

u4 headerSize;

/* offset to start of next section */

u4 endianTag;

u4 linkSize;

u4 linkOff;

u4 mapOff;

u4 stringIdsSize;

u4 stringIdsOff;

u4 typeIdsSize;

u4 typeIdsOff;

u4 protoIdsSize;

u4 protoIdsOff;

u4 fieldIdsSize;

u4 fieldIdsOff;

u4 methodIdsSize;

u4 methodIdsOff;

u4 classDefsSize;

u4 classDefsOff;

u4 dataSize;

u4 dataOff;

};

DexClassDef有一个classDataOff字段,指向一个DexClassData结构体,该结构体的directMethods字段又指向一个描述程序中调用的方法的DexMethod结构体,声明如下:

struct DexMethod{

//方法信息

u4 methodIdx;

u4 accessFlags;

u4 codeOff;

}

codeOff字段指向DexCode结构体,它的定义为:

struct DexCode {

//方法的实现代码

u2 registersSize;

u2 insSize;

u2 outsSize;

u2 triesSize;

u4 debugInfoOff;

/* file offset to debug info stream */

u4 insnsSize;

/* size of the insns array, in u2 units */

u2 insns[1];

}

其中insns字段内存储了该方法的dalvik字节码,进行字节码修改,主要就是寻找这个字段,并修改该字段的内容。

2.3 Android原生程序及其调用

原生代码运行在系统库层,对dalvik字节码的修改只能通过原生代码实现, 通过Java语言的JNI调用与原生库进行交互,利用NDK编程生成动态链接文件实现对字节码的修改。

NDK(native development kit)是Android平台对C和C++代码的支持,Android自诞生起就表达了对C代码的支持,NDK将这种支持加以具体实现。它包含一系列动态库开发工具,集成交叉编译,通过mk文件对CPU、平台等硬件条件进行透明化处理,生成.so文件并与Java层生成的文件随应用一起打包入APK压缩包,向市场发布。但Andoid明确表示NDK只支持部分功能,无法实现全C代码的Android软件。NDK编程的优点在于代码重用和代码保护,可以增加代码跨硬件的可移植性,或增大分析者逆向获取源代码结构的难度;它的缺点在于代码复杂度的大幅增加,可能给开发者带来不便和风险。因此,编程人员往往只对关键代码或对系统性能有较高要求的部分才使用C代码实现,如涉及显示器的操作[11,12]。

Java本地调用JNI是Java语言平台的组成部分,它提供了对C代码的支持,使得原生库像普通Java方法一样为主程序所调用,同时JNI也提供了原生代码对java代码的调用方案。它有一套与Java语言相对的数据类型、数据结构及函数标记。在JNI平台的支持下,Android应用可以通过灵活地调用C代码实现更多功能。如图3所示。

图3 JNI调用示意图

JNI的书写步骤包括:

(1) 编写带native声明方法的Java类;

(2) 使用Javac编译Java类;

(3) 使用Javah+Java生成头文件;

(4) 跟据头文件,实现本地代码;

(5) 编译生成动态连接库。

3 基于自修改字节码实现关键代码隐藏

本节设计了一段示例代码,该示例软件的作用是对数据进行简单加密,即把用户输入的数据按1.8倍输出,用以加密数据。同时,在逆向分析时,攻击者通过静态分析得出的结论却是用户输入的数据被直接输出,未进行乘法处理,从而无法分析出软件的真实流程。图4是示例软件的设计思路。

图4 软件设计

为了更加清晰地展示实验内容,该软件只实现了关键代码,修饰性的代码全部去除。

3.1 执行流程

(1) Java层主函数代码设计

创建包com.tim.parsetest,涉及的具体操作的实现代码在类文件SetDataMethod中实现;

设计一个方法setdata(),供主函数调用;

设计一个方法setdatahidden(),作为调用setdata ()时,软件实际运行的代码;

在主界面MainActivity中调用方法setdata();

本实验中,为了使实验内容更加直观,为输入数据赋值“1.0”,直接在界面输出结果值。

(2) 启动C层代码

Android系统通过System.loadlibrary()函数调用动态链接库.so文件,并首先执行JNI_Onload()函数。该函数主要目的是进行JNI版本的声明和代码初始化,相当于一个初始化函数。

本实验在JNI_Onload()函数内调用动态链接库parsingdex. so,该动态链接库的作用是在C层完成字节码的修改和替换。确保在软件调用动态链接库时,setdatahidden()对setdata()的替换可以在C层代码初始化期间完成,不需要显性地在Java层调用该方法,从而确保了setdatahidden()函数在代码执行路径中不出现。

(3) 寻找对应方法的DexCode结构体

由上文2.2节的分析,DexCode结构体中存储了方法对应的字节码,因此代码执行替换操作之前必须正确寻找和定位setdata()与setdatahidden()对应的的DexCode结构体。

第一步,定位odex文件,获取odex文件的基地址odexbase。先是跟据odex文件在系统中的存诸路径及格式构造odex文件名:

odexname=/data/dalvik-cache/data@app@com.tim.parsetest-%d.apk@classes.d

然后调用getmodulebase()方法搜索本进程的proc/self/ maps文件获取odex的基地址。

第二步,获取odex内存块大小odexsize。通过getmodulesize()方法获取系统maps文件内odex所占内存的起始值和结束值,它们的差值就是odex的大小。

第三步,获取dex文件位置dexbase。调用getdexstart()方法,在odex文件头读取dex文件偏移字段dexoffset的值,采用odexbase+dexoffset的方法得到dex内存块基址。读取maps文件的伪代码可如下所示:

fp=fopen(proc/self/maps);

while(fgets(line,fp)=1){

if(strstr(line,odex文件名)=1){

读取该行地址信息;

}

}

fclose;

第四步,解析dex文件头。对DexFile结构体的关键字段赋值,方便下一步操作。

第五步,调用getmethod()方法,寻找DexCode结构体。在系统中搜索该结构体的流程如图5所示。

图5 DexCode结构体的确定过程

通过枚举类结构DexClassDef,确定对应SetDataMethod类的DexClassDef结构体,同理,枚举DexMethod确定setdata()与setdatahidden()方法的DexMethod结构体。

(4) 修改读写权限

要想隐性地修改setdata()方法的dalvik字节码,必须调用mprotect()函数为相应内存区间增加PROT_WRITE声明,赋予软件将字节码写入setdata()的权限。

(5) 实现字节码的写入

以字符串数组的形式逐个替换setdata()方法的insns[]字段。可用如下伪代码表示:

mprotect(dex,PROT_READ|PROT_WRITE|PROT|EXEC);

for(i=0;i

insns_setdata[i] = insns_setdatahidden[i];

}

mprotect(dex,PROT_READ|PROT_WRITE);

//恢复权限的目的是防止软件在运行时出现不可预知的错误

3.2 实验结果

对代码进行编译和组建,生成dalvikmodifytest.apk文件。

利用工具ApkIDE对文件进行逆向,分析其软件功能。为了直观地展现结果,APK文件在组建时未做任何混淆。

(1) 静态分析

对软件进行逆向,发现主程序调用了setdata()方法,参数1.0,逆向代码如下:

invoke-virtual {v0, v2, v3}, Lcom/tim/parsetest/SetDataMethod;-> setdata(D)V

Setdata()方法中,输入的参数1.0被直接存入data域,此时,data=1.0,逆向代码为:

iput-object v0, p0, Lcom/tim/parsetest/SetDataMethod;->data:Ljava/jang/ Double;

随后getdata()方法将data值直接输出:

iget-object v0, p0, Lcom/tim/parsetest/SetDataMethod;->data:Ljava/jang/ Double;

return v0;

从逆向分析判断,软件将1.0存入data域后,通过getdata()直接输出,其结果应与输入参数一致,为1.0。从分析过程来看,setdatahidden()方法并未被调用。

(2) 实际运行

在Android 4.0版本系统中运行该APK,界面中输出了getdata()函数的运行结果如图6所示。

图6 真实的实验结果与逆向分析结果不符

按照逆向工程的步骤得出的结果是1.0,但实际运行的却是输入数据1.8倍的结果1.8,说明该软件并未执行setdata()方法,而是在调用setdata()方法时,执行了setdatahidden()方法的字节码。因此,软件的关键加密模块setdatahidden()被隐藏,受到了保护。

本实验成功地迷惑了逆向分析者,实现了对dalvik字节码的自修改,更改了代码的执行流程,增加了代码的迷惑性,证实了该方法在软件保护领域对抗逆向工程的可行性。

4 结 语

本文分析了软件逆向工程及其对抗,将研究点关注于增加代码迷惑性和改变代码执行流程,在研究了APK安装过程、dex文件结构及JNI调用的基础上,编写了一个简单的示例代码实现了自修改dalvik字节码,并证实了该方案在软件保护上的可用性和广阔前景。

下一步主要有两个方面的工作,一是采用更加成熟的方法实现字节码写入,以防止可能出现的内存块溢出;二是进一步研究该方法在对抗软件动态分析方面的可行性。

[1] 360互联网中心.2013年中国手机安全状况报告[EB/OL].(2014-02-11).[2014-09-11].http://awhzfien7r.l5.yunpan.cn/lkl QPERX j6bcPGgA.

[2] Android Police.Just How Bad Is App Piracy On Android Anyway? Hint: We’re Asking The Wrong Question[EB/OL].(2012-07-31).[2014-09-11].http://www.androidpolice.com/2012/07/31/editorial-just-how-bad-is-app-piracy-on-android-anyways-hint-were-asking-the-wrong-question/.

[3] 360互联网中心.2014年第一期中国移动支付安全报告[EB/OL].(2014 -03-11).[2014-9-11].http://aqvs9knlja.l5.yanpan.cn/lk/Q4VgpLKMLV9Xq.

[4] 伍景珠.基于Android平台的软件保护方案的研究与实现[D].北京:北京邮电大学,2013.

[5] Kanzaki Y,Monden A.Computer Software and Applications Conference[C].Dallas,USA:COMPSAC,2003.

[6] 徐江凌.基于反跟踪和自修改代码技术的软件保护系统设计[D].成都:电子科技大学,2010.

[7] 王祥根,司端锋,冯登国.一种基于自修改代码技术的软件保护方法[J].中国科学院研究生院学报,2009,26(5):688-694.

[8] 高兵,林果园,王莹.基于代码自修改的软件反跟踪技术结构[J].信息网络安全,2014(5):46-51.

[9] Patrick Schulz.Android Security Analysis Challenge Tampering Dalvik Bytecode During Runtime[EB/OL].(2013-03-25).[2014-09-11].http://blog.bluebox.com/2013/03/25/android-security-analysis-challenge-tampering-dalvik-bytecode-during-runtime/.

[10] 李兴华.Java开发实战经典[M].北京:清华大学出版社,2009:576-606.

[11] 马建设,赵雪红,苏萍,等.基于Android系统的视频播放器开发[J].计算机应用与软件,2013,30(11):136-137,175.

[12] 杨倩,杨明赵.Android显示服务器——SurfaceFlinger研究[J].计算机应用与软件,2014,31(6):324-326.

RESEARCH ON ANDROID SOFTWARE PROTECTION BASED ON SELF-MODIFYING BYTE CODE

Gao Qi Liu Kesheng Chang Chao Qiu Shiwan

(HefeiElectronicEngineeringInstitution,Hefei230037,Anhui,China)

Along with the copyright infringement occurs continuously, to strengthen the protection of Android software has become a hot research topic. In this paper we carry out analysis and comment on software reverse engineering as well as its countermeasures, and point out the research focus. Aiming at reverse engineering of Android software, after studying APK installation principle and the format of DEX file, we employ the scheme of self-modifying Dalvik byte code during the operation of software to have effectively changed code execution process, and increased the perplexity of code. Through the experiment we realise the concealment of key software modules, and lead to the analyser failed in finding the correct code flow, this proves that the method has the feasibility in software protection field, and provides a new idea for software protection.

Android Software protection Byte code Dex file Code self-modifying

2014-10-21。高琦,硕士生,主研领域:信息安全。刘克胜,教授。常超,博士生。邱世万,硕士生。

TP311.54

A

10.3969/j.issn.1000-386x.2016.04.054

猜你喜欢

调用字节逆向
逆向而行
No.8 字节跳动将推出独立出口电商APP
核电项目物项调用管理的应用研究
No.10 “字节跳动手机”要来了?
LabWindows/CVI下基于ActiveX技术的Excel调用
简谈MC7字节码
基于系统调用的恶意软件检测技术研究
逆向工程技术及应用
利用RFC技术实现SAP系统接口通信
人类进入“泽它时代”