本文来自于腾讯Bugly公众号(weixinBugly),未经作者同意,请勿转载,原文地址:https://mp.weixin.qq.com/s/WmJyiA3fDNriw5qXuoA9MA
作者:lilycai
本文主要讲述了代码混淆和资源混淆的原理,Studio默认的混淆方案,混淆的参数,以及如何对Apk进行代码混淆(自定义混淆文件)和资源混淆(结合微信混淆和美团混淆两种方案),避免Apk被逆向。
为什么要混淆
我们的apk在打包发布之前,都要进行混淆处理来避免源代码和资源文件被小白用户通过反编译拿到。未混淆代码的反编译操作非常简单,网上有很多教程, 也可以通过使用Android Studio自带的apk分析工具(Build—Analyze APK)直接看到未混淆Apk的源代码和原始的资源文件。对比图如下,从图中可以看到未混淆apk所有的代码都一目了然,随便改改资源和代码,就能变成一个新的apk。为了避免我们的劳动成果被窃取,也避免出现安全漏洞和隐患,此篇文章从混淆的原理到代码和资源文件的混淆实践做一下阐述。
混淆前:
混淆后:
混淆的原理
Java 是一种跨平台、解释型语言,Java 源代码编译成的class文件中有大量包含语义的变量名、方法名的信息,很容易被反编译为Java 源代码。为了防止这种现象,我们可以对Java字节码进行混淆。混淆不仅能将代码中的类名、字段、方法名变为无意义的名称,保护代码,也由于移除无用的类、方法,并使用简短名称对类、字段、方法进行重命名缩小了程序的size。
ProGuard由shrink、optimize、obfuscate和preverify四个步骤组成,每个步骤都是可选的,需要哪些步骤都可以在脚本中配置。 参见ProGuard官方介绍。
- 压缩(Shrink): 侦测并移除代码中无用的类、字段、方法、和特性(Attribute)。
- 优化(Optimize): 分析和优化字节码。
- 混淆(Obfuscate): 使用a、b、c、d这样简短而无意义的名称,对类、字段和方法进行重命名。
上面三个步骤使代码size更小,更高效,也更难被逆向工程。
- 预检(Preveirfy): 在java平台上对处理后的代码进行预检。
混淆流程图如下:
Proguard读入input jars(or wars,zips or directories),经过四个步骤生成处理之后的jars(or wars,ears,zips or directories),Optimization步骤可选择多次进行。
为了确定哪些代码应该被保留,哪些代码应该被移除或混淆,需要确定一个或多个Entry Point。Entry Point经常是带有main methods,applets,midlets的classes,它们在混淆过程中会被保留。我们来看一下Proguard的几个步骤如何处理Entry Points。
1. 在压缩阶段,Proguard从上述Entry Points开始遍历搜索哪些类和类成员被使用。其他没有被使用的类和类成员会移除。
2. 在优化阶段,Proguard进一步设置非Entry Point的类和方法为private、static和final来进行优化,不使用的参数会被移除,某些方法会被标记被内联。
3. 在混淆阶段,Proguard重命名非Entry Points的类和类成员。
4. 预检阶段是唯一没有触及Entry Points的阶段。
Android Studio 默认的混淆方案及字段解读
开启混淆
参见google官方文档压缩代码和资源
要通过Proguard启动代码压缩,在build.gradle文件内相应的构建类型中添加minifyEnabled true。
android {
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'),
'proguard-rules.pro'
}
}
...
}
除了 minifyEnabled 属性外,还有用于定义 ProGuard 规则的 proguardFiles 属性:
proguardFiles getDefaultProguardFile('proguard-android.txt'),
'proguard-rules.pro'
google的官方文档介绍:
getDefaultProguardFile(‘proguard-android.txt’) 方法可从 Android SDK tools/proguard/ 文件夹获取默认的 ProGuard 设置。要想做进一步的代码压缩,请尝试使用位于同一位置的 proguard-android-optimize.txt 文件。它包括相同的 ProGuard 规则,但还包括其他在字节码一级(方法内和方法间)执行分析的优化,以进一步减小 APK 大小和帮助提高其运行速度。
proguard-rules.pro 文件用于添加自定义 ProGuard 规则。默认情况下,该文件位于模块根目录(build.gradle 文件旁),内容为空。
通过试验,gradle 2.2之后,defaultProguardFile没有使用sdk目录下的proguard-android.txt,而是使用了gradle自带的proguard-android.txt,不同的gradle版本带有不同的默认混淆文件,在项目根目录的build/intermediates/proguard-files/proguard-android.txt-2.3.3(笔者用的gradle版本)即为gradle自带的混淆文件。在proguard-and