关于Android混淆的开源框架Mess的学习与分析

关于Android混淆知识点的两篇好文章:写给 Android 开发者的混淆使用手册, Android混淆从入门到精通

参考的资料:饿了么全面混淆插件 Messandroid 防破解, 代码混淆,代码保护

Mess是用来解决什么问题的

首先,在之前学过的关于Android混淆知识中我们知道,Android默认是不会混淆四大组件和自定义View的,或者换一个说法,出现在 xml 里的相关 Java 类默认是不会被混淆的。

你不禁会问,为什么Android默认要这么做?

答:因为 Proguard 原本是为 Java 打造的,它无法搜索到我们 AndroidManifest、布局等文件中引用了哪些 Java 类,因此如果 Java 代码变了而 XML 文件中的引用没变,就会造成反射失败,所以android默认这些被 XML 使用到的类需要 keep 住。

关于这一点,我们可以简单的验证一下:

打开build/intermediates/proguard-files/路径下的proguard-android.txt文件,这里面帮我们声明了许多混淆规则内容,包括:keep 所有继承自 View 的类,keep 所有继承自 Activity 的类,keep 所有 JavascriptInterface、native 方法声明,以及 keep 一些注解了 @Keep 的内容,例如:

好,说了这么多,Mess这个插件的目的就是在混淆的时候把这些顽固分子一起收拾了,让你的应用混淆的更彻底,更安全!

Mess的主要构成

Mess的项目地址:https://github.com/eleme/Mess

我把它下载到了本地,其主要一共就四个groovy文件:

                                        

MessExtension:用来存放需要被忽略的Proguard,比如那些本身也配置了相关混淆配置的依赖库,Mess会对这些依赖库                              进行混淆

Util:混淆时的工具类,这里面提供了一些方法如下

         renameProguardTxt(...):对Proguard文件进行重命名,然后存放到指定的路径

         hideProguardTxt(...):备份要被删除的proguard.txt 文件,用于最后的恢复

         recoverProguardTxt(...):恢复proguard.txt 文件

         sortMapping(...):根据传进来的Map的key的长短来排序

RewriteComponentTask:根据映射文件 mapping.txt 找到原先的类名,然后替换AndroidManifest,layout,menu和

                                          values 这些xml文件中的JAVA类,完成对其的混淆

MessPlugin:对transformClassesAndResourcesWithProguardForRelease这项Task的流程的调度,包括先后顺序等

Mess执行的具体步骤和流程

  1. 清空aapt_rules.txt 中的内容

aapt_rules.txt中记录着所有在 xml 里声明的 java 类(四大组件和自定义View等),并将它们都 keep 住,这个文件最终会被添加到 app 的混淆配置中,所以既然Mess想实现更全面的混淆,就必须删除它。在build/intermediates/proguard-rules/release下,你可以找到aapt_rules.txt,截了一部分代码如下:

既然知道要删掉它,首先需要找到aapt_rules.txt是从哪里生成的,系统的ProcessAndroidResources类中有这样一段代码:

该方法的名字就是获得AndroidResources进程中的Proguard输出文件,继续追踪我们发现,该方法所在的是一个名为VariantScope的接口,在它的实现类VariantScopeImpl中我终于看到了下面的这段代码:

到这里aapt_rules.txt的出生点已经找到,拿到路径后,在MessPlugin中是这样删除它的:

   2.如果需要混淆依赖库,则删除依赖库中的 proguard.txt 文件

Mess中采用的方式简单粗暴,直接将 proguard.txt 文件名最后加上 ~  ,这在linux中表示备份,以便之后文件的恢复。在Util中提供了如下方法:

对proguard.txt的备份和恢复的逻辑都在这里,然后在MessPlugin中先后调用:

  3.hook transformClassesAndResourcesWithProguard 获取混淆后的类映射关系 Map

注:hook翻译过来是钩子的意思,它能够将自身的代码「融入」被勾住(Hook)的程序的进程中,成为目标进程的一个部分

在一开始没有混淆之前:xml中的java类←→class文件

经过前面的步骤之后:xml中的java类←→混淆过的class文件

所以现在需要做的就是找到混淆过的class在xml中的原有java类名,然后把它给替换掉,也就是把它给混淆了。

这个映射关系要从/build/outputs/mapping/release/路径下的mapping.txt中找,它里面存放着混淆前后类、方法、类成员等的对照表,如下:

这一个个的箭头就是代表着一一对应的关系:混淆前和混淆后。Mess在RewriteComponentTask中用Map解析并存储了这些映射关系,相关代码如下:

在这段代码下边有一段注释:

“如果我们不对这个map进行长短的排序,就会出现这样的情况:

me.ele.foo -> me.ele.a

me.ele.fooNew -> me.ele.b(本该是这样)

 me.ele.fooNew -> me.ele.aNew(但不排序的话,会变成这样)

像这样,一个类的类名是另一个类名的开始部分,后面的替换就会出现bug。所以在存储完映射关系后,Mess调用了sortMapping(...)方法来进行排序,该方法的代码如下:

  4.通过映射 Map 替换 AndroidManifest.xml 里的 Java 原类名

在RewriteComponentTask中,紧接着上面的步骤,你就会看到下面的代码:

从这里就开始着手替换 AndroidManifest.xml中的Java原类名了,writeLine(...)方法如下所示:

逐行读取,然后进行相应的替换。

  5.通过映射 Map 替换 layout、menu 和 value 文件夹下的 xml 的 Java 原类名

还是在RewriteComponentTask中,有这样一个方法:

 很明显,它的作用就是用来判断文件路径是否是 layout、menu 和 value,它在处理完AndroidManifest.xml后随即被调用:

上图中的第二个红色框部分执行了相应的替换工作。

  6.再次执行 ProcessAndroidResources Task

经过前面的5个步骤之后,xml中的java类已经全部混淆,接下来需要再重新编译一次资源文件,即再次执行 ProcessAndroidResources Task。

到这里Mess六个步骤已经全部走完,再来回顾一下:

  1. 清空aapt_rules.txt 中的内容
  2. 如果需要混淆依赖库,则删除依赖库中的 proguard.txt 文件
  3. hook transformClassesAndResourcesWithProguard 获取混淆后的类映射关系 Map
  4. 通过映射 Map 替换 AndroidManifest.xml 里的 Java 原类名
  5. 通过映射 Map 替换 layout、menu 和 value 文件夹下的 xml 的 Java 原类名
  6. 再次执行 ProcessAndroidResources Task

Mess的开始工作的时间点

说了这么多,那么Mess是什么时候开始工作的呢

答:Mess在 class 打包成 dex 前完成所有的工作

 

 

 

 

©️2020 CSDN 皮肤主题: 技术工厂 设计师:CSDN官方博客 返回首页