逆向工程可以用来破解软件、提取资源等等,平时用来玩玩罢了。另一方面,也可以用来检测自己的软件的破解难度。Android反编译获取代码不难,主要是利用几个工具,难点在于如何分析这些被混淆的代码。本文主要叙述反编译工具的使用。上一次反编译APP是半年前,很久不用都快忘了,因此记录一下。
APK包的内容分析
apk文件本质是一个压缩包文件,可以将后缀改成rar等压缩格式后,解压可得到几个文件,包括:classes.dex和res等,其中dex里面是java代码,res里面是资源文件(包括布局、图片等)。如果想提取资源文件,直接从这里提取即可。
如果是单个dex文件,那么此处可以用dex2jar工具,将classes.dex转化成jar文件,再用JD-GUI查看jar文件即可。对于多个dex文件的情况(multidex)或者其他复杂情况(忘记半年前遭遇了什么),应先将apk转换成smali(此处采用apktool.jar),再将smali转换成dex(此处采用smali.jar),然后将dex转换成jar(此处采用dex2jar.bat),最后用JD-GUI查看jar文件。
具体步骤
1、 下载工具
JVM(包含jre)事先已经装好,然后将上述工具下载到同一个文件夹内,本人下载的包括:
apktool,(版本忘了),里面有apktool.bat和apktool.jar文件。
smali-2.1.3.jar,可以直接拿来用。
dex2jar-2.0.zip,解压后里面有d2j-dex2jar.bat等文件。
jd-gui-windows-1.4.0.zip,解压后里面有jd-gui.exe文件。
2、 apktool
java -jar apktool/apktool.jar d app.apk -o app
很简单的命令,java -jar执行jar文件,指定源文件,-o指定输出文件。(目录路径使用/或\好像都行)(但是d参数不知道是啥)
3、 smali2dex
java -jar smali-2.1.3.jar app/smali -o classes01.dex
得到classes01.dex文件。
4、 dex2jar
将命令行路径切换到dex2jar-2.0,并运行:
d2j-dex2jar.bat ../classes01.dex
执行批处理文件可得到classes01-dex2jar.jar文件。
5、 查看jar文件代码
运行jd-gui.exe,将jar文件拖到jd-gui界面内即可。
其他笔记
(半年前写的):
关于smali2dex 下载:点击打开链接 参考方法:点击打开链接
开始用新版本2.2.0的失败了(可能是java不兼容),后来用了2.1.3版成功了。命令:java -jar smali-2.1.3.jar -o 目标dex文件 [smali文件夹]
一个新工具: ApkToolPlus
其他参考: 点击打开链接
multiDex系列:【Error:Execution failed for task ‘:app:transformClassesWithDexForDebug’解决记录】
这个博客 讲了一些,挺好,应该可行。
但我的程序运行时还是挂了。最终我还是通过提取反编译技术,将jar包里重复的库删除,重新建立jar包。所以避免了这个错误。
附:反编译代码的解读规则
1、调用外部变量的规则access$002
2、if语句
//If语句
private boolean isPhoneNum(String s){
// the length should be valid
if (s == null || s.trim().isEmpty() || s.length()!=11)
return false;
// s should have no dot (.)
Pattern p = Pattern.compile("[^0-9]");
Matcher m = p.matcher(s);
boolean b = m.find();
if (b == true)
return false;
else
return true;
}
变成
private boolean isPhoneNum(String paramString)
{
if ((paramString == null) || (paramString.trim().isEmpty()) || (paramString.length() != 11)) {}
while (Pattern.compile("[^0-9]").matcher(paramString).find() == true) {
return false;
}
return true;
}
3、循环语句
//For语句
for (i=0;i<4;i++){
char c=s.charAt(i);
if (!( (c>='0')&&(c<='9')|| (c>='A')&&(c<='Z')|| (c>='a')&&(c<='z') ) ){
return false;
}
}
变成
for (;;)
{
if (i >= 4) {
break label72;
}
int j = paramString.charAt(i);
if (((j < 48) || (j > 57)) && ((j < 65) || (j > 90)) && ((j < 97) || (j > 122))) {
break;
}
i += 1;
}
label72:
还有很多规则,之后再总结一下。