Android混淆(Proguard)详解

目录:

1、混淆的作用及好处
2、混淆的原理
3、混淆的具体使用
--- 3.1、混淆的基本语法
--- 3.2、去除日志信息
4、更详细的语法及demo

1、混淆的作用及好处

混淆属于整个应用程序开发生命周期偏后期阶段的技术了,所以要考虑应用的安全性及性能的问题,混淆就是为了这种需求产生的一种技术,简单说,混淆就是将关键字和关键类名,修改为无意义的字符以起到迷惑试图反编译去查看源码的人。在一定程度上能过滤掉起码95%以上的反编译者,混淆是保障Android程序源码安全的第一道门槛,这是我的个人理解。
以上谈了下混淆的作用,而混淆的好处除了能保证源码安全性之外就大概是通过修改关键字为无意义字符串,或者剔除某些辅助类,比如Log,从而减少文件大小。

2、混淆的原理

以上混淆均指的是Proguard,Proguard是混淆代码的一个开源项目(proguard官网)

Java 是一种跨平台的、解释型语言,Java 源代码编译成中间”字节码”存储于 class 文件中。由于跨平台的需要,Java 字节码中包括了很多源代码信息,如变量名、方法名,并且通过这些名称来访问变量和方法,这些符号带有许多语义信息,很容易被反编译成 Java 源代码。为了防止这种现象,我们可以使用 Java 混淆器对 Java 字节码进行混淆。
混淆就是对发布出去的程序进行重新组织和处理,使得处理后的代码与处理前代码完成相同的功能,而混淆后的代码很难被反编译,即使反编译成功也很难得出程序的真正语义。被混淆过的程序代码,仍然遵照原来的档案格式和指令集,执行结果也与混淆前一样,只是混淆器将代码中的所有变量、函数、类的名称变为简短的英文字母代号,在缺乏相应的函数名和程序注释的况下,即使被反编译,也将难以阅读。同时混淆是不可逆的,在混淆的过程中一些不影响正常运行的信息将永久丢失,这些信息的丢失使程序变得更加难以理解。
混淆器的作用不仅仅是保护代码,它也有精简编译后程序大小的作用。由于以上介绍的缩短变量和函数名以及丢失部分信息的原因, 编译后 jar 文件体积大约能减少25% ,这对当前费用较贵的无线网络传输是有一定意义的。

反编译之后得到的类名

3、混淆的具体使用

3.1、模块(Module)下的build.gradle的配置
android{
  buildTypes{
    release { 
       // 是否进行混淆  
       minifyEnabled false  
       // 混淆文件的位置,其中'proguard-android.txt'为sdk默认的混淆配置,
       //'proguard-rules.pro' 是该模块下的混淆配置
       proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'  
    } 
  }
}

以上是proguard在模块下build.gradle文件中的配置信息,其中proguard-android.txt为sdk默认的混淆配置,proguard-rules.pro是在默认配置的基础上针对本模块做出的针对性混淆处理。

  • 注:proguard-android.txt的位置位于android-sdk/tools/proguard/proguard-android.txt
3.1、混淆的基本语法

这个语法的作用是定义出不需要混淆的源代码,那么编译时会自动将未定义的部分全都混淆。至于为什么要保留类名或方法名,主要有三个原因:

  • 让C/C++程序可以通过jni使用对应的java方法。
  • 四大组件在AndroidManifest.xml里面注册了,所以要保留。
  • R文件混淆会导致引用错误。

1、保留类名
2、保留方法名
3、保留类名和方法名

#保留位于View类中的get和set方法
-keepclassmembers public class * extends android.view.View{
    void set*(***);
    *** get*();
}
#保留在Activity中以View为参数的方法不变
-keepclassmembers class * extends android.app.Activity{
    public void *(android.view.View);
}
#保留实现了Parcelable的类名不变,
-keep class * implements android.os.Parcelable{ 
    public static final android.os.Parcelable$Creator *;
}
 #保留R$*类中静态成员的变量名
-keepclassmembers class **.R$*{
    public static <fields>;
}
3.2 去除日志信息

通过配置proguard,将android.util.Log置为无效代码,则可以去除apk中打印日志的代码。
1、将build.gradle添加'proguard-android-optimize.txt'文件,该文件中默认打开了优化开关。

android{
  buildTypes{
    release { 
       // 是否进行混淆  
       minifyEnabled false  
       // 混淆文件的位置,其中'proguard-android-optimize.txt'为sdk默认的混淆配置,
       //'proguard-rules.pro' 是该模块下的混淆配置
       proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'  
    } 
  }
}

2、配置语法

-assumenosideeffects class android.util.Log{
   public static boolean isLoggable(java.lang.String,int);
   public static int v(...);
   public static int i(...);
   public static int w(...);
   public static int d(...);
   public static int e(...);
}
-assumenosideeffects class com.example.Log.Logger{
   public static int v(...);
   public static int i(...);
   public static int w(...);
   public static int d(...);
   public static int e(...);
}

4、更详细的语法

-include {filename}    从给定的文件中读取配置参数   
-basedirectory {directoryname}    指定基础目录为以后相对的档案名称   
-injars {class_path}    指定要处理的应用程序jar,war,ear和目录   
-outjars {class_path}    指定处理完后要输出的jar,war,ear和目录的名称   
-libraryjars {classpath}    指定要处理的应用程序jar,war,ear和目录所需要的程序库文件   
-dontskipnonpubliclibraryclasses    指定不去忽略非公共的库类。   
-dontskipnonpubliclibraryclassmembers    指定不去忽略包可见的库类的成员。  
  
保留选项   
-keep {Modifier} {class_specification}    保护指定的类文件和类的成员   
-keepclassmembers {modifier} {class_specification}    保护指定类的成员,如果此类受到保护他们会保护的更好  
-keepclasseswithmembers {class_specification}    保护指定的类和类的成员,但条件是所有指定的类和类成员是要存在。   
-keepnames {class_specification}    保护指定的类和类的成员的名称(如果他们不会压缩步骤中删除)   
-keepclassmembernames {class_specification}    保护指定的类的成员的名称(如果他们不会压缩步骤中删除)   
-keepclasseswithmembernames {class_specification}    保护指定的类和类的成员的名称,如果所有指定的类成员出席(在压缩步骤之后)   
-printseeds {filename}    列出类和类的成员-keep选项的清单,标准输出到给定的文件   
  
压缩   
-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    混淆时不会产生形形色色的类名   
-keepattributes {attribute_name,...}    保护给定的可选属性,例如LineNumberTable, LocalVariableTable, SourceFile, Deprecated, Synthetic, Signature, and   
  
InnerClasses.   
-renamesourcefileattribute {string}    设置源文件中给定的字符串常量  

demo

-ignorewarnings                     # 忽略警告,避免打包时某些警告出现  
-optimizationpasses 5               # 指定代码的压缩级别  
-dontusemixedcaseclassnames         # 是否使用大小写混合  
-dontskipnonpubliclibraryclasses    # 是否混淆第三方jar  
-dontpreverify                      # 混淆时是否做预校验  
-verbose                            # 混淆时是否记录日志  
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*        # 混淆时所采用的算法  
  
-libraryjars   libs/treecore.jar  
  
-dontwarn android.support.v4.**     #缺省proguard 会检查每一个引用是否正确,但是第三方库里面往往有些不会用到的类,没有正确引用。如果不配置的话,系统就会报错。  
-dontwarn android.os.**  
-keep class android.support.v4.** { *; }        # 保持哪些类不被混淆  
-keep class com.baidu.** { *; }    
-keep class vi.com.gdi.bgl.android.**{*;}  
-keep class android.os.**{*;}  
  
-keep interface android.support.v4.app.** { *; }    
-keep public class * extends android.support.v4.**    
-keep public class * extends android.app.Fragment  
  
-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.support.v4.widget  
-keep public class * extends com.sqlcrypt.database  
-keep public class * extends com.sqlcrypt.database.sqlite  
-keep public class * extends com.treecore.**  
-keep public class * extends de.greenrobot.dao.**  
  
  
-keepclasseswithmembernames class * {       # 保持 native 方法不被混淆  
    native <methods>;  
}  
  
-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);  
}  
  
-keepclassmembers enum * {                  # 保持枚举 enum 类不被混淆  
    public static **[] values();  
    public static ** valueOf(java.lang.String);  
}  
  
-keep class * implements android.os.Parcelable {    # 保持 Parcelable 不被混淆  
  public static final android.os.Parcelable$Creator *;  
}  
  
-keep class MyClass;                              # 保持自己定义的类不被混淆  

参考

1、MOOC-Android代码混淆与加固技术
2、CSDN-Android proguard 详解
3、简书-ProGuard 最全混淆规则说明

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,406评论 6 503
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,732评论 3 393
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,711评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,380评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,432评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,301评论 1 301
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,145评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,008评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,443评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,649评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,795评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,501评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,119评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,731评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,865评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,899评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,724评论 2 354

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 172,110评论 25 707
  • 声明 这篇文章更多的是做一个整理,内容来自于ProGuard官方文档以及各种博客等,相关文章的链接在参考目录里,感...
    夷陵小祖阅读 3,679评论 0 23
  • https://yq.aliyun.com/articles/62980?utm_campaign=wenzhan...
    x360阅读 1,422评论 0 3
  • 什么是代码混淆 代码混淆就是将代码中的各种元素,如变量,方法,类和包的名字改写成无意义的名字,增加项目反编译后被读...
    蜗牛家族史阅读 5,144评论 1 4
  • 儿子目标“国际侦探家”,梦想战略图绘制自己中学、高中、大学拆分的小目标,最近看到很多家长开始给孩子小升初布局。看看...
    阿君姐阅读 237评论 3 5