欢迎来真孝善网,为您提供真孝善正能量书籍故事!

Android代码混淆原理及作用解析

时间:10-28 名人轶事 提交错误

其实Android代码混淆原理及作用解析的问题并不复杂,但是又很多的朋友都不太了解,因此呢,今天小编就来为大家分享Android代码混淆原理及作用解析的一些知识,希望可以帮助到大家,下面我们一起来看看这个问题的分析吧!

目录

1. 混淆编译器

如果按照混淆编译器来划分,Android代码混淆可以分为以下两个时期:

ProGuard:通用Java字节码优化工具,由比利时团队开发GuardSquare R8:ProGuard的继承者,专为Android设计,具有更好的编译性能和更好的编译产品。下图整理了随着Android Gradle Plugin版本迭代它们对应的变化。所做的更改:

Android Gradle Plugin版本迭代,令人困惑的编译器变化:

古代:ProGuard3.2.0:ProGuard(默认)、R8(引入) 3.4.0:R8(默认) 其中:DEX编译器变化:

远古时代:DX3.0.0:DX(默认)、D8(引入) 3.1.0:D8(默认) 如果需要修改Android Gradle Plugin的默认行为,可以在gradle.properties中添加配置:

启用和禁用R8# 显式启用R8

android.enableR8=true# 1. 仅针对Android 库模块禁用R8 编译器

android.enableR8.libraries=false

# 2. 禁用所有模块的R8 编译器

android.enableR8=false 启用和禁用D8# 显式启用D8

android.enableD8=true# 显式禁用D8

android.enableD8=false 此外,如果在应用程序模块的build.gradle 文件中设置useProguard=false,则将使用R8 编译器而不是ProGuard。

2. 四大功能

ProGuard和R8都提供四大功能:收缩器、优化器、混淆器和预验证器:

压缩(也称为tree shake):从应用及依赖项中删除未使用的类、方法和字段,以帮助避免64个方法的瓶颈

优化:删除更多未使用的代码,甚至通过代码分析重写代码

混淆:对重命名类/方法/字段使用无意义的短名称,增加逆向工程的难度

预校验:对于面向Java 6或Java 7 JVM的类文件,可以在编译时将预校验信息添加到类文件(StackMap和StackMapTable属性)中,以加快类加载效率。 Java 7 JVM 需要预验证,但对Android 平台没有影响

使用ProGuard时,部分编译流程如下图所示:

ProGuard 对.class 文件执行代码压缩、优化和混淆。 D8编译器执行脱糖并将.class文件转换为.dex文件。使用R8时,部分编译过程如下图所示:

R8 将脱糖(Desugar)、压缩、优化、混淆和 dex(D8 编译器)整合到一个步骤R8 对.class 文件执行代码压缩、优化和混淆。 D8编译器执行脱糖并将.class文件转换为.dex文件。 ProGuard与R8对比如下:

共同点:1.开源

2. R8支持所有现有的ProGuard规则文件

3. 两者都提供四大功能:压缩,优化,混淆,预校验不同点:1. ProGuard可以用于Java项目,而R8是专门为Android项目设计的

2. R8将脱糖、压缩、优化、混淆和dex(D8编译器)集成到一个步骤中,显着提高编译性能

关于 D8 编译器

将 .class 字节码转化为 .dex 字节码的过程被称为 DEX 编译,最初由DX编译器完成。与DX编译器相比,新的D8编译器的编译速度为更快,输出.dex文件为更小,但可以保持相同甚至更出色的应用程序运行时性能

3. 使用示例

无论使用 R8 还是 ProGuard,默认不会启用压缩、优化和混淆功能。这样的设计主要基于两个考虑:一方面是因为这些编译时任务会增加编译时间,另一方面是因为如果混淆保留规则没有完全定义,运行时会出现错误也可介绍。因此,最好使用只在应用的测试版本和发布版本中启用这些编译时任务,参考使用示例:

//构建.gradle

.

安卓{

构建类型{

//测试版本

预览{

//启用代码压缩、优化和混淆(由R8 或ProGuard 执行)

minifyEnabled true

//启用资源压缩(由Android Gradle 插件执行)

收缩资源true

//指定混淆保留规则文件

proguardFiles getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro"

}

//发布版本

发布{

minifyEnabled true

收缩资源true

proguardFiles getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro"

}

//开发版本

调试{

minifyEnabled false

}

}

.

}minifyEnabled:(默认)启用代码压缩、优化、混淆和预验证shrinkResources:启用资源压缩proguardFiles、proguardFile:指定ProGuard规则文件,前者可以指定多个参数。下面两段配置效果相同。 //方法一:

proguardFiles getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro"

//方法2:

proguardFile getDefaultProguardFile("proguard-android-optimize.txt")

前面提到的proguardFile "proguard-rules.pro":无论使用R8还是ProGuard,压缩、优化和混淆函数都是默认关闭。可以通过以下配置进行灵活控制:

整体关闭minifyEnabled 假

//这行没有任何作用

proguardFiles getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro"关闭压缩-dontshrink关闭优化(R8无效) -dontoptimize 注意:R8 不能关闭优化,也不允许修改优化的行为,实际上R8会忽略修改默认优化行为规则。例如,设置-optimizations 和-optimizationpasses 后,您将收到编译时警告:

AGPBI: {"kind":"警告","text":"忽略选项: -优化","sources":[{"file":"省略."}],"tool":"D8"}

AGPBI: {"kind":"warning","text":"忽略option: -optimizationpasses","sources":"省略."}],"tool":"D8"}关闭混淆(开发版推荐关闭混淆) -dontobfuscate关闭预校验(Android平台无效,建议关闭) -dontpreverify

4. ProGuard 规则文件

R8 延续了 ProGuard 使用规则文件修改默认行为的做法。很多情况下,规则文件也叫混淆保留规则文件,因为绝大多数规则该文件中定义的规则都是与代码混淆相关的。实际上,文件中还可以定义代码压缩、优化和预验证规则,因此更严格地称为ProGuard 规则文件。

在上一节中,我们提到使用proguardFiles 和proguardFile 来指定ProGuard 规则文件。对于任何项目,其ProGuard 规则文件都来自以下三个来源:

1、Android Gradle 插件编译时,Android Gradle插件会生成proguard-android-optimize.txt、proguard-android.txt,位于/build/intermediates/proguard-files/。除了注释之外,这两个文件唯一的区别是前者启用了代码压缩,而后者关闭了代码压缩,如下所示:

# proguard-android-optimize.txt

-优化!代码/简化/算术,代码/简化/转换,字段/*,类/合并/*

-优化5次

-允许访问修改

相同部分省略.# proguard-android.txt

-不优化

相同部分省略……混淆规则的相同部分中,以下部分比较特殊:

-keep 类android.support.annotation.Keep

-keep 类androidx.annotation.Keep

//保留@Keep注解的类并保留.TODO

-keep @android.support.annotation.Keep 类* {*;}

-keep @androidx.annotation.Keep 类* {*;}

//保留@Keep修饰的方法

-keepclasseswithmembers 类* {

@android.support.annotation.Keep;

}

-keepclasseswithmembers 类* {

@androidx.annotation.Keep;

}

//保留@Keep修改的字段

-keepclasseswithmembers 类* {

@android.support.annotation.Keep;

}

-keepclasseswithmembers 类* {

@androidx.annotation.Keep;

}

//保留@Keep修改的构造函数

-keepclasseswithmembers 类* {

@android.support.annotation.Keep(.);

}

-keepclasseswithmembers 类* {

@androidx.annotation.Keep(.);

它指定与@Keep注释相关的所有保留规则。这就解释了为什么用@Keep修改的成员不会混淆了吧?

2、Android Asset Package Tool 2 (AAPT2)在编译时,AAPT2 根据清单中对类、布局和其他应用程序资源的引用生成aapt_rules.txt,位于/build/intermediates/proguard-rules/debug/aapt_rules.txt。

例如,AAPT2 为清单中注册的每个组件添加保留规则:

引用于[项目路径]/app/build/intermediates/merged_manifests/release/AndroidManifest.xml:19

-保持类com.have.a.good.time.MainActivity {(); }

略.这里,AAPT2生成了MainActivity的保留规则,同时也指出了参考来源:AndroidManifest.xml:19。这是因为在启动一个Activity的过程中,需要使用反射来实例化每个具体的Activity。有兴趣的话可以看看ActivityThread#performLaunchActivity()-Instrumentation#newActivity()

3、Module创建新模块时,IDE 在模块的根目录中创建一个proguard-rules.pro 文件。当然,除了这个自动生成的文件之外,还可以根据需要创建额外的规则文件。例如,以下配置添加一个额外的规则文件用于发布:

.

安卓{

.

构建类型{

发布{

minifyEnabled true

proguardFiles getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro"

}

}

产品风味{

开发{

.

}

发布{

proguardFile "release-rules.pro"

}

}

}

.总结一下:

规则文件来源说明Android Gradle 插件编译时,AAPT2 由Android Gradle 插件生成。编译时,AAPT2 根据对应用程序清单中的类、布局和其他应用程序资源的引用生成保留规则。模块是由IDE 在创建新模块时创建的。或者如果minifyEnabled 属性设置为true(ProGuard 或 R8 会将来自上面列出的所有可用来源的规则组合在一起),则根据需要另外创建。为了查看完整的规则文件,您可以在proguard-rules.pro 中添加以下配置,以输出编译项目时应用的所有规则的完整报告:

-printconfiguration build/intermediates/proguard-files/full-config.txt

5. 组件化混淆

在组件化项目中,需要关注application Module和Library Module的行为差异以及组件化的资源聚合规则,总结如下以下要点:

编译时,各层Library Module会依次编译。最底层的Base Module会先被编译成aar文件。那么上层编译时,依赖于Module输出的aar文件/jar文件就会相应解压到模块的build中。当文件夹中的App Module层汇总完所有aar文件后,编译操作才真正开始。编译后的Module会覆盖之前编译的Module中的同名资源。组件化资源汇总Lib Module汇总为App Module,并使用更高版本。 Android Gradle 插件不会将聚合资源放置在exploded-aar 文件夹中。即便如此,将Lib Module 资源聚合到App Module 的规则是相同的。

我们用一个简单的例子来测试不同配置下的混淆结果:

配置一配置二配置三配置四App Module 开启混淆XXBase Module 开启混淆XX 示例程序:App Module 依赖于Base Module。将构建好的apk包拖到Android Studio面板中,分析Base类混淆结果。例如配置一的结果:

使用配置1时,Base类不进行混淆,所有测试结果如下:

配置一配置二配置三配置四App Module 开启混淆XXBase Module 开启混淆XX (结果) Base 类是否被混淆XX 可见,混淆开启由 App Module 决定, 与Lib Module 无关

现在我们分别在Lib Module和App Module的proguard-rules.pro中添加Base类的混淆保留规则,并在build.gradle中添加配置文件来测试是否可以保留Base类:

-keep class com.rui.base.Base测试结果如下:

配置位置Lib ModuleApp Module(结果)基类保留X可见:(默认情况)混淆规则以 App Module 中的混淆规则文件为准

这里介绍两种主流的组件化混淆方案:

在 App Module 中设置混淆规则该解决方案将所有混淆规则放置在应用程序模块的proguard-rules.pro 中。这是最简单、最直观的。缺点是移除Lib Module时,需要从App Module中移除相应的混淆规则。冗余的混淆规则虽然不会导致编译错误或运行错误,但仍然会影响编译效率。

很多第三方SDK都采用了这种组件化的混淆方案。在App Module中添加依赖时,还需要在proguard-rules.pro中添加独占混淆规则,以保证release版本正常运行。

在 App Module 中设置公共混淆规则,在 Lib Module 中设置专属混淆规则该方案为Lib Module的proguard-rules.pro设置了专属的混淆规则。但根据之前的测试,Lib Module中设置的混淆规则并没有生效。为了使规则生效,需要在Lib Module的build.gradle中添加以下配置:

.

安卓{

默认配置{

ConsumerProguardFiles "consumer-rules.pro"

}

}consumer-rules.pro 文件:

-keep class com.rui.base.Base 测试结果显示Base类已经被保留。这种使用consumerProguardFiles的方式有以下特点:

ConsumerProguardFiles 仅对Lib Module 有效,对App Module 无效。 ConsumerProguardFiles会将混淆规则输出为proguard.txt文件,并打包成aar文件。 App Module会使用aar文件中的proguard.txt来总结最终的混淆规则。这可以通过前面提到的-printconfiguration证明

6. 总结

ProGuard是一个Java字节码优化工具,而R8是专门为Android设计的,其编译性能和编译产品更好;

ProGuard和R8都提供了四大功能:压缩、优化、混淆和预验证。 ProGuard主要对.class文件进行代码压缩、优化和混淆,然后D8编译器进行脱糖,转换为.dex文件。 R8将压缩、优化、混淆、脱糖、dex合二为一;

ProGuard规则文件来自三个来源:Android Gradle插件、AAPT2和Module;

默认情况下,混淆规则基于应用模块中的混淆规则文件。使用Consumer-rules.pro 文件设置特定于Lib 模块的混淆规则。

用户评论

←极§速

我听说代码混淆可以保护程序不被破解,这是真的吗?

    有11位网友表示赞同!

巴黎盛开的樱花

我想知道混淆后的代码能不能阅读,对调试有什么影响吗?

    有7位网友表示赞同!

执念,爱

平时写程序的时候会用到代码混淆吗?

    有19位网友表示赞同!

疲倦了

Android 开发者都喜欢用代码混淆吗?

    有13位网友表示赞同!

在哪跌倒こ就在哪躺下

看标题感觉代码混淆应该是个很重要的技术啊!

    有15位网友表示赞同!

惯例

学习代码混淆需要掌握哪些知识?推荐点学习资源吧!

    有18位网友表示赞同!

*巴黎铁塔

我想知道不同类型的 Android 应用程序,它们的代码混淆方法有什么区别吗?

    有18位网友表示赞同!

Edinburgh°南空

除了保护程序,代码混淆还有其他用途吗?

    有19位网友表示赞同!

あ浅浅の嘚僾

请问代码混淆会影响程序的性能吗?

    有11位网友表示赞同!

tina

我现在是在学 Android 开发,听讲要学习代码混淆,我应该从哪里开始学习呢?

    有13位网友表示赞同!

汐颜兮梦ヘ

感觉现在有很多开发工具都支持代码混淆,是吗?

    有20位网友表示赞同!

◆乱世梦红颜

有没有什么好的代码混淆平台推荐吗?

    有20位网友表示赞同!

各自安好ぃ

代码混淆对程序安全性有哪些方面的提升?

    有11位网友表示赞同!

心脏偷懒

我想知道代码混淆的历史,和它发展到现在经历过哪些变化呢?

    有18位网友表示赞同!

玩味

学习代码混淆会不会让我在 Android 开发的道路上更上一层楼?

    有15位网友表示赞同!

断桥残雪

代码混淆对于个人开发项目有什么意义吗?

    有7位网友表示赞同!

素颜倾城

我想知道在使用代码混淆的时候,需要注意哪些问题?

    有11位网友表示赞同!

仰望幸福

代码混淆是不是一个很复杂的技术?

    有13位网友表示赞同!

来自火星球的我

学习代码混淆需要多久的时间才能掌握呢?

    有19位网友表示赞同!

陌潇潇

如果想学习更深入的代码混淆知识,去哪找资料合适?

    有12位网友表示赞同!

【Android代码混淆原理及作用解析】相关文章:

1.蛤蟆讨媳妇【哈尼族民间故事】

2.米颠拜石

3.王羲之临池学书

4.清代敢于创新的“浓墨宰相”——刘墉

5.“巧取豪夺”的由来--米芾逸事

6.荒唐洁癖 惜砚如身(米芾逸事)

7.拜石为兄--米芾逸事

8.郑板桥轶事十则

9.王献之被公主抢亲后的悲惨人生

10.史上真实张三丰:在棺材中竟神奇复活