soot.jimple.infoflow.cfg.LibraryClassPatcher Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of soot-infoflow Show documentation
Show all versions of soot-infoflow Show documentation
Soot extending data flow tracking components for Java
package soot.jimple.infoflow.cfg;
import java.util.Collections;
import soot.Body;
import soot.IntType;
import soot.Local;
import soot.Modifier;
import soot.RefType;
import soot.Scene;
import soot.SootClass;
import soot.SootField;
import soot.SootFieldRef;
import soot.SootMethod;
import soot.Type;
import soot.Unit;
import soot.VoidType;
import soot.javaToJimple.LocalGenerator;
import soot.jimple.Constant;
import soot.jimple.IntConstant;
import soot.jimple.InvokeExpr;
import soot.jimple.Jimple;
import soot.jimple.JimpleBody;
import soot.jimple.NullConstant;
import soot.jimple.Stmt;
import soot.jimple.StringConstant;
/**
* Class for patching OS libraries such as java.lang.Thread so that we get
* complete callgraphs
*
* @author Steven Arzt
*
*/
public class LibraryClassPatcher {
private final Constant stubConst = StringConstant.v("Stub!");
/**
* Helper interface to inject code into the Message.obtain() overloads
*
* @author Steven Arzt
*
*/
private static interface IMessageObtainCodeInjector {
public void injectCode(Body body, Local messageLocal);
}
public LibraryClassPatcher() {
}
/**
* Patches all supported system libraries
*/
public void patchLibraries() {
// Patch the android.os.Handler implementation
patchHandlerImplementation();
// Patch the java.lang.Thread implementation
patchThreadImplementation();
// Patch the android.app.Activity implementation (getApplication())
patchActivityImplementation();
// Patch the java.util.Timer implementation
patchTimerImplementation();
// Patch activity getFragmentManager()
patchActivityGetFragmentManager();
// Patch the various overloads of Message.obtain()
patchMessageObtainImplementation();
}
/**
* Patches the implementations of the various overloads of Message.obtain()
*/
private void patchMessageObtainImplementation() {
SootClass sc = Scene.v().getSootClassUnsafe("android.os.Message");
if (sc == null || sc.resolvingLevel() < SootClass.SIGNATURES)
return;
sc.setLibraryClass();
// We sometimes seem to be missing the constructor
SootMethod smMessageConstructor = Scene.v().grabMethod("()>");
if (smMessageConstructor == null)
return;
// Make sure that we have all fields
SootField tmp = sc.getFieldUnsafe("int what");
if (tmp == null) {
tmp = Scene.v().makeSootField("what", IntType.v());
sc.addField(tmp);
}
final SootField fldWhat = tmp;
tmp = sc.getFieldUnsafe("int arg1");
if (tmp == null) {
tmp = Scene.v().makeSootField("arg1", IntType.v());
sc.addField(tmp);
}
final SootField fldArg1 = tmp;
tmp = sc.getFieldUnsafe("int arg2");
if (tmp == null) {
tmp = Scene.v().makeSootField("arg2", IntType.v());
sc.addField(tmp);
}
final SootField fldArg2 = tmp;
tmp = sc.getFieldUnsafe("java.lang.Object obj");
if (tmp == null) {
tmp = Scene.v().makeSootField("obj", Scene.v().getObjectType());
sc.addField(tmp);
}
final SootField fldObj = tmp;
// Method obtain(Handler,int)
SootMethod smObtain1 = sc.getMethodUnsafe("android.os.Message obtain(android.os.Handler,int)");
if (smObtain1 != null && (!smObtain1.hasActiveBody() || isStubImplementation(smObtain1.getActiveBody()))) {
generateMessageObtainMethod(smObtain1, new IMessageObtainCodeInjector() {
@Override
public void injectCode(Body body, Local messageLocal) {
body.getUnits()
.add(Jimple.v().newAssignStmt(
Jimple.v().newInstanceFieldRef(messageLocal, fldWhat.makeRef()),
body.getParameterLocal(1)));
}
});
}
// Method obtain(Handler,int,int,int,Object)
SootMethod smObtain2 = sc
.getMethodUnsafe("android.os.Message obtain(android.os.Handler,int,int,int,java.lang.Object)");
if (smObtain2 != null && (!smObtain2.hasActiveBody() || isStubImplementation(smObtain2.getActiveBody()))) {
generateMessageObtainMethod(smObtain2, new IMessageObtainCodeInjector() {
@Override
public void injectCode(Body body, Local messageLocal) {
body.getUnits()
.add(Jimple.v().newAssignStmt(
Jimple.v().newInstanceFieldRef(messageLocal, fldWhat.makeRef()),
body.getParameterLocal(1)));
body.getUnits()
.add(Jimple.v().newAssignStmt(
Jimple.v().newInstanceFieldRef(messageLocal, fldArg1.makeRef()),
body.getParameterLocal(2)));
body.getUnits()
.add(Jimple.v().newAssignStmt(
Jimple.v().newInstanceFieldRef(messageLocal, fldArg2.makeRef()),
body.getParameterLocal(3)));
body.getUnits().add(Jimple.v().newAssignStmt(
Jimple.v().newInstanceFieldRef(messageLocal, fldObj.makeRef()), body.getParameterLocal(4)));
}
});
}
// Method obtain(Handler,int,int,int)
SootMethod smObtain3 = sc.getMethodUnsafe("android.os.Message obtain(android.os.Handler,int,int,int)");
if (smObtain3 != null && (!smObtain3.hasActiveBody() || isStubImplementation(smObtain3.getActiveBody()))) {
generateMessageObtainMethod(smObtain3, new IMessageObtainCodeInjector() {
@Override
public void injectCode(Body body, Local messageLocal) {
body.getUnits()
.add(Jimple.v().newAssignStmt(
Jimple.v().newInstanceFieldRef(messageLocal, fldWhat.makeRef()),
body.getParameterLocal(1)));
body.getUnits()
.add(Jimple.v().newAssignStmt(
Jimple.v().newInstanceFieldRef(messageLocal, fldArg1.makeRef()),
body.getParameterLocal(2)));
body.getUnits()
.add(Jimple.v().newAssignStmt(
Jimple.v().newInstanceFieldRef(messageLocal, fldArg2.makeRef()),
body.getParameterLocal(3)));
}
});
}
// Method obtain(Handler,int,Object)
SootMethod smObtain4 = sc.getMethodUnsafe("android.os.Message obtain(android.os.Handler,int,java.lang.Object)");
if (smObtain4 != null && (!smObtain4.hasActiveBody() || isStubImplementation(smObtain4.getActiveBody()))) {
generateMessageObtainMethod(smObtain4, new IMessageObtainCodeInjector() {
@Override
public void injectCode(Body body, Local messageLocal) {
body.getUnits()
.add(Jimple.v().newAssignStmt(
Jimple.v().newInstanceFieldRef(messageLocal, fldWhat.makeRef()),
body.getParameterLocal(1)));
body.getUnits().add(Jimple.v().newAssignStmt(
Jimple.v().newInstanceFieldRef(messageLocal, fldObj.makeRef()), body.getParameterLocal(2)));
}
});
}
}
/**
* Creates a new implementation for the given method
*
* @param sm The method for which to generate a new implementation
* @param injector Callback to inject additional code into the new method
*/
private void generateMessageObtainMethod(SootMethod sm, IMessageObtainCodeInjector injector) {
// Create the method
RefType tpMessage = RefType.v("android.os.Message");
sm.getDeclaringClass().setLibraryClass();
sm.setPhantom(false);
sm.addTag(new FlowDroidEssentialMethodTag());
// Create a body for the method
JimpleBody body = Jimple.v().newBody(sm);
sm.setActiveBody(body);
body.insertIdentityStmts();
// This method must exist, since we checked it before attempting any kind of
// message mocking
SootMethod smMessageConstructor = Scene.v().grabMethod("()>");
LocalGenerator lg = new LocalGenerator(body);
Local messageLocal = lg.generateLocal(tpMessage);
body.getUnits().add(Jimple.v().newAssignStmt(messageLocal, Jimple.v().newNewExpr(tpMessage)));
body.getUnits().add(Jimple.v()
.newInvokeStmt(Jimple.v().newSpecialInvokeExpr(messageLocal, smMessageConstructor.makeRef())));
if (injector != null)
injector.injectCode(body, messageLocal);
body.getUnits().add(Jimple.v().newReturnStmt(messageLocal));
}
/**
* Checks whether the given method body is a stub implementation and can safely
* be overwritten
*
* @param body The body to check
* @return True if the given method body is a stub implementation, otherwise
* false
*/
private boolean isStubImplementation(Body body) {
for (Unit u : body.getUnits()) {
Stmt stmt = (Stmt) u;
if (stmt.containsInvokeExpr()) {
InvokeExpr iexpr = stmt.getInvokeExpr();
SootMethod targetMethod = iexpr.getMethod();
if (targetMethod.isConstructor()
&& targetMethod.getDeclaringClass().getName().equals("java.lang.RuntimeException"))
if (iexpr.getArgCount() > 0 && iexpr.getArg(0).equals(stubConst))
return true;
}
}
return false;
}
/**
* Patch android.app.Activity getApplication method in order to return the
* singleton Application instance created in the dummyMainMethod.
*/
private void patchActivityImplementation() {
SootClass scApplicationHolder = createOrGetApplicationHolder();
SootClass sc = Scene.v().getSootClassUnsafe("android.app.Activity");
if (sc == null || sc.resolvingLevel() < SootClass.SIGNATURES || scApplicationHolder == null)
return;
sc.setLibraryClass();
SootMethod smRun = sc.getMethodUnsafe("android.app.Application getApplication()");
if (smRun == null || (smRun.hasActiveBody() && !isStubImplementation(smRun.getActiveBody())))
return;
smRun.setPhantom(false);
smRun.addTag(new FlowDroidEssentialMethodTag());
Body b = Jimple.v().newBody(smRun);
smRun.setActiveBody(b);
// add "this" local
Local thisLocal = Jimple.v().newLocal("this", sc.getType());
b.getLocals().add(thisLocal);
b.getUnits().add(Jimple.v().newIdentityStmt(thisLocal, Jimple.v().newThisRef(sc.getType())));
SootFieldRef appStaticFieldRef = scApplicationHolder.getFieldByName("application").makeRef();
// creating local to store the mApplication field
Local targetLocal = Jimple.v().newLocal("retApplication", appStaticFieldRef.type());
b.getLocals().add(targetLocal);
b.getUnits().add(Jimple.v().newAssignStmt(targetLocal, Jimple.v().newStaticFieldRef(appStaticFieldRef)));
Unit retStmt = Jimple.v().newReturnStmt(targetLocal);
b.getUnits().add(retStmt);
b.validate();
}
/**
* return the ApplicationHolder class (created if needed) This is a class with 1
* static field to save the application instance in
*/
public static SootClass createOrGetApplicationHolder() {
SootClass scApplication = Scene.v().getSootClassUnsafe("android.app.Application");
if (scApplication == null || scApplication.resolvingLevel() < SootClass.SIGNATURES)
return null;
String applicationHolderClassName = "il.ac.tau.MyApplicationHolder";
SootClass scApplicationHolder;
if (!Scene.v().containsClass(applicationHolderClassName)) {
scApplicationHolder = Scene.v().makeSootClass(applicationHolderClassName, Modifier.PUBLIC);
scApplicationHolder.setSuperclass(Scene.v().getSootClass("java.lang.Object"));
Scene.v().addClass(scApplicationHolder);
scApplicationHolder.addField(
Scene.v().makeSootField("application", scApplication.getType(), Modifier.PUBLIC | Modifier.STATIC));
scApplicationHolder.validate();
} else {
scApplicationHolder = Scene.v().getSootClassUnsafe(applicationHolderClassName);
}
return scApplicationHolder;
}
/**
* Creates a synthetic minimal implementation of the java.lang.Thread class to
* model threading correctly even if we don't have a real implementation.
*/
private void patchThreadImplementation() {
SootClass sc = Scene.v().getSootClassUnsafe("java.lang.Thread");
if (sc == null || sc.resolvingLevel() < SootClass.SIGNATURES)
return;
sc.setLibraryClass();
SootMethod smRun = sc.getMethodUnsafe("void run()");
if (smRun == null || (smRun.hasActiveBody() && !isStubImplementation(smRun.getActiveBody())))
return;
smRun.addTag(new FlowDroidEssentialMethodTag());
SootMethod smCons = sc.getMethodUnsafe("void (java.lang.Runnable)");
if (smCons == null || (smCons.hasActiveBody() && !isStubImplementation(smCons.getActiveBody())))
return;
smCons.addTag(new FlowDroidEssentialMethodTag());
SootClass runnable = Scene.v().getSootClassUnsafe("java.lang.Runnable");
if (runnable == null || runnable.resolvingLevel() < SootClass.SIGNATURES)
return;
// Create a field for storing the runnable
int fieldIdx = 0;
SootField fldTarget = null;
while ((fldTarget = sc.getFieldByNameUnsafe("target" + fieldIdx)) != null)
fieldIdx++;
fldTarget = Scene.v().makeSootField("target" + fieldIdx, runnable.getType());
sc.addField(fldTarget);
// Create a new constructor
patchThreadConstructor(smCons, runnable, fldTarget);
// Create a new Thread.start() method
patchThreadRunMethod(smRun, runnable, fldTarget);
}
/**
* Creates a synthetic "java.lang.Thread.run()" method implementation that calls
* the target previously passed in when the constructor was called
*
* @param smRun The run() method for which to create a synthetic
* implementation
* @param runnable The "java.lang.Runnable" interface
* @param fldTarget The field containing the target object
*/
private void patchThreadRunMethod(SootMethod smRun, SootClass runnable, SootField fldTarget) {
SootClass sc = smRun.getDeclaringClass();
sc.setLibraryClass();
smRun.setPhantom(false);
Body b = Jimple.v().newBody(smRun);
smRun.setActiveBody(b);
Local thisLocal = Jimple.v().newLocal("this", sc.getType());
b.getLocals().add(thisLocal);
b.getUnits().add(Jimple.v().newIdentityStmt(thisLocal, Jimple.v().newThisRef(sc.getType())));
Local targetLocal = Jimple.v().newLocal("target", runnable.getType());
b.getLocals().add(targetLocal);
b.getUnits().add(
Jimple.v().newAssignStmt(targetLocal, Jimple.v().newInstanceFieldRef(thisLocal, fldTarget.makeRef())));
Unit retStmt = Jimple.v().newReturnVoidStmt();
// If (this.target == null) return;
b.getUnits().add(Jimple.v().newIfStmt(Jimple.v().newEqExpr(targetLocal, NullConstant.v()), retStmt));
// Invoke target.run()
b.getUnits().add(Jimple.v().newInvokeStmt(
Jimple.v().newInterfaceInvokeExpr(targetLocal, runnable.getMethod("void run()").makeRef())));
b.getUnits().add(retStmt);
}
/**
* Creates a synthetic "(java.lang.Runnable)" method implementation that
* stores the given runnable into a field for later use
*
* @param smCons The () method for which to create a synthetic
* implementation
* @param runnable The "java.lang.Runnable" interface
* @param fldTarget The field receiving the Runnable
*/
private void patchThreadConstructor(SootMethod smCons, SootClass runnable, SootField fldTarget) {
SootClass sc = smCons.getDeclaringClass();
sc.setLibraryClass();
smCons.setPhantom(false);
Body b = Jimple.v().newBody(smCons);
smCons.setActiveBody(b);
Local thisLocal = Jimple.v().newLocal("this", sc.getType());
b.getLocals().add(thisLocal);
b.getUnits().add(Jimple.v().newIdentityStmt(thisLocal, Jimple.v().newThisRef(sc.getType())));
Local param0Local = Jimple.v().newLocal("p0", runnable.getType());
b.getLocals().add(param0Local);
b.getUnits().add(Jimple.v().newIdentityStmt(param0Local, Jimple.v().newParameterRef(runnable.getType(), 0)));
b.getUnits().add(
Jimple.v().newAssignStmt(Jimple.v().newInstanceFieldRef(thisLocal, fldTarget.makeRef()), param0Local));
b.getUnits().add(Jimple.v().newReturnVoidStmt());
}
/**
* Creates a dummy implementation of android.os.Handler if we don't have one
*/
private void patchHandlerImplementation() {
SootClass sc = Scene.v().getSootClassUnsafe("android.os.Handler");
if (sc == null || sc.resolvingLevel() < SootClass.SIGNATURES)
return;
sc.setLibraryClass();
SootClass runnable = Scene.v().getSootClassUnsafe("java.lang.Runnable");
if (runnable == null || runnable.resolvingLevel() < SootClass.SIGNATURES)
return;
SootMethod smPost = sc.getMethodUnsafe("boolean post(java.lang.Runnable)");
SootMethod smPostAtFrontOfQueue = sc.getMethodUnsafe("boolean postAtFrontOfQueue(java.lang.Runnable)");
SootMethod smPostAtTimeWithToken = sc
.getMethodUnsafe("boolean postAtTime(java.lang.Runnable,java.lang.Object,long)");
SootMethod smPostAtTime = sc.getMethodUnsafe("boolean postAtTime(java.lang.Runnable,long)");
SootMethod smPostDelayed = sc.getMethodUnsafe("boolean postDelayed(java.lang.Runnable,long)");
SootMethod smDispatchMessage = sc.getMethodUnsafe("void dispatchMessage(android.os.Message)");
if (smPost != null && (!smPost.hasActiveBody() || isStubImplementation(smPost.getActiveBody()))) {
patchHandlerPostBody(smPost, runnable);
smPost.addTag(new FlowDroidEssentialMethodTag());
}
if (smPostAtFrontOfQueue != null && (!smPostAtFrontOfQueue.hasActiveBody()
|| isStubImplementation(smPostAtFrontOfQueue.getActiveBody()))) {
patchHandlerPostBody(smPostAtFrontOfQueue, runnable);
smPostAtFrontOfQueue.addTag(new FlowDroidEssentialMethodTag());
}
if (smPostAtTime != null
&& (!smPostAtTime.hasActiveBody() || isStubImplementation(smPostAtTime.getActiveBody()))) {
patchHandlerPostBody(smPostAtTime, runnable);
smPostAtTime.addTag(new FlowDroidEssentialMethodTag());
}
if (smPostAtTimeWithToken != null && (!smPostAtTimeWithToken.hasActiveBody()
|| isStubImplementation(smPostAtTimeWithToken.getActiveBody()))) {
patchHandlerPostBody(smPostAtTimeWithToken, runnable);
smPostAtTimeWithToken.addTag(new FlowDroidEssentialMethodTag());
}
if (smPostDelayed != null
&& (!smPostDelayed.hasActiveBody() || isStubImplementation(smPostDelayed.getActiveBody()))) {
patchHandlerPostBody(smPostDelayed, runnable);
smPostDelayed.addTag(new FlowDroidEssentialMethodTag());
}
if (smDispatchMessage != null
&& (!smDispatchMessage.hasActiveBody() || isStubImplementation(smDispatchMessage.getActiveBody()))) {
patchHandlerDispatchBody(smDispatchMessage);
smDispatchMessage.addTag(new FlowDroidEssentialMethodTag());
}
}
/**
* Creates a new body for one of the dispatchMessage method in
* android.os.Handler
*
* @param method The method for which to create the implementation
* (dispatchMessage)
* @return The newly created body
*/
private Body patchHandlerDispatchBody(SootMethod method) {
SootClass sc = method.getDeclaringClass();
sc.setLibraryClass();
method.setPhantom(false);
Body b = Jimple.v().newBody(method);
method.setActiveBody(b);
Local thisLocal = Jimple.v().newLocal("this", sc.getType());
b.getLocals().add(thisLocal);
b.getUnits().add(Jimple.v().newIdentityStmt(thisLocal, Jimple.v().newThisRef(sc.getType())));
// Assign the parameters
Local firstParam = null;
for (int i = 0; i < method.getParameterCount(); ++i) {
Local paramLocal = Jimple.v().newLocal("param" + i, method.getParameterType(i));
b.getLocals().add(paramLocal);
b.getUnits().add(
Jimple.v().newIdentityStmt(paramLocal, Jimple.v().newParameterRef(method.getParameterType(i), i)));
if (i == 0)
firstParam = paramLocal;
}
// Invoke handler.handleMessage(Message)
b.getUnits()
.add(Jimple.v().newInvokeStmt(Jimple.v().newVirtualInvokeExpr(thisLocal,
Scene.v().makeMethodRef(sc, "handleMessage",
Collections.singletonList(method.getParameterType(0)), VoidType.v(), false),
firstParam)));
Unit retStmt = Jimple.v().newReturnVoidStmt();
b.getUnits().add(retStmt);
b.validate();
return b;
}
/**
* Creates a new body for one of the postXXX methods in android.os.Handler
*
* @param method The method for which to create the implementation
* @param runnable The java.lang.Runnable class
* @return The newly created body
*/
private Body patchHandlerPostBody(SootMethod method, SootClass runnable) {
SootClass sc = method.getDeclaringClass();
sc.setLibraryClass();
method.setPhantom(false);
Body b = Jimple.v().newBody(method);
method.setActiveBody(b);
Local thisLocal = Jimple.v().newLocal("this", sc.getType());
b.getLocals().add(thisLocal);
b.getUnits().add(Jimple.v().newIdentityStmt(thisLocal, Jimple.v().newThisRef(sc.getType())));
// Assign the parameters
Local firstParam = null;
for (int i = 0; i < method.getParameterCount(); i++) {
Local paramLocal = Jimple.v().newLocal("param" + i, method.getParameterType(i));
b.getLocals().add(paramLocal);
b.getUnits().add(
Jimple.v().newIdentityStmt(paramLocal, Jimple.v().newParameterRef(method.getParameterType(i), i)));
if (i == 0)
firstParam = paramLocal;
}
// Invoke p0.run()
b.getUnits().add(Jimple.v().newInvokeStmt(Jimple.v().newInterfaceInvokeExpr(firstParam,
Scene.v().makeMethodRef(runnable, "run", Collections.emptyList(), VoidType.v(), false))));
Unit retStmt = Jimple.v().newReturnStmt(IntConstant.v(1));
b.getUnits().add(retStmt);
return b;
}
/**
* Creates a dummy implementation of java.util.Timer if we don't have one
*/
private void patchTimerImplementation() {
SootClass sc = Scene.v().getSootClassUnsafe("java.util.Timer");
if (sc == null || sc.resolvingLevel() < SootClass.SIGNATURES)
return;
sc.setLibraryClass();
SootMethod smSchedule1 = sc.getMethodUnsafe("void schedule(java.util.TimerTask,long)");
if (smSchedule1 != null && !smSchedule1.hasActiveBody()) {
patchTimerScheduleMethod(smSchedule1);
smSchedule1.addTag(new FlowDroidEssentialMethodTag());
}
SootMethod smSchedule2 = sc.getMethodUnsafe("void schedule(java.util.TimerTask,java.util.Date)");
if (smSchedule2 != null && !smSchedule2.hasActiveBody()) {
patchTimerScheduleMethod(smSchedule2);
smSchedule2.addTag(new FlowDroidEssentialMethodTag());
}
SootMethod smSchedule3 = sc.getMethodUnsafe("void schedule(java.util.TimerTask,java.util.Date,long)");
if (smSchedule3 != null && !smSchedule3.hasActiveBody()) {
patchTimerScheduleMethod(smSchedule3);
smSchedule3.addTag(new FlowDroidEssentialMethodTag());
}
SootMethod smSchedule4 = sc.getMethodUnsafe("void schedule(java.util.TimerTask,long,long)");
if (smSchedule4 != null && !smSchedule4.hasActiveBody()) {
patchTimerScheduleMethod(smSchedule4);
smSchedule4.addTag(new FlowDroidEssentialMethodTag());
}
SootMethod smSchedule5 = sc
.getMethodUnsafe("void scheduleAtFixedRate(java.util.TimerTask,java.util.Date,long)");
if (smSchedule5 != null && !smSchedule5.hasActiveBody()) {
patchTimerScheduleMethod(smSchedule5);
smSchedule5.addTag(new FlowDroidEssentialMethodTag());
}
SootMethod smSchedule6 = sc.getMethodUnsafe("void scheduleAtFixedRate(java.util.TimerTask,long,long)");
if (smSchedule6 != null && !smSchedule6.hasActiveBody()) {
patchTimerScheduleMethod(smSchedule6);
smSchedule6.addTag(new FlowDroidEssentialMethodTag());
}
}
/**
* Patches the schedule() method of java.util.Timer by providing a fake
* implementation
*
* @param method The method to patch
*/
private void patchTimerScheduleMethod(SootMethod method) {
SootClass sc = method.getDeclaringClass();
sc.setLibraryClass();
method.setPhantom(false);
Body b = Jimple.v().newBody(method);
method.setActiveBody(b);
Local thisLocal = Jimple.v().newLocal("this", sc.getType());
b.getLocals().add(thisLocal);
b.getUnits().add(Jimple.v().newIdentityStmt(thisLocal, Jimple.v().newThisRef(sc.getType())));
// Assign the parameters
Local firstParam = null;
for (int i = 0; i < method.getParameterCount(); i++) {
Local paramLocal = Jimple.v().newLocal("param" + i, method.getParameterType(i));
b.getLocals().add(paramLocal);
b.getUnits().add(
Jimple.v().newIdentityStmt(paramLocal, Jimple.v().newParameterRef(method.getParameterType(i), i)));
if (i == 0)
firstParam = paramLocal;
}
// Invoke the run() method on the first parameter local
SootMethod runMethod = Scene.v().grabMethod("");
if (runMethod != null) {
Stmt invokeStmt = Jimple.v()
.newInvokeStmt(Jimple.v().newVirtualInvokeExpr(firstParam, runMethod.makeRef()));
b.getUnits().add(invokeStmt);
}
// Add the return statement
b.getUnits().add(Jimple.v().newReturnVoidStmt());
}
/**
* Modifies Activity::getFragmentManager() to return new
* MyFragmentManager(this);
*/
private void patchActivityGetFragmentManager() {
SootClass sc = Scene.v().getSootClassUnsafe("android.app.Activity");
if (sc == null || sc.resolvingLevel() < SootClass.SIGNATURES)
return;
sc.setLibraryClass();
SootMethod smGetFM = sc.getMethodUnsafe("android.app.FragmentManager getFragmentManager()");
if (smGetFM == null || smGetFM.hasActiveBody())
return;
Body b = Jimple.v().newBody(smGetFM);
smGetFM.setActiveBody(b);
Local thisLocal = Jimple.v().newLocal("this", sc.getType());
b.getLocals().add(thisLocal);
b.getUnits().add(Jimple.v().newIdentityStmt(thisLocal, Jimple.v().newThisRef(sc.getType())));
SootClass scFragmentTransaction = Scene.v().forceResolve("android.app.FragmentManager", SootClass.SIGNATURES);
Local retLocal = Jimple.v().newLocal("retFragMan",
Scene.v().getSootClassUnsafe("android.app.FragmentManager").getType());
b.getLocals().add(retLocal);
b.getUnits().add(Jimple.v().newAssignStmt(retLocal, Jimple.v().newNewExpr(scFragmentTransaction.getType())));
b.getUnits().add(Jimple.v().newReturnStmt(retLocal));
}
}