searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

Android污点分析工具FlowDroid源码分析

2024-08-07 09:33:48
84
0

Table of Contents

  1. [what is FlowDroid?]
  2. [what is soot?]
  3. [soot 使用]
  4. [编译]
  5. [调试]
  6. [源码初步阅读]
    1. [level-1 环境初始化]
    2. [level-2 污点规则解析]
    3. [level-3 Soot配置等]
    4. [level-4 分析主流程]
  7. [what is CG, CFG, ICFG]
  8. [源码调试和流程梳理]
  9. [问题总结]

what is FlowDroid?

针对APK实现的污点分析框架,其中包括的几个概念:

source 表示污点产生的位置
sink 表示目标触发的位置
taintWrapper 表示污点的传递规则
entry 表示程序的入口

void onCreate(Bundle b){
    TelephonyManager mgr = (TelephonyManager) this.getSystemService(TELEPHONY_SERVICE);
    String deviceId = mgr.getDeviceId();	// source
    SmsManager sms = SmsManager.getDefault();
    sms.sendTextMessage("+49 1234", null, deviceId, null, null); // sink, leak
}

污点从 deviceId 到发送,最后触发到信息泄漏的位置,一个分析就完成了

该框架的四个部分,看了下代码结构和命名,大概功能为:

soot-infoflow: 数据流分析核心包(基于Soot)
soot-infoflow-android: 与安卓特性相关的数据流分析
soot-infoflow-summaries:大部分自定义API的类封装
soot-infoflow-cmd:命令行入口

分析基础是soot框架程

what is soot?

该框架提供了apk静态分析的大部分功能,如apk文件反汇编,将java字节码和dex字节码翻译成中间语言

可以有四种输出结果的表示方式,这里主要使用Jimple 这种表示方式,
其实跟java非常像,用较少的信息来表示类、变量之间的关系,它只要15种opcode就可以描述

Soot 提供所有类之间相互关联,可生成CFG(control flow graph)

里边还整合Heros,做到了从指定的变量到另一个指定的变量的寻路过程

关于soot介绍文章暂时不耗费精力去爬,先关注主线

后续有时间再详细爬一爬的文章:

[soot静态分析框架]
[soot学习笔记]

soot 使用

soot 不支持java 16

使用soot 命令行跑目标java文件,坑可真多,,,最终

单个java文件生成 jimple

java -cp sootclasses-trunk-jar-with-dependencies.jar soot.Main -cp . -pp -f jimple Hello -d sootOut

针对整个包进行处理问题还没解决,暂时先记录

╰─ java -cp sootclasses-trunk-jar-with-dependencies.jar soot.Main -cp . -pp -f jimple -process-dir TestCase/src
Soot started on Wed Apr 21 15:06:51 CST 2021
Exception in thread "main" java.lang.Error: Error: Failed to load java.lang.CharSequence.
        at soot.JastAddJ.PathPart.getCompilationUnit(PathPart.java:109)
        at soot.JastAddJ.Program.getCompilationUnit(Program.java:844)
        at soot.JastAddJ.Program.getLibCompilationUnit_compute(Program.java:1517)
        at soot.JastAddJ.Program.getLibCompilationUnit(Program.java:1500)
        at soot.JastAddJ.Program.lookupLibType_compute(Program.java:1465)

先处理优先级比较搞的载荷收集工作

编译

配置依赖环境 jdk, FlowDroid, maven

编译:

cd FlowDroid && mvn compile -DSkipTests
...
...
[INFO] -----------------< de.fraunhofer.sit.flowdroid:parent >-----------------
[INFO] Building FlowDroid Parent Module 2.9.0-SNAPSHOT                    [5/5]
[INFO] --------------------------------[ pom ]---------------------------------
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary for FlowDroid Parent Module 2.9.0-SNAPSHOT:
[INFO]
[INFO] soot-infoflow ...................................... SUCCESS [06:00 min]
[INFO] soot-infoflow-android .............................. SUCCESS [02:44 min]
[INFO] StubDroid .......................................... SUCCESS [ 25.699 s]
[INFO] FlowDroid Command Line Util ........................ SUCCESS [  3.720 s]
[INFO] FlowDroid Parent Module ............................ SUCCESS [  0.001 s]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  09:14 min
[INFO] Finished at: 2021-04-19T10:48:58+08:00
[INFO] ------------------------------------------------------------------------

mvn的几个命令

mvn compile:  编译,将Java 源程序编译成 class 字节码文件
mvn test:     测试,并生成测试报告
mvn clean:    清除,将以前编译得到的旧的 class 字节码文件删除
mvn package:  打包,动态 web工程打 war包,Java工程打 jar 包
mvn install:  将项目生成 jar 包放在仓库中,以便别的模块调用

-DskipTests:  不执行测试用例,但编译测试用例类生成相应的class文件至target/test-classes下。
-Dmaven.test.skip=true: 不执行测试用例,也不编译测试用例类。

配置下 Android SDK, 编译生成jar包,跑一下测试样例:

╰─ java -jar soot-infoflow-cmd/target/soot-infoflow-cmd-jar-with-dependencies.jar -a soot-infoflow-android/testAPKs/enriched1.apk -p $ANDROID_SDK_HOME/platforms -s soot-infoflow-android/SourcesAndSinks.txt

[main] INFO soot.jimple.infoflow.cmd.MainClass - Analyzing app /mnt/d/Working/github/FlowDroid/soot-infoflow-android/testAPKs/enriched1.apk (1 of 1)...
[main] INFO soot.jimple.infoflow.android.SetupApplication - Initializing Soot...
[main] INFO soot.jimple.infoflow.android.SetupApplication - Loading dex files...
[main] INFO soot.jimple.infoflow.android.SetupApplication - ARSC file parsing took 0.0242925 seconds
[main] INFO soot.jimple.infoflow.memory.MemoryWarningSystem - Registered a memory warning system for 2,833.2 MiB
[main] INFO soot.jimple.infoflow.android.entryPointCreators.AndroidEntryPointCreator - Creating Android entry point for 1 components...
[main] INFO soot.jimple.infoflow.android.SetupApplication - Constructing the callgraph...
Found 55 instanceinvoke , 4 staticinvoke edge descriptions
...
[main] INFO soot.jimple.infoflow.android.SetupApplication$InPlaceInfoflow - The sink virtualinvoke $r10.<android.telephony.SmsManager: void sendTextMessage(java.lang.String,java.lang.String,java.lang.String,android.app.PendingIntent,android.app.PendingIntent)>($r6, $r11, $r12, $r13, $r14) in method <de.ecspride.reflectionprivacyleak1.ReflectionPrivacyLeak1: void onCreate(android.os.Bundle)> was called with values from the following sources:
[main] INFO soot.jimple.infoflow.android.SetupApplication$InPlaceInfoflow - - $r6 = virtualinvoke $r4.<android.telephony.TelephonyManager: java.lang.String getDeviceId()>() in method <de.ecspride.reflectionprivacyleak1.ReflectionPrivacyLeak1: void onCreate(android.os.Bundle)>
[main] INFO soot.jimple.infoflow.android.SetupApplication$InPlaceInfoflow - Data flow solver took 0 seconds. Maximum memory consumption: 133 MB
[main] INFO soot.jimple.infoflow.android.SetupApplication - Found 1 leaks

调试

原项目基于eclipse编译,这个ide太丑了。。。

查了下mvn项目导入jb的资料,实践下来用 intellij idea 调试步骤:

File -> New -> Project from Existing Sources… -> FlowDroid -> Import project from external model -> Maven

Settings -> Build, -> Build Tools -> Maven -> Maven home path

等待下完Maven插件以后,编译即可

Debug -> New Application -> soot-info-cmd -> soot.jimple.infoflow.cmd.MainClass -> params -> Apply

下好断点,即可开始调试

interesting!!!

源码初步阅读

直接使用 understand 先读一下整个结构

level-1 环境初始化

代码从 MainClass.run 开始派发

命令行处理,目标收集 Collections,输出目录创建,污点分析对象初始化等操作

后续可能需要详细理解的几个函数:

soot.jimple.infoflow.cmd.MainClass.initializeTaintWrapper
soot.jimple.infoflow.cmd.MainClass.injectStubDroidHierarchy
soot.jimple.infoflow.cmd.MainClass.createFlowDroidInstance
soot.jimple.infoflow.android.SetupApplication.setTaintWrapper

level-2 污点规则解析

代码由 soot.jimple.infoflow.android.SetupApplication.runInfoflow 开始派发

SourceSink文件解析(支持 xml, txt, rifl)

level-3 Soot配置等

soot.jimple.infoflow.android.SetupApplication.runInfoflow

Soot初始化和配置,获取SourceSink规则,

apk资源解析,查找应用入口点

需要详细理解的几个函数:

soot.jimple.infoflow.android.SetupApplication.parseAppResources
soot.jimple.infoflow.android.SetupApplication.processEntryPoint
soot.jimple.infoflow.android.SetupApplication.serializeResults

level-4 分析主流程

代码由 soot.jimple.infoflow.android.SetupApplication.processEntryPoint 开始派发

这部分代码需要详细调试跟一遍

what is CG, CFG, ICFG

代码中出现了很多类似的概念,理解这三者的区别

CG是表示整个程序中方法(函数)之间调用关系的图,图中的节点是方法,边表示调用关系。
例如方法foo()调用了方法bar(),则CG中应有一条从foo()到bar()的有向边。

CFG是表示一个方法内的程序执行流的图,图中的节点是语句(指令),边表示执行流。
例如语句A执行后的下一条语句是B,则CFG中应有一条从A到B的有向边。
条件语句(if-else, while-do)之后可能执行的语句不止一个,可能执行true-branch或false-branch,
所以CFG上条件语句节点的后缀会有多个,表示其后可能执行的不同branches。

ICFG(interprocedural control-flow graph),它的信息就是CG加上CFG的信息。
ICFG可以看做是给所有方法的CFG加上这些方法之间互相调用的边(CG)所形成的图。
调用边(call edge)从调用语句(call site)连到被调方法(callee)的入口。
与CG不同的是,ICFG除了调用边,还包含相应的返回边(return edge),从callee的出口连到call site之后执行的下一个语句。

源码调试和流程梳理

还要安装windows android sdk, jdk, 真是麻烦。。。

跟下函数 processEntryPoin

通过soot提取目标所有入口点信息,即class文件相关信息

entryPointClasses = {HashSet@2176}  size = 1
 0 = {SootClass@2821} "de.ecspride.reflectionprivacyleak1.ReflectionPrivacyLeak1"
   name = "de.ecspride.reflectionprivacyleak1.ReflectionPrivacyLeak1"
   shortName = "ReflectionPrivacyLeak1"
   fixedShortName = null
   packageName = "de.ecspride.reflectionprivacyleak1"
   fixedPackageName = null
   modifiers = 1
   fields = null
   subSigToMethods = {SmallNumberedMap@2827}
   methodList = {Collections$SynchronizedRandomAccessList@2828}  size = 10
     0 = {SootMethod@2837} "<de.ecspride.reflectionprivacyleak1.ReflectionPrivacyLeak1: void <init>()>"
     1 = {SootMethod@2838} "<de.ecspride.reflectionprivacyleak1.ReflectionPrivacyLeak1: java.lang.String deobfuscateString(java.lang.String)>"
     2 = {SootMethod@2839} "<de.ecspride.reflectionprivacyleak1.ReflectionPrivacyLeak1: void dummyActivityCalls()>"
     3 = {SootMethod@2840} "<de.ecspride.reflectionprivacyleak1.ReflectionPrivacyLeak1: void onCreate(android.os.Bundle)>"
     4 = {SootMethod@2841} "<de.ecspride.reflectionprivacyleak1.ReflectionPrivacyLeak1: void onDestroy()>"
     5 = {SootMethod@2842} "<de.ecspride.reflectionprivacyleak1.ReflectionPrivacyLeak1: void onPause()>"
     6 = {SootMethod@2843} "<de.ecspride.reflectionprivacyleak1.ReflectionPrivacyLeak1: void onRestart()>"
     7 = {SootMethod@2844} "<de.ecspride.reflectionprivacyleak1.ReflectionPrivacyLeak1: void onResume()>"
     8 = {SootMethod@2845} "<de.ecspride.reflectionprivacyleak1.ReflectionPrivacyLeak1: void onStart()>"
     9 = {SootMethod@2846} "<de.ecspride.reflectionprivacyleak1.ReflectionPrivacyLeak1: void onStop()>"
   interfaces = null
   isInScene = true
   superClass = {SootClass@2829} "android.app.Activity"
   outerClass = null
   isPhantom = false
   moduleName = null
   moduleInformation = null
   refType = {RefType@2830} "de.ecspride.reflectionprivacyleak1.ReflectionPrivacyLeak1"
   resolvingLevel = 3
   number = 1915
   line = 0
   col = 0
   mTagList = {ArrayList@2831}  size = 1
   0 = {SourceFileTag@2867} "ReflectionPrivacyLeak1.java"

通过 soot 生成 ICFG 控制流,截取部分:

STATIC edge: staticinvoke <dummyMainClass: de.ecspride.reflectionprivacyleak1.ReflectionPrivacyLeak1 dummyMainMethod_de_ecspride_reflectionprivacyleak1_ReflectionPrivacyLeak1(android.content.Intent)>(null) in <dummyMainClass: void dummyMainMethod(java.lang.String[])> ==> <dummyMainClass: de.ecspride.reflectionprivacyleak1.ReflectionPrivacyLeak1 dummyMainMethod_de_ecspride_reflectionprivacyleak1_ReflectionPrivacyLeak1(android.content.Intent)>

SPECIAL edge: specialinvoke $r0.<de.ecspride.reflectionprivacyleak1.ReflectionPrivacyLeak1: void <init>()>() in <dummyMainClass: de.ecspride.reflectionprivacyleak1.ReflectionPrivacyLeak1 dummyMainMethod_de_ecspride_reflectionprivacyleak1_ReflectionPrivacyLeak1(android.content.Intent)> ==> <de.ecspride.reflectionprivacyleak1.ReflectionPrivacyLeak1: void <init>()>

VIRTUAL edge: virtualinvoke $r0.<de.ecspride.reflectionprivacyleak1.ReflectionPrivacyLeak1: void onCreate(android.os.Bundle)>(null) in <dummyMainClass: de.ecspride.reflectionprivacyleak1.ReflectionPrivacyLeak1 dummyMainMethod_de_ecspride_reflectionprivacyleak1_ReflectionPrivacyLeak1(android.content.Intent)> ==> <de.ecspride.reflectionprivacyleak1.ReflectionPrivacyLeak1: void onCreate(android.os.Bundle)>

遍历 ICFG.cg 所有的 SootMethod(方法), 获取 SootMethod 中的 jimple 代码(方法对应的实现),

遍历所有jimple中的语句,如果存在 SourceSink 中,相应的加入到 collectedSources 和 collectedSinks

最后调用 forwardSolver.solve() 确认source点到sink点是否存在联通的数据路径,如果存在则认为是一个风险点

前向追踪的算法主要在heros中实现,暂时不去研究

总结下来,其实现的伪代码如下:

int sinkCount = 0;

// 如果 InfoflowCFG 存在 cg,则获取所有的SootMethod列表
for (SootMethod sm : getMethodsForSeeds(iCfg)) {
    // 获取每个SootMethod对应的jimple语句
    units = sm.getActiveBody().getUnits();
    for (Unit u : units) {
        if (u in getSourceInfo())
            collectedSources.add(s);
        if (u in getSinkInfo) {
            sinkCount++;
            collectedSinks.add(s);
        }
    }
}

// 查找Sink关联路径
if (sinkCount > 0):
    forwardSolver.solve();

问题总结

FlowDroid 是针对 apk 文件进行分析
如果apk文件过大,则会在生成 数据流调用图(ICFG)时占用大量时间和主机性能
如果apk加壳,则在反编译阶段就会出现问题

因此针对apk分析除了需要完善 SourceSink 规则之外,更多的要考虑程序的稳定性和效率问题

如果只针对 java 做污点分析的话,apk反编译问题可以很好的避开,但是效率问题仍然不能忽略
在后续的研究中,如果碰到效率问题,考虑将ICFG转成CG或CFG

0条评论
0 / 1000
idhyt
2文章数
0粉丝数
idhyt
2 文章 | 0 粉丝
idhyt
2文章数
0粉丝数
idhyt
2 文章 | 0 粉丝
原创

Android污点分析工具FlowDroid源码分析

2024-08-07 09:33:48
84
0

Table of Contents

  1. [what is FlowDroid?]
  2. [what is soot?]
  3. [soot 使用]
  4. [编译]
  5. [调试]
  6. [源码初步阅读]
    1. [level-1 环境初始化]
    2. [level-2 污点规则解析]
    3. [level-3 Soot配置等]
    4. [level-4 分析主流程]
  7. [what is CG, CFG, ICFG]
  8. [源码调试和流程梳理]
  9. [问题总结]

what is FlowDroid?

针对APK实现的污点分析框架,其中包括的几个概念:

source 表示污点产生的位置
sink 表示目标触发的位置
taintWrapper 表示污点的传递规则
entry 表示程序的入口

void onCreate(Bundle b){
    TelephonyManager mgr = (TelephonyManager) this.getSystemService(TELEPHONY_SERVICE);
    String deviceId = mgr.getDeviceId();	// source
    SmsManager sms = SmsManager.getDefault();
    sms.sendTextMessage("+49 1234", null, deviceId, null, null); // sink, leak
}

污点从 deviceId 到发送,最后触发到信息泄漏的位置,一个分析就完成了

该框架的四个部分,看了下代码结构和命名,大概功能为:

soot-infoflow: 数据流分析核心包(基于Soot)
soot-infoflow-android: 与安卓特性相关的数据流分析
soot-infoflow-summaries:大部分自定义API的类封装
soot-infoflow-cmd:命令行入口

分析基础是soot框架程

what is soot?

该框架提供了apk静态分析的大部分功能,如apk文件反汇编,将java字节码和dex字节码翻译成中间语言

可以有四种输出结果的表示方式,这里主要使用Jimple 这种表示方式,
其实跟java非常像,用较少的信息来表示类、变量之间的关系,它只要15种opcode就可以描述

Soot 提供所有类之间相互关联,可生成CFG(control flow graph)

里边还整合Heros,做到了从指定的变量到另一个指定的变量的寻路过程

关于soot介绍文章暂时不耗费精力去爬,先关注主线

后续有时间再详细爬一爬的文章:

[soot静态分析框架]
[soot学习笔记]

soot 使用

soot 不支持java 16

使用soot 命令行跑目标java文件,坑可真多,,,最终

单个java文件生成 jimple

java -cp sootclasses-trunk-jar-with-dependencies.jar soot.Main -cp . -pp -f jimple Hello -d sootOut

针对整个包进行处理问题还没解决,暂时先记录

╰─ java -cp sootclasses-trunk-jar-with-dependencies.jar soot.Main -cp . -pp -f jimple -process-dir TestCase/src
Soot started on Wed Apr 21 15:06:51 CST 2021
Exception in thread "main" java.lang.Error: Error: Failed to load java.lang.CharSequence.
        at soot.JastAddJ.PathPart.getCompilationUnit(PathPart.java:109)
        at soot.JastAddJ.Program.getCompilationUnit(Program.java:844)
        at soot.JastAddJ.Program.getLibCompilationUnit_compute(Program.java:1517)
        at soot.JastAddJ.Program.getLibCompilationUnit(Program.java:1500)
        at soot.JastAddJ.Program.lookupLibType_compute(Program.java:1465)

先处理优先级比较搞的载荷收集工作

编译

配置依赖环境 jdk, FlowDroid, maven

编译:

cd FlowDroid && mvn compile -DSkipTests
...
...
[INFO] -----------------< de.fraunhofer.sit.flowdroid:parent >-----------------
[INFO] Building FlowDroid Parent Module 2.9.0-SNAPSHOT                    [5/5]
[INFO] --------------------------------[ pom ]---------------------------------
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary for FlowDroid Parent Module 2.9.0-SNAPSHOT:
[INFO]
[INFO] soot-infoflow ...................................... SUCCESS [06:00 min]
[INFO] soot-infoflow-android .............................. SUCCESS [02:44 min]
[INFO] StubDroid .......................................... SUCCESS [ 25.699 s]
[INFO] FlowDroid Command Line Util ........................ SUCCESS [  3.720 s]
[INFO] FlowDroid Parent Module ............................ SUCCESS [  0.001 s]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  09:14 min
[INFO] Finished at: 2021-04-19T10:48:58+08:00
[INFO] ------------------------------------------------------------------------

mvn的几个命令

mvn compile:  编译,将Java 源程序编译成 class 字节码文件
mvn test:     测试,并生成测试报告
mvn clean:    清除,将以前编译得到的旧的 class 字节码文件删除
mvn package:  打包,动态 web工程打 war包,Java工程打 jar 包
mvn install:  将项目生成 jar 包放在仓库中,以便别的模块调用

-DskipTests:  不执行测试用例,但编译测试用例类生成相应的class文件至target/test-classes下。
-Dmaven.test.skip=true: 不执行测试用例,也不编译测试用例类。

配置下 Android SDK, 编译生成jar包,跑一下测试样例:

╰─ java -jar soot-infoflow-cmd/target/soot-infoflow-cmd-jar-with-dependencies.jar -a soot-infoflow-android/testAPKs/enriched1.apk -p $ANDROID_SDK_HOME/platforms -s soot-infoflow-android/SourcesAndSinks.txt

[main] INFO soot.jimple.infoflow.cmd.MainClass - Analyzing app /mnt/d/Working/github/FlowDroid/soot-infoflow-android/testAPKs/enriched1.apk (1 of 1)...
[main] INFO soot.jimple.infoflow.android.SetupApplication - Initializing Soot...
[main] INFO soot.jimple.infoflow.android.SetupApplication - Loading dex files...
[main] INFO soot.jimple.infoflow.android.SetupApplication - ARSC file parsing took 0.0242925 seconds
[main] INFO soot.jimple.infoflow.memory.MemoryWarningSystem - Registered a memory warning system for 2,833.2 MiB
[main] INFO soot.jimple.infoflow.android.entryPointCreators.AndroidEntryPointCreator - Creating Android entry point for 1 components...
[main] INFO soot.jimple.infoflow.android.SetupApplication - Constructing the callgraph...
Found 55 instanceinvoke , 4 staticinvoke edge descriptions
...
[main] INFO soot.jimple.infoflow.android.SetupApplication$InPlaceInfoflow - The sink virtualinvoke $r10.<android.telephony.SmsManager: void sendTextMessage(java.lang.String,java.lang.String,java.lang.String,android.app.PendingIntent,android.app.PendingIntent)>($r6, $r11, $r12, $r13, $r14) in method <de.ecspride.reflectionprivacyleak1.ReflectionPrivacyLeak1: void onCreate(android.os.Bundle)> was called with values from the following sources:
[main] INFO soot.jimple.infoflow.android.SetupApplication$InPlaceInfoflow - - $r6 = virtualinvoke $r4.<android.telephony.TelephonyManager: java.lang.String getDeviceId()>() in method <de.ecspride.reflectionprivacyleak1.ReflectionPrivacyLeak1: void onCreate(android.os.Bundle)>
[main] INFO soot.jimple.infoflow.android.SetupApplication$InPlaceInfoflow - Data flow solver took 0 seconds. Maximum memory consumption: 133 MB
[main] INFO soot.jimple.infoflow.android.SetupApplication - Found 1 leaks

调试

原项目基于eclipse编译,这个ide太丑了。。。

查了下mvn项目导入jb的资料,实践下来用 intellij idea 调试步骤:

File -> New -> Project from Existing Sources… -> FlowDroid -> Import project from external model -> Maven

Settings -> Build, -> Build Tools -> Maven -> Maven home path

等待下完Maven插件以后,编译即可

Debug -> New Application -> soot-info-cmd -> soot.jimple.infoflow.cmd.MainClass -> params -> Apply

下好断点,即可开始调试

interesting!!!

源码初步阅读

直接使用 understand 先读一下整个结构

level-1 环境初始化

代码从 MainClass.run 开始派发

命令行处理,目标收集 Collections,输出目录创建,污点分析对象初始化等操作

后续可能需要详细理解的几个函数:

soot.jimple.infoflow.cmd.MainClass.initializeTaintWrapper
soot.jimple.infoflow.cmd.MainClass.injectStubDroidHierarchy
soot.jimple.infoflow.cmd.MainClass.createFlowDroidInstance
soot.jimple.infoflow.android.SetupApplication.setTaintWrapper

level-2 污点规则解析

代码由 soot.jimple.infoflow.android.SetupApplication.runInfoflow 开始派发

SourceSink文件解析(支持 xml, txt, rifl)

level-3 Soot配置等

soot.jimple.infoflow.android.SetupApplication.runInfoflow

Soot初始化和配置,获取SourceSink规则,

apk资源解析,查找应用入口点

需要详细理解的几个函数:

soot.jimple.infoflow.android.SetupApplication.parseAppResources
soot.jimple.infoflow.android.SetupApplication.processEntryPoint
soot.jimple.infoflow.android.SetupApplication.serializeResults

level-4 分析主流程

代码由 soot.jimple.infoflow.android.SetupApplication.processEntryPoint 开始派发

这部分代码需要详细调试跟一遍

what is CG, CFG, ICFG

代码中出现了很多类似的概念,理解这三者的区别

CG是表示整个程序中方法(函数)之间调用关系的图,图中的节点是方法,边表示调用关系。
例如方法foo()调用了方法bar(),则CG中应有一条从foo()到bar()的有向边。

CFG是表示一个方法内的程序执行流的图,图中的节点是语句(指令),边表示执行流。
例如语句A执行后的下一条语句是B,则CFG中应有一条从A到B的有向边。
条件语句(if-else, while-do)之后可能执行的语句不止一个,可能执行true-branch或false-branch,
所以CFG上条件语句节点的后缀会有多个,表示其后可能执行的不同branches。

ICFG(interprocedural control-flow graph),它的信息就是CG加上CFG的信息。
ICFG可以看做是给所有方法的CFG加上这些方法之间互相调用的边(CG)所形成的图。
调用边(call edge)从调用语句(call site)连到被调方法(callee)的入口。
与CG不同的是,ICFG除了调用边,还包含相应的返回边(return edge),从callee的出口连到call site之后执行的下一个语句。

源码调试和流程梳理

还要安装windows android sdk, jdk, 真是麻烦。。。

跟下函数 processEntryPoin

通过soot提取目标所有入口点信息,即class文件相关信息

entryPointClasses = {HashSet@2176}  size = 1
 0 = {SootClass@2821} "de.ecspride.reflectionprivacyleak1.ReflectionPrivacyLeak1"
   name = "de.ecspride.reflectionprivacyleak1.ReflectionPrivacyLeak1"
   shortName = "ReflectionPrivacyLeak1"
   fixedShortName = null
   packageName = "de.ecspride.reflectionprivacyleak1"
   fixedPackageName = null
   modifiers = 1
   fields = null
   subSigToMethods = {SmallNumberedMap@2827}
   methodList = {Collections$SynchronizedRandomAccessList@2828}  size = 10
     0 = {SootMethod@2837} "<de.ecspride.reflectionprivacyleak1.ReflectionPrivacyLeak1: void <init>()>"
     1 = {SootMethod@2838} "<de.ecspride.reflectionprivacyleak1.ReflectionPrivacyLeak1: java.lang.String deobfuscateString(java.lang.String)>"
     2 = {SootMethod@2839} "<de.ecspride.reflectionprivacyleak1.ReflectionPrivacyLeak1: void dummyActivityCalls()>"
     3 = {SootMethod@2840} "<de.ecspride.reflectionprivacyleak1.ReflectionPrivacyLeak1: void onCreate(android.os.Bundle)>"
     4 = {SootMethod@2841} "<de.ecspride.reflectionprivacyleak1.ReflectionPrivacyLeak1: void onDestroy()>"
     5 = {SootMethod@2842} "<de.ecspride.reflectionprivacyleak1.ReflectionPrivacyLeak1: void onPause()>"
     6 = {SootMethod@2843} "<de.ecspride.reflectionprivacyleak1.ReflectionPrivacyLeak1: void onRestart()>"
     7 = {SootMethod@2844} "<de.ecspride.reflectionprivacyleak1.ReflectionPrivacyLeak1: void onResume()>"
     8 = {SootMethod@2845} "<de.ecspride.reflectionprivacyleak1.ReflectionPrivacyLeak1: void onStart()>"
     9 = {SootMethod@2846} "<de.ecspride.reflectionprivacyleak1.ReflectionPrivacyLeak1: void onStop()>"
   interfaces = null
   isInScene = true
   superClass = {SootClass@2829} "android.app.Activity"
   outerClass = null
   isPhantom = false
   moduleName = null
   moduleInformation = null
   refType = {RefType@2830} "de.ecspride.reflectionprivacyleak1.ReflectionPrivacyLeak1"
   resolvingLevel = 3
   number = 1915
   line = 0
   col = 0
   mTagList = {ArrayList@2831}  size = 1
   0 = {SourceFileTag@2867} "ReflectionPrivacyLeak1.java"

通过 soot 生成 ICFG 控制流,截取部分:

STATIC edge: staticinvoke <dummyMainClass: de.ecspride.reflectionprivacyleak1.ReflectionPrivacyLeak1 dummyMainMethod_de_ecspride_reflectionprivacyleak1_ReflectionPrivacyLeak1(android.content.Intent)>(null) in <dummyMainClass: void dummyMainMethod(java.lang.String[])> ==> <dummyMainClass: de.ecspride.reflectionprivacyleak1.ReflectionPrivacyLeak1 dummyMainMethod_de_ecspride_reflectionprivacyleak1_ReflectionPrivacyLeak1(android.content.Intent)>

SPECIAL edge: specialinvoke $r0.<de.ecspride.reflectionprivacyleak1.ReflectionPrivacyLeak1: void <init>()>() in <dummyMainClass: de.ecspride.reflectionprivacyleak1.ReflectionPrivacyLeak1 dummyMainMethod_de_ecspride_reflectionprivacyleak1_ReflectionPrivacyLeak1(android.content.Intent)> ==> <de.ecspride.reflectionprivacyleak1.ReflectionPrivacyLeak1: void <init>()>

VIRTUAL edge: virtualinvoke $r0.<de.ecspride.reflectionprivacyleak1.ReflectionPrivacyLeak1: void onCreate(android.os.Bundle)>(null) in <dummyMainClass: de.ecspride.reflectionprivacyleak1.ReflectionPrivacyLeak1 dummyMainMethod_de_ecspride_reflectionprivacyleak1_ReflectionPrivacyLeak1(android.content.Intent)> ==> <de.ecspride.reflectionprivacyleak1.ReflectionPrivacyLeak1: void onCreate(android.os.Bundle)>

遍历 ICFG.cg 所有的 SootMethod(方法), 获取 SootMethod 中的 jimple 代码(方法对应的实现),

遍历所有jimple中的语句,如果存在 SourceSink 中,相应的加入到 collectedSources 和 collectedSinks

最后调用 forwardSolver.solve() 确认source点到sink点是否存在联通的数据路径,如果存在则认为是一个风险点

前向追踪的算法主要在heros中实现,暂时不去研究

总结下来,其实现的伪代码如下:

int sinkCount = 0;

// 如果 InfoflowCFG 存在 cg,则获取所有的SootMethod列表
for (SootMethod sm : getMethodsForSeeds(iCfg)) {
    // 获取每个SootMethod对应的jimple语句
    units = sm.getActiveBody().getUnits();
    for (Unit u : units) {
        if (u in getSourceInfo())
            collectedSources.add(s);
        if (u in getSinkInfo) {
            sinkCount++;
            collectedSinks.add(s);
        }
    }
}

// 查找Sink关联路径
if (sinkCount > 0):
    forwardSolver.solve();

问题总结

FlowDroid 是针对 apk 文件进行分析
如果apk文件过大,则会在生成 数据流调用图(ICFG)时占用大量时间和主机性能
如果apk加壳,则在反编译阶段就会出现问题

因此针对apk分析除了需要完善 SourceSink 规则之外,更多的要考虑程序的稳定性和效率问题

如果只针对 java 做污点分析的话,apk反编译问题可以很好的避开,但是效率问题仍然不能忽略
在后续的研究中,如果碰到效率问题,考虑将ICFG转成CG或CFG

文章来自个人专栏
文章 | 订阅
0条评论
0 / 1000
请输入你的评论
0
0