Closed jeromew closed 11 months ago
Which apk? Which Android version?
Thanks for sharing!
the single apk feature was mis-behaving with deezer 7.1.4.88 installed yesterday from the google play store. device: samsung galaxy s5 running android 6.0.1 ; I agree this is very old by 2023 standards ;-)
Also note that inside the AndroidManifest there is
<meta-data android:name="com.android.vending.splits.required" android:value="true"/>
<meta-data android:name="com.android.stamp.source" android:value="https://play.google.com/store"/>
<meta-data android:name="com.android.stamp.type" android:value="STAMP_TYPE_DISTRIBUTION_APK"/>
<meta-data android:name="com.android.vending.splits" android:resource="@xml/splits0"/>
<meta-data android:name="com.android.vending.derived.apk.id" android:value="3"/>
so that is maybe another way that android has to require the splits. apk.sh currently only patches "android:isSplitRequired" which is also present in the manifest.
I can confirm that after setting the "com.android.vending.splits.required" to false, the single apk works
After some more testing, there seem to be another issue.
the app starts but after a specific click I get in adb logcat
10-17 20:26:37.774 5557 5557 I AndroidRuntime: VM exiting with result code 0, cleanup skipped.
10-17 20:27:00.274 6377 6377 D AndroidRuntime: Shutting down VM
10-17 20:27:00.894 6377 6377 E AndroidRuntime: FATAL EXCEPTION: main
10-17 20:27:00.894 6377 6377 E AndroidRuntime: Process: xxx.android.app, PID: 6377
10-17 20:27:00.894 6377 6377 E AndroidRuntime: java.lang.RuntimeException: Unable to start activity ComponentInfo{xxx.android.app/com.xxx.feature.UnkActivity}: android.view.InflateException: Binary XML file line #2: Binary XML file line #2: Error inflating class xxx.android.masthead.MastheadCoordinatorLayout
10-17 20:27:00.894 6377 6377 E AndroidRuntime: at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3253)
10-17 20:27:00.894 6377 6377 E AndroidRuntime: at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3349)
10-17 20:27:00.894 6377 6377 E AndroidRuntime: at android.app.ActivityThread.access$1100(ActivityThread.java:221)
10-17 20:27:00.894 6377 6377 E AndroidRuntime: at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1794)
10-17 20:27:00.894 6377 6377 E AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:102)
Thanks for sharing jeromew! Is the app still not working? Do you figured out why?
After some more debugging, I don't think this Exception trace is related to apk.sh.
It is related to a problem in the decode/build cycle of apktool that misses some @drawable resources references. I don't know exactly what is the problem but it is not with apk.sh. This is probably a problem specific to the application I was testing.
I fixed my problem in the split-apk case by using 'apktool d -r base.apk', the -r
option avoiding the resource decoding step.
I don't think it would work in the single apk case because there are resources that would need to be merged and if the resource decoding step is lossy that would create the Exception issue.
btw PR #25 is still necessary to start the app in the single/merged apk scenario
Thanks for your work @jeromew! PR merged. After all, do you managed to correctly merge the apks?
No I worked with the apktool -r
flag that does not decode the resources but then all the resource files (including AndroidManifest.xml) are binary files which makes it hard patching them or even detecting the MainActivity to inject frida.
the script I gave when I created the issue works for re-installing base.apk & splits after smali modifications (even adding frida manually). I found a way to execute it on the device from a .sh script if you think it could be a good addition to apk.sh, but you'll have to decide on the apk.sh API to decide how to handle the single/splitted in parallel
# sign apks
ls -1 *.apk | xargs -I{} ~/.apk.sh/sdk_root/build-tools/33.0.1/apksigner sign --ks-pass pass:keykey --ks ../my-key.keystore {}
# push signed apks to android device
ls -1 *.apk | xargs -I{} ~/.apk.sh/sdk_root/platform-tools/adb push {} /data/local/tmp/{}
REMOTECODE=$(cat <<"EOF"
TOTALSIZE=`wc -c /data/local/tmp/*.apk | tail -n 1 | cut -f1 -d " "`
SESSIONID=`pm install-create -S $TOTALSIZE | tr -dc '0-9'`
INDEX=0
for f in /data/local/tmp/*.apk
do
let SIZE=`wc -c ${f} | cut -f1 -d " "`
echo streaming ${f}
pm install-write -S ${SIZE} ${SESSIONID} ${INDEX} ${f}
let INDEX=${INDEX}+1
done
pm install-commit ${SESSIONID}
rm /data/local/tmp/*.apk
exit
EOF
)
echo "$REMOTECODE"
# install app on android device
~/.apk.sh/sdk_root/platform-tools/adb shell "$REMOTECODE"
I digged a little bit further on the single apk problem.
it seems that the resources exist in one of the split apk, but apktool does not replace them with a DUMMY tag. It simply puts drawable="@null"
instead so the DUMMY replacement mechanism does not recover the resource id and those resource links go missing in the final apk.
ok I may have found the issue (I need to re-do a whole decode / build round trip)
According to the changelog of apktool - https://github.com/iBotPeaches/Apktool/releases/tag/v2.9.0 the 2.9.0 version introduced a new option called "res-mode" which has an impact on how missing ressources are handled.
The default res-mode is "remove" (DECODE_RES_RESOLVE_REMOVE) which does what I observe, setting missing resources to @null.
but when calling "apktool_2.9.0.jar d -resm dummy base.apk", the DUMMY placeholders are appearing ! hopefully the apk.sh DUMMY replacement sequence should do the correct thing now.
Note that the options for the res-mode are
switch (mode) {
case "remove":
case "delete":
config.setDecodeResolveMode(Config.DECODE_RES_RESOLVE_REMOVE);
break;
case "dummy":
case "dummies":
config.setDecodeResolveMode(Config.DECODE_RES_RESOLVE_DUMMY);
break;
case "keep":
case "preserve":
config.setDecodeResolveMode(Config.DECODE_RES_RESOLVE_RETAIN);
break;
default:
System.err.println("Unknown resolve resources mode: " + mode);
System.err.println("Expect: 'remove', 'dummy' or 'keep'.");
System.exit(1);
}
It now works with PR#27.
Note that I added "--resource-mode dummy" without checking that the apktool version is >= 2.9.0 so we could say this is not compatible with apktool < 2.9.0. This seems ok to me as working on an older apktool version should not be recommended.
apktool cli doc - https://apktool.org/docs/cli-parameters
Also note that I had to change the DUMMY replacement strategy because the one-by-one strategy was simply too slow on my setup and the app I used for testing.
Thanks @jeromew! v1.0.7 contains your PR!
@ax @jeromew I experience the same issue for APK that have split file. I got this exception
Process: com.package, PID: 8459
04-13 14:59:53.979 8459 8459 E AndroidRuntime: at com.package.ui.MainActivity.m0(Unknown Source:41)
04-13 14:59:53.979 8459 8459 E AndroidRuntime: Caused by: android.content.res.Resources$NotFoundException: Drawable com.package:drawable/APKTOOL_DUMMY_3ed with resource ID #0x7f0803ed
I try couple of things:
Are you using the latest version? Can u open a new issue?
Yes I am using the last version.I transferred the comment to a new issue. https://github.com/ax/apk.sh/issues/36 @ax I just check and I am using 1.0.6 not the last version of the apk.sh. I will double check with the new version.
Hello,
I tried to pull a splitted apk and apk.sh built a file.single.apk. This file.single.apk did not work as expected after installation (android complained about missing components and proposed to re-download the app via the app store)
After some research, I found how to install splitted apks (avoiding the need for the single apk hack)
this creates an install session on the devices and then writes the different apks in this session.
Using this the installed app starts correctly