前言
很早之前逛看雪论坛看到有人提到过一件事:安卓高版本在安装apk时可以不解压lib中的so文件,而将其直接映射到内存中实现加载。当时虽然觉得有必要了解一下这个事情,但是自己并没有碰到这种case所以就搁置了。这不最近连着两次踩到这个坑了,就正好拿出来水一篇文章,这次的关键字是extractNativeLibs
。
extractNativeLibs介绍
什么是extractNativeLibs
extractNativeLibs
是AndroidManifest.xml中的一个字段,它的官方描述如下
此属性指示软件包安装程序是否将原生库从 APK 提取到文件系统。如果设置为 “false”,则原生库以未压缩的形式存储在 APK 中。虽然您的 APK 可能较大,但应用应该加载得更快,因为库是在应用运行时直接从 APK 加载。
首先第一句,此属性指示软件包安装程序是否将原生库从 APK 提取到文件系统。
,说明当该值设置为false
时,apk在安装后不会将lib中的SO文件提取到安装目录,这样的好处在于同样的SO文件不会出现两份,节约空间。
第二句和第三句,如果设置为false
,apk中的SO文件在打包时将会以未压缩的形式出现,这样系统在加载APK的同时也会将SO文件映射到内存中而无需进行解压缩,提高加载速度;同时由于SO文件未被压缩所以会导致安装包的尺寸会变大。
总结一下,根据extractNativeLibs
的值的不同进行对比,总体来说利大于弊:
extractNativeLibs | True | False |
---|---|---|
是否压缩SO文件 | True | False |
安装后是否提取SO文件 | True | False |
安装包大小 | 小 | 大 |
加载速度 | 慢 | 快 |
extractNativeLibs的默认值
同样来自官方描述
extractNativeLibs 的默认值取决于 minSdkVersion 和您使用的 AGP 版本。在大多数情况下,默认行为很可能符合您的预期,您无需显式设置此属性。
可以知道extractNativeLibs在打包时的默认值是会由打包工具自动根据情况设定的,比如我在compileSdk 31; minSdk 23; targetSdk 31
的情况下,extractNativeLibs
的默认值可能就是false
extractNativeLibs的使用
想要对extractNativeLibs
的值进行设置主要有两种方式,第一种就是直接修改AndroidManifest.xml即可。第二种看官方描述:
代码语言:javascript复制从 AGP 4.2.0 开始,extractNativeLibs 清单属性已被 DSL 选项 useLegacyPackaging 取代。 您应该使用应用的 build.gradle 文件中的 useLegacyPackaging(而非清单文件中的 extractNativeLibs)来配置原生库压缩行为。如需了解详情,请参阅版本说明使用 DSL 打包压缩的原生库。
我们建议以未压缩的形式打包原生库,因为这会减小应用安装大小,缩减应用下载大小,并缩短用户的应用加载时间。不过,如果您希望 Android Gradle 插件在构建应用时打包压缩后的原生库,请在应用的 build.gradle 文件中将 useLegacyPackaging 设置为 true:
android {
packagingOptions {
jniLibs {
useLegacyPackaging true
}
}
}
实际上两种方式最终的结果都是修改了打包后的apk中AndroidManifest.xml中的对应字段值。
extractNativeLibs对逆向的影响
PatchSo
在逆向中很常用的一个技巧就是对apk安装后的so文件进行patch然后替换原来的so文件,这样可以绕过签名校验。这种方式的前提是extractNativeLibs
必须为true
,否则在apk安装目录下并不会找到任何的so文件可以让我们进行patch。
重打包
一个apk如果它的extractNativeLibs
设置为false
,那么如果我们直接对apk重打包并签名是无法安装的,会出现如下报错:
Failure [INSTALL_FAILED_INVALID_APK: Failed to extract native libraries,res=-2]
原因是重打包后的apk必须要进行对齐。参考Java Failure [INSTALL_FAILED_INVALID_APK: Failed to extract native libraries, res=-2]
官方说明如下:
注意:如果您在使用 apksigner 为 APK 签名后又对 APK 做了更改,则 APK 的签名将会失效。因此,要使用 zipalign 等工具,您必须在为 APK 签名之前使用。
我们需要用zipalign进行对齐,并且必须要在使用apksigner
进行签名之前对齐。