-
-
Notifications
You must be signed in to change notification settings - Fork 708
Instrumenting Android Apps with Soot
In Soot we have added support for reading and writing Dalvik bytecode with Soot. This is done with Dexpler, mainly developed by a group around Alexandre Bartel, and with some enhancements by Ben Bellamy, Eric Bodden as well as Frank Hartmann and Michael Markert. Dexpler converts Dalvik bytecode into Jimple’s three-address code.
Reference: "Dexpler: Converting Android Dalvik Bytecode to Jimple for Static Analysis with Soot", In ACM SIGPLAN International Workshop on State Of the Art in Java Program Analysis, doi:10.1145/2259051.2259056, 2012.
First grab the latest version of Soot, for instance our nightly build. Also check out the directory at https://github.com/Sable/android-platforms. This directory contains different versions of the Android standard library that Soot requires for resolving types of apps you analyze or instrument. Next we implement a driver class with a main method into which we stick the following code:
//prefer Android APK files// -src-prec apk
Options.v().set_src_prec(Options.src_prec_apk);
//output as APK, too//-f J
Options.v().set_output_format(Options.output_format_dex);
// resolve the PrintStream and System soot-classes
Scene.v().addBasicClass("java.io.PrintStream",SootClass.SIGNATURES);
Scene.v().addBasicClass("java.lang.System",SootClass.SIGNATURES);
The first option instructs Soot to load Android APK files. The second one instructs Soot to produce a Dex/APK file as output. (In theory you could also convert Java into Dex or Dex into Java and so on.) The last two options tell Soot to load two classes which we will require for our instrumentation but which may otherwise not be required by the instrumented APK.
Next we add a Transform to Soot:
PackManager.v().getPack("jtp").add(new Transform("jtp.myInstrumenter", new BodyTransformer() {
@Override
protected void internalTransform(final Body b, String phaseName, @SuppressWarnings("rawtypes") Map options) {
final PatchingChain units = b.getUnits();
//important to use snapshotIterator here
for(Iterator iter = units.snapshotIterator(); iter.hasNext();) {
final Unit u = iter.next();
u.apply(new AbstractStmtSwitch() {
public void caseInvokeStmt(InvokeStmt stmt) {
//code here
}
});
}
}
}));
This will walk through all Units of all Bodies in the APK and on every InvokeStmt will invoke the code which I labeled with “code here”.
At this place we can now insert the following:
InvokeExpr invokeExpr = stmt.getInvokeExpr();
if(invokeExpr.getMethod().getName().equals("onDraw")) {
Local tmpRef = addTmpRef(b);
Local tmpString = addTmpString(b);
// insert "tmpRef = java.lang.System.out;"
units.insertBefore(Jimple.v().newAssignStmt(
tmpRef, Jimple.v().newStaticFieldRef(
Scene.v().getField("<java.lang.System: java.io.PrintStream out>").makeRef())), u);
// insert "tmpLong = 'HELLO';"
units.insertBefore(Jimple.v().newAssignStmt(tmpString,
StringConstant.v("HELLO")), u);
// insert "tmpRef.println(tmpString);"
SootMethod toCall = Scene.v().getSootClass("java.io.PrintStream").getMethod("void println(java.lang.String)");
units.insertBefore(Jimple.v().newInvokeStmt(
Jimple.v().newVirtualInvokeExpr(tmpRef, toCall.makeRef(), tmpString)), u);
//check that we did not mess up the Jimple
b.validate();
}
This causes Soot to insert a System.out.println("HELLO")
just before the method invocation but only if the target of this invocation is an onDraw method.
Last but not least, don’t forget to actually call Soot’s main method:
soot.Main.main(args);
And that’s it! Piece of cake, isn’t it? All you now need to do is run your driver class with the following arguments:
-android-jars path/to/android-platforms -process-dir your.apk
Here path/to/android-platforms
is the path to the platform JAR files you downloaded earlier and your.apk
is the path to the APK you with to instrument. The option -process-dir
instructs Soot to process all classes inside this APK.
As a result you will find a new APK with the same name inside the directory ./sootOutput
.
You can download the entire code of the example here: AndroidInstrument.java
Also check out Soot's webpage.
NOTE: If you find any bugs in those tutorials (or other parts of Soot) please help us out by reporting them in our issue tracker.
- Home
- Getting Help
- Tutorials
- Reference Material
- General Notions
- Getting Started
- A Few Uses of Soot
- Using Soot as a Command-Line Tool
- Using the Soot Eclipse Plugin
- Using Soot as a Compiler Framework
- Building Soot
- Coding Conventions
- Contributing to Soot
- Updating the Soot Web Page
- Reporting Bugs
- Preparing a New Soot Release