快速反编译 AndroidManifest 并重新打包之旅

背景

由于拿到一个第三方的 app 安装到我们车机上不能显示完整的 UI 界面,发现此 app 的 targetSdk=18,而我们车机 =27,解决方案是修改 app 的 targetSdk=27

可能的解决方案

由于 apk 中的 xml 文件都是经过编译后二进制文件,不能够直接修改,于是凭我肤浅的水平,认为可能的操作方案如下:

  1. 找到二进制中代表 targetSdk 值的位置,直接修改此处二进制值
  2. 将 apk 中反编译的代码开到一个新项目里重新编译
1. 直接修改二进制 AndroidManifest

要搞懂二进制数据的结构才能被有效读取,我在查找 targetSdk 时参考了以下这篇文章
Android逆向之旅—解析编译之后的AndroidManifest文件格式

研究了一下结构以后,发现直接修改 Manifest 的办法并不是很好,是一个看起来简单,但实际复杂的方式,而且背后一定还藏着别的什么不知道的坑,于是放弃了这种办法

2. 将 apk 反编译的代码开一个新项目编译

反编译 classes.dex 用到的工具:
dex2jar
命令:d2j-dex2jar --force classes.dex

反编译 AndroidManifest 的工具:
Apktool
命令:apktool d xxx.apk

新开一个 Android Studio Application 工程,将反编译的 AndroidManifest 文件替换工程下的 AndroidManifest,并将反编出来的 classes.jar 放到 libs 下进行依赖,同时删除 build.gradle 中多余的 implementation,只保留我们用到的 jar

再把 src/main 目录下除 AndroidManifest 外的内容删除(包括 res 目录)

这样,基本上结构就搭起来了。

另外,由于我们删除了 res,会导致 AndroidManifest 里面的有关 Theme 的属性会报错找不到资源,如果对 UI 背景没有要求的话,最快的办法就是直接删除这些属性就好了。

最重要的事别忘了,修改 build.gradle 中的 targetSdk=27

扫描二维码关注公众号,回复: 10713660 查看本文章

所以你以为到这里就可以了吗,No,还有很关键的几点要做,这也是我踩完坑后的心血。

很关键的几点
  1. 删除 jar 里的 R.class 和 BuildConfig.class
    我们要手动把 classes.jar 中的 R 和 BuildConfig 删除,避免打包时发生异常:Program type already present
    注意只是删除 R.class,其他的什么 R$id.class,R$drawable.class 不要动

  2. 使用 assembleRelease 来打包一个未签名的 apk
    为什么要未签名的?因为我们要自己加签。由于签名时会对资源文件做处理,我们无法使用原 apk 中的签名文件

  3. 替换资源
    将原 apk 中的 resources.arsc, res 目录替换到我们编译的 apk

  4. 签名
    我们用 jdk 的签名工具 jarsigner 来做签名,首先制作一个签名文件 .jks,再使用命令

// sign_file.jks 签名文件路径
// signed.apk  签名后新的 apk 路径  
// no-sign.apk 未签名的 apk 路径
// test 签名别名,制作签名文件时设置的 alias

jarsigner -verbose -keystore  sign_file.jks -signedjar no-sign.apk signed.apk test

至此,一个只修改了 AndroidManifest 再重编译的 apk 就实现好了

延伸思考:当我们想快速将一个在较低平台上实现的 apk 应用到较高版本的平台,此办法是一个非常有效率的方法,能够达到快速编译部署并开始使用。

发布了27 篇原创文章 · 获赞 3 · 访问量 5653

猜你喜欢

转载自blog.csdn.net/candyngwh/article/details/99337757