soot-oss / soot

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

These two apks are crashing after a simple unpack/repack with Soot #999

Closed louison closed 4 years ago

louison commented 6 years ago

Hi there, I'm trying to instrument APKs in order to hook some of their methods. For the two following APKs, I'm able to unpack-repack-align-sign them successfully but when I'm starting to run them on an Emulator, they both crash for the same reason :

I order to debug that, I did not instrumented the applications and only unpacked and repackaged them. I also tried to do the same with apktool and it appears that it works fine with it. (No crash for both of the apps).

Does someone know how soot handles the repackaging of an apk after loading it ?

Here are the two apks : • le_monde.apk: https://transfer.sh/XbUq9/le_monde.apk • leboncoin.apk: https://transfer.sh/VRcW6/leboncoin.apk

In order to reproduce the bug you must :

  1. Init soot with the following options :
    Options.v().set_allow_phantom_refs(true);
    Options.v().set_validate(true);
    Options.v().set_src_prec(Options.src_prec_apk);
    Options.v().set_android_jars(PATH_TO_ANDROID_JARS);
    Options.v().set_process_dir(Collections.singletonList(apk.getAbsolutePath()));
    Options.v().set_process_multiple_dex(true);
    Options.v().set_whole_program(true);
    Options.v().set_output_dir(outputDirectory);
    Options.v().set_output_format(Options.output_format_dex);
    Options.v().set_force_overwrite(true);
    Scene.v().loadNecessaryClasses();
  2. Repackage the application using :
    PackManager.v().writeOutput();
  3. zipalignand sign the output apk
  4. Install and run the apk in an emulator.
    • For le_monde.apk the app will not crash until you try to navigate on an article (it's a newspaper app)
    • For leboncoin.apkthe app will crash as soon as it will try to load the Main activity.

Thank you in advance for your help, Best,

Louison

mbenz89 commented 6 years ago

I order to debug that, I did not instrumented the applications and only unpacked and repackaged them. I guess this also led to the exception you state?

Generally, it is hard to say what went wrong here. I also stumbled across some apps which Soot was not able to correctly reassemble. I'm afraid you will have to track down the problem yourself. Maybe you could start with comparing the SootClasses that are read in and written out with the original classes and see if there are obvious things missing/incorrect which would have an impact on the cast stated in the exception.

Are these class names obfuscated?

louison commented 6 years ago

Hi @mbenz89, I bypassed the problem for a while by only using apktool. But now I encounter the problem again and I feel bad for not having answered to your previous answer. Sorry for that.

The classes names are obfuscated and it seems that it is always linked to classes belonging to com.google.android.gms.internal

Where and how would you advise me to start my investigation to compare read in and written out SootClasses ?

Thank you in advance

louison commented 6 years ago

So I investigated this bug a bit closer by translating dex to java source code and I found the following :

// leboncoin.apk original (not repackaged by Soot) --> source code

@Hide
public final class zzatv
{
  @Hide
  private static Api.zzf<zzaux> zzefb = new Api.zzf();
  private static final Api.zza<zzaux, Api.ApiOptions.NoOptions> zzefc = new zzatw();
  public static final Api<Api.ApiOptions.NoOptions> zzefd = new Api("AppDataSearch.LIGHTWEIGHT_API", zzefc, zzefb);
  private static zzaur zzefe = new zzauz();
}
// leboncoin.apk repackaged by Soot  --> source code

@Hide
public final class zzatv
{
  @Hide
  private static Api.zzf<zzaux> zzefb = new Api.zzf();
  private static final Api.zza<zzaux, Api.ApiOptions.NoOptions> zzefc = new zzatw();
  public static final Api<Api.ApiOptions.NoOptions> zzefd = new Api("AppDataSearch.LIGHTWEIGHT_API", zzefc, zzefb);
  private static zzaur zzefe = (zzaur)new zzauz();
}

It looks like Soot had wrongly interpreted a part of the byte code. Does someone know where I can investigate further to find out where did Soot make this wrong ?

Thank you

StevenArzt commented 6 years ago

The casts are normally introduced by the type assigner. In the last line of your code snippet, the declared type of the variable is "zzaur", which is apparently correct, since it is the same type as in the original APK file. The right side also constructs an instance of the same class, i.e., "zzauz". The question now is: What is the relationship between "zzaur" and "zzauz"? The original code can only work if "zzaur" is a (transitrive) superclass of "zzauz" (or an interface that some class along the hierarchy implements). Is this the case? If not, the original code is already buggy.

If the class hierarchy is correct in the original APK, you need to check it in the Soot-generated APK as well. Is "zzaur" still a superclass of "zzauz" there or is it still an interface implemented by some class along the way? If not, that's your bug and Soot messes up the hierarchy.

If the hierarchy is still correct, we're facing something weird and need to talk again.

mbenz89 commented 5 years ago

I'm witnessing the same issue with another app:

04-10 13:08:36.888  5508  5578 E AndroidRuntime: FATAL EXCEPTION: pool-10-thread-1
04-10 13:08:36.888  5508  5578 E AndroidRuntime: Process: com.mal.saul.coinmarketcap, PID: 5508
04-10 13:08:36.888  5508  5578 E AndroidRuntime: java.lang.ExceptionInInitializerError
04-10 13:08:36.888  5508  5578 E AndroidRuntime:    at com.google.android.gms.d.b.a(dalvik_source_com.mal.saul.coinmarketcap-51.apk)
04-10 13:08:36.888  5508  5578 E AndroidRuntime:    at com.google.android.gms.internal.b.gr.<clinit>(dalvik_source_com.mal.saul.coinmarketcap-51.apk)
04-10 13:08:36.888  5508  5578 E AndroidRuntime:    at com.google.android.gms.b.a.a(dalvik_source_com.mal.saul.coinmarketcap-51.apk)
04-10 13:08:36.888  5508  5578 E AndroidRuntime:    at com.google.android.gms.internal.d.fd.b(dalvik_source_com.mal.saul.coinmarketcap-51.apk)
04-10 13:08:36.888  5508  5578 E AndroidRuntime:    at com.google.android.gms.internal.d.fd.a(dalvik_source_com.mal.saul.coinmarketcap-51.apk)
04-10 13:08:36.888  5508  5578 E AndroidRuntime:    at com.google.android.gms.internal.d.fe.run(dalvik_source_com.mal.saul.coinmarketcap-51.apk)
04-10 13:08:36.888  5508  5578 E AndroidRuntime:    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
04-10 13:08:36.888  5508  5578 E AndroidRuntime:    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
04-10 13:08:36.888  5508  5578 E AndroidRuntime:    at java.lang.Thread.run(Thread.java:761)
04-10 13:08:36.888  5508  5578 E AndroidRuntime: Caused by: java.lang.ClassCastException: com.google.android.gms.internal.j.d cannot be cast to com.google.android.gms.d.i
04-10 13:08:36.888  5508  5578 E AndroidRuntime:    at com.google.android.gms.d.b.<clinit>(dalvik_source_com.mal.saul.coinmarketcap-51.apk)
04-10 13:08:36.888  5508  5578 E AndroidRuntime:    ... 9 more

App: com.mal.saul.coinmarketcap-51.apk