对于android程序来说,因为java程序非常容易被反编译,所以开发的android程序也处于非常不安全的处境。
android编译后的apk文件其实是一个压缩包,把后缀名改为zip,打开后就可以看到apk由以下的文件组成:
assets
res
AndroidManifest.xml
resources.arsc
classes.dex
lib
META-INF。。。
classes.dex就是所有编译后的class,现在有很多工具可以对它反编译。我先用了dex2jar把classes.dex转换为一个jar,然后用jd-gui打开这个jar一看,所有的程序代码一清二楚。。。虽然现在提倡分享,并不介意分享源码,但因为程序中涉及到卖的产品本身需要安全控制,要不别人看明白代码,然后修改安全控制,重新编译后,等于是别人可以免费得到卖的产品了。
还好现在android好像从2.2开始内置了proguard工具,它位于android安装目录下tools/proguard目录中,它是一个开源的对java代码进行混淆优化的工具。而且使用非常简单,创建android工程以后,工程目录下会自动生成一个proguard.cfg文件,这个文件是用于proguard对代码混淆的配置文件,默认情况如下:
-optimizationpasses 5
-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-dontpreverify
-verbose
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.app.backup.BackupAgentHelper
-keep public class * extends android.preference.Preference
-keep public class com.android.vending.licensing.ILicensingService
-keepclasseswithmembernames class * {
native <methods>;
}
-keepclasseswithmembernames class * {
public <init>(android.content.Context, android.util.AttributeSet);
}
-keepclasseswithmembernames class * {
public <init>(android.content.Context, android.util.AttributeSet, int);
}
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}
proguard在这最重要的作用就是混淆代码,看上面的配置,大概可以知道它怎么使用,比如-keepclasseswithmembernames就是要保留类中的成员函数,在这里它保留了native函数的声明,这是由于jni调用的时候,是根据native函数名,所以如果它被混淆了,程序将无法用jni调用c写的这个函数。同理,由于我在程序中需要jni改变java类中的成员变量的值,所以我还需要保留这些变量,我在cfg加上如下规则:
-keepclassmembernames class * {
int mBitmapWidth;
int mBitmapHeight;
}
更多的配置查看http://proguard.sourceforge.net/
在默认情况下,proguard是不打开的。如果需要proguard混淆代码,首先在default.properties中加上proguard.config=proguard.cfg,编译后然后右键工程弹出菜单,选择"Android Tools"->"Export signed application package...",按弹出的对话框操作(如果没生成keystore,首先创建,然后导出数字签名的apk)。成功后在工程目录会加一个目录proguard,里面包含四个文件:dump.txt,mapping.txt,seeds.txt,usage.txt,这些文件包含了proguard到底如何替换混淆代码的信息,retrace时需要用到。
至此,java代码就被混淆优化了。再用dex2jar,jd-gui查看反编译的java代码。发现所有的变量还有自己写的class都被替换成a,b,c,ab等等的,要读懂程序就没那么容易了。
虽然现在读懂程序比较难,但相信还是难不住那些有耐心有“钻研”的家伙啊,因为混淆后程序结构还是一目了然呀,所以仅仅如此并不能加大破解的难度,这时候我自己觉得的有几种方法来增加破解难度:1。关键性代码用c写,然后用jni调用;2。关键性的class动态从服务器上取得,避免在客户端被反编译;3。对class加密,然后自己重写class load的地方再解密;4。好像说都写中文变量名,就反编译不了,因为大部分工具都只支持英文,但如此程序也只能运行在中文环境;5。java防反编译可以做到反编译后的代码是乱七八糟的,但用的工具忘记了,(哎,没有记录的习惯惹的)。这些方法由于项目时间的原因,下一步要好好研究