前言

从v2.8开始,FlowDroid集成ICCTA模块,只要提供指定格式的ICC信息(即ICC model),FlowDroid可以在CallGraph(CG)中增加重定向边,弥补ICC的在CG中的不连续(如下)。本篇文章小结为了让FlowDroid实现ICC插桩,构造尽可能完整且有效的ICC model的过程。

1
2
3
4
eg. Activity1在onCreate()中调用startActivity(),调起Activity2。
ICCTA在CG中实现如下:
Activity1#onCreate() -> redirector1() -> Activity2#dummyMain() ->
Activity2#onCreate()

获取完整有效的ICC model

方案一:IC3中获取ICC model

FlowDroid中的ICCTA模块以IC3生成的ICC model作为输入样例。所以首先尝试的方法从IC3中获取ICC model。

IC3生成ICC model过程如下:

  • step1: 首先通过反编译工具dare获取apk的.class文件。
  • step2: 以.class文件作为输入,调用IC3 jar包,配合指定参数生成ICC model。

问题及解决方案

问题一:dare工具老旧,大多数应用反编译阶段就失败了,无法获取.class文件。

使用别人修改过的IC3

github有别人修改过的jar包modified-IC3.jar,只要求输入apk不需要反编译,粗略逆向发现其在源码中也使用了Dex的文件修改库dexLib2对apk做解析,相当于集成了反编译这一步。然而运行modified-IC3.jar生成ICC model, 依旧有些和dare+IC3相同的错误没法生成ICC model。

dex2jar+IC3

另一个思路是,其他反编译工具替换dare生成.class文件,这里使用了d2j-dex2jar。将结果输入到IC3并运行IC3,可以生成ICC model,但得到的ICC model只包含来自AndroidManifest.xml的组件基本信息而不包含ICC 信息字段,或者包含ICC字段信息但输入到FlowDroid中也没有产生重定向边。

问题二:IC3生成的ICC model没有包含有用的ICC 字段信息(exit_points字段)

Flowdroid导出反编译class + IC3

FlowDroid也在github上提供了他们自己用IC3生成的ICC model。对于那些dex2jar+IC3的方法中出现有效ICC model输入到FlowDroid后无法产生重定向边的测试应用,可以在FlowDroid中找到对应的ICC mode,然后输入到FlowDroid中是可以产生重定向边的。比较两个出处的ICC model发现仅有exit_point字段的id值和statement值稍有差异。由于IC3官方文档的网站没有维护,所以对C3的使用和结果解读没有找到清晰的说明,这里通过IC3,ICCTA,FlowDroid等多处提及IC3的github仓库中issue寻找答案。在某个issue中提到“id”表示调用ICC 方法的指令位置,statement表示ICC方法(记录的应该是jimple语句)。在上述信息的反馈中,导致ICC model失效的原因可能是反编译工具不同导致差异,使得比如指令位置位移不同等问题。解决方法是先运行FlowDroid导出反编译结果,然后输入到IC3生成ICC model,最后再将ICC model输入到FlowDroid。

最终可以获得ICC model,但IC3在真实应用上的表现很不好,不足以支撑分析需要。

方案二:ICCBot结果转换为ICCmodel

IC3工具在应对真实应用时存在明显不足,故采取其他更有效提取ICC的工具,再将工具结果转换为与IC3格式相同的ICC model,这里采用ICCBot

这里分为两步:

  • step1: 分析ICC model各字段含义
  • step2: 从ICCBot中提取ICC结果,转换为与IC3格式相同的ICC model

问题及解决方案

问题一:ICC model 各字段含义

name: 应用包名,manifest.package

version: 应用版本号,manifest.android:versionCode

used_permissions: 应用所申请的权限, uses-permission.android:name

components{ //组件信息,ICC包在其中

name: 组件名

kind: 组件类型, ACTIVITY等4大组件

exported: true/false 当minSdkVersion或targetSdkVersion为16或者更低时他的默认值是true。如果是17和以上的版本默认值是false。

extras{ //如果组件通过extra传递信息则存在该字段, 在调用getStringExtra的组件中出现。}

Intent_filters{

attributes {

kind: ACTION

value:

​ }

attributes {

kind: CATEGORY

value:

}

}

exit_points{ //如果有ICC,则存在该字段,显式Intent,隐式Intent不同 }

}

analysis_start:开始分析时间戳

analysis_end:结束分析时间戳

举例
  • extras字段

    以Droid Bench/ActivityCommunICation3.apk为例,代码:

    image3

    ICC model:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    components {
    name: "edu.mit.ICC_componentname_class_constant.InFlowActivity"
    ...
    ...
    extras {
    extra: "DroidBench"
    instruction {
    statement: "$r3 = virtualinvoke $r2.<android.content.Intent: java.lang.String getStringExtra(java.lang.String)>(\"DroidBench\")"
    class_name: "edu.mit.ICC_componentname_class_constant.InFlowActivity"
    method: "<edu.mit.ICC_componentname_class_constant.InFlowActivity: void onCreate(android.os.Bundle)>"
    id: 5
    }
    }
    }

    //“class_name”类里的“method”方法中的“statement”语句调用了getStringExtra,该语句在类中的绝对位置为第5行(id),这个位置与反编译结果有关
  • 显式Intent

以Droid Bench/ActivityCommunICation3.apk为例,代码:

image2

ICC model:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
components {
name: "edu.mit.ICC_componentname_class_constant.OutFlowActivity"
...
...
...
exit_points {
instruction {
statement: "virtualinvoke r0.<edu.mit.ICC_componentname_class_constant.OutFlowActivity: void startActivity(android.content.Intent)>($r8)"
class_name: "edu.mit.ICC_componentname_class_constant.OutFlowActivity"
method: "<edu.mit.ICC_componentname_class_constant.OutFlowActivity: void onCreate(android.os.Bundle)>"
id: 16
}
kind: ACTIVITY
Intents {
attributes {
kind: EXTRA
value: "DroidBench"
}
attributes {
kind: CLASS
value: "edu/mit/ICC_componentname_class_constant/InFlowActivity"
}
attributes {
kind: PACKAGE
value: "edu.mit.ICC_componentname_class_constant"
}
}
}
}

  • 隐式Intent

以DroidBench/EventOrdering1.apk为例,代码:

image4

ICC model:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
components {
name: "edu.mit.ICC_event_ordering.OutFlowActivity"
exit_points {
instruction {
statement: "virtualinvoke r0.<edu.mit.ICC_event_ordering.OutFlowActivity: void startActivity(android.content.Intent)>($r2)"
class_name: "edu.mit.ICC_event_ordering.OutFlowActivity"
method: "<edu.mit.ICC_event_ordering.OutFlowActivity: void onCreate(android.os.Bundle)>"
id: 6
}
kind: ACTIVITY
Intents {
attributes {
kind: ACTION
value: "edu.mit.ICC_event_ordering.ACTION"
}
}
}
}

问题二:从ICCBot中提取ICC model

分析源码,分析FlowDroid对ICC model的实际使用过程,删减ICC model,仅保留必要字段的最小集合。提取ICCBot的生成的ICC信息,转变为缩减版ICC model输入到FlowDroid中。ICC model必要字段包括:

  • manifest中的所有组件name值:在ICCTA识别ICC的target component时,是直接在ICC model中,通过匹配conponent name,检查是否存在target component。所以ICC model必须包含注册过的所有组件。
  • exit_points中的所有字段:exit_points提供ICC的相关信息,包括发起组件的信息(package,class,ICC 方法的caller),ICC 方法(如startActivity等),目标组件的信息(从Intent中提取的信息,显式Intent提取组件名,隐式Intent提取action,catogory等Intent filter)。