APP下载

面向动态加载的Android恶意行为动静态检测方法

2019-12-12郑晓梅杨宇飞潘正东

计算机应用与软件 2019年12期
关键词:调用静态动态

郑晓梅 杨宇飞 程 硕 潘正东

1(南京中医药大学信息技术学院 江苏 南京 210023)2(南京大学计算机科学与技术系 江苏 南京 210023)3(南京大学计算机软件新技术国家重点实验室 江苏 南京 210023)

0 引 言

随着移动智能终端的普及,Android系统的市场范围在不断扩大,Android应用程序的规模也在逐年扩大。数据显示,目前仅在Google Play就有373万应用,并且以每个月数万个的速度增加。然而,其中约13%为低品质应用,大部分包含恶意代码,显示出不同的恶意行为,例如盗取用户短信内容、盗取用户通信录信息、自动订购付费业务、泄漏用户位置信息等行为,用户往往很难鉴别[1]。此外,由于国内第三方市场往往缺乏严格的审查制度,让大量垃圾应用拥入,用户的隐私安全和正常使用都得不到保障[2],因此针对Android平台的恶意软件检测技术显得格外重要。

此外,Android新推出的动态加载技术支持分离执行体的方式实现运行时的动态程序加载,这虽然可以实现热更新、快速修复bug等功能[3],但同时也给恶意行为检测带来了新的挑战。开发者可以在执行过程中通过动态加载方式下载并运行恶意行为程序[4],而传统的静态代码分析技术无法有效检测[5]。

针对该问题,提出了一种动静态相结合的Android程序恶意行为检测技术,先针对宿主App采用静态分析技术,提取程序的控制流图,通过分析动态加载点的位置进行路径制导的动态执行,以获得动态加载的APK。然后,再针对其进行静态分析获得控制流图[6],通过对宿主App和被加载APK的控制流组合,得到整个系统的完整控制流图。针对该控制流图进行遍历和恶意行为模式的匹配,就可以完成对完整App的检测。本文基于所提出的恶意代码检测方法,开发了相应的原型工具、构造了实例,并且进行了实例研究。

1 相关工作及背景

现有的恶意代码检测技术主要分为静态分析和动态分析。静态分析是在获取源码或编译体的情况下不运行程序直接进行程序分析;动态分析主要是通过运行程序,在运行时收集相应的上下文环境、虚拟机及操作系统等信息,进而完成分析。

常用的静态分析技术包括抽象语法树分析、语义分析、控制流分析、数据流分析[7]、污点分析[8]、程序切片[9]等,目的是验证代码是否规范、安全、可靠、便于维护。静态分析能够提供程序所有可能执行的情况,其执行速度快、效率高,但相对于动态分析,静态分析采用了很多推断机制,因此误报率也较高。同时,静态分析需要在进行分析前获得程序的所有源码或编译体,对于执行体分离的运行时加载程序难以实施静态分析。相比之下,动态分析因为是在执行过程中收集信息,因此准确,误报率较低。而且对于动态加载的执行体,也可以非常方便地在运行时完成加载和执行。但动态分析的缺点也非常明显,那就是环境配置和执行过程的时间成本太高,而且难以保证覆盖程序的所有路径[13]。

目前主要的Android分析工具有Soot(Java字节码分析工具)、IntelliDroid(该工具为动态分析Android恶意软件提供目标输入)、FlowDroid(基于污点分析的静态分析工具)。Soot是加拿大麦吉尔大学的Sable课题组研发的Java字节码分析工具,主要用于对字节码的分析、插桩、优化等,是Java和Android静态分析方面应用最广泛的工具之一。Soot工具支持Call-graph 构造、定义/调用链、模板驱动的程序内数据流分析、污点分析等。IntelliDroid是一个为动态分析Android 恶意软件提供目标输入的工具。由于Android应用程序的入口点很多,包含很多的事件,仅仅触发包含敏感API的Handler是不足的,有可能需要按照一定的顺序触发多个Handler,才会触发真正的恶意行为,而IntelliDroid能做到触发事件及其顺序。利用IntelliDroid,可以有目的性地去触发所期望的目标函数,而不是传统的fuzzing方式。FlowDroid是Sable小组开发的,以Soot为基础,基于污点分析的静态分析工具,目的是检测Android 应用程序中是否存在从source到sink的数据流[10],其中source是用户的敏感数据(如短信、联系人、数据库等),sink是泄露方式(如短信发送、因特网等)。

静态方法和动态执行方法单独使用在检测动态加载的Android应用上时往往不能取得充分的结果。恶意代码的静态分析方法容易被开发者绕过,开发者可以选择先开发正常应用通过静态检测,后期加入恶意的动态加载文件实现恶意行为。而单独使用动态方法难以覆盖所有的执行路径,也无法充分检测出恶意行为。

2 检测方法的设计及实现

工作基于IntelliDroid将动态加载API(DexClassLoader)作为目标函数,从而获得加载的程序,用作进一步分析和检测。此外,采用source & sink的方式进行污点分析检测。使用FlowDroid以APK文件作为静态污点分析的输入,模拟了完整的Android应用生命周期来处理回调,source、sink的检测通过解析从APK文件中抽取的manifest文件、Dalvik虚拟机字节码文件和xml布局文件,生成一种dummy main函数,模拟activity生命周期,建立函数调用控制流图CFG。

在上述研究的基础上,本文提出面向动态加载的Android应用恶意代码检测方法。

2.1 方法概述

恶意代码检测方法整体框架如图1所示,在整个框架中,分为三个模块:宿主App检测模块、动态加载文件分析模块和完整恶意行为分析模块。

图1 恶意代码检测方法整体框架

该恶意代码检测方法大致的步骤如下:

(1) 对分析应用程序进行逆向工程。提取出APK(Android application package)中的dex字节码文件、资源文件和配置文件,然后利用工具将Android的dex字节码文件转化为静态分析工具能够处理的Java的class字节码文件(.class)。

(2) 进行静态分析。使用IntelliDroid工具,对逆向生成的Java字节码文件进行静态分析,包括调用图分析和控制流分析,检测工程中是否使用了动态加载技术,生成到达动态加载点的路径,抽取构成路径的事件序列,生成路径上的条件约束,作为后续动态执行过程中的依赖输入。

(3) APK插桩。使用Soot工具对原始APK进行插桩,在动态加载点插入记录信息的代码,使得当App触发动态加载时,能够记录下动态加载文件的存储路径、被加载的类信息、被调用的方法信息等,并输出到文件中。

(4) 进行约束求解和动态执行事件序列。利用z3求解器对路径上的约束进行求解,然后利用Android模拟器的adb调试工具,执行路径上的事件序列,触发动态加载,得到被动态加载的文件。

(5) 分析检测被动态加载的文件。利用Soot工具,对被动态加载的文件进行控制流分析,生成相关类的包含方法signature的控制流图,得到外部文件的相关调用序列。

最后将步骤2中得到的调用方法序列与步骤5中得到的动态加载文件的调用序列拼接,形成完整的包含外部方法的序列。遍历该序列,进行恶意行为检测,不仅可以检测出动态加载文件中的恶意行为,还能检测出宿主App和动态加载文件两者组合产生的恶意行为。

在此框架方法的基础上,部署整个工程成Web项目,通过前后端交互的方式,实现用户在前端简单操作上传APK,等待后端分析检测完成后,直接展示给用户分析检测报告。

2.2 宿主App检测模块

宿主App检测模块主要对宿主App进行分析,目的是生成宿主App内部的控制流信息,提取出动态加载文件、记录下动态加载的相关参数信息,用于后续模块分析。主要步骤如下:

(1) APK逆向阶段,结合使用Apktool和dex2jar工具,将APK解包,把Android 字节码文件(.dex)逆向转化为静态分析工具能够处理的Java字节码文件(.class)。

(2) 静态分析阶段,判断宿主App是否采用动态加载技术和生成可以到达动态加载点的路径,以及该路径上的语句和约束。使用IntelliDroid工具,对逆向生成的Java字节码文件进行静态分析,包括调用图分析和控制流分析,检测工程中是否使用了动态加载技术,生成到达动态加载点的路径,抽取构成路径的事件序列,生成路径上的条件约束,作为后续动态执行过程中的依赖输入。

修改IntelliDroid的配置文件,将目标方法设置为动态加载相关的API。依据动态加载技术的使用方法,创建DexClassLoader或PathClassLoader类加载器后,都需要调用类加载器的loadClass方法来将目标类加载进来,因此将loadClass方法作为目标方法,修改targeted-Methods.txt配置文件,填写。这是Java方法的一种三地址码表示形式,包含了方法的类信息、参数信息以及返回值信息,与普通的只包含方法名称信息的表示方法相比,能明显降低匹配错误,更加精确地定位目标方法。

静态分析完成后,将在指定的输出目录生成一些结果文件,包括appInfo.json(App静态分析的文件结果:mainActivity,到达目标方法路径的起点和终点等)、constrainsM_N.py(约束文件,表示要触发第M条路径上第N个受约束的事件需要满足的约束)和instrPath.json(到达动态加载点的所有路径控制流文件,记录了该路径上的所有调用语句及其顺序)。

(3) APK插桩阶段,使用Soot工具对原始APK进行插桩,在动态加载点插入记录信息的代码,当App触发动态加载时,能够记录下动态加载文件的存储路径、被加载的类信息、被调用的方法信息等,并输出到文件中。DexClassLoader的构造方法如下:

DexClassLoader (String dexPath,

String optimizedDirectory,

String librarySearchPath,

ClassLoader parent)

共有4个参数,其中:dexPath表示外部文件的路径,optimizedDirectory表示外部文件释放的路径,librarySearchPath表示包含native libraries的文件目录列表(一般设置为null),parent表示父类加载器。主要关心参数dexPath,在DexClassLoader构造完成后,只需将dexPath指向的文件拷贝到预先设定好的目录下,就能得到被加载的文件而且不会被系统删除,用于后续的外部文件分析。

此外,在应用程序执行loadClass和getMethod方法之后,插入代码分别记录下类的名称和方法的名称,并存储在预先建立好的log文件中,用于后续的外部文件分析。插桩完成后,得到了经过“改造”的APK文件,后续将该APK文件安装在Android模拟器上,动态执行该App,来获取外部文件和动态加载调用的相关信息。

(4) 解析约束阶段,使用z3求解器,对静态分析生成的约束文件进行求解,依次执行时间序列,达到触发动态加载的目的,并且在这个过程中执行插桩的代码,记录输出相应的信息。执行完成之后,将动态加载文件和记录信息的log日志从Android 系统中提取到本地,作为后续动态加载文件分析的依赖。

2.3 动态加载文件分析模块

动态加载文件分析模块主要对动态加载文件进行分析,目的是依据记录的动态加载的相关参数信息,生成动态加载文件中的控制流信息。主要步骤如下:

(1) 外部文件预处理阶段,根据Android开发者文档的说明,动态加载的文件可以是dex文件、apk文件和jar文件三种类型,并且apk文件和jar文件必须包含classes.dex文件。依据动态加载的原理,无论被加载的文件是哪种格式,其本质上都是先将包含的dex文件释放到临时目录,然后再加载该dex文件。因此预处理的第一步是先将动态加载文件解包,将其中包含的dex文件拷贝到指定目录再进行处理。

预处理包括两个步骤:一是逆向处理,同样使用dex2jar工具,将动态加载的dex文件逆向转化为Java字节码文件,生成包含所有Java字节码(.class)文件的文件夹,并且保证每层文件夹都以该层的包名称来命名;二是对动态加载文件进行简单扫描,分析其中包含的类和方法,生成相应文件的方法表,将classes.jar作为处理对象,使用"jar tf classes.jar grep.class"指令来获取jar文件中的所有类信息,再使用"javap-cp classes.jar"指令以类名作为参数来获取每个类中的方法信息,将结果存放在methods.txt文件中。

(2) 外部方法静态分析阶段,使用Soot工具,对逆向后的Java字节码文件进行静态分析,生成目标类的控制流,并依据生成的方法表,对控制流在JDK和Android SDK层面进行方法的展开,将控制流对象序列化,保存在文件中。

生成控制流图相关的main方法位于soot.tools.CFGViewer类中,只需要指定要分析的类的完整信息(即包含PackageName和ClassName,以“.”来分隔)以及相关CLASSPATH(一般指android.jar和jre/lib/rt.jar),即可生成该类中所有方法的控制流信息。类信息从之前动态执行之后保存在本地的log文件中读取。

Soot在控制流分析的过程中,对每条指令做了简化,仅包含调用方法的名称而略去了所在类和返回值类型这两个重要的信息,因此对Soot源码进行修改,使得生成的控制流中包含方法完整的signature,图2是修改前后的比较。

图2 Soot源码修改前后生成的控制流语句对比

为了更好地记录和利用控制流信息,定义了一个变量来在内存中保存该控制流信息,其数据结构为Map>>。其中Map的键key表示方法名称,List表示控制流的一条路径,Map的值value表示该方法所有的控制流路径。除此之外,还使用第三方工具fastjson将该Map序列化存储到文件中,方便后续对控制流的进一步操作。

由于Soot控制流分析的局限性,分析得到的某个方法的控制流不能够做到对方法调用的进一步展开,因此需要解决这一问题。为了保证工作的正确性以及处理效率,将方法展开的范围限定为整个动态加载文件的工程中,即只对预处理阶段得到的方法表中的方法进行展开,其余方法视为JDK级别、SDK级别以及第三方依赖方法不做展开处理。为了提高方法展开的效率,还定义了一个静态变量AllControlFlow来存储各个类的控制流信息,避免了对序列化后存储的控制流文件的重复读取,AllControlFlow是Map对象,以类名作为key键,以相对应的控制流(即上文中提到的Map)作为value值。具体解决方案的伪代码如算法1所示。

算法1控制流中的方法展开过程

输入:原始、未做展开的方法控制流

过程:methodExpand

1.for 控制流中的每条路径path do

2. for 每条路径中的调用语句call do

3. if call调用的方法在方法表methodTable中then

4. if call调用的方法在AllContolFlow中能找到then

5. 直接从AllControlFlow中得到相应的控制流controlFlow

6. 用controlFlow替换该调用语句

7. else

8. 利用Soot生成调用的方法所在类的控制流controlFlow

9. 将controlFlow更新到AllControlFlow

10.用controlFlow替换该调用语句

11.end if

12. end if

13. end for

14.end for

15.更新展开后的控制流到AllControlFlow中

16.更新序列化文件

在展开的过程中,为了兼顾效率和准确性,设定了最大展开深度,避免出现因为递归层数较深造成的长时间循环的现象。如果将最大展开深度设置为无穷大,那么最终得到的控制流可以认为是仅包含Java和Android API调用的序列。至此,得到了动态加载文件的控制流信息。

2.4 完整恶意行为分析模块

将宿主App的控制流与动态加载文件的控制流进行合并,得到完整的控制流,逐个路径进行扫描检测敏感API,与预先设定的恶意行为模式进行匹配,得到最终的分析检测结果。

2.4.1控制流合并

经过宿主App的检测与分析以及动态加载文件的检测与分析,分别得到了APK内部与外部的控制流信息。根据APK内部的控制流中的动态加载点的信息,在不同的动态加载点插入相应的外部方法的控制流,就得到了完整的控制流信息。在宿主App内部的控制流中,对每一条控制流语句进行了编号,作为确定位动态加载的依据。同时,每条路径还定义了名为invokePoints的变量,记录下动态加载方法调用语句相对应的控制流语句的编号,结合log文件中记录的global Loading Method,即可得知动态加载调用的方法和调用所在的位置,将外部的相应方法的控制流插入该位置即可[11]。控制流合并的伪代码如算法2所示。

算法2控制流合并

输入:内部控制流interCF、外部控制流outerCF

过程:controlFlowMerge

1.for interCF中的每条路径path do

2. for 每条路径path中的invokePoints do

3. for 每个invokePoints中的插入点point do

4. 读取log文件中point对应globalLoading Method信息

5. 根据global Loading Method信息,从outerCF中获取相应方法的控制流methodControlFlow

6. 根据point,定位到相应的invoke调用语句

7. 用methodControlFlow替换该invoke语句

8. end for

9. end for

10.end for

输出:合并后的控制流mergedCF。

2.4.2恶意代码检测阶段

定义一些典型的恶意行为模式,如窃取短信内容、窃取通讯录信息、窃取用户位置信息等。将有关恶意行为的API称之为敏感API,敏感API可以分为两类:获取用户隐私信息的API,称之为source-API;泄露用户隐私信息的API,称之为sink-API。主要依据FlowDroid的污点分析的配置文件,搜集了一些Android开发中会使用到的敏感API,并同样使用配置文件的形式,使得敏感API可配置,能自行添加删除[12]。

对敏感API 进行简单的语义分析,使得在执行恶意代码检测之后,能够给出较为准确的检测报告,反映出软件的可能存在的具体恶意行为。例如,进行控制流分析之后,其中一条路径上调用了getLastKnownLocation()方法,可以分析出软件获取了用户的定位信息;接着在该路径上又调用了sendTextMessage()方法,可以分析出软件将某些信息以SMS短信的形式发送出去,两者结合可以判断,软件可能存在通过SMS短信泄露用户位置信息的隐私泄露行为。类似地,对多种API组合进行了恶意行为模式的定义,关键信息为隐私的种类和泄露的方式,即:该软件可能存在获取用户XX隐私,并通过XX方式将其泄露的恶意行为。

2.5 原型工具实现

根据提出的恶意代码检测方法,在现有工具的基础上,实现了能够完整执行恶意代码检测流程的原型工具,其简要框架如图3所示。

图3 原型工具框架图

主要依赖Soot和IntelliDroid工具,实现本文工作中的静态分析和插桩工作,使用ApkTool工具对Android应用进行逆向工程,使用z3求解器求解约束实现动态执行。

3 实 验

通过实验对所提出的面向动态加载的Android应用恶意代码检测方法进行评估。

3.1 存在恶意行为的动态加载应用的检测

(1) 本次实验采用的实例,是一款名为“阅读神器”的App,来源于国内知名移动安全论坛——看雪论坛,由论坛用户上传提供,并称该应用可能存在木马行为。该应用申请了SMS即短信权限,通过查看APK中的AndroidManifest.xml文件,可以得知主要是SEND_SMS和READ_SMS权限,这与应用本身作为阅读软件的用途不相符。通过将该App安装在Android虚拟机上并测试,却发现该App在表面上并没有明显恶意行为。

(2) 宿主App的检测与分析阶段,首先将APK文件进行逆向处理,生成相应的Java字节码文件,以及解包APK中的资源文件;对逆向处理后的应用进行静态分析,生成宿主App内部的控制流信息和触发动态加载的事件序列及其约束。接着对原始APK read.apk进行插桩,植入相关代码,生成插桩完成之后的APK read-ins.apk;将read-ins.apk和静态分析产生的事件序列及其约束作为输入,进行动态执行操作,插桩后的Apk被安装在Android模拟器上,解析约束,执行事件序列。最终得到被动态加载的文件cao.apk和动态执行记录文件log.txt。结果显示经过逆向的APK的资源文件中同样存在一个名为cao.apk的文件,位于/res/raw目录下,经过文件的MD5值计算和对比,可以判定两者为同一文件,代表着该应用动态加载的目标文件位于工程内部的资源文件中。

(3) 在动态加载文件的检测与分析阶段,得到动态加载文件cao.apk之后,对其进行控制流分析,根据log.txt文件中的记录,动态加载调用的xcvwreoipurew.zxcbwqioewr.xcvzmbnwerqoi.zxcvbnm类中的faxinxi方法。该方法的控制流图,如图4所示。

图4 faninxi方法的控制流图

该方法调用了sendMultipartTextMessage这一API,属于敏感API,在后续过程中观察是否能检测出可能存在的恶意行为。

(4) 经过合并和检测,得出了检测报告。根据检测报告显示,该应用调用getMessageBody方法来读取用户短信内容,获取了用户的隐私数据,然后调用了sendMultipartTextMessage方法将隐私数据以短信的形式发送出去,不但会泄露用户的隐私,还会造成额外的短信费用,可以将其作为一种恶意行为。检测结果与之前通过人工查看控制流的预测相吻合。

此外,通过逆向原始APK,阅读反编译后的源码,结合静态分析生成的事件序列后发现,动态加载的调用位于短信服务的onReceive方法中,因此猜想该应用会在用户收到短信的情况下,读取短信内容,并将其发送给预设的收件人,造成隐私泄露和不知情扣费。后续利用telnet向Android模拟器模拟发短信,确实触发了该应用的动态加载,进一步证明了预测的正确性。

3.2 正常应用加入动态加载恶意行为的检测

(1) 使用开源应用Good Weather项目地址:https://github.com/qqq3/-good-weather。Good Weather作为一款天气软件,拥有获取设备定位信息的权限,因此我们对其进行改造,在原始代码中获取定位信息之后,插入执行动态加载的代码,达到将定位信息发送至预设服务器的目的,来模拟隐私信息的泄露。

(2) 为了保证实验的公正,使用恶意软件在线检测网站VirusTotal对样本进行检测,并与结果进行对比。先对未插入任何代码的Good Weather应用进行检测。63种不同公司的检测方法均没有检测出Good Weather本身包含恶意代码,因此认为该样本是纯净的。

接着对插入动态加载代码之后的Good Weather应用进行检测,63种不同公司的检测方法中有62种没有检测出Good Weather本身包含恶意代码,仅仅有一个公司给出了风险告警,因此可以大致认为经过改造之后的包含恶意的Good Weather应用不能被绝大部分检测方法发现恶意代码。下面将展示对该应用的检测结果,由于上文已经对具体实现方法进行了详细介绍,因此该实例仅介绍检测结果和分析。

第一条路径存在隐患,从获取隐私到泄漏的路径如图5所示。

图5 插入代码后的Good Weather的本文工作检测结果

可以看出,工作实现的工具成功地检测出了该隐私泄露,准确定位到了隐私信息和泄露相关的API调用,即通过getLatitude()获取用户的位置信息,使用okhttp框架的post请求,将该隐私信息发送到预先启动的服务器上。宿主App中本身就包含获取定位信息的代码,插入的仅有DexClassLoader的构造和类加载、方法调用的简单代码,而在动态加载文件中实现了基于okhttp框架的post请求的发送的功能,两者独立的情况下不存在恶意行为,但两者结合起来就是一种典型的通过post请求泄露用户隐私的恶意行为。

通过以上的检测、分析和对比,证明了利用动态加载技术可以躲避当前大部分的恶意代码检测,实现对用户隐私信息的盗取。而提出和实现的恶意代码检测方法,能够有效针对这一情况,提高检测的准确率,减少恶意软件的漏报。

4 结 语

提出的基于控制流的动静态结合检测方法,针对Android动态加载机制进行恶意代码检测,并开发出了相关工具,能有效地检测出应用中的恶意行为,可以作为Android第三方市场上架应用前对应用程序的检测手段。

接下来的工作中,拟将从以下几个方面来进一步改善目前所提出检测方法:(1) 通过更加准确的静态分析、更高效率的约束求解以及更加高效的控制流分析方法,大幅度提高整个工程的恶意代码的检测效率。(2) 对敏感API的调研仍需要继续进行,通过搜集更多的恶意应用,了解更多的恶意行为。(3) 形成完整的工具平台。

猜你喜欢

调用静态动态
国内动态
国内动态
国内动态
最新进展!中老铁路开始静态验收
静态随机存储器在轨自检算法
核电项目物项调用管理的应用研究
动态
系统虚拟化环境下客户机系统调用信息捕获与分析①
油罐车静态侧倾稳定角的多体仿真计算
利用RFC技术实现SAP系统接口通信