private ResultSourceInfo findDataFlowPathForSink(Stmt sinkStmt, Local sinkLokal, List<ResultSourceInfo> allDataFlows) { for(ResultSourceInfo singleFlow : allDataFlows){ Stmt[] statements = singleFlow.getPath(); AccessPath[] accessPath = singleFlow.getPathAccessPaths(); for(int i = 0; i < statements.length; i++) { Stmt currentStmt = statements[i]; if(currentStmt == sinkStmt) { if(accessPath[i].getPlainValue() == sinkLokal) return singleFlow; } else if(currentStmt instanceof AssignStmt) { AssignStmt assignStmt = (AssignStmt)currentStmt; Value lhs = assignStmt.getLeftOp(); if(lhs == sinkLokal) return singleFlow; } } } return null; }
@Override public void onResultsAvailable( IInfoflowCFG cfg, InfoflowResults results) { // Dump the results if (results == null) { print("No results found."); } else { for (ResultSinkInfo sink : results.getResults().keySet()) { print("Found a flow to sink " + sink + ", from the following sources:"); for (ResultSourceInfo source : results.getResults().get(sink)) { print("\t- " + source.getSource() + " (in " + cfg.getMethodOf(source.getSource()).getSignature() + ")"); if (source.getPath() != null && !source.getPath().isEmpty()) print("\t\ton Path " + source.getPath()); } } } }
@Override public void onResultsAvailable( IInfoflowCFG cfg, InfoflowResults results) { // Dump the results if (results == null) { print("No results found."); } else { Test.cfg = cfg; Test.results = results; for (ResultSinkInfo sink : results.getResults().keySet()) { print("Found a flow to sink " + sink + ", from the following sources:"); for (ResultSourceInfo source : results.getResults().get(sink)) { print("\t- " + source.getSource() + " (in " + cfg.getMethodOf(source.getSource()).getSignature() + ")"); if (source.getPath() != null) print("\t\ton Path " + Arrays.toString(source.getPath())); } } } }
/** * This method iterates over all sources from the FlowDroid-results and extracts the * category of the specific source. If there is no category found, it will return an empty set, * otherwise the correct categories will be added. * @param sourcesInfo: all possible sources from which we try to identify the category * @return: set of categories for specific sink */ private Set<String> getDataIdList(Set<ResultSourceInfo> sourcesInfo){ Set<String> dataIdList = new HashSet<String>(); for(ResultSourceInfo sInfo : sourcesInfo){ if(sInfo.getSource().containsInvokeExpr()){ InvokeExpr invExpr = sInfo.getSource().getInvokeExpr(); for(SourceSinkDefinition meth : sources) { AndroidMethod am = (AndroidMethod) meth.getMethod(); if(am.getSignature().equals(invExpr.getMethod().getSignature())) { dataIdList.add(am.getCategory().toString()); } } } else if (isSourceInfoParameter(sInfo)){ dataIdList.add(unknownCategory); } else throw new RuntimeException("Currently not supported"); } return dataIdList; }
private String getSourceCategory(ResultSourceInfo sourceInfo){ if(sourceInfo.getSource().containsInvokeExpr()){ InvokeExpr invExpr = sourceInfo.getSource().getInvokeExpr(); for(SourceSinkDefinition meth : sources) { AndroidMethod am = (AndroidMethod) meth.getMethod(); if(am.getSignature().equals(invExpr.getMethod().getSignature())){ return am.getCategory().toString(); } } } else if(isSourceInfoParameter(sourceInfo)){ return unknownCategory; } else throw new RuntimeException("Currently not supported"); return null; }
/** * Return true if the method corresponding to the source 'si' is an * Inter Component Communication source method such as "Intent.getExtras()". * @param si * @param cfg * @return */ private boolean isInterComponentSourceNoCallback(ResultSourceInfo si, BiDiInterproceduralCFG<Unit, SootMethod> cfg){ if(!si.getSource().containsInvokeExpr()) return false; InvokeExpr invExpr = si.getSource().getInvokeExpr(); SootMethod sm = invExpr.getMethod(); for(SourceSinkDefinition meth : sources){ AndroidMethod am = (AndroidMethod) meth.getMethod(); if(am.getCategory() == CATEGORY.INTER_APP_COMMUNICATION){ if(am.getSubSignature().equals(sm.getSubSignature())) { log.info("source is: "+ am); return true; } } } return false; }
public static Set<ResultSourceInfo> removeDuplicatedFlows(Set<ResultSourceInfo> allDataFlows) { Set<ResultSourceInfo> copy = new HashSet<ResultSourceInfo>(allDataFlows); for(ResultSourceInfo dataFlow1 : allDataFlows) { Stmt[] dataFlowPath1 = dataFlow1.getPath(); for(ResultSourceInfo dataFlow2 : allDataFlows) { Stmt[] dataFlowPath2 = dataFlow2.getPath(); if(dataFlowPath1 != dataFlowPath2 && Arrays.asList(dataFlowPath2).containsAll(Arrays.asList(dataFlowPath1))) copy.remove(dataFlow1); } } return copy; }
public Set<ResultSourceInfo> prepareDataFlowPathsForSMTConverter() { //This step is necessary for storing the ResultSourceInfo elements into a set //The result ResultSourceInfo object does only represent a source and not the dataflow. //But with the PathAgnosticResults flag, one can force the ResultSourceInfo object //to consider the path (see equals method) InfoflowConfiguration.setPathAgnosticResults(false); //control flow involved return prepareDataFlowsDependingOnControlFlow(results, FrameworkOptions.mergeDataFlows); }
private boolean isInterComponentSourceCallback(ResultSourceInfo si, BiDiInterproceduralCFG<Unit, SootMethod> cfg){ if(isSourceInfoParameter(si)){ SootMethod sm = cfg.getMethodOf(si.getSource()); if(entryPointCreator.getCallbackFunctions().containsKey(sm.getDeclaringClass())){ if(entryPointCreator.getCallbackFunctions().get(sm.getDeclaringClass()).contains(sm.getSignature())) return true; } } return false; }
private static ResultSourceInfo mergeDataFlowsIntoSingleDataFlow(Stmt statementToEnrich, ResultSourceInfo originalPath, ResultSourceInfo pathToMerge) { List<Stmt> pathStmts = new ArrayList<Stmt>(Arrays.asList(originalPath.getPath())); List<AccessPath> accessPaths = new ArrayList<AccessPath>(Arrays.asList(originalPath.getPathAccessPaths())); List<Stmt> pathToMergeStmts = new ArrayList<Stmt>(Arrays.asList(pathToMerge.getPath())); List<AccessPath> pathToMergeAccessPaths = new ArrayList<AccessPath>(Arrays.asList(pathToMerge.getPathAccessPaths())); int index = pathStmts.indexOf(statementToEnrich); // if(index < 0) // throw new RuntimeException("Woops, there is something wonkey here"); // // for(int i = 0; i < pathToMergeStmts.size(); i++) { // pathStmts.add(index, pathToMergeStmts.get(i)); // accessPaths.add(index, pathToMergeAccessPaths.get(i)); // index +=1; // } List<Pair<Stmt,AccessPath>> dataToMerge = new ArrayList<Pair<Stmt,AccessPath>>(); int position; for(position = 0; position < pathToMergeStmts.size(); position++) { if(pathStmts.contains(pathToMergeStmts.get(position)) && !dataToMerge.isEmpty()) { int indexToInsertBefore = pathStmts.indexOf(pathToMergeStmts.get(position)); indexToInsertBefore -= 1; // for(Pair<Stmt,AccessPath> pair : dataToMerge) { // pathStmts.add(indexToInsertBefore, pair.getFirst()); // accessPaths.add(indexToInsertBefore, pair.getSecond()); // ++indexToInsertBefore; // } } else if(!pathStmts.contains(pathToMergeStmts.get(position))) { dataToMerge.add(new Pair<Stmt,AccessPath>(pathToMergeStmts.get(position), pathToMergeAccessPaths.get(position))); } } if(!dataToMerge.isEmpty()) { for(Pair<Stmt,AccessPath> pair : dataToMerge) { pathStmts.add(index, pair.getFirst()); accessPaths.add(index, pair.getSecond()); ++index; } } return new ResultSourceInfo(accessPaths.get(0), pathStmts.get(0), null, pathStmts, accessPaths); }
private void standardDataFlowToSMTConvertion(ResultSourceInfo dataFlow, IInfoflowCFG cfg, Set<ResultSourceInfo> preparedDataFlowsForSMT, Table<Stmt, Integer, Set<String>> splitInfos) { SMTConverter converter = new SMTConverter(sources); for(int i = 0; i < dataFlow.getPath().length; i++) { System.out.println("\t" + dataFlow.getPath()[i]); System.out.println("\t\t" + dataFlow.getPathAccessPaths()[i]); } converter.convertJimpleToSMT(dataFlow.getPath(), dataFlow.getPathAccessPaths(), targetUnits, cfg, splitInfos); dataFlowsToSMTPrograms.put(new DataFlowObject(dataFlow.getPath()), converter.getSmtPrograms()); //dynamic value information dynamicValueInfos.putAll(converter.getDynamicValueInfos()); converter.printProgramToCmdLine(); File z3str2Script = new File(FrameworkOptions.Z3SCRIPT_LOCATION); if(!z3str2Script.exists()) throw new RuntimeException("There is no z3-script available"); SMTExecutor smtExecutor = new SMTExecutor(converter.getSmtPrograms(), z3str2Script); Set<File> smtFiles = smtExecutor.createSMTFile(); Set<Object> values = new HashSet<Object>(); for(File smtFile : smtFiles) { String loggingPointValue = smtExecutor.executeZ3str2ScriptAndExtractLoggingPointValue(smtFile); if(loggingPointValue != null) { loggingPointValue = fixSMTSolverIntegerOutput(loggingPointValue, dataFlow.getPath()[0]); //SMT solver only returns hex-based UTF-8 values in some cases; we fixed this with our own hexToUnicode converter if(loggingPointValue != null && loggingPointValue.contains("\\x")) addAdditionalUnicodeValue(loggingPointValue, values); if(loggingPointValue != null) values.add(loggingPointValue); System.out.println(String.format("Extracted loggingpoint-value: %s", loggingPointValue)); } } System.out.println("####################################"); //add values to fuzzy-seed Stmt stmt = dataFlow.getSource(); CodePosition position = codePositionManager.getCodePositionForUnit(stmt); if(constantBasedValuesToFuzz.containsKey(position.getID())) constantBasedValuesToFuzz.get(position.getID()).addAll(values); else constantBasedValuesToFuzz.put(position.getID(), values); }
private void splitAPI_DataFlowtoSMTConvertion(ResultSourceInfo dataFlow, IInfoflowCFG cfg, Set<ResultSourceInfo> preparedDataFlowsForSMT, Table<Stmt, Integer, Set<String>> splitInfos) { SMTConverter converter = new SMTConverter(sources); for(int i = 0; i < dataFlow.getPath().length; i++) { System.out.println("\t" + dataFlow.getPath()[i]); System.out.println("\t\t" + dataFlow.getPathAccessPaths()[i]); } //we remove the first statement (split-API method) int n = dataFlow.getPath().length-1; Stmt[] reducedDataFlow = new Stmt[n]; System.arraycopy(dataFlow.getPath(), 1, reducedDataFlow, 0, n); //currently only possible if there is a constant index for the array if(hasConstantIndexAtArrayForSplitDataFlow(reducedDataFlow)) { String valueOfInterest = getValueOfInterestForSplitDataflow(reducedDataFlow); converter.convertJimpleToSMT(reducedDataFlow, dataFlow.getPathAccessPaths(), targetUnits, cfg, null); converter.printProgramToCmdLine(); File z3str2Script = new File(FrameworkOptions.Z3SCRIPT_LOCATION); if(!z3str2Script.exists()) throw new RuntimeException("There is no z3-script available"); SMTExecutor smtExecutor = new SMTExecutor(converter.getSmtPrograms(), z3str2Script); Set<File> smtFiles = smtExecutor.createSMTFile(); for(File smtFile : smtFiles) { String loggingPointValue = smtExecutor.executeZ3str2ScriptAndExtractValue(smtFile, valueOfInterest); if(loggingPointValue != null) { Stmt splitStmt = dataFlow.getPath()[0]; int index = getConstantArrayIndexForSplitDataFlow(reducedDataFlow); if(splitInfos.contains(splitStmt, index)) splitInfos.get(splitStmt, index).add(loggingPointValue); else { Set<String> values = new HashSet<String>(); values.add(loggingPointValue); splitInfos.put(splitStmt, index, values); } } System.out.println(loggingPointValue); } System.out.println("####################################"); } }
@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("Build code for new 'WaitPDPActivity"); // building the code has to be done here (not in the Main class, otherwise Jimple validation will fail String mainActivityClass = UpdateManifestAndCodeForWaitPDP.getMainActivityName(Settings.instance.getApkPath()); String packageName = UpdateManifestAndCodeForWaitPDP.getApplicationPackageName(Settings.instance.getApkPath()); UpdateManifestAndCodeForWaitPDP.updateWaitPDPActivity(packageName, mainActivityClass); // update packagename in field of WaitPDP class SootClass sc = Scene.v().getSootClass(Settings.INSTRUMENTATION_HELPER_JAVA); SootField sf1 = sc.getFieldByName("applicationPackageName"); Util.changeConstantStringInField(sf1, packageName); 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("--------"); } }
private List<Unit> instrumentIntentAddings(BiDiInterproceduralCFG<Unit, SootMethod> cfg, Unit unit, InvokeExpr sinkExpr, Set<ResultSourceInfo> sourceInfo){ if(isMethodInterComponentSink(sinkExpr.getMethod())){ SootMethod method = cfg.getMethodOf(unit); Body body = null; if(method.hasActiveBody()) body = method.retrieveActiveBody(); else throw new RuntimeException("No body found!"); Set<String> sourceCategories = getDataIdList(sourceInfo); final String hashSetType = "java.util.HashSet"; List<Unit> generated = new ArrayList<Unit>(); //HashSet initialization Local hashSetLocal = generateFreshLocal(body, RefType.v(hashSetType)); NewExpr newExpr = Jimple.v().newNewExpr(RefType.v(hashSetType)); AssignStmt assignStmt = Jimple.v().newAssignStmt(hashSetLocal, newExpr); generated.add(assignStmt); //constructor call SpecialInvokeExpr constructorCall = Jimple.v().newSpecialInvokeExpr(hashSetLocal, Scene.v().getMethod("<java.util.HashSet: void <init>()>").makeRef()); InvokeStmt constructorCallStmt = Jimple.v().newInvokeStmt(constructorCall); generated.add(constructorCallStmt); //add categories to HashSet for(String cat : sourceCategories){ InterfaceInvokeExpr addCall = Jimple.v().newInterfaceInvokeExpr(hashSetLocal, Scene.v().getMethod("<java.util.Set: boolean add(java.lang.Object)>").makeRef(), StringConstant.v(cat)); InvokeStmt addCallStmt = Jimple.v().newInvokeStmt(addCall); generated.add(addCallStmt); } //get Intent Value intent = sinkExpr.getArg(0); List<Object> args = new ArrayList<Object>(); args.add(RefType.v("android.content.Intent")); args.add(intent); args.add(RefType.v(hashSetType)); args.add(hashSetLocal); StaticInvokeExpr sie = Instrumentation.createJimpleStaticInvokeExpr( Settings.INSTRUMENTATION_HELPER_JAVA, "addTaintInformationToIntent", args); InvokeStmt invStmt = Jimple.v().newInvokeStmt(sie); generated.add(invStmt); return generated; } return Collections.emptyList(); }
private boolean isSourceInfoParameter(ResultSourceInfo sInfo) { return sInfo.getSource() instanceof IdentityStmt && ((IdentityStmt) sInfo.getSource()).getRightOp() instanceof ParameterRef; }