基于代码特征多维度分析实现Android应用的版权保护
2014-10-29李青
李青
【摘要】 随着智能终端的普及,Android平台的市场占有率已经跃居世界首位,基于Android的应用开发日益增多。但由于Android系统的开源性和开放性,在给开发带来巨大方便的同时,也给一些恶意开发者破解和修改Android应用留有可乘之机。这些恶意开发者通过利用反向工程工具来修改他人的应用后,冠以自己的名称对外进行发布销售,严重损害了原作者的利益,更有甚者在其中穿插了黄色反动信息,严重违反了国家的法律政策。本文提出通过提取Android应用代码特征后,利用组件相似度检测、Java类布局比较、代码控制流比较以及文本相似度比较四个维度来进行盗版应用自动检测。并基于该方法对Android应用发布平台反盗版的系统架构进行了设计实现。
【关键词】 Android应用 版权保护 反向工程 代码特征
一、引言
依赖着整个手机行业从功能机时代跨越至智能机时代的科技飞跃,Android操作系统已经迅速崛起,成为全球市场占有率首位的智能移动终端操作系统。它的使用涵盖了智能手机、平板电脑、电视机顶盒以及其他嵌入式便携电子设备。
Android操作系统在如此短的时间内取得了巨大的市场成功,很大一部分要归功于系统的开放性和易于上手的开发套件。Google公司为Android开发者提供了手把手的起步文档、简单易用的开发套件和在线论坛。系统基于Linux开发,代码开源可读,任何个人和第三方厂商都可以很快速的写出一个属于自己的应用。也正是因为系统的开放性和技术的透明,不良开发者可以比较容易的对应用进行反向工程,对原有应用进行小规模篡改,替换内部的资源文件,改头换面后作为自己的应用推向市场,从而从中获利。
对于各类应用发布平台而言,盗版应用会导致平台内应用大量同质化,产品品质下降,同时降低平台声誉,带来法律风险。从长远来看,这种行为更严重扰乱了Android应用市场秩序,且影响整个产业链的健康发展。
令人担忧的是,当下各种应用发布平台仅能做到对版权文档进行书面审核和人工测试。这种测试主观因素高,且费时费力。鉴于此,本文设计了一套较有效的借助代码特征分析和数据库存储比对的自动化工具來进行辅助检测。
二、Android应用篡改和盗版方式分析
知己知彼,百战不殆。只有深入了解不良开发者如何篡改应用,才能从源头上抑制他们的欺骗手段。通常不良开发者有两类。
一类是“盗版商”,他们获取利益的主要手段是将市面上的应用进行小规模的修改,重新包装,然后作为一款新的应用进行上市推广。通常他们会首先获取Android应用的可执行文件(apk文件),通过反向工程工具(例如APKTools)进行反编译。在反编译后得到资源文件、配置文件、smali代码和动态链接库文件。其中,资源文件是安卓应用在执行过程中所需要的一些图片、布局和字符串等文件;配置文件是Android应用的权限设置和一些基本程序信息;smali代码实质上为反编译后的代码,但是可读性较差,如果原作者在编译时使用了代码混淆,smali基本不可读懂;动态链接库为程序运行过程中需要调用的一些外部函数。从反编译后得到的这些素材来看,修改者最容易做到的是直接替换资源文件,特别是更换图片或者字符串(参见图1)。而更有能力的开发者,在源代码未被混淆的前提下,则可以通过修改配置文件和smali代码,绕过一些校验功能,并增加一些自己的功能代码,使得新的程序与原有程序在体验上有一定差异。
另一类是“翻版商”,他们和“盗版商”的最大区别是:“盗版商”通常没有应用的源码,他们的主要盗版工具是反向编译;而“翻版商”实际上是原版应用的作者或者获得了原版应用的源码。“翻版商”可以对源码进行大量的类名替换或者函数名替换、注入新的代码逻辑或者修改资源以后,将原应用改头换面作为一款新的应用推向市场。“翻版商”通过将一款应用复制为多款应用来躲避应用市场的监督管控,达到大量吸费的目的。
但无论上述哪种不良开发者,通常都会从成本出发,避免对应用进行过于复杂的修改。一般的做法是直接替换资源文件,使应用的体验有直接的变化。如果一款应用只是部分借鉴了另一款应用的思路或者功能,但是算法和架构完全自行重写,那么就不能够认为是恶意盗版。这就好比OICQ和ICQ的关系,不能认为他们功能类似,就认定前者盗版后者。因此,“盗版程序”和“翻版程序”从代码分析上来看,基本特征都得以保留。这也为接下来子反盗版之路中的“证据”捕捉,提供了足够的信息。(图1)
三、四种代码相似度判定维度介绍
针对上述不良开发者通用的盗版手段,本文将着重从反编译后的代码寻找蛛丝马迹,以此来判定两个Android应用是否在整体上相似。这可以从四个方面入手。
3.1 组件相似度
在Android操作系统中,应用程序执行的单元是系统预定义的各种组件。组件相似度检测可通过解析安装包中的配置文件内容来得到程序的各个组件声明和之相关联的参数及资源信息,最终进行相似度比较。
确切的说,Android操作系统提供给开发者预先封装好的类作为应用程序中的基本组件,它们是:Activity、Service、Content Provider和BroadcastReceiver。而在组件之间,Android系统提供了Intent作为内部信息传送方式。任何Android应用,都需要通过继承、调用和扩展以上四大基本组件来构造自己。
同时,Android系统要求开发者在一个配置文件(AndroidManifest.xml,参见代码1)中将自己定义的组件以及组件间用于通信的Intent全部声明出来。该配置文件同时还定义了整个应用所需要的系统权限。
因此,通过解析反编译后的AndroidManifest.xml便可以知道,一个应用中有多少个自定义Activity、Service、Content Provider和BroadcastReceiver,同时也能知道,他们之间谁和谁交互了哪些Intent。
对于普通的修改者而言,这个方法几乎完全可以决定源码拷贝是否存在。而对于有能力替换所有文件名称甚至类定义的不良开发者而言(虽然从成本考虑通常不会如此,且迄今为止smali注入基本都仅限于函数级,该假设仅为了考虑到所有可能性),以上各种组件声明、组件和组件之间的通信关系,也能给两个应用的相似度判断带来很大的帮助。
代码1. AndroidManifest.xml样例
3.2 Java类布局比较
Android操作系统的代码开发是基于Linux和Java的。 Java语法中,每定义一个类,都需要指定这个类所在的包(Package),以及该Package下的各层目录。这是一种树型结构,表示了包、目录路径和类的关系。树的根节点代表程序的根目录(即最顶层的包),分支节点代表程序子目录,叶子节点是具体的类。
通过反编译后的smali代码,可以推导出软件的整体类布局树,然后通过树路径相似度矩阵算法或者编辑距离算法比较得出Java类布局相似度。
3.3代码控制流比较
一个应用包含的自定义函数少则数十个,多则上万个。这些函数之间有着错综复杂的调用关系。把函数的调用关系抽象出来,可以得到一个有向图。图中每个节点代表一个函数,有向边代表与之相连的两个节点(函数)之间存在调用关系。这样的有向图,在本文中被定义为代码控制流。(见图2)
图2. 代码控制流比较
较有能力的不良开发者可以通过smali注入来进行函数级的修改。然而与一个应用中数量巨大的函数调用关系相比,这点修改在代码控制流相似度比较中通常显得微不足道。
3.4 文本相似度比较
文本相似度比较已经广泛应用于信息检索、机器翻译、自动问答等系统。目前可以搜索到的算法就有余弦算法、BM25算法、Nakatsu算法和LD算法等多种。
反编译后的smali代码本质依然是文本文档,将传统文本的比较方法借鉴到代码比较中也不算是完全的创新手段。相信大多数程序员都有过使用diff命令或者BeyondCompare这样的工具进行代码比较。只是此处的文本相似度更具备函数级的针对性,而非diff命令的逐行文本精确匹配方式。
我们已经在文章中多次强调,不良开发者不会投入巨大的精力去修改通篇代码。并且在现实中,也没有人有能力去通过修改smali来完全替换类级别的构造。如果原作者在编译过程中开启了代码混淆,反编译后的smali代码将完全不可读。考虑到以上这些因素,在代码层面上,引入文本相似度比较手段,针对作者自定义的函数进行相关性统计,在协助判定两个应用的相似度上,是相当有效的手段。
四、基于多维度的应用相似度判定算法
正如前文中描述的,通过反编译应用的APK包,可以得到该应用的配置文件、smali代码、资源文件和动态链接库。忽略掉容易被替换的资源文件和不会被改变的动态链接库。上述四个维度相似度的判定将主要利用配置文件和smali代码。其中:
1、通过比较两个应用的配置文件(AndroidManifest.xml)中組件和组件间的通信关系(Intent),可以得到组件相似度的最终值,设为A。
2、解析smali代码中各文件的头部信息,查找关键字为.class之后的内容,便可得到包和目录路径(参见代码2)。将路径信息抽象为路径树后,利用树相似度比较算法,可以得到应用的Java类布局相似度,设为B。
3、通过分析smali代码和smali语法说明可以知道,smali代码中函数调用都是以invoke-xxxx{parameter}, methodtocall的格式进行的。以invoke-作为关键字查找,定位到methodtocall(被调用函数)[2],便可以得到代码控制流图(参见代码2),然后使用同构图算法进一步得到应用的代码控制流相似度,设为C。
4、最后,使用invoke-查找出所有的函数调用行,通过空格分解出关键字,分别定义为操作符、参数、被调函数。在去除操作符、参数、系统函数调用等可能干扰文本特征的因素后,利用余弦相似度算法(当然,其他文本相似度比较算法也可)对两组应用的smali代码进行文本相似度检测,则可以得到文本相似度,设为D。
根据应用的特质和应用平台自身的情况,可以将上述四种比较结果直接输出进行可视化比较,考虑有2个维度的相似度在80%以上即可判定为相似。通常情况下,组件相似度和文本相似度比较能够快速的定位到直接替换资源文件的“盗版软件”,而Java类布局相似度和代码控制流相似度能够准确定位替换了源码函数名和类名的“翻版软件”。(代码2)
五、应用相似度判定系统设计
以上算法使用了四个维度相似度判定后的方式,这为实际生产使用提供了可操作性。对于一个应用发布平台而言,在系统设计和实现时需要兼顾成本和效率。
对于每一个进入系统的应用,反编译该应用后,系统应当存储应用的组件结构、组件关系、树形结构、有向图结构、配置文件和smali文件关键字向量。在日常的业务流程中,通常需要在线进行应用特征查找和比对,考虑到应用发布的数量巨大,这些数据也并非结构化数据,使用针对大数据和文本处理设计的Nosql数据库能够较好的降低成本提高效率。而出于快速响应的要求,在运算方面,建议使用多服务器并行的算法,利用分布式运算来缩小整体运算时间,提升用户感知。使用Map-reduce的算法加多台刀片机可能要比使用少量的多CPU小型机要更加经济和有效[3]。
应用相似度的最终结果可以使用报表或者图形化界面展示,作为应用发布平台流程环节中的参考。应用发布平台既可以在应用申报过程中利用该能力判定一款新应用是否与平台中已有应用重合。也可以反向利用该能力,在某款平台中应用需要重传包体的时候,检测包体是否被改动过,避免二次测试浪费人力。
六、结束语
随着Android阵营的日益强大,Android应用市场的管理也将越来越规范化。对于各应用发布平台而言,如何有效的保障平台内应用水准,缩短应用审批流程,提高应用上线速度,将决定其成败。
本文使用了组件相似度比较、Java类布局比较、代码控制流比较和文本相似度比较四个维度,探测应用相似度,最终输出报表或者图形化界面,供应用评审人员参考和查证。应用发布平台可以在以较低的成本建设该能力平台后,使用该能力进行应用的初步筛选盗版和简化应用二次测试过程,从而减少人力成本,提高审核效率。然而,Android作为Java语言的延伸产品,想要完全防止代码反编译和篡改几乎不可能。技术的进步会使应用篡改的手段更加丰富,防范和鉴别不良应用的方式也需要随着时代和科技的进步不断的优化和扩展。
参 考 文 献
[1] Android-apktool A tool for reverse engineering Android apk files[EB/OL]. http://code.google.com/p/android-apktool 2003-11-11.
[2] Smali An assembler/disassemble for Androids dex format[EB/OL]. https://code.google.com/p/smali. 2013-11-11.
[3]潘偉,利用文本余弦相似度实现Android应用的版权保护[J],中国新通信,2014(2),P53-55.
[4] Cosine similarity From Wikipedia, the free encyclopedia[EB/OL]. http://en.wikipedia.org/wiki/Cosine_similarity. 2014-4-14.
[5] How to avoid reverse engineering of an APK file? [EB/OL]. http://stackoverflow.com/questions/13854425/how-to-avoid-reverse-engineering-of-an-apk-file. 2013-2-8