Skip to content
This repository was archived by the owner on Aug 25, 2021. It is now read-only.

JAADAS reachability analysis

flankerhqd edited this page Jun 25, 2018 · 3 revisions

JAADAS reachability analysis

JAADAS中的reachability analysis基于全局的Call graph,主要代码逻辑如下:

分析的总入口点依然在entry函数中:

  def entry(enableDataFlowOut: Boolean): Iterable[VulnResult]={
    G.reset
    prepareMethodTraversal

    var mid = doNaiveAPIScan ++ doAPIMethodScan ++ doCrashAnalysis ++ doManifestAnalysis ++ doImplicitScan
    implicit val icfg = prepareFatCfg
    mid = mid ++ doConstantAPIScan ++ doReachabilityAnalysis ++ doSensitiveInfoFlow
    if(enableDataFlowOut){
      System.gc
      System.gc
      mid = mid ++ doSensitiveInfoFlowOut //very slow!
    }
    mid
  }

doReachabilityAnalysis函数即为可到达性分析的入口点。

##两类不同的分析 在entry函数中值得注意的一点是, 事实上entry包含了过程内和过程间两类分析, 以prepareFatCfg为分割点。

prepareMethodTraversal函数只为过程内分析做准备,其的主要工作就是将APK加载,对每个加载进来的函数进行字节码分析并转换为中间语言。在这个函数完成后,我们可以实施过程内的分析,例如我们可以调用Soot的API去获取具体的语句是invoke还是赋值,可以生成函数内控制流图(Control Flow Graph),但是我们在这个时候并没有整体的Call Graph可以使用。

prepareFatCfg则是对过程间分析准备的一个包装函数, 其中有很多可以配置的参数

  def prepareFatCfg: IInfoflowCFG={
    val app: SetupApplication = new SetupApplication(platformPath, apkPath)
    app.setStopAfterFirstFlow(false)
    app.setEnableImplicitFlows(true)
    app.setEnableStaticFieldTracking(true)
    app.setEnableCallbacks(false)
    app.setEnableExceptionTracking(false)
    app.setCodeEliminationMode(CodeEliminationMode.PropagateConstants)

    JadeCfg.setJcustom_clinit_enabled(true)
    JadeCfg.setcallbacks_enabled(false)
    JadeCfg.setfield_taint_propagate_enabled(false)//I don't care for constant api scan
    JadeCfg.setintent_special_wrapper_tacking_enabled(false) //don't care neither
    JadeCfg.setpublic_component_only_enabled(false)

    val easyTaintWrapper: EasyTaintWrapper = new EasyTaintWrapper(taintwrapperFile)
    app.setTaintWrapper(easyTaintWrapper)
    app.calculateSourcesSinksEntrypoints(sourceSinkDataFlowOut)
    System.out.println("Running data flow analysis...")
    app.generateInfoflowCFG
  }

这里面有两个地方是可以配置的

  • SetupApplication: 该选项来源于FlowDroid,确定了一些TaintAnalysis和调用图生成的参数。因为我们现在prepareFatCfg并不是为了在这里实现taintanalysis,而只是需要一个minimum的,在无UI callback交互的情况下的callgraph,我们选择cost最低的参数
  • JadeCfg: 这是JAADAS添加的参数,如注释所示,在跨过程constant api scan和reachability analysis中,我们选择关闭setfield_taint_propagate_enabledsetintent_special_wrapper_tacking_enabled这两个参数。(可以注意到这两个参数在后续infoflow analysis中是打开的)
    • setintent_special_wrapper_tacking_enabled 这个参见soot.jimple.infoflow.taintWrappers/EasyTaintWrapper.java, 是对FlowDroid的一个修改。
		if (stmt.getInvokeExpr() instanceof InstanceInvokeExpr) {
			InstanceInvokeExpr iiExpr = (InstanceInvokeExpr) stmt.getInvokeExpr();			
			if (taintedPath.isEmpty()
					 || iiExpr.getBase().equals(taintedPath.getPlainValue())) {
				// If the base object is tainted, we have to check whether we must kill the taint
				if (wrapType == MethodWrapType.KillTaint)
					return Collections.emptySet();
				
				// If the base object is tainted, all calls to its methods always return
				// tainted values (mark: original flowdroid code/comment but not acceptable)
				//FLANKER FIX: however this will generate huge false positives
				if (stmt instanceof DefinitionStmt) {
					DefinitionStmt def = (DefinitionStmt) stmt;

					// Check for exclusions
					//if (wrapType != MethodWrapType.Exclude)
					//FLANKER FIX: only wrapType=>CreateTaint should be tainted here
					//FLANKER FIX: special process intent (and bundle?), create taint if call is get***
					if (JadeCfg.intent_special_wrapper_tacking_enabled() &&
							( (iiExpr.getBase().getType().toString().equals("android.content.Intent") || iiExpr.getBase().getType().toString().equals("android.os.Bundle"))
									&& method.getName().startsWith("get"))) {
						taints.add(new AccessPath(def.getLeftOp(), true));
					}
					else {
						if (wrapType == MethodWrapType.CreateTaint) //flanker fix: only accept CreateTaint
							taints.add(new AccessPath(def.getLeftOp(), true));
					}
				}

				// If the base object is tainted, we pass this taint on
				taints.add(taintedPath);
			}
		}

这里主要有两个问题:FlowDroid的做法是如果一个base object被taint了,那么所有针对这个object的函数调用均返回taint。这会导致大量false postive. 这里主要有两点修改的地方

  • 如果FlowDroid的做法是如果一个base object被taint了,那么所有针对这个object的函数调用均返回taint,这种模拟相对来说有点偷懒。JAADAS在此修改为只继续传播Taintwrapper中已声明的函数,同时继续传播Intent和Bundle中的get系函数

  • 在Reachability Analysis中,我们需要将所有的component都包括进来, 所以用 JadeCfg.setpublic_component_only_enabled(false),而在intent dataflow analysis中,由于漏洞利用中一般不考虑不导出的组件,这个参数可以设为true.

在这些参数给定之后,我们调用generateInfoflowCFG函数生成全局ICFG和callgraph.

Reachability Analysis

在Callgraph生成之后,我们就可以在上面进行查询.

    val methods: ReachableMethods = Scene.v.getReachableMethods
    val reader: QueueReader[MethodOrMethodContext] = methods.listener

获取了目前从callgraph入口可到达的函数,以iterator形式返回

    val directReader: BufferedReader = new BufferedReader(new FileReader(new File(reachabilityFile)))
    val lists: Set[String] = new HashSet[String]
    val ret = new ListBuffer[VulnResult]()
    var string: String = directReader.readLine

读取预先配置的文件,文件中包含需要权限的系统API, 例如phone call , power相关.

 while (reader.hasNext) {
      val method: SootMethod = reader.next.method
      if (method.hasActiveBody) {
        val body: Body = method.getActiveBody
        for (unit <- body.getUnits) {
          val stmt: Stmt = unit.asInstanceOf[Stmt]
          if (stmt.containsInvokeExpr) {
            val expr: InvokeExpr = stmt.getInvokeExpr
            val relateMethod: SootMethod = expr.getMethod
            if (lists.contains(relateMethod.getSignature)) {
              System.out.println("find capability leak!")
              System.out.println(relateMethod.getSignature + " @ " + method)
              ret.append(VulnResult.toReachabilityVulnResult(stmt, method))
            }
          }
        }
      }
    }

扫描可到达的函数体,检查其中的调用语句是否指向需要权限的系统API. 如果是,那么证明该函数存在权限泄漏.

权限泄漏检测改进点

JAADAS中数据流分析支持路径回溯, 但权限泄漏的路径回溯还没有实现, 建议用BFS实现下.

Clone this wiki locally