法律状态公告日
法律状态信息
法律状态
2019-10-29
授权
授权
2017-07-14
实质审查的生效 IPC(主分类):G06F21/56 申请日:20170116
实质审查的生效
2017-06-20
公开
公开
【技术领域】
本发明属于Android平台上应用程序的静态分析和内部回调建模技术领域,具体涉及一种基于回调函数建模自动生成Android应用回调序列的方法。
【背景技术】
当前移动设备已经成为人们生活必不可少的一部分。为了满足人们日益增长的应用需求,移动设备上的应用层出不穷。其中基于Android平台的应用数量巨大并且仍在持续增长,大量的Android平台上的应用被证明具有功能或安全性方面的问题。因此,确保移动应用功能的正确性和使用的安全性越来越成为人们的关键需求。
对Android应用进行安全检查,静态分析,需要将apk文件反编译成介于java代码和二进制码之间的smali代码,并对smali代码进行静态分析。区别于传统的桌面应用程序,Andorid系统具有事件驱动的特性,虽然这个特性为其带来诸多用户体验的优势,然而高度的交互性不可避免的增加了程序分析和测试的难度。因为Android平台的事件驱动特性,在对Android应用进行静态分析基础上创建相应模型的方法比直接对源码进行分析要更具优势。
基于目前工作,能够总结以下两个结论:
1)回调函数序列,作为Android系统的一项主要特性,在分析和测试移动应用的过程中占据关键地位。以此为基础的回调函数序列提取技术弥补了传统程序分析方法的不足。与传统方法不同,回调函数序列不再考虑程序的控制流或数据流,而是关注事件序列的发生和相关特征的更新处理。因此,回调函数序列能够解决由事件不确定性引起的逻辑问题,如事件异常,回调函数序列违法等,而这些问题利用传统的分析技术是难以解决的。
2)现有的回调函数序列的处理工作仅仅是目标导向。即针对特殊问题构建特定的回调序列,所生成的序列往往是粗粒度、不可移植且不完备的。片面构建方法的缺陷主要表现在两方面:一是没有对生命周期回调,GUI(Graphic User Interface)回调,系统驱动回调,组件间关系进行统一构建。其原因是难以找到一个统一的序列模式。例如,检测一些控件的变化状态必须要处理其在不同组件间的传递关系,控件的变化与组件间的传递动作二者难以统一,一个不完备的模型序列使得分析的结果易于出错。二是不同类型的逻辑缺陷往往存在于同一程序块中。当前的部分构建方法无法利用一种通用的方法加以处理,从而严重限制了其实用性。另外,部分构建也使得所构建的序列模型难以运用到其他场景。
【发明内容】
本发明旨在使用静态分析的方法,为Android平台上的应用建立一种统一的回调序列模型,即提供一种基于回调函数建模自动生成Android应用回调序列的方法。该方法考虑了生命周期回调函数,GUI回调函数和系统驱动回调函数,它不仅对生命周期回调关系、注册关系这两种主要的应用组件内部的回调关系进行统一抽象生成回调序列,更重要的是关注了不同类型组件之间的跳转回调关系,生成组件跳转回调序列,从而提供完备的细粒度回调信息,便于分析各类相关的时序属性,比如权限使用属性等。
本发明提供的基于回调函数建模自动生成Android应用回调序列的方法包含以下步骤:
步骤1、搭建Android回调信息库;
步骤2、以Android应用的smali类型源码为输入,进行函数-回调映射预处理;
步骤3、根据生命周期时序关系,生成生命周期回调序列;
步骤4、识别注册或释放注册动作的关键连接点,生成由注册或释放注册引起的非生命周期回调序列;
步骤5、识别Activity跳转及Service跳转动作的关键连接点,生成跳转链接;
步骤6、生成由Activity跳转和Service跳转引起的非生命周期回调序列。
本发明的具体设计实现如下:
1.搭建Android回调信息库
该库记录了该发明中用到的Android信息集合,待分析的Android应用中包含的相关集合均为该库中相应集合的子集。
依据Android平台中回调函数库的基础信息,构建Android回调信息库中的以下集合:
(1)白名单集:每个元素包含无用代码所在的Android本地库及其他依赖库文件的名称及其他相关属性。
(2)注册关系集:每个元素包含注册关系的关键连接点及其他相关属性。
(3)释放注册关系集:每个元素包含释放关系的关键连接点名称及其他相关属性。
(4)组件间跳转函数集:每个元素包含Activity跳转或Service跳转的关键连接点名称及其他相关属性。
(5)回调函数集:每个元素包含回调函数名,回调函数类型,所属类名及其他相关属性。
该库可以根据需要扩充,其中每个集合可根据需要添加或删除元素,任一元素的属性也可以根据需要更改。
2.函数-回调映射预处理
在Android回调信息库的基础上,要对输入的Android应用的smali代码进行函数回调映射预处理,获取到回调函数集合callbackSet,非回调函数集合funSignedSet和反映每一对非回调函数与其相应的回调入口的映射关系的函数-回调映射列表。
初始化回调函数集callbackSet和开发者自定义的非回调函数集funSignedSet为空集。过滤掉白名单下的所有无用代码,对整个应用的有效代码中的所有函数进行遍历。每遍历到一个函数定义,就标记这个函数的前驱函数和后继函数,并对该函数进行分类标记,分类标记方法是:查看该函数的名称是否出现在Android回调信息库中回调函数集中,如果出现,则为callbackSet添加新元素,包含函数名,所属类名,参数描述,前驱函数,后继函数,所属组件类型,回调函数类型七个属性。组件类型集合为{activity,service,receiver,other};回调函数类型集合为{lifecycle,GUI,System-driven}分别表示生命周期回调函数,用户界面交互回调和系统驱动回调。如果该函数名称未出现在Android回调信息库总的回调函数集中,则为funSignedSet添加新元素包含函数名,所属类名,参数描述,前驱函数,后继函数,所属组件类型六个属性。基于这两个集合,以每一个回调函数作为调用者,即前驱函数,依次搜索被调用者,即后继非回调函数,并且迭代搜索后继,直到没有后继的非回调函数,在遍历过程中,记录该初始回调函数整个搜索调用顺序来生成函数-回调映射列表中的一条记录,该列表反映每一对非回调函数与其相应的回调入口的映射关系;若该回调函数没有后继的非回调函数,则不生成记录。
3.生成生命周期回调序列
以组件类型及组件源码作为输入,生成生命周期回调序列,生成过程涉及四个步骤:
(1)对一组件C,在Android回调信息库中找出组件类型与C的类型一样的全部生命周期回调函数,生成C的全生命周期回调集合C.lifecycle,为C.lifecycle添加三个并不是真实存在的辅助回调函数节点onActiveStart,onActiveEnd以及onTerminal,用于标识组件的如下状态:运行开始,运行结束和销毁结束,以此来显式限定组件的活动域以及跳转时机。
(2)生成C的对应组件类型的完备生命周期序列图(ELG)。若C为activity,生成串行回调序列C.init->C.onCreate、C.onCreate->C.onStart、C.onStart->C.onResume、C.onPause->C.onResume、C.onPause->C.onStop、C.onStop->C.onDestroy、C.onStop->C.onCreate、C.onStop->C.onRestart、C.onRestart->C.onStart、C.onPause->C.onCreate、C.onResume->C.onActiveStart、C.onActiveEnd->C.onPause、C.onDestroy->C.onTerminal。若C为service且以onBind开始,那么生成串行回调序列C.init->C.onCreate、C.onCreate->C.onBind、C.onBind->C.onActiveStart、C.onActiveEnd->C.onUnbind,C.onUnbind->C.onDestroy,C.onDestroy->C.onTerminal。若C为service且不以onBind开始,那么生成串行回调序列C.init->C.onCreate、C.onCreate->C.onStartCommand、C.onStartCommand->C.onActiveStart、C.onActiveEnd->C.onDestroy、C.onDestroy->C.onTerminal。若C为receiver,生成串行回调序列C.onReceive->C.onActiveStart、C.onActiveEnd->C.onTerminal。
(3)初始化被实现的生命周期回调集合lifeNodes为空,在函数-回调映射预处理得到的callbackSet集合中识别回调类型为生命周期回调函数的元素,每出现一个生命周期回调函数,就为lifeNodes添加一个新元素,最终添加上onActiveStart,onActiveEnd和onTerminal三个辅助节点得到组件C被实现的生命周期回调lifeNodes,以ELG中所有节点为全集,求lifeNodes的补集得到未被实现的生命周期回调函数隐藏节点集合hiddenNodes。
(4)对每一个hiddenNodes集合中的元素hiddenNode,找到其父亲节点hiddenNode.f和子节点hiddenNode.s,并生成串行序列hiddenNode.f->hiddenNode.s,将以hiddenNode作为出发节点和终止节点的所有序列删除。最终得到组件C的生命周期串行回调序列。
在对Android应用分析建模过程中,需要对其所有组件均做以上四步操作。
4.生成由注册或释放注册引起的非生命周期回调序列
生成由注册或释放注册引起的非生命周期回调序列的生成过程涉及以下四个步骤:
(1)识别注册或释放注册动作的关键连接点,关键连接点为关键连接函数的调用语句。过滤掉白名单的无用代码后,扫描Android应用的smali源码,对每一行源码匹配Android回调信息库注册关系集中元素的关键连接点名,若匹配成功,则找到一个注册或释放注册动作的关键连接点。关键连接点名如:setOnClickListener,unregisterListener等。
(2)对每一个关键连接点R,找到它的前驱回调函数invoker,并记录其类型,方法为:记录关键连接点R被调用的函数即R的前驱函数R.p,若其为一个回调函数,则invoker=R.p,停止;否则,R=R.p,利用函数-回调映射表,搜索R的前驱函数。
(3)对每一个关键连接点R,找到它的后继回调函数节点集invokees,方法为:识别关键连接函数的参数,搜素参数的内部类实现源码,找到内部类中定义的非生命周期回调函数即为invokees。
(4)对invokees中每个元素invokee,若invoker类型为生命周期回调lifecycle,那么生成串行回调序列onActiveStart->invokee->onActiveEnd,若invoker类型为非生命周期回调,那么生成串行回调序列invoker->invokee->onActiveEnd。
5.生成跳转链接
生成跳转链接的生成过程涉及以下三个步骤:
(1)识别Activity跳转动作和Service跳转动作的关键连接点。过滤掉白名单的无用代码后,扫描Android应用的smali源码(本次扫描与识别注册或释放注册动作的关键连接点的扫描为同一次),对每一行源码匹配Android回调信息库组件间跳转函数集中元素的关键连接点名,若匹配成功,则找到一个Activity跳转动作或Service跳转动作的关键连接点。关键连接点名如:startActivity,startService,stopService等。
(2)对每一个关键连接点,搜索关键连接点的前驱回调invoker,并搜索关键连接点的后继组件。搜索后继组件方法为:将关键连接点的前驱回调invoker的函数实现作为关键代码段,对关键代码段的每行代码,若存在“const-class”关键字,则“L”字符及之后的字符串构成后继组件名;若存在“const-string”和“setClassName”关键字,则后继组件名为“””字符之后到倒数第二个字符所构成的字符串。以上匹配是为了识别使用intent实现组件跳转的不同方式。比如下面这行源码:
Const-class v2,Lcom/example/ury/OtherActivity
解析出的后继组件名为“Lcom/example/ury/OtherActivity”。
之后通过后继组件名来获取整个后继组件B。
(3)为“startActivity”关键连接点生成connection_activity类型链接,为“startService”关键连接点生成connection_service类型链接,为“stopService”关键连接点生成connection_stop_service类型链接。每个链接包含关键连接点名、链接类型、关键连接点前驱回调invoker、连接点所在组件(前驱组件A)及类型、转到的目的组件(后继组件B)及类型七个属性,其中链接类型集合为{connection_activity,connection_service,connection_stop_service}。
6.生成由Activity跳转和Service跳转引起的非生命周期回调序列
以跳转链接为基础,为connection_activity类型的跳转链接生成A.onActiveEnd->B.init和B.onTerminal->A.onActiveStart的串行回调序列。因为在Android平台上,组件activicy跳转到另一个activity,那么后面的Activity会完全覆盖前一个,所以Activity间的跳转只能生成串行回调序列,而组件activicy跳转到另一个service,两个组件是同时运行的,service运行在后台,因而为connection_service类型链接生成A.invoker->B.init的并行回调序列;为connection_stop_service类型链接生成B.onTerminal->A.的并行回调序列。
本发明的优点和积极效果:
本发明方法考虑了生命周期回调函数,GUI回调函数和系统驱动回调函数,它不仅对生命周期回调关系、注册关系这两种主要的应用组件内部的回调关系进行统一抽象生成回调序列,还关注了不同类型组件之间的跳转回调关系,生成组件跳转回调序列,从而为Android平台上的应用建立了一种统一的回调序列模型,提供完备的细粒度回调信息。在该统一的回调序列模型的基础上,能够发展出很多应用,比如进行漏洞检测,发现回调陷阱,use-after-free逻辑缺陷等。
【附图说明】
图1为一个activity组件的java事例源码。
图2为生成的activity组件的完备生命周期回调序列图。
图3为生成的减去未实现生命周期回调函数的生命周期回调序列图。
图4为生成注册关系引起的非生命周期回调序列后的模型图。
图5为生成activity跳转关系引起的非生命周期回调序列后的模型图。
图6为基于回调函数建模自动生成Android应用回调序列方法的总体流程图。
【具体实施方式】
根据本发明方法,实现对图1的java源码自动生成统一回调序列。
本发明首先搭建出Android回调信息库,构建白名单集,注册关系集,释放注册关系集,组件间跳转函数集,回调函数集。
对图1所示源码进行函数-回调映射预处理。初始化回调函数集callbackSet和开发者自定义的非回调函数集funSignedSet为空集。对图1的源码进行扫描,每扫描到一个函数定义,就标记这个函数的前驱函数和后继函数,并对该函数进行分类标记,分类标记方法是:查看该函数的名称是否出现在Android回调信息库中回调函数集中,如果出现,则为callbackSet添加新元素,包含函数名,所属类名,参数描述,前驱函数,后继函数,所属组件类型,回调函数类型七个属性。如果该函数名称未出现在Android回调信息库中的回调函数集中,则为funSignedSet添加新元素包含函数名,所属类名,参数描述,前驱函数,后继函数,所属组件类型六个属性。基于这两个集合,以每一个回调函数作为调用者,依次搜索被调用后继非回调函数,并且迭代搜索后继,直到没有后继的非回调函数,在遍历过程中,记录该初始回调函数整个搜索调用顺序来生成函数-回调映射列表中的一条记录;若该回调函数没有后继的非回调函数,则不生成记录。由于仅有回调函数ShareMyPosition.onResume存在非回调后继ShareMyPosition.performLocation并且ShareMyPosition.performLocation没有非回调后继函数,因而函数-回调映射列表仅存在一条记录。最终获取到的回调函数集callbackSet、非回调函数集funSignedSet及函数-回调映射列表分别如表1、表2、表3所示。
表1回调函数集callbackSet
表2非回调函数集funSignedSet
表3函数-回调映射表
之后生成完备的生命周期序列图,如图2。初始化被实现的生命周期回调集合lifeNodes为空,在函数-回调映射预处理得到的callbackSet集合中识别回调类型为“lifecycle”的元素,每出现一个生命周期回调函数,就为lifeNodes添加一个新元素,最终添加上onActiveStart,onActiveEnd和onTerminal三个辅助节点得到组件C被实现的生命周期回调lifeNodes,在callbackSet中匹配回调函数类型为“lifecycle”的元素,得到实现的生命周期回调集合lifeNodes为{ShareMyPosition.init,ShareMyPosition.onCreate,ShareMyPosition.onResume,ShareMyPosition.onPause,ShareMyPosition.onActiveStart,ShareMyPosition.onActiveEnd,ShareMyPosition.onTerminal}。初始化hiddenNodes集合为ELG中全部节点集合,对hiddenNodes的每个元素hiddenNode,若该元素在lifeNodes集合中,则在hiddenNodes集合中删除该元素,最终得到未被实现的生命周期回调函数隐藏节点集合hiddenNodes为{ShareMyPosition.onStart,ShareMyPosition.onRestart,ShareMyPosition.onStop,ShareMyPosition.onDestory}。对一个hiddenNode节点ShareMyPosition.onStart,找到其父亲节点为ShareMyPosition.onCreate和子节点ShareMyPosition.onResume,并生成串行序列ShareMyPosition.onCreate->ShareMyPosition.onResume,并将序列ShareMyPosition.onCreate->ShareMyPosition.onStart和ShareMyPosition.onStart->ShareMyPosition.onResume删除。同样对hiddenNodes中的其他元素做类似操作,得到如图3的序列图。
然后识别注册或释放注册动作的关键连接点,生成由注册或释放注册引起的非生命周期回调序列。扫描源码寻找与Android回调信息库中注册关系集和释放注册关系集的元素相匹配的语句,若匹配,则为一个注册或释放注册动作的关键连接点。找到的四个注册动作的关键连接点为{locationManager.requestLocationUpdates,AlertDialog.setNeutralButton,AlertDialog.setPositiveButton,AlertDialog.setNegativeButton},没有找到释放注册动作的关键连接点。以连接点locationManager.requestLocationUpdates为例,该连接点被函数ShareMyPosition.performLocation函数调用,即该连接点的前驱函数为ShareMyPosition.performLocation,由于ShareMyPosition.performLocation为非回调函数,那么通过函数-回调映射列表找到它的前驱函数为ShareMyPosition.onResume,该函数为一个回调函数,停止搜索。那么locationManager.requestLocationUpdates的前驱回调为ShareMyPosition.onResume。寻找其后继回调为ShareMyPosition.onLocationChanged。因为该前驱回调是一个生命周期回调,所以该注册关系为lifecycle->non-lifecycle,对应生成ShareMyPosition.onActiveStart->ShareMyPosition.onLocationChanged->ShareMyPosition.onActiveEnd串行序列。对其他三个注册动作关键连接点做类似操作,得到如图4的序列图。
识别Activity跳转及Service跳转动作的关键连接点,生成跳转链接。扫描源码寻找与Android回调信息库中组件间跳转函数集的元素相匹配的语句,若匹配,则为一个组件间跳转动作的关键连接点。找到的两个跳转动作关键连接点为{startActivity(option),startActivity(share)}。对关键连接点生成跳转链接如表4。
表4跳转链接表
最后为每个跳转链接生成由Activity跳转引起的非生命周期回调序列。对链接startActivity(option),由于该链接类型为connection_activity,因此生成串行回调序列ShareMyPosition.onActiveEnd->option.init和option.onTerminal->ShareMyPosition.onActiveStart。同理对另一链接生成类似序列,最终完整的回调序列模型图如图5,整个算法结束。
机译: 一种计算机实现的方法,用于自动生成至少一个代表驱动程序功能的基于块的建模环境块
机译: 基于轮廓的序列自动生成机器以及序列自动生成方法
机译: 基于轮廓的序列自动生成机器以及序列自动生成方法