1、ApkTool介绍
它是一个为逆向工程师打造的用于反编译Android 二进制 app的工具。它可以将资源解码为几乎原始的形式,并在修改之后重建它们。
1.1、功能
- 将资源反编译为几乎原始的格式(包括resources.arsc、classes.dex、9.png和XML文件)
- 重新编译这些反编译后的资源为二进制apk/jar
- 可以处理依赖框架资源的APK
- Smali 调试 (在
2.1.0
版本已经移除,建议替换为idea或android studio插件IdeaSmali)
1.2、源码工程介绍
Apktool是一个Android 工程,它包含了一些子工程和一些依赖:
- brut.apktool.lib ——(apktool的library库)
- brut.apktool.cli —— apktool的入口,程序命令的接口定义在这里
- brut.j.dir —— 工具
- brut.j.util —— 工具
- brut.j.common —— 工具
工程源码下载地址:https://github.com/iBotPeaches/Apktool
1.3、构建步骤
我们用gradle来构建会非常简单,首先你要clone远程代码仓库;
git clone git://github.com/iBotPeaches/Apktool.git
- cd Apktool
- 接下来unix系统用
./gradlew
或者windows系统用gradlew.bat
[./gradlew][gradlew.bat] build shadowJar
– 编译Apktool工程,和生成最终的二进制可运行文件
构建完成后你可以在以下目录找到一个jar文件
./brut.apktool/apktool-cli/build/libs/apktool-xxxxx.jar
2、ApkTool 工程源码分析
2.1、能解析的文件格式和对应的工具
- 对于dex文件,apktool使用了dexlib2来进行读/修改/写操作。使用baksmali库反编译dex文件为smali格式。同时使用smali工具回编译smali到dex格式,再通过dexlib2写为dex文件
- 对于apk里面的所有xml格式,apktool采用了自己解析的方式,它的主要实现在AXmlResourceParser里面。并结合xpp3库读取解析后的xml文件信息。在回编译的时候使用Android的aapt工具。
- resources.arsc文件解析也采用了自己解析的方式,主要实现在ARSCDecoder类里面,回编译的时候使用了aapt
- 其它的一些assets、so、META-INF都是直接copy
2.2、ApkTool的反编译流程
这幅图描述了apktool如何将apk里面文件转换为可阅读文件的过程,里面使用到了上面介绍的工具。结合这张图在阅读源码上帮助会很大。
整体来说apktool对resources.arsc和xml这两种二进制格式文件采用了自己解析的方式,这些二进制文件的格式可以参考这篇文章:https://blog.csdn.net/jiangwei0910410003/article/details/50628894
我也非常开心买了作者的这本书:《Android应用安全防护和逆向分析》,也非常推荐这本书,全网只有它对Android二进制文件的分析最为和详细。
2.3、ApkTool工程类图结构
Apktool工程的核心在于decorder文件夹下面的这些解析工具类,有兴趣的同学可以详细研究一下。
它也依赖了一些第三方库:
- xpp3: XmlPullParser,以流的方式解析xml文件
- aapt: android提供的资源打包工具,后面官方升级了并默认推荐使用aapt2版本,不过目前aapt仍然广泛使用。
- dexlib2:操作dex文件
- smali:回编译smali文件到dexlib2可识别格式,结合dexlib2将smali文件转为dex文件
- baksmali:将dex转smali
3、ApkTool常见打包问题
3.1、error: No resource identifier found for attribute ‘compileSdkVersion’ in package ‘android’
错误日志:
1 2 3 4 5 6 7 |
【warn】命令执行失败:W: /xxxxxxx/packtool/bat/test/./../../output/debug/temp/apk/AndroidManifest.xml:2: error: No resource identifier found for attribute 'compileSdkVersion' in package 'android' 【warn】命令执行失败:W: 【warn】命令执行失败:W: /xxxxxx/packtool/bat/test/./../../output/debug/temp/apk/AndroidManifest.xml:2: error: No resource identifier found for attribute 'compileSdkVersionCodename' in package 'android' 【warn】命令执行失败:W: 【warn】命令执行失败:brut.androlib.AndrolibException: brut.common.BrutException: could not exec (exit code = 1): [xxxx/pack/tools/aapt/28.0.0/mac/aapt, p, --min-sdk-version, 14, --target-sdk-version, 26, --version-code, 1, ... 【warn】命令执行失败! 【Exception】java.lang.RuntimeException: 合包时apktool执行失败 |
解决方案:
在运行打包之前先执行下面的命令:
1 |
apktool empty-framework-dir |
原因分析:
本地有两个版本的apktool,首先用旧版本的apktool打包成功,然后再用新版本的apktool打包就出问题。
原因是旧版本的apktool先下载了对应的framework的apk到本地,再用新版本apktool打包时发现本地有framework.apk就直接使用而不会去更新framework.apk,但是该旧版本的framework.apk可能和新版本apktool不兼容,所以出现上面的问题了。
详细分析:
根据apktool官方的介绍,也印证了我们上面的错误分析结论:
Apktool官方对Frameworks的介绍:https://ibotpeaches.github.io/Apktool/documentation/
官方的意思是:
Apktool和framework.apk是绑定在一起的。这个文件在被使用的时候会拷贝到$Home/apktool/framework/1.apk。
注意:Apktool不关心对应路径下面的framework的版本是多少。它会假设这个framework是最新的,所以apktool升级的时候需要删除旧的framework
apktool依赖的framework在不同的系统上会放在不同的位置:
- unix –
$HOME/.local/share/apktool
- windows –
%UserProfile%\AppData\Local\apktool
- mac –
$HOME/Library/apktool
另一种推荐的解决方案:
如果你本地有多个版本的apktool,或你需要有多个不同的framework同时存在。你需要更简单的方法来切换这些framework,具体方法如下:
你需要为这些多个不同的framework打上对应的tag
在使用apktool解包的时候,这样使用:
你不需要在合包的时候选择framework的tag,apktool会自动使用和解包时相同的tag。
4、ApkTool 断点调试
学习apktool源码最快的方式是可以断点调试里面的代码。让ApkTool可以断点调试需要以下几步:
1、Android Studio菜单Run > Edit Configuration… > 添加一个Application类型的Configuration,配置如下:
- 设置Main class 为 brut.apktool.Main
- Program arguments 这里是apktool解包或合包的参数,我们可以先预置一个apk包在工程目录,然后对它进行解包操作。例如:d apk/game.apk -o apk/output/
- Working directory 为Apktool的工程目录
- use classpath of module: 选定apktool-cli
2、菜单上点击debug运行刚刚添加的config(apktool-run)
就可以顺利断点到你想要的位置了