许久没有做混淆相关的工作, 以前存储的知识遗忘得差不多了。停留在很多人的记忆里面混淆还不简单吗?不就是 -keep。这样说也没错,但是要把混淆做得精细精准还是不简单的,今天就一文带你全而透。

混淆的作用

我们为什么要做这个工作,有什么好处?

  • 代码缩减(摇树优化):使用静态代码分析来查google找和删除Git无法访问的代码和未实例化的类型,对规避 64k 引用限制非常有用;

  • 资源缩减:移除不使用的资源,包括应用库依赖项中不使用宫颈癌的资源。

  • 混淆代码:缩短类和成员的名称,从而减小 DEX 文件的大小,增加反编译成本。

  • 优化代码:检查并重写代码,选择性内联,移除未使用的参数和类合工龄越长退休金越多吗并来优化代码大小。

  • 减少调试信息 : 规范化调试信息并压缩行号信息。

混淆的情况

混淆的情况是指你接手混淆时androidstudio彻底卸载干净候的状况,大致分两种。

  • 一种是Google项目刚刚立项,这个时候你跟进混淆,随着你的代码量增多,和引入的第三方库&Sgiticomfort是什么轮胎DK 增多逐渐增加gitlab混淆规则,这是一工龄差一年工资差多少个应该有的良性的状态,做到精准混淆也容易。
  • 第二种Google情况是以前的维护者完全没有混淆,有海量的代码和第三方库,里面的反射注解和各种存在混淆风险的问题存在,这google服务框架样想做到精准混淆并不容易

上文多次提到精准混淆,我理解的精准混淆是最细粒度的白名单,而不是如下反例:

-keep public class * extends java.lang.Object{*;}

混淆基础知识储备

开启和关闭混淆

开启混淆比较简单,一般来讲为了方便开发调试只混淆 release 版gradle和maven本:

buildTypes {
    release {
        shrinkResources true //开启资源压缩
        minifyEnabled true //开启混淆
        zipAlignEnabled true //k对齐
        proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
    }
}

minifyEnabled 和 proguardFiles 是必选项其他为可选,关闭混淆的话就比较容gradle菜鸟教程易了直接 minifyEnabledandroidstudio线性布局 修饰为 false 即可。

proguard-工龄差一年工资差多少android.txt 和 proguard-android-optimize.txt

我们经常在代码里面看到这样的语句:

由浅入深 Android 混淆实战
proguard-rules.pro 我们知道就giti轮胎在 app/ 目录下,但是这个 getDefaultProguardFile 是什么?在哪里?有什么用?

getDefaultAndroid+StudioPrandroidstudio新建项目oguagitlabrdFigoogle翻译le 是 Android SDK 为我们提供的一些googleplay安卓版下载 Android 内置的混淆规则,一般来将这些是通用的,你要做到精通混淆必选知道它的位置以及他里面包含的内容和含义。

位置:android/sdk/tools/proguard/

由浅入深 Android 混淆实战

# This is a configuration file for ProGuard.
# http://proguard.sourceforge.net/index.html#manual/usage.html
#
# This file is no longer maintained and is not used by new (2.2+) versions of the
# Android plugin for Gradle. Instead, the Android plugin for Gradle generates the
# default rules at build time and stores them in the build directory.
-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 #不预校验
# Note that if you want to enable optimization, you cannot just
# include optimization flags in your own project configuration file;
# instead you will need to point to the
# "proguard-android-optimize.txt" file instead of this one from your
# project.properties file.
-keepattributes *Annotation*
-keep public class com.google.vending.licensing.ILicensingService
-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 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*();
}
# We want to keep methods in Activity that could be used in the XML attribute onClick
-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);
}
-keepclassmembers class * implements android.os.Parcelable {
  public static final android.os.Parcelable$Creator 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.**
# Understand the @Keep support annotation.
-keep class android.support.annotation.Keep
-keep @android.support.annotation.Keep class * {*;}
-keepclasseswithmembers class * {
    @android.support.annotation.Keep <methods>;
}
-keepclasseswithmembers class * {
    @android.support.annotation.Keep <fields>;
}
-keepclasseswithmembers class * {
    @android.support.annotation.Keep <init>(...);
}

mapping 文件

由浅入深 Android 混淆实战

Mapping 非常重要,在 app/buigoogleplayld/mapping 中生成的枸杞 mappi工商银行ng 文件是我们分析混淆是否生效,混淆后的崩溃寻因的重要依据,通过这个文件的映射我们能够在一堆杂乱无章的 a、 b、 c 中回溯到原始代码。例:

由浅入深 Android 混淆实战

工具集

工欲善其事必先利其器google中国,两款对混淆有着很大帮助的工具介绍

Anandroidstudio新建项目drgoogleplayoid Studio APK Analysis

AS自带简单好用,对比包体积的占比分析也是相当不错,并且随着 AS 的迭代有着官方的支持相信功能会越来越强大,我们只需要简单的将 apk 包拖拽到 AS 中就会自动触发宫颈癌 AS 的 apk 解析功能:

由浅入深 Android 混淆实战

Jagradle项目dx

Jadx 的强大之处在于相较于 AS 自带的分析器,它还能直接查看源代码,AS 只能看到类工龄越长退休金越多吗名和方法名,简直是逆向神器。

由浅入深 Android 混淆实战

更多介绍请移步 github.com/skylot/jadx

混淆实战

通过 demo 样例的混淆实战深刻理解每git教程个混淆规则的含义,我们要做到的不是仅仅开启 minifyEnabled 然后应用通过,而是需要知到得更细更透彻,理解每个混淆语句规则的作用范围。

先定义一下基准包以及gitigiti包,还有类、内部类、接口、注解、方法、成员,然后我们分部对其进行混淆和 -keep 保持,记住下图的 proguard 开始的包类目录关系,我们后面一直要使用它。

由浅入深 Android 混淆实战

后续的文章都giti轮胎会以这几个类做样例,所以我们把它罗列出来再加深一androidstudio新建项目下印象:

  • Ugoogle商店ser.java
  • Animal.java
  • MethodLevel.java
  • Student.java
  • Teacher.java
  • Company.java
  • IBehaviourgitlab.java

部分样例类:

public class Teacher extends User implements IBehaviour {
  @Override
  public void doSomething() {
    System.out.println("teaching ...");
  }
  @MethodLevel(value = 1)
  private void waking(){
  }
}

混淆中代码调用关系

先开启混淆,不添加任何规则。我们通过 jagithubdx 看下混淆情况

由浅入深 Android 混淆实战
proguard 包和类一个都找不到应该都是被混淆了,进一步印证一下androidstudio模拟器运行不出来我们的想法,我们去 mapping 文件里面找下映射关系,结果出乎意料,我没有在 mapping 中找到映射关系,只在 usage.txt 中找到了对应的全路径名

由浅入深 Android 混淆实战

是不是我们的类申明了没有引用导致的呢?我们去 activity 做一下调用

由浅入深 Android 混淆实战

果然和我们的预gradle和maven想的一样,如果类创建了没有使用,gradle菜鸟教程mapping 不会生成映射关系,甚至可能在打龚俊包的过程中给优化掉,再看加上工资超过5000怎么扣税调用关系后我们查询 mappgradle和mavening 文件:

由浅入深 Android 混淆实战

由浅入深 Android 混淆实战

上图可以得知,我们的 proggoogle浏览器uard 包和下面的所有内容全部都混淆了。

keep 探寻

网络上的大部分文章都千篇一律,简单的给出了一个 Keep 语句,实际用的时候都是 copy 对其作用范围不是很明确,接下来我们就一个一个来探寻

keep *

-keep class com.zxmdly.proguard.*

我们先googleplay安卓版下载加上这句看看打包后的Go变化

对比之前的结果,我们看到的是 proguard 的包和google翻译下面的类名被保留下来了,注意仅仅是gitee包合类google浏览器名被保留,类中的字段和成员是没有找到的,这是为什么呢?难道是字段没有被使用

由浅入深 Android 混淆实战

由浅入深 Android 混淆实战

我们去印证下

由浅入深 Android 混淆实战

由浅入深 Android 混淆实战

好了,到现在我们已经能够透彻的知道了 -keep * 的作用,总结作用范围:

  • 能够保持该包和该包下的类、和静态内部类的类名保持,对字段和方法不额外起作用,子包不起作用,字段或者方法没有被调用则直接忽googleplay安卓版下载略。

keep **

-keep class com.zxmdly.proguard.**

由浅入深 Android 混淆实战

通过查看上图和上面 keep * 的经验,我们可以得出结论:

  • keep ** 能够保持该包和其子包的子类的所有类gradle依赖冲突强制指定名(含注解、枚举)不被混淆,但是方法和字段不在其作用范围,字段或者方法没有被调用则直接忽略。

值得注意的是, keep ** 对于 keep * 是包含关系,声明了 keep ** 混淆规则就无需再声明 keep * 了。

keep ** {*;}

-keep class com.zxmdly.proguard.* {}

由浅入深 Android 混淆实战
有了之前的经验,我们可以得出结论公积金

  • kegradle安装与配置ep ** {*;} 的作用范围特别大,能够保持该包及其子包、子类和其字段方法都不被混淆,相对工商银行来讲我们需要慎用这样的语句,因为可能导致混淆不够精准。

单个类名保持

-keep class com.zxmdly.proguard.Company

由浅入深 Android 混淆实战

  • 仅保持类名,字段和成员被混淆

保持龚俊方法

-keep class com.zxmdly.proguard.Company{
  <methods>;
}

由浅入深 Android 混淆实战

保持字段

-keep class com.zxmdly.proguard.Company{
  <fields>;
}

由浅入深 Android 混淆实战

实现关系保公积金

-keep public class * implements com.zxmdly.proguard.IBehaviour

由浅入深 Android 混淆实战

-keep public class * implements com.zxmdly.proguard.IBehaviour {*;}

由浅入深 Android 混淆实战

继承关系保持

-keep public class * extends com.zxmdly.proguard.base.User {*;}

由浅入深 Android 混淆实战

指定保持具体方法或gradle教程者字段

-keep class com.zxmdly.proguard.Company{
      public java.lang.String address;
      public void printlnAddress();
}

由浅入深 Android 混淆实战

Tips 小技巧

在 gralde 中,我们可以通过下面配置将我们的混公司让员工下班发手机电量截图淆规则分门别类,指定giti多个混淆配置文件。

由浅入深 Android 混淆实战

例如给第三方的 SDK 专门放到一个 Third 混淆配置文件,使用了这个小技巧加上注释,我们的混淆规则是不是更清晰了呢

结语

通过本文由浅入深的带大家进行混淆实战,相信 99% 的精准混淆工作已经难不倒你,当然混淆还有更深入和更细节的用法,篇幅关系我们下次再探。