反编译Apk时你是否遇到过下图中的错误,反编译进行到某个dex文件时就报错了。
于是根据错误信息ApkDecoder.decode
到apktool源码中查找
if (hasSources()) {
switch (mDecodeSources) {
case DECODE_SOURCES_NONE:
mAndrolib.decodeSourcesRaw(mApkFile, outDir, "classes.dex");
break;
case DECODE_SOURCES_SMALI:
mAndrolib.decodeSourcesSmali(mApkFile, outDir, "classes.dex", mBakDeb, mApi);
break;
}
}
if (hasMultipleSources()) {
// foreach unknown dex file in root, lets disassemble it
Set files = mApkFile.getDirectory().getFiles(true);
for (String file : files) {
if (file.endsWith(".dex")) {
if (! file.equalsIgnoreCase("classes.dex")) {
switch(mDecodeSources) {
case DECODE_SOURCES_NONE:
mAndrolib.decodeSourcesRaw(mApkFile, outDir, file);
break;
case DECODE_SOURCES_SMALI:
mAndrolib.decodeSourcesSmali(mApkFile, outDir, file, mBakDeb, mApi);
break;
}
}
}
}
}
从源码中可以看到apktool会先找到classes.dex
进行反编译,然后再遍历后缀名为.dex
的所有文件进行反编译。
那么只要在apk中添加一个假的.dex
文件就能导致apktool反编译失败。
那如何在自己的apk中添加假的dex呢?
- 反编译apk
通过以下命令反编译apk
apktool d -s -r xxx.apk
- 添加假的dex文件
在反编译结果文件夹中创建一个空文件命名为'classes.dex'(实际上任何名称都行只要后缀名为.dex
)
- 回编译apk
用一下命令回编译apk
apktool b .
- apk签名
因为apk反编译之后签名信息会丢失,因此需要重新签名。
可以用jarsigner
命令。
这样一个新的apk就出来了,这时可以用apktool
再反编译试试,是不是会报错
那遇到这种apk该如何正确反编译呢?
简单粗暴的做法:修改apktool源码增加try catch
if (hasMultipleSources()) {
// foreach unknown dex file in root, lets disassemble it
Set files = mApkFile.getDirectory().getFiles(true);
for (String file : files) {
if (file.endsWith(".dex")) {
if (! file.equalsIgnoreCase("classes.dex")) {
switch(mDecodeSources) {
case DECODE_SOURCES_NONE:
mAndrolib.decodeSourcesRaw(mApkFile, outDir, file);
break;
case DECODE_SOURCES_SMALI:
// 增加异常捕捉防止反编译dex文件过程出错导致退出程序
try{
mAndrolib.decodeSourcesSmali(mApkFile, outDir, file, mBakDeb, mApi);
}catch (Throwable t){
t.printStackTrace();
}
break;
}
}
}
}
}
附:
apktool源码地址:https://github.com/iBotPeaches/Apktool
测试apk下载地址:http://cdn.video4.cn/mock-dex.apk