package de.ecspride.util; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.xmlpull.v1.XmlPullParserException; import soot.Body; import soot.Local; import soot.Printer; import soot.RefType; import soot.Scene; import soot.SootClass; import soot.SootField; import soot.SootMethod; import soot.Type; import soot.Unit; import soot.Value; import soot.javaToJimple.LocalGenerator; import soot.jimple.AssignStmt; import soot.jimple.InvokeStmt; import soot.jimple.Jimple; import soot.jimple.SpecialInvokeExpr; import soot.jimple.StaticInvokeExpr; import soot.jimple.StringConstant; import soot.jimple.infoflow.android.manifest.ProcessManifest; import soot.util.EscapedWriter; import de.ecspride.Settings; import de.ecspride.instrumentation.Instrumentation; /** * Different util methods which do not fit into the transformer class (PolicyEnforcementTransformer). * @author Siegfried Rasthofer * */ public class Util { private static Logger log = LoggerFactory.getLogger(Util.class); public static boolean isAndroidClass(SootClass c){ return c.getName().startsWith("android."); } public static void clearSootOutputJimpleDir(){ System.err.println("deleting sootOutput folder..."); cleanFolder(Settings.sootOutput); } private static void cleanFolder(String fileName) { File outputDir = new File(fileName); if (!outputDir.exists()) return; for (String fileInDir : outputDir.list()) { File f = new File(outputDir.getAbsolutePath() + File.separator + fileInDir); if (f.isDirectory()) cleanFolder(f.getAbsolutePath()); f.delete(); } } public static void writeJimpleFiles(SootClass c){ String correctFormat = c.getPackageName().replace(".", File.separator); File dir = new File(Settings.sootOutput + File.separator + "/jimple" + File.separator + correctFormat); dir.mkdirs(); String fileName = c.getName().substring(c.getName().lastIndexOf(".") + 1); try{ PrintWriter pw = new PrintWriter( new EscapedWriter(new OutputStreamWriter( new FileOutputStream(dir.getAbsolutePath() + "/" + fileName + ".jimple")))); Printer.v().printTo(c, pw); pw.close(); } catch (IOException e) { e.printStackTrace(); } catch (Exception e){ e.printStackTrace(); } } /** * This is a kind of hack and includes much more instrumentation which is necessary; * But it is still sound ;-). * @param apkFileLocation: apk file path */ public static void initializePePInAllPossibleClasses(String apkFileLocation){ try { ProcessManifest manifest = new ProcessManifest(apkFileLocation); Set<String> entryClasses = manifest.getEntryPointClasses(); for(String entryClass : entryClasses){ SootClass sc = Scene.v().getSootClass(entryClass); List<SootClass> allSuperClasses = Scene.v().getActiveHierarchy().getSuperclassesOf(sc); for(SootClass subclass : allSuperClasses) if(subclass.getName().equals("android.content.Context")){ initializePeP(sc); break; } } } catch (IOException | XmlPullParserException ex) { System.err.println("Could not read Android manifest file: " + ex.getMessage()); throw new RuntimeException(ex); } } private static void initializePeP(SootClass sc){ SootMethod onCreate = null; log.info("add Pep initialization in class "+ sc); for(SootMethod sm : sc.getMethods()){ if(sm.getName().equals("onCreate") && sm.getParameterCount() == 1 && sm.getParameterType(0).toString().equals("android.os.Bundle")){ onCreate = sm; } } if(onCreate != null){ List<Unit> generated = new ArrayList<Unit>(); Body body = onCreate.retrieveActiveBody(); Local thisLocal = body.getThisLocal(); SootClass context = Scene.v().forceResolve("android.content.Context", SootClass.BODIES); // SootMethod applicationContext =sc.getMethod("android.content.Context getApplicationContext()"); SootMethod applicationContext = context.getMethod("android.content.Context getApplicationContext()"); SpecialInvokeExpr virtInvExpr = Jimple.v().newSpecialInvokeExpr(thisLocal, applicationContext.makeRef()); Local applicationContextLocal = generateFreshLocal(body, RefType.v("android.content.Context")); generated.add(Jimple.v().newAssignStmt(applicationContextLocal, virtInvExpr)); List<Object> args = new ArrayList<Object>(); args.add(RefType.v("android.content.Context")); args.add(applicationContextLocal); StaticInvokeExpr staticInvExpr = Instrumentation.createJimpleStaticInvokeExpr(Settings.instance.INSTRUMENTATION_HELPER_JAVA, Settings.instance.INSTRUMENTATION_HELPER_INITIALIZE_METHOD, args); generated.add(Jimple.v().newInvokeStmt(staticInvExpr)); Unit onCreateSpecialInvoke = getSuperOnCreateUnit(body); if(onCreateSpecialInvoke == null) throw new RuntimeException("error: super.onCreate() statement missing in method "+ onCreate); body.getUnits().insertAfter(generated, onCreateSpecialInvoke); } } private static Local generateFreshLocal(Body b, Type type){ LocalGenerator lg = new LocalGenerator(b); return lg.generateLocal(type); } public static Unit getSuperOnCreateUnit(Body b) { for(Unit u : b.getUnits()){ if(u instanceof InvokeStmt){ InvokeStmt invStmt = (InvokeStmt)u; if(invStmt.getInvokeExpr().getMethod().getSubSignature().equals("void onCreate(android.os.Bundle)")) return u; } } return null; } public static void changeConstantStringInField(SootField sf, String newConstantString) { SootClass sc = sf.getDeclaringClass(); SootMethod sm = sc.getMethodByName("<clinit>"); boolean hasBeenUpdated = false; for (Unit u: sm.retrieveActiveBody().getUnits()) { if (u instanceof AssignStmt) { AssignStmt ass = (AssignStmt)u; Value lop = ass.getLeftOp(); if (lop.toString().equals(sf.toString())) { System.out.println("previous string: "+ ass); ass.setRightOp(StringConstant.v(newConstantString)); hasBeenUpdated = true; System.out.println("updated string : "+ ass); } } } if (!hasBeenUpdated) throw new RuntimeException("error: no StringConstant found for field "+ sf); } }