soot-oss / soot

Soot - A Java optimization framework
GNU Lesser General Public License v2.1
2.89k stars 710 forks source link

Problem with Soot output apk file #1615

Open totoR13 opened 3 years ago

totoR13 commented 3 years ago

Hello,

I’m leveraging Soot to modify some classes in an apk (specifically only classes in the AndroidManifest’s package name). This is a snippet of my code:

MyTransformer t = new MyTransformer(manifestPackageName);
PackManager.v().getPack("jtp").add(new Transform("jtp.injectControls", t));

class MyTransformer extends BodyTransformer {
    String packageName;
    public MyTransformer(String packageName) { this.packageName = packageName; }

    @Override
    protected void internalTransform(Body b, String phaseName, Map<String, String> options) {
        if (!b.getMethod().getDeclaringClass().getName().contains(this.packageName))
            return;
        // Perfom some modification/instrumentation
        b.validate();
    }
}

The tool works correctly and Soot create an output apk file with the modification. When I sign the output apk file with a certificate, install it on an emulator/device and try to run it, I'll receive several errors on classes belonging to third party libraries (that are not contained into the app's package name).

For example, if I modify this apk, Soot works fine and create an output apk file. After the installation on a device/emulator, when I try to run the output apk file, I receive the following stack trace:

java.lang.RuntimeException: An error occurred while executing doInBackground()
E AndroidRuntime:       at android.os.AsyncTask$3.done(AsyncTask.java:353)
E AndroidRuntime:       at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:383)
E AndroidRuntime:       at java.util.concurrent.FutureTask.setException(FutureTask.java:252)
E AndroidRuntime:       at java.util.concurrent.FutureTask.run(FutureTask.java:271)
E AndroidRuntime:       at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
E AndroidRuntime:       at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
E AndroidRuntime:       at java.lang.Thread.run(Thread.java:764)
E AndroidRuntime: Caused by: java.lang.ExceptionInInitializerError
E AndroidRuntime:       at com.google.android.gms.ads.internal.d.a(Unknown Source:172)
E AndroidRuntime:       at com.google.android.gms.ads.internal.d.a(Unknown Source:11)
E AndroidRuntime:       at com.google.android.gms.internal.ads.fu.b(Unknown Source:255)
E AndroidRuntime:       at com.google.android.gms.internal.ads.t62.a(Unknown Source:103)
E AndroidRuntime:       at com.mopub.mobileads.GooglePlayServicesAdapterConfiguration.initializeNetwork(Unknown Source:95)
E AndroidRuntime:       at com.mopub.common.AdapterConfigurationManager$a.doInBackground(Unknown Source:237)
E AndroidRuntime:       at android.os.AsyncTask$2.call(AsyncTask.java:333)
E AndroidRuntime:       at java.util.concurrent.FutureTask.run(FutureTask.java:266)
E AndroidRuntime:       ... 3 more
E AndroidRuntime: Caused by: java.lang.ClassCastException: com.google.android.gms.internal.ads.g8 cannot be cast to com.google.android.gms.internal.ads.f8
E AndroidRuntime:       at com.google.android.gms.internal.ads.e8.<clinit>(Unknown Source:14)
E AndroidRuntime:       ... 11 more

The strange thing is that I receive that stack trace from classes that are not modified because they belong to a different package (the initial check of the internalTransform function). This seems that Soot modifies also library classes that don't belong to the app's package.

You can find an example of modified app at this link. In this file I only injected a new java class ('embedded.Test'), with the following code:

private static void injectClasses(String[] classes) {
        for (String c: classes)
            Scene.v().addBasicClass(c, SootClass.BODIES);

        Scene.v().loadNecessaryClasses();

        for (String c: classes)
            Scene.v().getSootClass(c).setApplicationClass(); // Mark class to be part of output
}

The execution of this apk file raises the same exception detailed before.

Is there a way to avoid this problem? Do you have an idea of the motivation behind this behavior?

Thank you in advance. Regards,

linghuiluo commented 3 years ago

Hi, I used this piece of code to instrument the apk you provided https://github.com/secure-software-engineering/COVA/blob/26743ea5f8b8214d50959a8faaebe2c479bb6007/cova_automatic/src/main/java/cova/automatic/instrument/SootInstrumenter.java#L35 Then the TypeResolver threw an exception.

So you might take a look at this method https://github.com/soot-oss/soot/blob/3966f565db6dc2882c3538ffc39e44f4c14b5bcf/src/main/java/soot/dexpler/DexBody.java#L473 A lot of transformations are happening there and they can not be disabled with options, unless you comment them

totoR13 commented 3 years ago

Hi, Is the problem related to the transformation from bytecode to Jimple and vice-versa?

Thank you. Regards,

linghuiluo commented 3 years ago

Did you set up all the soot options correctly? If so, it can be that there is a bug in the transformation.