您的位置:首页 > 移动开发 > Android开发

Android ProGuard代码混淆

2016-10-21 10:52 357 查看

关于混淆

代码混淆(Obfuscated code)亦称花指令,是将计算机程序的代码,转换成一种功能上等价,但是难于阅读和理解的形式的行为。代码混淆可以用于程序源代码,也可以用于程序编译而成的中间代码。执行代码混淆的程序被称作代码混淆器。目前已经存在许多种功能各异的代码混淆器。

众所周知,Java虽然是编译型的语言,但是由于Java编译后的字节码的抽象级别较高,因此它们较容易被反编译。为了防止我们的劳动成果被人窃取,我们通常会将Java程序混淆后打包,增大别人反编译时的难度。

当然,并不是混淆后,别人就无法反编译我们的程序了,否则这个混淆就可以改为加密了。代码混淆并不能真正阻止反向工程,只能增大其难度。因此,对于对安全性要求很高的场合,仅仅使用代码混淆并不能保证源代码的安全。混淆是将代码中的各种元素,如变量,函数,类的名字改写成无意义的名字,然后进行打包,加大别人反编译我们的程序后的理解难度。

另外,因为混淆过程中会精简被混淆的类的类、变量、函数的名字,丢弃无用类和资源,因此混淆也会在一定程度上压缩编译后的文件大小。

混淆也会给我们自己带来一些问题。首先是时间成本上的增加,虽然混淆很简单,短则一两个小时,多则一两天就可以搞定,但是这个时间成本依旧存在。更重要的是,混淆会给我们的调试带来很大的困难,精简后的类、函数、变量名,给我们定位出错带来了一定的难度。对于支持反射的Java,代码混淆有可能与反射发生冲突,因此在与反射相关的类需要避免混淆。

Android的代码混淆默认使用ProGuard工具,在Android Developer上有相关介绍。

混淆配置步骤

以Android Studio为例。

首先,我们需要在Module中的build.gradle中进行混淆配置。通常,我们在混淆时,只对release版本进行混淆,debug版本混淆很明显除了给自己调试增加难度外,没任何用。配置示例如下:

apply plugin: 'com.android.application'

android {

...

buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}


minifyEnabled true
即表示开启混淆。下一行
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
是指定多个混淆配置文件,
getDefaultProguardFile('proguard-android.txt')
表示使用默认配置文件
proguard-android.txt
,后面的
proguard-rules.pro
即为我们自己编写的混淆配置文件。

在build.gradle指定的文件中,按照ProGuard语法编写混淆配置。

签名打包。

ProGuard语法

#指定代码的压缩级别0-7
-optimizationpasses 5
#是否使用大小写混合
-dontusemixedcaseclassnames
#是否混淆第三方jar
-dontskipnonpubliclibraryclasses
#混淆时是否做预校验
-dontpreverify
#混淆时是否记录日志
-verbose
# 混淆时所采用的算法
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
#从给定的文件中读取配置参数
-include {filename}
#指定基础目录为以后相对的档案名称
-basedirectory {directoryname}
#指定要处理的应用程序jar,war,ear和目录
-injars {class_path}
#指定处理完后要输出的jar,war,ear和目录的名称
-outjars {class_path}
#指定要处理的应用程序jar,war,ear和目录所需要的程序库文件
-libraryjars {classpath}
#指定不去忽略非公共的库类。
-dontskipnonpubliclibraryclasses
#指定不去忽略包可见的库类的成员。
-dontskipnonpubliclibraryclassmembers
## 保留选项
#保护指定的类文件和类的成员
-keep {Modifier} {class_specification}
#保护指定类的成员,如果此类受到保护他们会保护的更好
-keepclassmembers {modifier} {class_specification}
#保护指定的类和类的成员,但条件是所有指定的类和类成员是要存在。
-keepclasseswithmembers {class_specification}
#保护指定的类和类的成员的名称(如果他们不会压缩步骤中删除)
-keepnames {class_specification}
#保护指定的类的成员的名称(如果他们不会压缩步骤中删除)
-keepclassmembernames {class_specification}
#保护指定的类和类的成员的名称,如果所有指定的类成员出席(在压缩步骤之后)
-keepclasseswithmembernames {class_specification}
#列出类和类的成员-keep选项的清单,标准输出到给定的文件
-printseeds {filename}
## 压缩
#不压缩输入的类文件
-dontshrink
-printusage {filename}
-whyareyoukeeping {class_specification}
## 优化
#不优化输入的类文件
-dontoptimize
#优化时假设指定的方法,没有任何副作用
-assumenosideeffects {class_specification}
#优化时允许访问并修改有修饰符的类和类的成员
-allowaccessmodification
## 混淆
#不混淆输入的类文件
-dontobfuscate
-printmapping {filename}
#重用映射增加混淆
-applymapping {filename}
#使用给定文件中的关键字作为要混淆方法的名称
-obfuscationdictionary {filename}
#混淆时应用侵入式重载
-overloadaggressively
#确定统一的混淆类的成员名称来增加混淆
-useuniqueclassmembernames
#重新包装所有重命名的包并放在给定的单一包中
-flattenpackagehierarchy {package_name}
#重新包装所有重命名的类文件中放在给定的单一包中
-repackageclass {package_name}
#混淆时不会产生形形色色的类名
-dontusemixedcaseclassnames
#保护给定的可选属性,例如LineNumberTable,LocalVariableTable, SourceFile, Deprecated, Synthetic, Signature, and InnerClasses.
-keepattributes {attribute_name,...}
#设置源文件中给定的字符串常量​
-renamesourcefileattribute {string}


混淆示例

# 指定代码的压缩级别
-optimizationpasses 5
-dontusemixedcaseclassnames
# 是否混淆第三方jar
-dontskipnonpubliclibraryclasses
-dontpreverify
-keepattributes SourceFile,LineNumberTable
-verbose
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*

-libraryjars libs/httpmime-4.1.3.jar
-libraryjars libs/libammsdk.jar
-libraryjars libs/fastjson-1.1.34.android.jar
-libraryjars libs/commons-lang.jar
-libraryjars libs/weibosdkcore.jar

# webview + js
# keep 使用 webview 的类
-keepclassmembers class com.goldnet.mobile.activity.InfoDetailActivity {
public *;
}
# keep 使用 webview 的类的所有的内部类
-keepclassmembers   class com.goldnet.mobile.activity.InfoDetailActivity$*{
*;
}

# 保持哪些类不被混淆
-keep class android.** {*; }
-keep public class * extends android.view
-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.pm
-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

-keepattributes *Annotation*

# 保持 native 方法不被混淆
-keepclasseswithmembernames class * {
native <methods>;
}

# 保持自定义控件类不被混淆
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet);
}
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet, int);
}

-keepclasseswithmembers class * {
void onClick*(...);
}
-keepclasseswithmembers class * {
*** *Callback(...);
}

# keep setters in Views so that animations can still work.
# see http://proguard.sourceforge.net/manual/examples.html#beans -keepclassmembers public class * extends android.view.View {
void set*(***);
*** get*();
}

# 保持枚举 enum 类不被混淆
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}

# 保持 Parcelable 不被混淆
-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}

-keepclassmembers class **.R$* {
public static <fields>;
}

# http client
-keep class org.apache.http.** {*; }

# keep 泛型
-keepattributes Signature

# 新浪微博
-keep class com.sina.**{*;}

# volley
-dontwarn com.android.volley.jar.**
-keep class com.android.volley.**{*;}

# actionbarsherlock
-dontwarn com.actionbarsherlock.**
-keep class com.actionbarsherlock.**{*;}

-dontwarn com.cairh.app.sjkh.**
-keep class com.cairh.app.sjkh.**{*;}


混淆注意事项

根据代码混淆的原理(最主要的就是反射需要用到包名和类名方法名,而混淆会修改类名为其它无意义名字),Android代码在使用混淆使需要注意:

Android系统组件应避免混淆。

被Jni调用的Java类要避免混淆。

所有的native方法不能被混淆

自定义View不应该被混淆。

枚举类不应该被混淆。

注解不应该被混淆

序列化的类(Parcelable)要避免混淆

利用GSON等解析工具解析Json的Bean类,不应该被混淆。

数据库驱动不应该被混淆。

aidl文件不能被混淆

Android建议不要混淆某些类,比如BackupAgent、ILicensingService等

在使用第三方工程的时候,一般会有说明混淆时候要注意哪些要避免混淆,按照其说明加入混淆配置中。

默认混淆

对于以上提到的注意事项,有些使用过混淆的朋友可能会觉得奇怪,我没有避免混淆Android系统组件,比如Activity,Service等等,为什么也没问题呢?这是因为在Android的默认配置中,已经做了相关配置,默认配置如下:

# This is a configuration file for ProGuard.
# http://proguard.sourceforge.net/index.html#manual/usage.html -dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-verbose
# Optimization is turned off by default. Dex does not like code run
# through the ProGuard optimize and preverify steps (and performs some
# of these optimizations on its own).
-dontoptimize
-dontpreverify
# If you want to enable optimization, you should include the
# following:
# -optimizations !code/simplification/arithmetic,!code/simplification/cast,!field/*,!class/merging/*
# -optimizationpasses 5
# -allowaccessmodification
#
# Note that you cannot just include these flags in your own
# configuration file; if you are including this file, optimization
# will be turned off. You'll need to either edit this file, or
# duplicate the contents of this file and remove the include of this
# file from your project's proguard.config path property.
-keepattributes *Annotation*
-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.BackupAgent
-keep public class * extends android.preference.Preference
-keep public class * extends android.support.v4.app.Fragment
-keep public class * extends android.app.Fragment
-keep public class com.android.vending.licensing.ILicensingService
# For native methods, see http://proguard.sourceforge.net/manual/examples.html#native -keepclasseswithmembernames class * {
native <methods>;
}
-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*(...);
}
-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);
}
# For enumeration classes, see http://proguard.sourceforge.net/manual/examples.html#enumerations -keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}
-keepclassmembers class **.R$* {
public static <fields>;
}
# The support library contains references to newer platform versions.
# Don't warn about those in case this app is linking against an older
# platform version.  We know about them, and they are safe.
-dontwarn android.support.**


欢迎转载,转载请保留文章出处。湖广午王的博客[http://blog.csdn.net/junzia/article/details/52879823]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android 代码混淆