防止反编译
2.3版本以上在eclipse自动生成的default.properties文件中加上一句“proguard.config=proguard.cfg”可以对代码进行混淆,反编译后是很难看懂的。
2.3之前的SDK版本也没关系,把上面的proguard.cfg文件复制一份放到项目中,然后进行相同的操作即可。
上面的方法可能不行,因为Adt版本更新后发现两个 文件都 没有
试试这个吧
工程的根目录,会自动生成两个ProGuard的混淆文件:proguard-project.txt和project.properties(在老版本的ADT中,只会生成一个叫proguard.cfg的文件)。
看后面一段注释:
#To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home) ,意指要让ProGuard 来压缩和混淆代码,把这句注释去掉即可!所以,我们只要把这段 下面一句注释取消即可
示例:
# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt(就这句)
不过这里要注意:不能试图通过运行eclipse中的Run as 和 Debug as 菜单来生成混淆代码,必须 将apk导出才行,当然你可以选择“签名”或者“不签名”
- 这样一步操作后,算是代码混淆完成了。那么怎么才能检验我们真的混淆了代码了呢?首先,我们能够看到在工程的根目录新生产了一个文件夹proguard,里面有四个文件,其内容如下:
dump.txt : 描述了apk中所有类 文件中内部的结构体。( Describes the internal structure of all the class files in the .apk file )
mapping.txt : 列出了原始的类、方法和名称与混淆代码见得映射。( Lists the mapping between the original and obfuscated class, method, and field names. )
seeds.txt : 列出了没有混淆的类和方法。( Lists the classes and members that are not obfuscated )
usage.txt : 列出congapk中删除的代码。( Lists the code that was stripped from the .apk )
同时使用反编译软件对新生成的apk反编译后会发现,里面的类名、方法和变量等,都变成了简单的a、b、c、d等毫无含义的字母,这样就达到了混淆的目的
反编译
1.用apktool 把apk–> 资源包(java代码变成smali文件看不懂的),可以修改资源包里面的文件。
2.apk后缀名改成zip或rar解压,获取 classes.dex 文件,用dex2jar转换成jar包(注:直接解压出来的资源文件是不能直接打开的,要用第一步的反编译工具)。
3.用jd-ui等java反编译工具直接查看java代码。
4.把java代码和第一版的资源包整到一起重新组成一个新的应用。
5.用apktool 重新编译。
6.用签名工具重新签名。
7.重新发布带新的签名的应用。
注:如果不用改java代码,只是换换风格和汉化2.3.4步则不用做。
另外有人做了个工具套装,集成了apktool dex2jar jd-ui
那么如何签名呢
Java代码:
package com.wl.test;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
public class ReStrore {
public static void main(String[] args) {
// 说明 :
// 解决使用 JDK 1.7 对 Android apk 签名后程序无法安装的问题
/*
同样的程序发布过程,在同事的机器上(JDK 1.6)签名后可以正常安装,但是在我机器上(JDK 1.7)签名后安装说签名错误无法安装。
找到了解决的办法,需要在签名程序 jarsigner 增加如下参数
-digestalg SHA1 -sigalg MD5withRSA
此参数对 JDK 1.6 没有影响。
*/
/*
* You are trying to sign an already signed apk. You need to export an unsigned apk file and then sign it with jarsigner.
* 只能给 未签名的 apk签名
* 已经签过名的不能再次签名 ---------------->
*
* 解决办法 ----------->如何 给 已经签名的 apk 重新签名 -------->删除 好压删除 META-INF 目录 ,然后运行此程序即可
*
*
*
*/
//sourcePath是要签名的apk路径,targetPath是签名后生成的文件路径,key为使用的keystore路径,passwd为keystore对应的密码,alias是keystore的别名。
signApk("D:/HelloWorld.apk", "D:/HelloWorld3.apk", "D:/Keystore", "123456", "wangli");
// getAlias("D:/Keystore", "123456");
}
public static boolean signApk(String sourcePath, String targetPath, String key,
String passwd, String alias) {
if (sourcePath == null || targetPath == null || passwd == null|| key == null)
return false;
File file = new File(sourcePath);
if (!file.exists())
return false;
file=new File(key);
if(!file.exists())
return false;
String jdk7Param = " -digestalg SHA1 -sigalg MD5withRSA";
String cmd = "jarsigner -verbose -keystore " + key + jdk7Param+ " -signedjar " + targetPath + " " + sourcePath + " " + alias;
Process process=null;
try {
process = Runtime.getRuntime().exec(cmd);
OutputStream outputStream = process.getOutputStream();
outputStream.write(passwd.getBytes());
outputStream.close();
InputStream inputStream = process.getInputStream();
InputStreamReader reader = new InputStreamReader(inputStream);
BufferedReader bufferedReader = new BufferedReader(reader);
String line = null;
while ((line = bufferedReader.readLine()) != null) {
System.out.println(line);
if(line.contains("incorrect"))
return false;
}
bufferedReader.close();
} catch (IOException e) {
e.printStackTrace();
return false;
}
return true;
}
//如果不知道怎么获取alias,可以使用下面的代码,alias可以在工程根目录下的alias.txt中查看:
public static void getAlias(String key, String passwd){
String cmd = "cmd.exe /c keytool -list -v -keystore "+key+" -storepass "+passwd+" > ./alias.txt";
try {
Process process=null;
process= Runtime.getRuntime().exec(cmd);
if (process != null) {
InputStream inputStream = process.getErrorStream();
InputStreamReader reader = new InputStreamReader(inputStream);
BufferedReader bufferedReader = new BufferedReader(reader);
String line = null;
while ((line = bufferedReader.readLine()) != null) {
System.out.println(line);
}
bufferedReader.close();
reader.close();
inputStream.close();
process.destroy();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
收工