package de.ecspride;
import java.util.Map;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import de.ecspride.events.EventInformation;
import de.ecspride.events.EventInformationParser;
import de.ecspride.pep.ConfigForPolicyEnforcementPoint;
import de.ecspride.pep.PolicyEnforcementPoint;
import de.ecspride.util.SourcesSinks;
import de.ecspride.util.UpdateManifestAndCodeForWaitPDP;
import de.ecspride.util.Util;
import soot.PackManager;
import soot.Scene;
import soot.SootClass;
import soot.SootField;
import soot.SootMethod;
import soot.jimple.infoflow.InfoflowConfiguration;
import soot.jimple.infoflow.android.SetupApplication;
import soot.jimple.infoflow.android.data.AndroidMethod;
import soot.jimple.infoflow.taintWrappers.EasyTaintWrapper;
import soot.jimple.infoflow.taintWrappers.ITaintPropagationWrapper;
import soot.options.Options;
public class Main {
public static Logger log = LoggerFactory.getLogger(Main.class);
public static long startTime = 0;
public static void main(String[] args) {
startTime = System.currentTimeMillis();
long d = 0;
Set<AndroidMethod> sources, sinks;
log.info("Starting Intrumentation-PEP");
//arguments will be set
Settings.instance.parseCommandLineArgs(args);
log.info("Initialize Soot and FlowDroid.");
//Soot is initialized
Settings.instance.initialiseSoot();
//clean the sootOutput dir before start
Util.clearSootOutputJimpleDir();
//parse the eventInformation.xml file in order to extract all information about the
//events we will cover
EventInformationParser eventInfoParser = new EventInformationParser();
Map<String, EventInformation> eventInformation = eventInfoParser.parseEventInformation();
if (log.isDebugEnabled()) {
log.debug("All Event Information:");
for (String k: eventInformation.keySet()) {
log.debug("event information for "+ k);
log.debug(""+ eventInformation.get(k));
}
log.debug("");
}
SourcesSinks sourcesSinks = new SourcesSinks();
//get Android sources
sources = sourcesSinks.getAndroidSourcesMethods(Settings.instance.sourceFile);
//get Android sinks
sinks = sourcesSinks.getAndroidSinkMethods(Settings.instance.sinkFile);
//get SetupApplication
SetupApplication setupApp = new SetupApplication(Settings.instance.androidJar == null
? Settings.instance.androidPlatforms : Settings.instance.androidJar, Settings.instance.apkFile);
try{
//initialize SetupApplication
setupApp.calculateSourcesSinksEntrypoints(sources, sinks);
}catch(Exception ex){
ex.printStackTrace();
System.exit(0);
}
d = (System.currentTimeMillis() - startTime);
log.info("Initialization done. Duration: "+ d +" ms.");
log.info("Starting taint analysis and bytecode instrumentation.");
startTime = System.currentTimeMillis();
runFlowDroid(setupApp, eventInformation);
d = (System.currentTimeMillis() - startTime);
log.info("Taint analysis and bytecode instrumentation have finished. Duration: " + d +" ms");
}
private static void runFlowDroid(SetupApplication setupApp, Map<String, EventInformation> eventInformation){
ITaintPropagationWrapper taintWrapper = null;
try{
taintWrapper = new EasyTaintWrapper(Settings.instance.taintWrapperFile);
}
catch(Exception ex){
ex.printStackTrace();
System.exit(0);
}
setupApp.setTaintWrapper(taintWrapper);
setupApp.setSootConfig(new ConfigForPolicyEnforcementPoint());
//settings
setupApp.getConfig().setEnableStaticFieldTracking(false);
setupApp.getConfig().setFlowSensitiveAliasing(false);
setupApp.getConfig().setEnableImplicitFlows(false); // TODO: add an option for this
InfoflowConfiguration.setAccessPathLength(1);
PolicyEnforcementPoint pep = new PolicyEnforcementPoint(
eventInformation,
setupApp.getSources(),
setupApp.getSinks(),
setupApp.getEntryPointCreator());
setupApp.runInfoflow(pep);
log.info("Wrap main activity in the manifest");
UpdateManifestAndCodeForWaitPDP.redirectMainActivity(Settings.instance.getApkPath());
// Configure Soot for output writing
Settings.instance.addInstrumentedClassToApplicationClass();
Settings.instance.setDummyMainToLibraryClass();
// set Soot's output directory
Options.v().set_output_dir(Settings.sootOutput);
// update javaclasses with targetPDP class if any was given.
if (Settings.pdpClass != null) {
String targetPDPFullClass = Settings.pdpClass.split(":")[1];
String targetPDPpackage = Settings.pdpClass.split(":")[0];
SootClass sc = Scene.v().getSootClass(Settings.INSTRUMENTATION_HELPER_JAVA);
SootField sf1 = sc.getFieldByName("pdpPackage");
Util.changeConstantStringInField(sf1, targetPDPpackage);
SootField sf2 = sc.getFieldByName("pdpClassFull");
Util.changeConstantStringInField(sf2, targetPDPFullClass);
log.info("updated fields for taget pdf: "+ targetPDPFullClass +" - "+ targetPDPpackage);
}
// write output file (.class or .apk)
for (SootClass sc : Scene.v().getClasses()) {
for (SootMethod sm : sc.getMethods()) {
if (sm.hasActiveBody()) {
sm.getActiveBody().validate();
}
}
}
PackManager.v().writeOutput();
// update manifest
UpdateManifestAndCodeForWaitPDP.replaceManifest(Settings.instance.apkFile);
// add background image
UpdateManifestAndCodeForWaitPDP.addBackgroundFile(Settings.instance.apkFile);
}
public static void dumpJimple() {
log.info("output jimple files:");
for (SootClass sc: Scene.v().getApplicationClasses()) {
Util.writeJimpleFiles(sc);
log.debug("application class: "+ sc);
for (SootMethod sm: sc.getMethods()) {
if (sm.isConcrete() && !sm.toString().contains("de.ecspride.javaclasses")) {
System.out.println("m: "+ sm);
if (null == sm.getSource()) {
System.out.println("no source!");
} else {
System.out.println("source: "+ sm.getSource());
}
System.out.println(sm.retrieveActiveBody());
}
}
}
}
}