代码混淆技术有哪些(新手必知这7个代码混淆技术)

摘 要:

代码混淆,作为一种知识产权的保护手段,经常被开发者用于保护应用程序的代码资源。然而,随着Android市场份额的不断扩大,越来越多的恶意软件也开始使用代码混淆来隐藏其真实意图,对抗常见的检测工具。针对Android系统常见的四种代码混淆手段:标识符重命名、字符串加密、Java反射以及应用加壳,在Android软件数据集上进行了调研和分析,分析结果表明,Android恶意软件对代码混淆的使用情况与普通软件差异较大,能够辅助安全工程师对恶意软件进行识别与检测。

内容目录:

0 引 言1 基本原理

1.1 APK文件的结构

1.2 代码混淆在Android中的使用

1.2.1 标识符重命名

1.2.2 字符串加密1.2.3 Java反射

1.2.4 应用加壳

2 扫描框架的设计与实现

2.1 标识符重命名的检测方法

2.2 字符串的检测方法

2.3 Java反射检测方法

2.4 应用加壳检测方法

3 扫描结果与分析

3.1 数据集

3.2 标识符重命名扫描

3.3 字符串加密扫描

3.4 Java反射扫描

3.5 应用加壳扫描

4 结 语

00

引 言

代码对于普通开发者而言是非常重要的知识产权。为了保护代码资源,防止其被随意剽窃,开发者通常会使用代码混淆这一技术。然而,代码混淆无异于一把双刃剑,虽然能有效防止开发者的代码被恶意使用,但也极大程度上增加了安全分析师的分析成本。此外,恶意软件开发者还可以利用代码混淆来隐藏自己的真实意图,从而逃脱自动分析工具的扫描。与传统领域的应用相比,因为Java语言天生的易于逆向的特征,代码混淆技术对于安卓(Android)应用具有更重要的意义。

Android操作系统是使用人数最多的移动操作系统。统计信息显示,截至2020年12月,谷歌官方应用程序商店(Google Play)共有超过350万款应用可供下载,月平均下载人次超过500万。因此,对Android应用的代码混淆技术使用情况进行调研具有很重要的意义。一方面,开发者可以了解到目前主流的代码混淆技术,并判断是否要为自己的应用添加相应的保护。另一方面,安全分析师可以了解到不同种类的应用在代码混淆技术的使用方式上的异同,从而设计出更好的代码分析工具。

基于此,设计并实现了一套针对Android应用的代码混淆扫描框架,并对四种常见的代码混淆技术:标识符重命名、字符串加密、Java反射以及应用加壳设计了相应的检测算法。将检测算法运行在超过10万款Android应用上,并对统计结果进行了分析。

01

基本原理

1.1 APK文件的结构

Android应用程序包(Android Aapplication Package,APK)文件包含了一款Android应用的全部内容,通常由四个路径:res、assets、lib以及META-INF,以及三个文件:AndroidManifest.xml、classes.dex以及resources.arsc组成。它们的具体用途如下。

(1)res:此路径下存放了Android的资源文件,这些资源文件将会被映射到.R文件当中。

(2)assets:此路径与res路径功能类似,用来存放APK的静态资源文件。与res路径不同的是,开发者可以在此路径下创建任意深度的子路径,并且存放任意文件类型的文件。

(3)lib:此路径下存放着为不同CPU平台编译的文件,通常是各种库文件,如.so文件等。

(4)META-INF:此路径用来存放一款应用的签名信息,可以用来校验应用的完整性。

(5)AndroidManifest.xml:Android应用的清单文件,用来存放应用的基本信息,包括名称,版本,所需权限以及组件等。每个Android应用都只包含一个清单文件。

(6)classes.dex:存放Android应用中的所有类信息。此文件可以被Android Dalvik虚拟机理解并执行。

(7)resources.arsc:此文件存放应用中的资源文件以及其对应的ID。

1.2 代码混淆在Android中的使用

1.2.1 标识符重命名

标识符重命名通过将变量中的语义信息抹除,可以有效增加逆向者的攻击成本,从而被广泛使用。如下代码片段表明,经过标识符重命名之后,在没有上下文的环境下,逆向者很难弄清类a的实际含义。

代码混淆技术有哪些(新手必知这7个代码混淆技术)

1.2.2 字符串加密

由于应用中的字符串包含了非常多的语义信息,逆向者通常会将其作为理解程序语义的突破口。如1.2.1小节程序片段表明,即便混淆了程序中出现的标识符名称,有经验的逆向者仍然可以依靠字符串来猜测函数的功能。因此,字符串加密被作为一种有效的混淆手段。在Android应用开发的过程中,字符串加密可应用在多个阶段,包括Java代码编译阶段、Java字节码转Dex文件阶段等。

对于恶意代码开发者来说,字符串加密能够有效地抹除程序语义信息,抵御部分基于硬编码特征的扫描工具的检测。假如加密算法实现得足够复杂,还能够有效地增加逆向过程的时间成本。下面的代码展示了字符串加密的例子。

1.2.3 Java反射

Java反射机制是一种具有与类进行动态交互能力的一种机制,是Java语言的常用手段,能够使得开发者在程序运行时了解类、方法和变量的信息,动态地创建类的实例或调用方法。反射强调动态交互,通过运行时加载,在需要时可以随时随意的利用反射这种机制来进行操作。在Android程序开发领域,Java反射通常在需要访问隐藏属性或者调用方法来改变原来程序的逻辑中使用,常用来调用标注有hidden注解的应用程序编程接口(Application Programming Interface,API)。

以下为使用Java反射的一个简单示例:

反射在普通软件中的使用与恶意软件存在较大的差异。普通软件通常会利用反射进行Java本地接口(Java Native Interface,JNI)调用或后向兼容性的检测,恶意软件则会利用反射去隐藏控制流,从而抵抗静态分析工具的检测,或使用反射将原本正常的函数调用变得十分臃肿,加强对逆向者的干扰。

1.2.4 应用加壳

02

扫描框架的设计与实现

图1展示了本文所使用的扫描框架的设计原理。为了增加扫描结果的覆盖性,首先从三种不同的数据源中爬取Android应用程序,其次使用Androguard工具对其进行解包。无法解包成功的应用实例将被剔除。在解包之后,使用自行设计的四种混淆手段检测方法对应用进行扫描,并对扫描结果进行手工分析与汇总。

图1 扫描框架设计

2.1 标识符重命名的检测方法

通过对多种Android代码混淆工具进行调研,研究发现,使用了标识符重命名的Android程序在标识符的分布上会与未混淆的Android程序产生较大差异。为了准确地表示这种差异,设计了基于3-Gram词频的标识符重命名检测算法,其具体流程如下。

(1)数据预处理:针对某Android应用,提取其全部标识符名称,组成集合Set_id。

(2)特征生成:针对Set_id中的所有标识符,使用3-Gram方法抽取其所有元组,统计各元组的出现频次,组成固定长度的向量并作归一化。

(3)模型训练:从开源仓库F-Droid下载3 147款未经混淆的Android应用程序组成集合Set_app,使用两种不同的混淆器(ProGuard和DashO)对Set_app中的应用程序的标识符进行重命名,进而生成了未经混淆与经过混淆的两种正负样本集合。对样本集合中的应用程序进行数据预处理与特征生成得到特征集合Set_feat,再依靠特征集合Set_feat训练支持向量机(Support Vector Machine,SVM)分类器。

训练出来的SVM分类器可以判断某Android应用是否进行了标识符重命名混淆。

2.2 字符串的检测方法

由1.2.2小节可知,加密能够将Android应用中的字符串变得随机,并且难以理解。而字符串的随机性可以用信息熵来描述。加密后的字符串较之普通字符串,往往拥有更高的信息熵。

信息熵的通用计算公式如:

式中,

表示事件的个数,

表示事件

的发生概率。

在本系统的实现中,抽取了一个Android应用中出现的所有字符串并将其合并。假设合并后的字符串为

中出现的字符种类共为

表示第

个字符

出现的概率,则

,其中

表示

中出现的次数,

表示字符串的长度。最终通过式(1)计算获得信息熵。

接下来,进一步复用了2.1小节展示的思路,针对一款Android应用抽取其全部字符串并组合,计算其信息熵,并使用信息熵来训练SVM分类器。

2.3 Java反射检测方法

2.4 应用加壳检测方法

应用加壳通常有较高的开发门槛,因此开发者往往选择专门厂商提供的应用加壳服务,如梆梆加固、360加固等等。由于应用加壳功能通常作为一种云服务出售,使用某厂商加壳功能的应用在代码层面通常具有相似的特征。基于此,人工分析了若干应用加壳厂商,并从中抽取了相应的静态特征进行扫描,若某应用命中了这条特征,则可以认为它使用了该厂商的应用加壳服务。本文选取的特征如表1所示。

表1 常用应用加壳服务及其对应的静态特征

03

扫描结果与分析

3.1 数据集

为了使扫描的结果更具有代表性,从3种不同渠道收集了共114 560款Android应用。数据集囊括了来自Google官方市场和中国第三方市场的Android应用以及恶意软件。具体的数量信息如表2所示。

表2 数据集详情

3.2 标识符重命名扫描

表3展示了数据集中标识符重命名的扫描结果。可以看出,中国第三方市场和恶意软件中的Android应用使用标识符重命名的频率更高。而Google官方市场中仅有不到一半的Android应用使用了标识符重命名。对此现象的解释是,Google官方市场针对软件剽窃提采取了更为严格的监管措施,从而使得对于软件开发者来说代码混淆并不是必须的工作。

表3 标识符重命名使用情况

3.3 字符串加密扫描

在进一步人工判断了恶意软件与正常软件针对标识符重命名的不同策略后。发现,恶意软件倾向于使用更复杂的命名策略,比如使用相似的字母组成不同的字符串,如Ill1II与ll1II1中使用了l、I、1三种不同字符。除此之外,恶意软件还常常利用Java的重载特性,用毫无关联的词汇替代原有的标识符。这种情况对安全分析师造成了较强的干扰。

表4展示了数据集中字符串加密的扫描情况。可以看到,Google官方市场与中国第三方应用市场中均极少使用字符串加密,而恶意软件中使用字符串加密的样例占比超过5%。

表4 字符串加密使用情况

3.4 Java反射扫描

通过进一步手工分析了使用字符串加密的恶意软件样例,发现字符串加密通常与标识符重命名结合起来,通过将字符串的加解密函数名更改为毫无关联的词组,从而误导安全分析师。比如,在软件com.solodroid.materialwallpaper中,字符串的解密函数被命名为NavigationItem;->getDrawable(),从字面分析,其意义可能为获取图像资源的函数。

表5展示了数据集中的Android应用对Java反射的使用情况。可以看出,反射作为一种Java语言的高级用法,在各种类型的应用中被使用的比例较为接近。

表5 Java反射使用情况

进一步分析不同类型的Android应用使用反射调用的真实目标,发现恶意应用倾向于使用Java反射调用敏感的API,或使用Java反射将普通的调用臃肿化,从而增加逆向分析师的分析成本。而普通应用则通常只考虑应用程序的兼容性。这种方法的差异可以从表6中清晰地看出。

表6 Java反射调用频率最高的前两位使用情况

3.5 应用加壳扫描

扫描结果显示,在114 560款Android应用当中,共有7 408款应用使用了加壳技术,占比百分之6.5%。具体到各厂商提供的加壳服务的数据如表7所示。

表7 应用加壳使用情况

在进一步的人工分析当中发现,使用了加壳技术的应用非常难于自动化分析,往往需要通过虚拟机或人工脱壳,才能够获取原应用文件,此举通常能够比较好地保护开发者的代码资源。

04

结 语

引用本文:徐玄骥,董帅克,张智斌.应用于Android软件的代码混淆使用情况分析[J].通信技术,2021,54(6):1486-1491.

徐玄骥,硕士,主要研究方向为安卓系统安全,软件漏洞利用与分析;董帅克,博士,主要研究方向为网络攻防方面的研究;张智斌,学士,副教授,主要研究方向为基于网络的计算机软件技术、工业控制技术。

发表评论

登录后才能评论