为FlowDroid加上addJavascriptInterface分析(下)(未完待续)

其实我们最初的目的已经实现了,本文讲如何实现对callback的精准标记Source,最后讲一下对整个FlowDroid代码的理解和评价。

一、CallbackSourceMode

这个属性只出现在 checkCallbackParamSource 里,用于判断某些parameter是否是source。在 NoParametersAsSources 和 AllParametersAsSources 都好理解,这个 SourceListOnly困扰了我很久,直到写完本文都不知道这是个啥,而且这个值是默认值,经过阅读代码和写测试,结论是 SourceListOnly 是一个废掉的功能,而且会导致 NullPointerException 。

先在 sourceMethods 里查询,key是 getParentMethod ,就是这个参数所在的方法名。而 sourceMethods是在解析 SourcesAndSinks.txt 时构建的。以onClick为例,必须要将 OnClickListener.onClick 加入到配置文件中,才可以作为索引被查到。

之后做一些简单的判断,如果方法的参数总数大于参数的下标,直接return掉,否则返回对应的 SourceSinkDefinition 。恩,看起来比较合理,但问题也在这里, methodDef 是查表查到的,很久之前就被初始化, methodDef.getParameters 返回是 null 。

那么是否是初始化过程出现问题了呢?在 SetupApplication.runInfoflow() 中,调用 PermissionMethodParser.fromFile() ,解析配置文件并且对sourceMethods进行初始化。

直接使用了构造方法,这个构造方法的 getParameters 本来就是空,长期都没有人对其进行赋值,所以nullptr很好理解,这也佐证了我的观点,这个功能就是个辣鸡功能啊,没有任何用处,还不如用 AllParametersAsSources ,简单粗暴。

二、精准标记参数

举个例子

显然第一个参数不是我们需要的,而 AllParametersAsSources会把它也标记了,但 ctx 是没有任何用处的,会导致额外的误报。例如在 startActivity 调用时,就会说来自2个source,分别是 ctx 和 intent ,在 startActivity时参数并不是我们可以控制的,但却被认为是合理的sink点。所以必须要精准标记来减少误报。

理论上可以针对每个方法的每个参数进行过滤,但是写起来太复杂,而且配置文件也不好写。于是实现了稍微懒一点的方法,按照类名进行过滤,加个黑白名单。稍微写写配置文件和filter即可,懒得贴代码了,就在 AbstractCallbackAnalyzer.analyzeClassInterfaceCallbacks 里,加一层filter即可,很简单。

三、FlowDroid流程总结

啊,这部分应该是很长很长的,不知道需要写多久,先占个坑,慢慢往上添,本文应该是全网第一篇吧,哈哈哈。

1、比较重要的配置选项

主要列举一下我关注的选项,因为这个非常多,而且部分功能是作者默认没有开启的。

针对某些回调函数的参数是否被标记为Source,有三个选项,NoMatch、MatchAll、MatchSensitiveOnly。例如OnClickListener.onClick(View view)中的view是否被认为是source,默认是MatchSeneitiveOnly,实际测试过程中发现这个选项是坏的,所以通常是开启为MatchAll,再加上一些自己的判断。

组件生命周期中的参数是否被认为是 Source,当我们关心exported组件时候,这个要设置为true。

针对multi-dex的处理,当然是需要的。

是否开启反射的检测(似乎没啥用,不知道怎么用)

建议关掉,因为开着的话会造成各种各样莫名其妙的 crash,经常在OnFlyCallGraph里和OnFlyCallGraphBuilder里发生。

重建路径时的选项,首先会影响效率,因为要回溯一下从sink到source的路径,这里有三个选项,无/高速/高质量,区别也不大清楚,我只知道Precise慢的要死,真的要死,在Result中可以拿到ResultSourceInfo后可以 getPath 拿各个句子的Unit。

是否将findViewById的结果作为source。作者可能用于监视某些View,我觉得不大需要,直接关掉。

几个timeout,防止跑如死循环(这个东西还是经常跑死的)

2、基础用法

FlowDroid主要用于检测代码的可达性,可用于检测信息泄露,例如在 Log 里打印了明文的密码(手动艾特 Twitter,哈哈哈),处理从Sources到Sinks之间的连接。

举个简单的例子,本文也会经常使用这个例子。

这时候在SourceSink.txt里写

source 的意思就是这个变量作为起点,sink 的意思是这个函数调用作为终点,如果 sink 的参数里是被 taint 过的变量的话,就认为找到了一条路径。

在这个例子里,就表示所有的toLowerCase的结果都是source,将来被打印到log里。OK,我们提高一下难度,如果这个string后来被经过了处理,被放到了其他变量里,调用某些方法,是否还能被追踪到呢?这就涉及到了WrapTaintter。稍微复杂一点。

这时候FlowDroid也是可以测到的,加法在这里被翻译成了StringBuilder.append操作,因为默认的 EasyTaintWrapper.txt里有以下几行:

比如String foo = s + “foo”,翻译一下就是

因为有<java.lang.StringBuilder: java.lang.StringBuilder append(java.lang.String)>,如果参数是被taint过的话,那么StringBuilder在调用过这句话时候,也会被 taint 掉。再翻译到java的话,因为s被污染了,foo也被污染了,bar 也被污染了,所以最后仍然是可以找到路径的。

同理,再举个例子,对Map的一些操作,当元素被污染时,Map 本身也会被污染,也是在TaintWrapper里实现的。

嗯,这就是最基本的用法了,可以根据需要添加自己的 source/sink/taint,有个坑点就是对于继承关系的处理,是否被 taint 还需要多写 testcase 去测一下(例如InputStream系列)。结论就是(不保证一定对),在

 

3、运行流程

入口在SetupApplication.runInfoflow,先解析SourceSink的定义文件

我用的是 txt 版本的配置文件,parser 主要就是解析文件从而生成Set<SourceSinkDefinition>,用于标记特定的source/sink。SourceSinkDefinition 是一个很重要的类,构造方法有多种,这里使用的是

这种构造方法是没有定义baseObjects、parameters、retValue 的,将来在寻找Source/Sink时可能有坑。因为baseObjects、parameters需要上下文关系,我们解析文件时候还没有开始分析,这种SourceSinkDefinition是不完整的。在之后分析CallGraph时候也会产生新的SourceSinkDefinition,那种才是完整的。

 

 

 


=============================================================
随着访客的增多,LeadroyaL在本站流量的开支越来越多了,曾经1元能用1个月,现在1元只能用3天。如果觉得本文帮到了你,希望能够为服务器的流量稍微打赏一点,谢谢!

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*

code