Android--ProGuard混淆

作者: 芒果味的你呀 | 来源:发表于2017-12-11 17:00 被阅读37次

为什么要混淆?

增大反编译难度,类和类成员会被随机命名。

混淆的四个功能:

我们通常说的proguard包括四个功能,shrinker(压缩), optimizer(优化),obfuscator(混淆),preverifier(预校验)。

混淆的过程
  • shrink压缩: 检测并移除没有用到的类,变量,方法和属性;默认开启,用以减小应用体积,移除未被使用的类和成员,并且会在优化动作执行之后再次执行(因为优化后可能会再次暴露一些未被使用的类和成员)。
  • optimize优化: 优化代码,非入口节点类会加上private/static/final, 没有用到的参数会被删除,一些方法可能会变成内联代码。默认开启,在字节码级别执行优化,让应用运行的更快。
  • obfuscate混淆: 使用短又没有语义的名字重命名非入口类的类名,变量名,方法名。入口类的名字保持不变。默认开启,增大反编译难度,类和类成员会被随机命名,除非用keep保护。
  • preverify预校验: 预校验代码是否符合Java1.6或者更高的规范(唯一一个与入口类不相关的步骤)

配置文件

在工程应用目录的gradle文件,经常会看到以下配置。这表明对release版本进行混淆处理。(minifyEnabled true),在工程目录下会有一个proguard-rules.pro文件,我们就可以在其中加入混淆规则。

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

keep配置-避免混淆

原则上,代码混淆后越乱越无规律越好,但有些地方我们是要避免混淆的,否则程序运行就会出错,所以我们要在需要的地方避免混淆。这里我们主要用到的配置为-keep,用这个保证一些需要的地方避免混淆。

  • 一颗星表示只是保持该包下的类名,而子包下的类名还是会被混淆
    -keep class com.tencent.qq.*
  • 两颗星表示把本包和所含子包下的类名都保持。
    -keep class com.tencent.qq.**

用以上方法保持类后,你会发现类名虽然未混淆,但里面的具体方法和变量命名还是变了

  • 既想保持类名,又想保持里面的内容不被混淆
    -keep class com.tencent.qq.* {*;}
    -keep class com.tencent.qq.** {*;}
  • 避免所有继承Activity的类被混淆
    -keep public class * extends android.app.Activity
  • 避免所有实现 android.os.Parcelable的类被混淆
    -keep class * implements android.os.Parcelable
  • 如果一个类中你不希望保持全部内容不被混淆
    • 保留一个类中的内部类不被混淆用符号$
    • 只是希望保护类下的特定内容,就可以使用<init>; //匹配所有构造器<fields>; //匹配所有域<methods>; //匹配所有方法方法
    • 还可以在<fields>或<methods>前面加上private 、public、native等来进一步指定不被混淆的内容。
例子
1.表示保持ScriptFragment内部类JavaScriptInterface中的所有public内容不被混淆
-keep class com.tencent.qq.fragment.ScriptFragment$JavaScriptInterface {
   public *;
}
2.表示One类下的所有public方法都不会被混淆
-keep class cn.hadcn.test.One {
    public <methods>;
}
3.加入参数,比如以下表示用JSONObject作为入参的构造函数不会被混淆
-keep class cn.hadcn.test.One {
   public <init>(org.json.JSONObject);
}
  • -keep是会保持类名的,如果不需要保持类名,只需要把该类下的特定方法保持不被混淆就好,那你就不能用-keep方法。需要用keepclassmembers这样就可以混淆类名的同时,只混淆某类的特定方法。

其他配置

-dontshrink 声明不压缩输入文件 (默认所有没有被引用到的类都会被删除,除了-keep相关配置指定的类。)
-dontoptimize 声明不优化输入文件。默认情况下,优化选项是开启的,并且所有的优化都是在字节码层进行的。
-dontobfuscate声明不混淆。默认情况下,混淆是开启的。除了keep配置中声明的类,其它的类或者类的成员混淆后会改成简短随机的名字。
-optimizationpasses n指定执行几次优化,默认情况下,只执行一次优化。执行多次优化可以提高优化的效果,但是,如果执行过一次优化之后没有效果,就会停止优化,剩下的设置次数不再执行。这个选项只在optimizate阶段有效

混淆注意事项

有一些是不能混淆的

  • 关于反射:需要把反射调用的类,变量,方法设置为不混淆
  • 与服务端交互时,使用GSON、fastjson等框架解析服务端数据时,所写的JSON对象类不混淆,否则无法将JSON解析成对应的对象;
  • 使用第三方开源库或者引用其他第三方的SDK包时,如果有特别要求,也需要在混淆文件中加入对应的混淆规则;
  • 有用到WebView的JS调用也需要保证写的接口方法不混淆,jni方法不可混淆。原因是这种方法需要和native方法保持一致。
  • Parcelable的子类和Creator静态成员变量不混淆,否则会产生Android.os.BadParcelableException异常;
-keep class * implements android.os.Parcelable {
    public static final android.os.Parcelable$Creator *;
}
  • 使用enum类型时需要注意避免以下两个方法混淆,因为enum类的特殊性,以下两个方法会被反射调用。
-keepclassmembers enum * {  
    public static **[] values();  
    public static ** valueOf(java.lang.String);  
}

反编译看源代码

混淆后再次生成apk时,默认会在工程目录app/build/outputs/mapping/release下生成一个mapping.txt文件,这就是混淆规则,我们可以根据这个文件把混淆后的代码反推回源本的代码。

相关文章

  • Android--ProGuard混淆

    为什么要混淆? 增大反编译难度,类和类成员会被随机命名。 混淆的四个功能: 我们通常说的proguard包括四个功...

  • js反混淆

    颜文字反混淆颜文字混淆.png 混淆2混淆2.png

  • Android Proguard混淆小记

    混淆的基本语法 常规不可混淆的代码 1.腾讯系列SDK混淆 2.GSON混淆 3.ButterkKnife混淆 4...

  • Android 混淆相关

    Android 混淆原则 混淆 ProGuard常用语法 混淆基本指令

  • Android打包那些事

    目录 一.混淆(Proguard) 混淆是打包过程中最重要的流程之一,这里所说的的混淆是包括代码混淆和资源的“混淆...

  • 2018-04-21FCN结果分析

    一、混淆矩阵confusion matrix 1,混淆矩阵 2,分类器评估方法:准确率和混淆矩阵*** 使用混淆矩...

  • Android混淆(Proguard)详解

    目录: 1、混淆的作用及好处2、混淆的原理3、混淆的具体使用--- 3.1、混淆的基本语法--- 3.2、...

  • APP常用的安全技巧

    代码中使用混淆,不要使用默认AB混淆,可以使用空白混淆 混淆配置中去除:-keepattributes Sourc...

  • Android代码混淆

    待整理。。。 参考: Android混淆从入门到精通 Android代码混淆之混淆规则 代码混淆规则配置文件:pr...

  • 不能使用混淆的情况

    不能使用混淆的情况 反射使用的元素 最好不要让一些Bean对象混淆 四大组件不能混淆 注解不能混淆 不能混淆枚举中...

网友评论

    本文标题:Android--ProGuard混淆

    本文链接:https://www.haomeiwen.com/subject/ylciixtx.html