平時逆向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)