Android 代码混淆

代码混淆的作用

代码混淆主要作用是使代码在编译过程中让原本方便阅读的代码进行一定规则的混淆和对代码进行一定量的优化。

代码混淆的意义

代码混淆的意义在于将原本开发时方便阅读的代码在编译过后,让代码变成那一阅读分析的代码,这样就使得在本人反向编译后在去阅读分析代码变得困难,增加APP的安全性,也可以使用代码混淆来规避掉一些开发过程中没有使用过的类等信息不打入到包中减小包体积等。

对比代码混淆与不混淆的区别,首先在项目的app/build/outputs/apk目录下可以找到构建后的APK文件,然后在AS中点击APK直接可以看见APK的结构,下面是开启和未开混淆的结构图:

Android 代码混淆_第1张图片
未开启混淆APK结构.png

在未开启混淆下代码的结构可以非常清晰的观看(根本不需要分析),包名、类名、方法名全部直接暴露,直接可以阅读APK的结构。

Android 代码混淆_第2张图片
开启混淆APK结构.png

在开启混淆下代码的结构变得复杂(包名、类名、方法名等都被混淆),混淆后APK的结构对比未开启混淆是的结构来看,名称和结构都会发生差异,所以在使用混淆后会加大对代码的可阅读和可分析性,所以开启混淆可以增加APP的安全性。

同时代码混淆还有预校验功能

开启混淆后代码中从未使用过的累不会打入APK包中:

Android 代码混淆_第3张图片
混淆代码优化效果.png

项目结构如下:

Android 代码混淆_第4张图片
项目结构.png

Android代码混淆使用ProGuard技术

Android代码混淆使用ProGuard工具,ProGuard是代码优化和混淆工具,能够提供对Java类文件的压缩、优化、混淆,和预校验。压缩的步骤是检测并移除未使用的类、字段、方法和属性。优化的步骤是分析和优化方法的字节码。混淆的步骤是使用短的毫无意义的名称重命名剩余的类、字段和方法。压缩、优化、混淆使得代码更小,更高效。

Android代码混淆

Android开启代码混淆

Android代码开启混淆首先要在app的build文件中配置开启混淆,创建项目时默认是只设置了正式包且是false不开启混淆,一般来说开发混淆只需要在开发完成打包阶段使用,没有必要在日常开发过程中进行混淆,因为在代码开启混淆后很多方便阅读的代码都被混淆,会增加日常开发调试难度,所以混淆一般只在正式打包时开启就好。

默认开启混淆是false.png

在开启混淆后Android会自动创建一个名为proguard-android-optimize的文件,在项目的gradle文件中的开启混淆代码中加入path=${getDefaultProguardFile('proguard-android-optimize.txt')},在编译项目时会打印文件的路径,打印的文件目录为项目下的app\build\intermediates\proguard-files,文件中就是Android自动生成的混淆文件,所以开启混淆后Android会自动存在一个混淆文件和一份项目中的混淆文件,两份文件共同将项目混淆,开发中主要注重项目中的混淆文件(proguard-rules.pro)即可。

Android 代码混淆_第5张图片
gralde文件配置.png

使用混淆需要掌握一些基础的语法,下面会继续介绍。

配置proguard-rules.pro文件

配置proguard-rules.pro文件,也就是说编写混淆规则,常用的混淆配置以及要注意的点下面说明。

-keep

保护类或者类中的函数方法等。

#(保护了类名)
-keep class com.leavy.test.user

#保护了 public static void的没有参数的函数)
-keep class com.leavy.test.user{
  public static void *();
  native ;
}

#(保护所有)
-keep class com.leavy.test.user{
  *;
}

-keepclassmembers

指定类成员或者函数不被混淆,但是keepclassmembers不会管类名只会针对类中信息。

#(没有指定类中成员,所以都被混淆了)
-keepclassmembers class com.leavy.test.user
#指定成员中所有View对象不混淆
-keepclassmembers class com.leavy.test.user{
  View * ;
}

-keepclasseswithmembers

指定类和类成员不被混淆,前提是指定的类成员存在。

#(保护类名,但是没指定成员,所以函数名被混淆)
-keepclasseswithmembers class com.leavy.test.user
#指定成员中native方法不参与混淆
-keepclasseswithmembers class com.leavy.test.user{
        native ;
    }

补充一下基础些的混淆

#不做优化
-dontoptimize
#忽略大小写交替的写法(UserMethod—>usermethod)
-dontusemixedcaseclassnames
#不跳过非公共的类
-dontskipnonpubliclibraryclasses

更多的混淆规则可以看proguard官网

mapping

开启混淆后在app/build/outputs/mapping/debug目录下会有mapping.txt,mapping.txt中记录了混淆代码记录(记录了源代码对应的混淆文件),可以根据mapping解析混淆后的错误日志来完成对错误日志的分析。mapping具体实例如下图所示:

Android 代码混淆_第6张图片
mapping内容.png

注意

代码混淆后会对代码中的类名、成员名、方法名做混淆处理,也就是说在使用有用到反射或者JNI时一定要保证不被混淆,比如注解使用时,通过APT来反射到成员名、方法名等来实现相应操作,有用到反射或JNI的地方一定要保证不被混淆。

混淆后代码错误的查找及定位

代码经过混淆后在程序发生异常时,给出的错误日志也会随着代码混淆相应的被混淆掉,所以在混淆后代码发生问题是需要特别处理下来定位错误信息。

Android 代码混淆_第7张图片
混淆后错误日志.png

首先从上图可以看出,代码混淆后准确的错误代码位置在日志中打印结果(at b.a.a.a.a(:16))并不清晰(这里只执行非常简单的1/0错误代码,所以感觉错误信息还是很好猜,但是复杂代码就不容易看出问题根源了),所以这是要分析定位错误就需要特殊处理。

首先在混淆文件中加入配置信息

#保留资源文件和行号信息(可以在错误日志中显示)
 -keepattributes SourceFile,LineNumberTable

执行retrace.bat -verbose mapping文件 bug文件

在SDK安装的文件夹下面进到sdk/tools/groguard/bin/目录下,然后新建个文本文件(.txt就可以),然后把在as中的错误日志赋值到新建的文本文件中(这里新建文件叫bug.txt),然后把在app/build/outputs/mapping/debug中的mapping.txt文件拷贝到sdk/tools/groguard/bin/目录下,在文件夹搜索框中输入cmd进入dos界面中然后执行:

retrace.bat  -verbose mapping文件  bug文件

然后在dos界面内就会出现如下所示:

Android 代码混淆_第8张图片
解析错误日志信息.png

从解析错误日志信息中可以看到之前混淆过后的错误信息,就被解析成为未被混淆的代码信息和行号,就可以定位到指定的错误信息。

你可能感兴趣的:(Android 代码混淆)