soot-oss / soot

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

Cannot pack back to APK file in multi-dex mode #614

Open zhhailon opened 8 years ago

zhhailon commented 8 years ago

APK files analysed with -process-multiple-dex cannot be packed back to APK. Instead, only one classes.dex is created.

xwlin-roy commented 8 years ago

Soot doesn't support dex splitter now.

565

2) Dex files are often split because the dex format has a restriction on the maximum number of classes and methods. If we merge it all and write it back out, the output file will be invalid and will fail to load on the device. We don't have a dex splitter yet.

StevenArzt commented 8 years ago

That's right, implementing a dex splitter is still an open task someone needs to tackle in the future,

ftc commented 7 years ago

I am having this problem too and there is a possible workaround: output class files and then use "dx" (the android sdk dex compiler) with the --multi-dex option to recompile it. Theoretically you should be able to move all the origional resource files over from the old apk and put the new dex files in.

I have not gotten it to work myself yet as my instrumentation makes soot fail on outputting class files for some reason that I am still debugging but perhaps it will work for you.

ftc commented 7 years ago

So I have come back around to the point where I need this again and am still having trouble with it. Has anyone managed to get multi dex output working? My attempt at outputting class files and then recompiling them to dex is resulting in an exception when the apk is loaded on the phone:

--------- beginning of crash
04-20 13:12:59.383  3564  3564 E AndroidRuntime: FATAL EXCEPTION: main
04-20 13:12:59.383  3564  3564 E AndroidRuntime: Process: org.droidplanner.android.debug, PID: 3564
04-20 13:12:59.383  3564  3564 E AndroidRuntime: java.lang.VerifyError: Rejecting class kotlin.jvm.internal.ClassReference because it
 failed compile-time verification (declaration of 'kotlin.jvm.internal.ClassReference' appears in /data/app/org.droidplanner.android.
debug-1/base.apk:classes2.dex)
04-20 13:12:59.383  3564  3564 E AndroidRuntime:        at kotlin.jvm.internal.ReflectionFactory.getOrCreateKotlinClass(ReflectionFac
tory.java:35)
04-20 13:12:59.383  3564  3564 E AndroidRuntime:        at kotlin.jvm.internal.Reflection.getOrCreateKotlinClass(Reflection.java:60)
04-20 13:12:59.383  3564  3564 E AndroidRuntime:        at org.droidplanner.android.fragments.widget.video.MiniWidgetSoloLinkVideo.<c
linit>(MiniWidgetSoloLinkVideo.kt:25)
04-20 13:12:59.383  3564  3564 E AndroidRuntime:        at org.droidplanner.android.fragments.widget.TowerWidgets$SOLO_VIDEO.getMinim
izedFragment(TowerWidgets.kt:42)
04-20 13:12:59.383  3564  3564 E AndroidRuntime:        at org.droidplanner.android.fragments.widget.TowerWidgets$SOLO_VIDEO.getMinim
izedFragment(TowerWidgets.kt:36)
04-20 13:12:59.383  3564  3564 E AndroidRuntime:        at org.droidplanner.android.fragments.WidgetsListFragment.addWidget(WidgetsLi
stFragment.java:132)
04-20 13:12:59.383  3564  3564 E AndroidRuntime:        at org.droidplanner.android.fragments.WidgetsListFragment.generateWidgetsList
(WidgetsListFragment.java:157)

I have documented the attempt at the workaround I suggested earlier below:

I first set up a project which reads in an APK and writes out java .class files:

Soot code:

Options.v().set_output_format(Options.output_format_class)
Options.v().set_allow_phantom_refs(true)
Options.v().set_process_dir([ apk path ])
Options.v().set_output_dir([ output directory])
Options.v().set_keep_line_number(true)
Options.v().set_process_multiple_dex(true)
Options.v().set_whole_program(true)
val path: String = Scene.v().getSootClassPath

Scene.v().setSootClassPath(path + ":" + config.instDir +":" + sys.env("JAVA_HOME") + "/jre/lib/rt.jar")
val classes: scala.collection.mutable.Buffer[String] = JUtils.getClasses(config.instDir)
classes.foreach(a => Scene.v().addBasicClass(a))
PhaseOptions.v().setPhaseOption("cg", "enabled:false")

soot.Main.main("-w")

I then compile the class files into dex with the following command:

Android/Sdk/build-tools/24.0.0/dx --dex --multi-dex --output="output.apk" .

Finally I take the old apk and extract it, put the new dex files inside, re zip it, re sign it and then try to run it on the phone at which point it crashes.

The android app I am running on is here: https://github.com/DroidPlanner/Tower

Thank you for the help!

pavanupb commented 4 years ago

@zhhailon Is this still relevant?

zhhailon commented 4 years ago

@zhhailon Is this still relevant?

I haven't been dealing with this problem for a long time. The approach by @ftc seems to work, but requires extra non-soot steps.