forked from noidsirius/SootTutorial
-
Notifications
You must be signed in to change notification settings - Fork 0
/
AndroidLogger.java
69 lines (59 loc) · 3.58 KB
/
AndroidLogger.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
package dev.navids.soottutorial.android;
import soot.*;
import soot.jimple.*;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
public class AndroidLogger {
private final static String USER_HOME = System.getProperty("user.home");
private static String androidJar = USER_HOME + "/Library/Android/sdk/platforms";
static String androidDemoPath = System.getProperty("user.dir") + File.separator + "demo" + File.separator + "Android";
static String apkPath = androidDemoPath + File.separator + "/calc.apk";
static String outputPath = androidDemoPath + File.separator + "/Instrumented";
public static void main(String[] args){
if(System.getenv().containsKey("ANDROID_HOME"))
androidJar = System.getenv("ANDROID_HOME")+ File.separator+"platforms";
// Clean the outputPath
final File[] files = (new File(outputPath)).listFiles();
if (files != null && files.length > 0) {
Arrays.asList(files).forEach(File::delete);
}
// Initialize Soot
InstrumentUtil.setupSoot(androidJar, apkPath, outputPath);
// Add a transformation pack in order to add the statement "System.out.println(<content>) at the beginning of each Application method
PackManager.v().getPack("jtp").add(new Transform("jtp.myLogger", new BodyTransformer() {
@Override
protected void internalTransform(Body b, String phaseName, Map<String, String> options) {
// First we filter out Android framework methods
if(AndroidUtil.isAndroidMethod(b.getMethod()))
return;
JimpleBody body = (JimpleBody) b;
UnitPatchingChain units = b.getUnits();
List<Unit> generatedUnits = new ArrayList<>();
// The message that we want to log
String content = String.format("%s Beginning of method %s", InstrumentUtil.TAG, body.getMethod().getSignature());
// In order to call "System.out.println" we need to create a local containing "System.out" value
Local psLocal = InstrumentUtil.generateNewLocal(body, RefType.v("java.io.PrintStream"));
// Now we assign "System.out" to psLocal
SootField sysOutField = Scene.v().getField("<java.lang.System: java.io.PrintStream out>");
AssignStmt sysOutAssignStmt = Jimple.v().newAssignStmt(psLocal, Jimple.v().newStaticFieldRef(sysOutField.makeRef()));
generatedUnits.add(sysOutAssignStmt);
// Create println method call and provide its parameter
SootMethod printlnMethod = Scene.v().grabMethod("<java.io.PrintStream: void println(java.lang.String)>");
Value printlnParamter = StringConstant.v(content);
InvokeStmt printlnMethodCallStmt = Jimple.v().newInvokeStmt(Jimple.v().newVirtualInvokeExpr(psLocal, printlnMethod.makeRef(), printlnParamter));
generatedUnits.add(printlnMethodCallStmt);
// Insert the generated statement before the first non-identity stmt
units.insertBefore(generatedUnits, body.getFirstNonIdentityStmt());
// Validate the body to ensure that our code injection does not introduce any problem (at least statically)
b.validate();
}
}));
// Run Soot packs (note that our transformer pack is added to the phase "jtp")
PackManager.v().runPacks();
// Write the result of packs in outputPath
PackManager.v().writeOutput();
}
}