/** * Resolve the concrete target of a special invoke using our modified semantics for special invoke * expression. */ private SootMethod resolveSpecialInvokeTarget(SpecialInvokeExpr si) { SootMethod target = null; try { target = SootUtils.resolve(si.getMethodRef()); } catch (CannotFindMethodException e) { logger.error("Cannot find concrete method target for special invoke: {}", si); return null; } String targetSubSig = target.getSubSignature(); SootClass current = target.getDeclaringClass(); while (true) { if (current.declaresMethod(targetSubSig)) { return current.getMethod(targetSubSig); } // not a match in current, try superclass on next loop if (current.hasSuperclass()) current = current.getSuperclass(); else { logger.error("Cannot find concrete method target for special invoke: {}", si); droidsafe.main.Main.exit(1); return null; } } }
/** * Clone non-static ancestor methods that are not hidden by virtual dispatch and that are * reachable based on a pta run. */ private void cloneReachableNonHiddenAncestorMethods(SootClass ancestor) { if (ClassCloner.isClonedClass(ancestor)) { logger.error("Cloning method from clone: {}", ancestor); droidsafe.main.Main.exit(1); } // create all methods, cloning body, replacing instance field refs for (SootMethod ancestorM : ancestor.getMethods()) { if (ancestorM.isAbstract() || ancestorM.isPhantom() || !ancestorM.isConcrete() || SootUtils.isRuntimeStubMethod(ancestorM)) continue; // never clone static methods if (ancestorM.isStatic()) continue; // clone only reachable methods if (!cloneAllMethods && !PTABridge.v().getReachableMethods().contains(ancestorM)) continue; // check if this method already exists if (containsMethod(ancestorM.getSignature())) { // System.out.printf("\tAlready contains method %s.\n", ancestorM); continue; } // turn off final for ancestor methods if (ancestorM.isFinal()) ancestorM.setModifiers(ancestorM.getModifiers() ^ Modifier.FINAL); cloneMethod(ancestorM, ancestorM.getName()); } }
public void transform() { if (clazz.isPhantom()) return; // build ancestor // List<SootClass> ancestors = Scene.v().getActiveHierarchy().getSuperclassesOf(clazz); List<SootClass> ancestors = new LinkedList<SootClass>(); // fill in ancestor list without using Soot.Hierarchy SootClass curAncestor = clazz; while (curAncestor.hasSuperclass()) { ancestors.add(curAncestor.getSuperclass()); curAncestor = curAncestor.getSuperclass(); } for (SootClass ancestor : ancestors) { if (ancestor.isPhantom()) continue; cloneReachableNonHiddenAncestorMethods(ancestor); } // modify ancestors fields for (SootClass ancestor : ancestors) { if (ancestor.isPhantom()) continue; SootUtils.makeFieldsVisible(ancestor); } cloneHiddenAncestorMethodsAndFixInvokeSpecial(); }
private void dumpTextGraph(SootMethod caller, PrintStream printStream, int level) { String indent = indentString(level); caller.getTags(); printStream.printf("%s %s\n", indent, caller.toString()); Iterator<Edge> iterator = callGraph.edgesOutOf(caller); callgraphSet.add(caller); // boolean appClass = caller.getDeclaringClass().isApplicationClass(); boolean systemApi = API.v().isSystemMethod(caller); /* printStream.printf("%s Declaring method %s: app %s\n", indent, caller.toString(), systemApi? "False": "True"); */ String subindent = indentString(level + 1); Set<Object> calleeSet = new HashSet<Object>(); while (iterator != null && iterator.hasNext()) { Edge edge = iterator.next(); if (!systemApi) { List<Stmt> invokeStmtList = SootUtils.getInvokeStatements(caller, edge.tgt()); for (Stmt stmt : invokeStmtList) { if (calleeSet.contains(stmt)) continue; printStream.printf("%s #[%s] ", subindent, stmt); SourceLocationTag tag = SootUtils.getSourceLocation(stmt); if (tag != null) { printStream.printf(": %s", tag.toString()); } printStream.printf("\n"); calleeSet.add(stmt.toString()); } } if (!callgraphSet.contains(edge.tgt())) { dumpTextGraph(edge.tgt(), printStream, level + 1); } else { // already in the call graph, just print it out if (calleeSet.contains(edge.tgt())) continue; printStream.printf("%s %s\n", subindent, edge.tgt().toString()); calleeSet.add(edge.tgt()); } } }
/** * Return true if the clone already contains a method that would resolve to this method, this is * the test that mimics virtual dispatch, so we don't clone in methods that would not be called. */ private boolean containsMethod(String signature) { // check this class for the method with polymorpism String mName = SootUtils.grabName(signature); String[] args = SootUtils.grabArgs(signature); String rtype = SootUtils.grabReturnType(signature); for (SootMethod curr : methods) { if (!curr.getName().equals(mName) || curr.getParameterCount() != args.length) continue; // check the return types Type returnType = SootUtils.toSootType(rtype); if (!SootUtils.isSubTypeOfIncluding(returnType, curr.getReturnType())) continue; boolean foundIncompArg = false; for (int i = 0; i < args.length; i++) { if (!SootUtils.isSubTypeOfIncluding( SootUtils.toSootType(args[i]), curr.getParameterType(i))) { foundIncompArg = true; continue; } } // at least one parameter does not match! if (foundIncompArg) continue; return true; } // didn't find it return false; }
private static String getReachableLines() { int totalReachableLines = 0; for (SootMethod sm : PTABridge.v().getReachableMethods()) { totalReachableLines += SootUtils.getNumLines(sm); } return Integer.toString(totalReachableLines); }
/** * 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); }
/** Dumps out the call chain in json format * */ public void dump_json(PrintStream fp, String indent) { fp.printf("%s{ %s,\n", indent, json_field("type", type)); fp.printf("%s %s,\n", indent, json_field("link", link)); String sig = method.getSignature(); fp.printf("%s %s,\n", indent, json_field("signature", sig)); if (stmt != null) { SootMethodRef invoke = stmt.getInvokeExpr().getMethodRef(); String invokeSig; try { SootMethod concrete = SootUtils.resolve(stmt.getInvokeExpr().getMethodRef()); invokeSig = concrete.getSignature(); } catch (CannotFindMethodException e1) { logger.debug("Cannot find concrete method for {} in SourceCallChainInfo.dump_json()", stmt); invokeSig = invoke.getSignature(); } if (!invokeSig.equals(sig)) { fp.printf("%s %s,\n", indent, json_field("source-signature", invokeSig)); } } SourceLocationTag slt = (stmt == null) ? SootUtils.getMethodLocation(method) : getSourceLocation(stmt); if (slt != null) { fp.printf("%s %s", indent, json_field("src-loc")); fp.printf( "{ %s, %s},\n", json_field("class", slt.getClz()), json_field("line", slt.getLine())); } fp.printf("%s %s,\n", indent, json_field("syscalls", syscalls)); fp.printf("%s %s,\n", indent, json_field("calls", calls)); if ((contents != null) && (contents.length > 0)) { fp.printf("%s %s,\n", indent, json_field("score", score)); fp.printf("%s %s [\n", indent, json_field("contents")); String delim = ""; for (SourceCallChainInfo cci : contents) { fp.print(delim); delim = ",\n"; cci.dump_json(fp, indent + " "); } fp.printf("\n%s]}", indent); } else { fp.printf("%s %s\n", indent, json_field("score", score)); fp.printf("%s}", indent); } }
/** Count taint on prims or strings */ private static Set<InfoValue> getTaintSet(Value v, MethodOrMethodContext momc) { Set<InfoValue> taints = null; if (v instanceof Local && v.getType() instanceof PrimType) { taints = InformationFlowAnalysis.v().getTaints(momc, (Local) v); } else if (PTABridge.v().isPointer(v) && SootUtils.isStringOrSimilarType(v.getType())) { taints = new HashSet<InfoValue>(); for (IAllocNode node : PTABridge.v().getPTSet(v, momc.context())) { taints.addAll(InformationFlowAnalysis.v().getTaints(node, momc)); } } return taints; }
/** gets the source location for unit (which must be a stmt) * */ public static SourceLocationTag getSourceLocation(Unit s) { return SootUtils.getSourceLocation((Stmt) s); }