/** * For a concrete method (declared in an application class), find statements containing an invoke * expression for which the method is one of the method in 'allEventInformation' (i.e., * getLine1Number(), ...). * * @param cfg */ private void doAccessControlChecks(BiDiInterproceduralCFG<Unit, SootMethod> cfg) { for (SootClass sc : Scene.v().getApplicationClasses()) { for (SootMethod sm : sc.getMethods()) { if (sm.isConcrete()) { Body body = sm.retrieveActiveBody(); // only instrument application methods (i.e., not methods declared in PEP helper classes // or in a Java library classes or in an Android classes, ...) if (isInstrumentationNecessary(sm)) { // important to use snapshotIterator here Iterator<Unit> i = body.getUnits().snapshotIterator(); log.debug("method: " + sm); while (i.hasNext()) { Stmt s = (Stmt) i.next(); if (s.containsInvokeExpr()) { InvokeExpr invExpr = s.getInvokeExpr(); String methodSignature = invExpr.getMethod().getSignature(); if (allEventInformation.containsKey(methodSignature)) { log.debug("statement " + s + " matches " + methodSignature + "."); ResultSinkInfo sink = null; outer: for (ResultSinkInfo key : results.getResults().keySet()) { // iterate over all the arguments of the invoke expression // and check if an argument is a tainted sink. If one is // set variable 'sink' to the ResultSinkInfo key. for (Value v : invExpr.getArgs()) { Value pathValue = key.getAccessPath().getPlainValue(); if (v == pathValue) { sink = key; log.debug("found a sink: " + pathValue); break outer; } } } if (sink != null) { log.debug("instrument with data flow information )" + s + ")"); instrumentSourceToSinkConnections(cfg, sink, s instanceof AssignStmt); instrumentWithNoDataFlowInformation( methodSignature, s, invExpr, body, s instanceof AssignStmt); } else { log.debug("instrument without data flow information (" + s + ")"); instrumentWithNoDataFlowInformation( methodSignature, s, invExpr, body, s instanceof AssignStmt); } } } // if stmt containts invoke expression } // loop on statements } } } } }
@Override public void onResultsAvailable(IInfoflowCFG cfg, InfoflowResults results) { log.info( "FlowDroid has finished. Duration: " + (System.currentTimeMillis() - Main.startTime) + " ms."); Main.startTime = System.currentTimeMillis(); Settings.instance.setDummyMainToLibraryClass(); this.results = results; if (log.isDebugEnabled()) { log.debug(""); log.debug("InfoFlow Results"); MultiMap<ResultSinkInfo, ResultSourceInfo> r = results.getResults(); for (ResultSinkInfo k : r.keySet()) { log.debug("ResultSinkInfo: " + k); for (ResultSourceInfo rsi : r.get(k)) { log.debug(" source: " + rsi); } } log.debug(""); } log.info("Starting bytecode instrumentation."); log.info("Adding code to initialize PEPs."); Util.initializePePInAllPossibleClasses(Settings.instance.getApkPath()); log.info("Redirect main activity"); String mainActivityClass = UpdateManifestAndCodeForWaitPDP.redirectMainActivity(Settings.instance.getApkPath()); UpdateManifestAndCodeForWaitPDP.updateWaitPDPActivity(mainActivityClass); log.info("Adding Policy Enforcement Points (PEPs)."); doAccessControlChecks(cfg); log.info("Instrumentation is done."); if (Settings.mustOutputJimple()) { log.info("-------- Dumping Jimple bodies."); Main.dumpJimple(); log.info("--------"); } }
/** * @param cfg * @param sink * @param assignmentStatement */ private void instrumentSourceToSinkConnections( BiDiInterproceduralCFG<Unit, SootMethod> cfg, ResultSinkInfo sink, boolean assignmentStatement) { sourceSinkConnectionCounter += 1; // loop through the sinks for (ResultSinkInfo key : results.getResults().keySet()) { log.debug("compare: " + key); log.debug(" to: " + sink); // if the current sink is the sink at the unit tagged with 'sink' if (key.equals(sink)) { // loop through the sources for (ResultSourceInfo si : results.getResults().get(key)) { Stmt stmt = si.getSource(); SootMethod sm = cfg.getMethodOf(stmt); Body body = sm.retrieveActiveBody(); // Source instrumentation. The three type categories for the source are: // - callback // - ICC source method (i.e., Intent.getExtras()) // - not a callback and not an ICC source method (i.e., getLine1Number()) // if (isInterComponentSourceCallback(si, cfg)) { throw new RuntimeException("Callbacks as sources are not supported right now"); } else if (isInterComponentSourceNoCallback(si, cfg)) { // only invoke expression are treated here if (stmt.containsInvokeExpr()) { // only statements that return a android.os.Bundle are currently supported if (stmt instanceof DefinitionStmt) { DefinitionStmt defStmt = (DefinitionStmt) stmt; Value leftValue = defStmt.getLeftOp(); if (leftValue.getType().equals(RefType.v("android.os.Bundle"))) { List<Object> args = new ArrayList<Object>(); args.add(IntType.v()); args.add(IntConstant.v(sourceSinkConnectionCounter)); args.add(RefType.v("android.os.Bundle")); args.add(leftValue); InvokeExpr invExpr = Instrumentation.createJimpleStaticInvokeExpr( Settings.INSTRUMENTATION_HELPER_JAVA, "registerNewSourceSinkConnection", args); InvokeStmt invStmt = Jimple.v().newInvokeStmt(invExpr); Unit instrumentationPoint = null; if (stmt instanceof IdentityStmt) { instrumentationPoint = getLastIdentityStmt(body); } else { instrumentationPoint = stmt; } body.getUnits().insertAfter(invStmt, instrumentationPoint); log.debug("insert a: " + invStmt); } else { System.err.println("We do only support android.os.Bundle right now!"); } } } } else { String sourceCat = getSourceCategory(si); if (sourceCat != null) { List<Object> args = new ArrayList<Object>(); args.add(IntType.v()); args.add(IntConstant.v(sourceSinkConnectionCounter)); args.add(RefType.v("java.lang.String")); args.add(StringConstant.v(sourceCat)); InvokeExpr invExpr = Instrumentation.createJimpleStaticInvokeExpr( Settings.INSTRUMENTATION_HELPER_JAVA, "registerNewSourceSinkConnection", args); InvokeStmt invStmt = Jimple.v().newInvokeStmt(invExpr); Unit instrumentationPoint = null; if (stmt instanceof IdentityStmt) instrumentationPoint = getLastIdentityStmt(body); else instrumentationPoint = stmt; body.getUnits().insertAfter(invStmt, instrumentationPoint); log.debug("insert b: " + invStmt); } } // sink instrumentation if (sink.getSink().containsInvokeExpr()) { Body bodyOfSink = cfg.getMethodOf(key.getSink()).getActiveBody(); InvokeExpr invExpr = sink.getSink().getInvokeExpr(); List<Unit> generated = new ArrayList<Unit>(); generated.addAll( instrumentIntentAddings(cfg, stmt, invExpr, results.getResults().get(key))); EventInformation sinkEventInfo = allEventInformation.get(invExpr.getMethod().getSignature()); EventInformation sourceEventInfo = allEventInformation.get(si.getSource().getInvokeExpr().getMethod().getSignature()); generated.addAll( generatePolicyEnforcementPoint( key.getSink(), invExpr, bodyOfSink, sourceSinkConnectionCounter, assignmentStatement)); log.debug("body with data flow:\n" + body); for (Unit u : generated) { log.debug("gen: " + u); } if (sinkEventInfo.isInstrumentAfterStatement()) bodyOfSink.getUnits().insertAfter(generated, key.getSink()); else bodyOfSink.getUnits().insertBefore(generated, key.getSink()); } else throw new RuntimeException("Double-Check the assumption"); } // loop through the sources } // if the sink at the unit is the current sink } // loop through the sinks }