平时逆向apk,大部分公司仍是都是使用混淆技术作为基础的。这周末,脱了腾讯最新版本的乐固的壳,正在研究。 无聊之余,想和你们聊一聊关于ApkTool这个项目,以为工程师们写的仍是很好的。 本章先大致的介绍一下ApkTool,而后之后的文章在依次的说下项目的各个模块。java
使用ApkTool的时候,老是有的公司插入一些干扰代码来防止ApkTool逆向,这个时候就须要咱们读过ApkTool的源码, 而后手动定位问题所在解决问题了linux
项目地址git
Apktool是一个项目的集合,包含子项目和一些依赖项。 分为了如下几个子项:github
JDK 7或8 (OpenJDK不能够) gitshell
ApkTool项目使用Gradle工具构建windows
我用的是windows环境, 首先咱们从git上clone安全
git clone git://github.com/iBotPeaches/Apktool.git
cd Apktool
./gradlew.bat
#linux的话就是gradlew文件了
复制代码
编译完成后,文件位置在这里"./brut.apktool/apktool-cli/build/libs/apktool-xxxxx.jar"bash
windows有一个最大长度文件路径限制。在ApkTool的存盘路径,因为Windows上最多255个字符的限制,咱们须要强制执行一些要求。ide
这里总共留下了37个字符来克隆Windows的项目。也就是说,目录的深度不要太深。 举个栗子,下面的路径就能够,个人就是存放到了工具
D:/gitclone/Apktool
复制代码
这里总共占了19个字符。因此,不要将这个目录的长度太深,超过37.
执行./gradlew命令以后,会输出以下
Building SNAPSHOT (master): 3879b9
:brut.apktool:compileJava NO-SOURCE
:brut.apktool:processResources NO-SOURCE
:brut.apktool:classes UP-TO-DATE
:brut.apktool:jar
:brut.apktool:assemble
:brut.apktool:license
:brut.apktool:compileTestJava NO-SOURCE
:brut.apktool:processTestResources NO-SOURCE
:brut.apktool:testClasses UP-TO-DATE
:brut.apktool:test NO-SOURCE
:brut.apktool:check
:brut.apktool:build
:brut.j.common:compileJava UP-TO-DATE
:brut.j.common:processResources NO-SOURCE
:brut.j.common:classes UP-TO-DATE
:brut.j.common:jar UP-TO-DATE
:brut.j.util:compileJava UP-TO-DATE
:brut.j.util:processResources NO-SOURCE
:brut.j.util:classes UP-TO-DATE
:brut.j.util:jar UP-TO-DATE
:brut.j.dir:compileJava UP-TO-DATE
:brut.j.dir:processResources NO-SOURCE
:brut.j.dir:classes UP-TO-DATE
:brut.j.dir:jar UP-TO-DATE
注: 某些输入文件使用了未经检查或不安全的操做。
注: 有关详细信息, 请使用 -Xlint:unchecked 从新编译。
:brut.apktool:apktool-lib:compileJava
:brut.apktool:apktool-lib:processResources
:brut.apktool:apktool-lib:classes
:brut.apktool:apktool-lib:jar
:brut.apktool:apktool-cli:compileJava
:brut.apktool:apktool-cli:processResources NO-SOURCE
:brut.apktool:apktool-cli:classes
:brut.apktool:apktool-cli:jar
:brut.apktool:apktool-cli:assemble
:brut.apktool:apktool-cli:license
:brut.apktool:apktool-cli:compileTestJava NO-SOURCE
:brut.apktool:apktool-cli:processTestResources NO-SOURCE
:brut.apktool:apktool-cli:testClasses UP-TO-DATE
:brut.apktool:apktool-cli:test NO-SOURCE
:brut.apktool:apktool-cli:check
:brut.apktool:apktool-cli:build
:brut.apktool:apktool-lib:assemble
:brut.apktool:apktool-lib:license
:brut.apktool:apktool-lib:compileTestJava
:brut.apktool:apktool-lib:processTestResources
:brut.apktool:apktool-lib:testClasses
:brut.apktool:apktool-lib:test
:brut.apktool:apktool-lib:check
:brut.apktool:apktool-lib:build
BUILD SUCCESSFUL in 1m 25s
15 actionable tasks: 9 executed, 6 up-to-date
19:25:03: Task execution finished 'build'.
复制代码
最后就编译成功了
相信这个你们都不陌生,毕竟平时常常用的,那我就说两个经常使用指令
apk拆包 apktool d ******.apk
apk二次打包 apktool b your_path
首先咱们用idea将项目打开, 而后看Main.java类,路径就在brut.apktool/apktool-cli/src/main...../Main.java
源码以下,我加了注释:
public static void main(String[] args) throws IOException, InterruptedException, BrutException {
// 设置verbosity的默认值,后面会根据咱们传入的参数更改
//
Verbosity verbosity = Verbosity.NORMAL;
//命令行解析器,主要用于解析咱们输入的命令
CommandLineParser parser = new DefaultParser();
CommandLine commandLine;
//这个方法内部主要就是初始化咱们关心的一些选项
_Options();
try {
//分析出有效的参数等
commandLine = parser.parse(allOptions, args, false);
} catch (ParseException ex) {
//错误处理,打印错误信息,而后打印帮助信息,退出程序
System.err.println(ex.getMessage());
usage();
return;
}
//首先检查verbose选项
if (commandLine.hasOption("-v") || commandLine.hasOption("--verbose")) {
verbosity = Verbosity.VERBOSE;
} else if (commandLine.hasOption("-q") || commandLine.hasOption("--quiet")) {
verbosity = Verbosity.QUIET;
}
//设置好verbose
setupLogging(verbosity);
//检测是不是使用advance,
if (commandLine.hasOption("advance") || commandLine.hasOption("advanced")) {
setAdvanceMode(true);
}
boolean cmdFound = false;
for (String opt : commandLine.getArgs()) {
//若是有解包指令,那么执行cmdDecode,如下相似
if (opt.equalsIgnoreCase("d") || opt.equalsIgnoreCase("decode")) {
cmdDecode(commandLine);
cmdFound = true;
} else if (opt.equalsIgnoreCase("b") || opt.equalsIgnoreCase("build")) {
cmdBuild(commandLine);
cmdFound = true;
} else if (opt.equalsIgnoreCase("if") || opt.equalsIgnoreCase("install-framework")) {
cmdInstallFramework(commandLine);
cmdFound = true;
} else if (opt.equalsIgnoreCase("empty-framework-dir")) {
cmdEmptyFrameworkDirectory(commandLine);
cmdFound = true;
} else if (opt.equalsIgnoreCase("publicize-resources")) {
cmdPublicizeResources(commandLine);
cmdFound = true;
}
}
//若是没有命令未找到,那么先看看有没有version选项,有的话就打印版本信息
//没有的话,弹出帮助文档,而后退出了
if (!cmdFound) {
if (commandLine.hasOption("version")) {
_version();
System.exit(0);
} else {
usage();
}
}
}
复制代码
本篇做为一个开篇,就是开个头,若是你对如何分析打包解包有很大的兴趣, 那么欢迎本身去认真分析cmdDecode方法,还有cmdBuild方法, 还有ApkTool里面的ApkDecoder,Androlib等关键的类,关键的方法。
算是但愿和读者一块儿探讨一些思路,还有就是若是想研究resources.arsc,或者dex文件等,代码部分和文件的格式密切相关
后序但愿本身可以一点一点补全,也但愿你们能督促我,
我的网站:MartinHan的小站
知乎:MartinHan01)