赞
踩
由于Android项目是基于java语言的,而java属于高层抽象语言,易于反编译,其编译后的程序包包含了大量的源代码变量、函数名、数据结构等信息,根据其编译打包后的APK文件,可以非常容易的得到 近乎源代码质量 的反编译代码。如果不加混淆,相当于直接将源代码拱手送人,内容严密的app权限审核可以说是形同虚设。如果大家想避免自己的成果被别人夺取,然后重新修改策划而额外增加的工作量,那就尽量得自己的Android项目加上混淆吧。
android平台的混淆原理是把代码中原来有具体含义的包名,类名,变量名,方法名等名称全部替换成按顺序排列的无意义的英文字母a、b、c….这样代码结构没有变化,还可以运行得到一样的结果,并且就算代码被反编译出来,别人想弄懂代码的架构和具体意思也比较难。
比较常用的方法有以下两种:
启用代码混淆
找到Android项目目录下的project.properties文件,如果需要对项目进行全局混码,只需要进行一步操作:将project.properties文件中的“# proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt”中的“#”去掉就可以了。
但是如果有一些代码不能被混淆,比如引入了第三方jar文件或加入了so文件,需要调用里面的方法,那么调用JNI访问so文件的方法就不能被混码。在导出的时候,可能不会报错。但是在手机上运行的时候,需要调用so文件的时候,就会报某某方法无法找到。这个时候就需要用到proguard-project.txt。
编写混淆脚本
找到Android项目目录下的“proguard-project.txt”文件,在proguard-project.txt文件中,你需要做的就是指定混淆规则,还有指明要过滤那些文件或代码块。具体内容来看一个例子:
-ignorewarnings
-optimizationpasses 7 #指定代码的压缩级别 0 - 7
-dontusemixedcaseclassnames #是否使用大小写混合
-dontskipnonpubliclibraryclasses #是否混淆第三方jar
-dontpreverify #混淆时是否做预校验(可去掉加快混淆速度)
-verbose #混淆时是否记录日志(混淆后生产映射文件 map 类名 -> 转化后类名的映射
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/* #淆采用的算法
-keep public class * extends android.app.Activity #所有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>; #保持 native 的方法不去混淆
}
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet); #保持自定义控件类不被混淆,指定格式的构造方法不去混淆
}
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet, int);
}
-keepclassmembers class * extends android.app.Activity {
public void *(android.view.View); #保持指定规则的方法不被混淆(Android layout 布局文件中为控件配置的onClick方法不能混淆)
}
-keep public class * extends android.view.View { #保持自定义控件指定规则的方法不被混淆
public <init>(android.content.Context);
public <init>(android.content.Context, android.util.AttributeSet);
public <init>(android.content.Context, android.util.AttributeSet, int);
public void set*(...);
}
-keepclassmembers enum * { #保持枚举 enum 不被混淆
public static **[] values();
public static ** valueOf(java.lang.String);
}
-keep class * implements android.os.Parcelable { #保持 Parcelable 不被混淆(aidl文件不能去混淆)
public static final android.os.Parcelable$Creator *;
}
-keepnames class * implements java.io.Serializable #需要序列化和反序列化的类不能被混淆(注:Java反射用到的类也不能被混淆)
-keepclassmembers class * implements java.io.Serializable { #保护实现接口Serializable的类中,指定规则的类成员不被混淆
static final long serialVersionUID;
private static final java.io.ObjectStreamField[] serialPersistentFields;
!static !transient <fields>;
private void writeObject(java.io.ObjectOutputStream);
private void readObject(java.io.ObjectInputStream);
java.lang.Object writeReplace();
java.lang.Object readResolve();
}
-keepattributes Signature #过滤泛型(不写可能会出现类型转换错误,一般情况把这个加上就是了)
-keepattributes *Annotation* #假如项目中有用到注解,应加入这行配置
-keep class **.R$* { *; } #保持R文件不被混淆,否则,你的反射是获取不到资源id的
-keepclassmembernames class com.cgv.cn.movie.common.bean.** { *; } #转换JSON的JavaBean,类成员名称保护,使其不被混淆
-assumenosideeffects #g过滤代码中的日志
class android.util.Log
{
public static ***
e(...);
public static ***
w(...);
public static ***
wtf(...);
public static ***
d(...);
public static ***
v(...);
}
# 下面都是项目中引入的第三方 jar包 ==== 引入jar包的绝对路径
#-libraryjars libs/android-support-v4.jar
#-dontwarn android.support.v4.**
#-keep class android.support.v4.**{ *; }
#-keep interface android.support.v4.**{*;}
#-keep public class * extends android.support.v4.**{*;}
#-keep public class * extends android.app.Fragment
-libraryjars libs/armeabi-v7a/libijkffmpeg.so
-dontwarn com.google.protobuf.nano.**
-keep class com.google.protobuf.nano.**{*;}
-dontwarn com.google.gson.**
-keep class com.google.gson.**{*;}
# 第三方统计SDK友盟相关过滤
-keepclassmembers class * { #友盟SDK中的部分代码使用,反射来调用构造函数
public <init> (org.json.JSONObject);
}
-keep public class [com.wormhole.sdk].R$*{ #过滤R文件,友盟SDK需要引用导入工程的资源文件
public static final int *;
}
具体哪行代码是什么作用大部分上面都有注释,比较常用的有以下几点:
1.从脚本中可以看到,混淆中保留了继承自Activity、Service、Application、BroadcastReceiver、ContentProvider等基本组件。
2.保留了所有的Native变量名及类名,所有类中部分以设定了固定参数格式的构造函数,枚举等等。(详细信息请参考\examples中的例子及注释)
3.需要序列化和反序列化的类不能被混淆。(注:Java反射用到的类也不能被混淆)
4.保持R文件不被混淆,否则,你的反射是获取不到资源id的。
5.过滤引入的第三方jar包,so文件和外部lib等
//过滤第三方jar包,com.google.gson替换成要想要过滤的包名
-dontwarn com.google.gson.**
-keep class com.google.gson.**{*;}
//过滤so文件,libs/armeabi-v7a/libijkffmpeg.so换成想过滤的搜文件路径
-libraryjars libs/armeabi-v7a/libijkffmpeg.so
如果你想把你的Android项目打包成jar文件然后再混淆,那这种方法比较适合
只需要选择java文件即可,其他配置文件什么的都不用选择
至此就完成了jar文件的混淆,并保存了混淆文件。
当然,如果你已经写好的混淆文件,那么直接通过导入混淆文件进行混淆就行了。具体操作如下:
1.打开progrard目录,执行 bin目录下的proguardgui.bat。
2.点击第一个选项“Proguard”,再点击“Load configuration”,选择你的混淆文件进行加载。
3.然后点击Process,然后点击View configuration查看是否是已经修改过后的配置文件。
好了,至此已经把我所了解的Android混淆机制及使用方法介绍完毕,如果有错误的地方或者有不明了之处请大家留言指出。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。