L-JINBIN / ApkDataMultiplexing

APK数据复用优化
128 stars 33 forks source link

某些原始apk so文件数据复用优化后会无法安装 #5

Closed zwc456baby closed 5 months ago

zwc456baby commented 5 months ago

某些原始 apk 数据复用优化后会无法安装

两个 && 应该改成 ||

这样改也可以:

                // 必须4k对齐
                if (innerEntry.getMethod() == ZipMaker.METHOD_STORED || innerEntry.getDataOffset() % 4 != 0) {
                    String name = innerEntry.getName();
                    if (name.equals("resources.arsc") || name.endsWith(".so")) {
                        System.out.println(name + " getDataOffset: " + (innerEntry.getDataOffset() % 4));
                        System.out.println(name + " getMethod: " + (innerEntry.getMethod() == ZipMaker.METHOD_STORED));
                        continue;
                    }
                }

输出:

lib/armeabi/libxxx.so getDataOffset: 0
lib/armeabi/libxxx.so getMethod: true

经过打印 innerEntry.getDataOffset() % 4 发现是启用了 4k 对齐,但是 innerEntry.getMethod()METHOD_STORED 。这样改就正常了。

zwc456baby commented 5 months ago

原来是:innerEntry.getMethod() == ZipMaker.METHOD_STORED && innerEntry.getDataOffset() % 4 != 0

改:innerEntry.getMethod() == ZipMaker.METHOD_STORED || innerEntry.getDataOffset() % 4 != 0

不知道有什么副作用,还是单纯的编码错误。

L-JINBIN commented 5 months ago

这里是有点问题,你提到的apk应该是AndroidManifest的extractNativeLibs属性设置为false了,此时so文件必须使用STORED方式压缩,并且4096对齐,而不是4对齐,这样改就行了,你测试看看

                    // 必须4k对齐
                    if (innerEntry.getMethod() == ZipMaker.METHOD_STORED) {
                        String name = innerEntry.getName();
                        if (name.equals("resources.arsc") && innerEntry.getDataOffset() % 4 != 0) {
                            continue;
                        }
                        if (name.endsWith(".so") && innerEntry.getDataOffset() % 4096 != 0) {
                            continue;
                        }
                    }
L-JINBIN commented 5 months ago

我这里的思路是不去判断AndroidManifest里面的属性如何,只要arsc文件是STORED的,就必须4对齐,只要so文件是STORED的,就必须4096对齐。所以你说的 && 改 || 并不正确,只是这样放弃了对STORED存储的文件进行优化,刚好避开了bug

zwc456baby commented 5 months ago

感谢作者回复,我用了上面的代码测试,现象依旧是这样的:

163037.jpg

另外补充更多信息,(最终根源确实没找到,还一直在尝试阅读源码)

源 apk 40M 大小左右,添加 origin.apk 后是80M左右。使用我前面提到的 两个 && 改成 || 后 apk 大小 60m 左右。数据复用没有包括 so 文件了。可以正常安装

我调用了复用和 v3 v2 签名:

DataMultiplexing.optimize()
V2V3SchemeSigner.sign()

当我保持 && ,或者上一个回复的 4096 对齐,apk大小从 80M 未复用前,到40M 左右,基本与原始 apk 大小保持。然后用这个 apk 安装会出现损坏

当我使用这个损坏的包,使用 mt 管理器,对apk重新签名,这个 apk 就可以安装了(apk保持 40M左右)。

另外我也尝试了 360 加固工具箱中的 签名工具 ,使用 360 的重新签名也一样可以安装,但是apk会恢复到 80M 大小左右。

这个问题也许是 数据复用优化 和签名工具共同作用导致的。 也许签名工具没有考虑到某种情况?

现在我自己的结论是:不复用 so 没问题。复用 so后,不用 V2V3SchemeSigner.sign ,而是其他工具签名也没问题 (其实也是复用失效)

我使用的测试 apk 是: [VCAMSX](https://github.com/iiheng/VCAMSX)