知道了Apktool 的基本用法Apktool 使用教程 - 简书,以及Apktool的全部参数配置Apktool 参数详解 - 简书之后,对于Apktool的用法,可以说已经基本搞定,不过源码的阅读也是比不可少的,懂得源码,能改会改,才是解决棘手问题的根本能力。
注意:本文使用的源码为github上拉取的最新代码,2.4.2版本,目前暂未发布。 -- 2020年3月18日
1、查看apktool.jar的入口类
通过查看jar包的Manifest.MF文件,看到入口类为brut.apktool.Main
![](https://img.haomeiwen.com/i5776171/fb8b5f21e8cfb3a3.png)
2、使用Android studio打开apktool的源码
![](https://img.haomeiwen.com/i5776171/128565b3bfba4172.png)
3、找到入口类 brut.apktool.Main
main函数主要做了以下事情,很简单,此处不详述。
(1)设置系统属性 System.setProperty("java.awt.headless", "true");
这里的system,系统指的是 JRE (runtime)system,不是指 OS。
(2)new一个命令行解析器,后续进行命令行参数的解析
(3)初始化配置类,包括各种配置,日志输出等级,是否处理资源文件等等
分所属分别存储在 normalOptions;DecodeOptions;BuildOptions;等变量中
(4)设置日志级别,初始化Logger,设置是否打印步骤日志
(5)解析到底是反编译、重新打包还是安装framework等参数
4、反编译资源
private static void cmdDecode(CommandLine cli)
(1)创建核心类ApkDecoder,其构造方法中,new了一个Androlib类
(2)解析反编译相关的配置,都设置到decoder中备用
![](https://img.haomeiwen.com/i5776171/a964319e65a66ac3.png)
(3)创建输出目录
![](https://img.haomeiwen.com/i5776171/94c3bd96560e9e94.png)
(4)调用反编译核心方法
![](https://img.haomeiwen.com/i5776171/9ac239c235bdf5ee.png)
(5)decod方法
将--keep-broken-res配置值,存入AndrolibResources类中
检查输出目录,输入文件是否OK,不OK抛出异常
OK则创建输出目录
![](https://img.haomeiwen.com/i5776171/2e3e3e0627de0003.png)
输出我们最常见到的一句log
![](https://img.haomeiwen.com/i5776171/75d7041c9fb6402b.png)
之后就开始主要的反编译逻辑了。
(6)处理资源
![](https://img.haomeiwen.com/i5776171/2b55053f23635d96.png)
(7)具体的解析流程,网上各位大神分析的很到位。这里推荐一个,部分注释也是参考了这位的帖子内容!
ApkTool项目解析resources.arsc详解 - 掘金
5、反编译源码
(1)反编译最基础的classes.dex文件
![](https://img.haomeiwen.com/i5776171/62519bac7d4f53e2.png)
(2)输出log,开始反编译dex
![](https://img.haomeiwen.com/i5776171/d07a54d24436bf69.png)
进入 SmaliDecoder 的 decode 方法。
最终执行Baksmali库的方法进行反编译
![](https://img.haomeiwen.com/i5776171/f4a02305af04ba0a.png)
具体解析过程,后续我准备再写一篇关于 Baksmali 文章吧。
解析 dex 可以参考:Android逆向笔记 —— DEX 文件格式解析 - 掘金
(3)处理多个dex,和解析一个dex一个道理,不再重复
![](https://img.haomeiwen.com/i5776171/d717507a7827fa2b.png)
6、处理assets和libs
![](https://img.haomeiwen.com/i5776171/2d5071b2d1fa25cb.png)
7、处理未知文件
![](https://img.haomeiwen.com/i5776171/f7fac95728876b4d.png)
未知文件指非apk固定文件的内容:
"classes.dex", "AndroidManifest.xml", "resources.arsc", "res", "r", "R", "lib", "libs", "assets", "META-INF", "kotlin"
![](https://img.haomeiwen.com/i5776171/6849cbc63a68ad83.png)
将未知文件拷贝到 unknown 目录,并且记录下这些文件。
记录不压缩的文件,读取文件压缩等级,当文件压缩等级为不压缩或者文件符合下列类型时,不进行压缩。
![](https://img.haomeiwen.com/i5776171/37a3c6e52b7c40ed.png)
![](https://img.haomeiwen.com/i5776171/61842a21bac81ccd.png)
![](https://img.haomeiwen.com/i5776171/de044795cd28d4ab.png)
处理原始文件,如果你配置了 -c, --copy-original ,则会将 AndroidManifest.xml 和 META-INF 拷贝到 original 目录下。如下图:
![](https://img.haomeiwen.com/i5776171/917e20a5cb7ee9fb.png)
![](https://img.haomeiwen.com/i5776171/d2ee2752c7f6cb67.png)
8、生成 apktool.yml 文件
![](https://img.haomeiwen.com/i5776171/e44c19dbfe258a76.png)
![](https://img.haomeiwen.com/i5776171/173b897c7e983473.png)
apktool.yml 内容示例如下:
![](https://img.haomeiwen.com/i5776171/0ca600be0b6cddfb.png)
(1)putUsesFramework(meta); 记录使用的framework ---- usesFramework配置项
(2)putSdkInfo(meta); 记录sdkversion信息。 ---- sdkInfo配置项
(3)putPackageInfo(meta);记录packageInfo。 ---- packageInfo配置项
(4)putVersionInfo(meta); 记录包体versioncode,versionname ---- versionInfo配置项
(5)putSharedLibraryInfo(meta);记录是否是一个库。 ---- sharedLibrary配置项
(6)putSparseResourcesInfo(meta); 这个暂时没去了解。---- sparseResources配置项
不过看注释,是与aapt2有关的东西,aapt1忽略这个。估计是aapt1和aapt2之间的处理差异,记录下来,方便重新打包时进行不同的处理。
![](https://img.haomeiwen.com/i5776171/e4519d3a67d74e46.png)
(7)putUnknownInfo(meta); 记录未知文件。 ---- unknownFiles配置项
(8)putFileCompressionInfo(meta);记录文件压缩信息。 ---- doNotCompress配置项
8、小结
粗浅的写了一些流程上的东西,目前只是总结了反编译过程。具体的一些细节,比如 resources.arsc 的解析过程,我也是参考网上大佬的帖子来进行一步步解析的,所以没有自己再去重复写,自己也肯定没有大佬们写的好。另外dex的反编译因为apktool也是直接使用的baksmali库来进行的,后续自己阅读的时候再另起帖子说说。
下面一篇就还是写写重新打包就算完成任务啦。
附上apktool和baksmali的github地址
GitHub - iBotPeaches/Apktool: A tool for reverse engineering Android apk files
网友评论