/** * Make sure that all invoke special targets are cloned into the class from ancestors. This might * mean that we have to clone hidden methods, and change their names. So clone them in, and update * the clone to original map, and update the invoke special Also, this will update invoke specials * that target methods cloned in previous call to above cloneReachableNonHiddenAncestorMethods() */ private void cloneHiddenAncestorMethodsAndFixInvokeSpecial() { Set<SootClass> parents = SootUtils.getParents(clazz); boolean debug = false; // (clazz.getName().contains("ResultDisplayer")); boolean cloneAdded = false; do { cloneAdded = false; for (SootMethod method : clazz.getMethods()) { if (method.isAbstract() || method.isPhantom() || !method.isConcrete()) continue; if (debug) System.out.println(method); Body body = null; try { body = method.retrieveActiveBody(); } catch (Exception ex) { logger.info("Exception retrieving method body {}", ex); continue; } StmtBody stmtBody = (StmtBody) body; Chain units = stmtBody.getUnits(); Iterator stmtIt = units.iterator(); while (stmtIt.hasNext()) { Stmt stmt = (Stmt) stmtIt.next(); if (stmt.containsInvokeExpr() && stmt.getInvokeExpr() instanceof SpecialInvokeExpr) { SpecialInvokeExpr si = (SpecialInvokeExpr) stmt.getInvokeExpr(); SootMethod target = resolveSpecialInvokeTarget(si); // si.getMethod(); if (debug) System.out.printf("\t%s %s", si, target); if (clonedToOriginal.values().contains(target)) { // found target of invoke special, and it has been cloned, so change the invoke // special SootMethod cloneOfTarget = clonedToOriginal.inverse().get(target); si.setMethodRef(cloneOfTarget.makeRef()); if (debug) System.out.println("\tChange ref " + cloneOfTarget); } else if (parents.contains(target.getDeclaringClass())) { // target has not been cloned, but should be cloned, so clone it and change ref of // invoke String name = target.getName() + CLONED_METHOD_SUFFIX + (cloned_method_id++); SootMethod clonedMethod = cloneMethod(target, name); si.setMethodRef(clonedMethod.makeRef()); cloneAdded = true; if (debug) System.out.println("\tClone and Change ref " + clonedMethod); } } } } } while (cloneAdded); }
/** * 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 } } } } }
public static boolean isTarget( AnalysisDirection direction, SootMethod enclosingMethod, Unit unit, Iterable<AnalysisTarget> targets) { if (!(unit instanceof AssignStmt)) return false; Stmt s = (Stmt) unit; if (!s.containsInvokeExpr()) return false; InvokeExpr ie = s.getInvokeExpr(); for (AnalysisTarget target : targets) { if (target.matches(direction, enclosingMethod, ie)) return true; } return false; }
@SuppressWarnings({"unchecked", "rawtypes"}) private Set<SootField> collectBlockField(JavaCriticalSection cs) { Set result = new HashSet(); int startLine = cs.getStartLine(); int endLine = cs.getEndline(); Body body = cs.getSootMethod().getActiveBody(); PatchingChain<Unit> units = body.getUnits(); for (Unit u : units) { Stmt s = (Stmt) u; LineNumberTag linetag = (LineNumberTag) s.getTag("LineNumberTag"); if (linetag == null) continue; int line = linetag.getLineNumber(); if (line < startLine || line > endLine) { continue; } List<ValueBox> Fieldslist = u.getUseBoxes(); Fieldslist.addAll(u.getDefBoxes()); for (ValueBox box : Fieldslist) { Value v = box.getValue(); if (v instanceof JInstanceFieldRef) { result.add(((JInstanceFieldRef) v).getField()); } } if (s.containsInvokeExpr()) { // 用调用图获得调用目标 Callees callees = new Callees(getCallGragh(), u); for (SootMethod invokeMethod : callees.explicits()) { if (invokeMethod == null) continue; Collection use = scaner.getUseInstanceFields(invokeMethod); Collection mod = new HashSet(); if (needMod) { mod.addAll(scaner.getModInstanceFields(invokeMethod)); } if (use != null) result.addAll(use); result.addAll(mod); } } } return result; }
@Override public Type appliesInternal(AndroidMethod method) { SootMethod sm = getSootMethod(method); if (sm == null) { System.err.println("Method not declared: " + method); return Type.NOT_SUPPORTED; } // We are only interested in setters if (!sm.isConcrete()) return Type.NOT_SUPPORTED; try { Set<Value> paramVals = new HashSet<Value>(); for (Unit u : sm.retrieveActiveBody().getUnits()) { // Collect the parameters if (u instanceof IdentityStmt) { IdentityStmt id = (IdentityStmt) u; if (id.getRightOp() instanceof ParameterRef) paramVals.add(id.getLeftOp()); } // Check for invocations if (u instanceof Stmt) { Stmt stmt = (Stmt) u; if (stmt.containsInvokeExpr()) if (stmt.getInvokeExpr() instanceof InstanceInvokeExpr) { InstanceInvokeExpr iinv = (InstanceInvokeExpr) stmt.getInvokeExpr(); if (paramVals.contains(iinv.getBase())) if (iinv.getMethod().getName().startsWith(methodName)) return Type.TRUE; } } } return Type.FALSE; } catch (Exception ex) { System.err.println("Something went wrong:"); ex.printStackTrace(); return Type.NOT_SUPPORTED; } }
/** * @param g * @param numFormals number of parameters need to be taken into account, since abc will generate * auxiliary parameters for proceed call, so this analysis needs the number of parameters * originly declared in around advice * @param withReturn if the around adivce has return value */ public ProceedAnalysis(UnitGraph g, int numFormals, boolean withReturn) { super(g); this.g = g; exactProceedSet = new HashSet<Stmt>(); nonExactProceedSet = new HashSet<Stmt>(); UnchangedParamsAnalysis paramAnalysis = null; // if numformals = 0, dont need paramAnalysis if (numFormals >= 0) paramAnalysis = new UnchangedParamsAnalysis(g, numFormals); UnchangedReturnAnalysis returnAnalysis = new UnchangedReturnAnalysis(g); ExceptionBeforeProceedAnalysis exceptionAnalysis = new ExceptionBeforeProceedAnalysis(g); // calcualte exactProceedSet and nonExactProceedSet for (Iterator uIt = g.getBody().getUnits().iterator(); uIt.hasNext(); ) { Unit unit = (Unit) uIt.next(); if (unit instanceof Stmt) { Stmt s = (Stmt) unit; if (withReturn) { // care only AssignStmt if (s instanceof AssignStmt && s.containsInvokeExpr() && ImpactUtil.isProceed(((InvokeExpr) s.getInvokeExpr()).getMethod())) { boolean exact = false; int matchArg = numFormals; // if numformals = 0, dont need paramAnalysis analysis if (numFormals > 0) { matchArg = numMatchArgs(numFormals, paramAnalysis, s); } // System.out.println("invoke match arg = " + matchArg); if (matchArg == numFormals) { // should check return value and exceptions if (returnAnalysis.isReachReturn(s)) { if (!exceptionAnalysis.hasExceptionBefore(s)) { exact = true; } } } if (exact) exactProceedSet.add(s); else nonExactProceedSet.add(s); } } else { // care only InvokeStmt if (s instanceof InvokeStmt && s.containsInvokeExpr() && ImpactUtil.isProceed(((InvokeExpr) s.getInvokeExpr()).getMethod())) { boolean exact = false; int matchArg = numFormals; // if numformals = 0, dont need paramAnalysis analysis if (numFormals > 0) { matchArg = numMatchArgs(numFormals, paramAnalysis, s); } // System.out.println("invoke match arg = " + matchArg); if (matchArg == numFormals) { // should check exceptions if (!exceptionAnalysis.hasExceptionBefore(s)) { exact = true; } } if (exact) exactProceedSet.add(s); else nonExactProceedSet.add(s); } } } } doAnalysis(); }
public void assureAllSyncInCallGraph(Collection<JavaCriticalSection> criticalSections) { System.out.println("[assureAllSyncInCallgraph] starting"); Date start = new Date(); ReachableMethods oldReach = Scene.v().getReachableMethods(); // Collection et = EntryPoints.v().all(); // ReachableMethods reachableFromMain = new ReachableMethods(cg, et); // reachableFromMain.update(); Set<SootMethod> notInCG = new HashSet<SootMethod>(); for (JavaCriticalSection cs : criticalSections) { SootMethod m = cs.getSootMethod(); if (!oldReach.contains(m)) notInCG.add(m); } Set<SootMethod> alreadyInCG = new HashSet<SootMethod>(); for (Iterator<MethodOrMethodContext> it = oldReach.listener(); it.hasNext(); ) { alreadyInCG.add(it.next().method()); } /* * for(Iterator<?> it=cg.sourceMethods();it.hasNext();){ SootMethod m = * (SootMethod)it.next(); alreadyInCG.add(m); if(notInCG.contains(m)){ * notInCG.remove(m); } } */ // add new methods to the call graph Stack<SootMethod> worklist = new Stack<SootMethod>(); for (SootMethod m : notInCG) { worklist.push(m); } while (!worklist.isEmpty()) { SootMethod m = worklist.pop(); if (alreadyInCG.contains(m) || m == null) { continue; } alreadyInCG.add(m); Body body = m.retrieveActiveBody(); for (Unit u : body.getUnits()) { if (!(u instanceof Stmt)) { continue; } Stmt s = (Stmt) u; if (!s.containsInvokeExpr()) { continue; } InvokeExpr invoke = s.getInvokeExpr(); SootMethod declCallee = invoke.getMethod(); Collection<SootMethod> targets = new ArrayList<SootMethod>(); if (declCallee.isStatic()) { targets.add(declCallee); } else { // XXX: pay attention to reflexive call, thread call, and // etc. // Here we do not add edges for implicit targets, as these // parts of methods is not reachable // from the entry, and they will most likely to be analyzed // in a very conservative ways. InstanceInvokeExpr iie = (InstanceInvokeExpr) invoke; Local receiver = (Local) iie.getBase(); NumberedString subSig = iie.getMethodRef().getSubSignature(); if (invoke instanceof SpecialInvokeExpr) { SootMethod tgt = VirtualCalls.v().resolveSpecial((SpecialInvokeExpr) invoke, subSig, m); targets.add(tgt); } else { Type t = receiver.getType(); if (t instanceof ArrayType) { // t = RefType.v("java.lang.Object"); targets.add(declCallee); } // BottomType bug else if (t instanceof soot.jimple.toolkits.typing.fast.BottomType) { System.out.println("BottomType:" + s); } else if (t instanceof soot.NullType) { System.out.println("NullType:" + s); } else { SootClass c = ((RefType) t).getSootClass(); // Soot has a type resolving bug, and here may be // exceptions try { Set<SootMethod> callees = Scene.v().getOrMakeFastHierarchy().resolveAbstractDispatch(c, declCallee); targets.addAll(callees); } catch (Exception e) { System.out.println(e.getMessage()); } } } } for (SootMethod t : targets) { // add call edge Edge e = new Edge(m, s, t); Scene.v().getCallGraph().addEdge(e); // add to worklist if (t.isConcrete() && !alreadyInCG.contains(t)) { worklist.push(t); } } } } // infer entries for the methods not reachable from main entry List<SootMethod> entries = Scene.v().getEntryPoints(); _patchedEntries = new ArrayList<SootMethod>(notInCG); for (SootMethod m : notInCG) { // XXX there can be recursive calls, so for simple processing, all // methods not in old // call graph should be added to the entry. Checking the // non-existence of incoming edges // may miss some recursively called methods // if(!cg.edgesInto(m).hasNext()){ entries.add(m); // } } // update reachable methods Scene.v().setReachableMethods(null); }
public static boolean isCtorCall(Stmt s) { return s.containsInvokeExpr() && (s.getInvokeExpr() instanceof SpecialInvokeExpr) && s.getInvokeExpr().getMethod().getName().equals("<init>"); }
/** * @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 }