Android 高级混淆和代码保护技术

这是一篇关于 Android 代码保护的文章,旨在介绍代码混淆、防止逆向工程的各种高级技巧。
混淆
Android 官方集成了 Proguard 以供我们进行代码混淆工作,关于 Proguard 你可以搜索到各种它的 rules 解释,这些文章千篇一律,因此我不再赘述,只说一些特别的有用的技巧:

一般情况下,Android 的 gradle 中都会默认写着:

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

这一行代码很多人不了解。它的意思是,指定了两个 Proguard rules 文件,一个是通过 getDefaultProguardFile() 方法获得官方自带的混淆规则文件路径,另一个是与当前 gradle 相同目录下的 proguard-rules.pro 文件路径。

后者就在我们项目中,由我们书写的,没什么好说的,我们要关注的是前者这个默认 Proguard 文件,它的内容是什么你有曾探究过吗?没有的话,你可以在你的系统文件里搜索 proguard-android.txt 就应该能把它找出来,具体自己去看,我就说一些关键的,这个默认文件中帮我们声明了许多混淆规则内容,包括:keep 所有继承自 View 的类,keep 所有继承自 Activity 的类,keep 所有 JavascriptInterface、native 方法声明,以及 keep 一些注解了 @Keep 的内容。

所以你知道为什么默认情况下,即使你自己一条规则都没有加入,你的自定义 View 和 Activity 都被保留下来了吧,至少类名都没有被混淆。

那么为什么官方默认会帮我们写下这些?为什么 View 和 Activity 默认情况下应该被保留呢?

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

对于这个问题,饿了么 的团队提供了一个鲜为人知的 gradle 插件 用来无伤混淆 Activity 和 View,这个项目叫 Mess:https://github.com/eleme/Mess ,具体内容各位可以稍后自行去阅读其文档和教程,链接最后都还会附于末尾。简单来说,Mess 弥补了 Proguard 不能检索 XML 文件的缺点,帮 Proguard 完成了 Activity 和 View 的改名及 mapping。

话说回来,前面我建议各位都去逐行了解下默认混淆配置文件,因为只有这样,你才知道整个混淆工具帮你做了什么,了解清楚之后,我建议的一个做法是,把这个默认文件拷贝到你的项目目录之下,删掉 getDefaultProguardFile(‘proguard-android.txt’),再引入现存于你目录之下的原默认文件。这么做的好处是,方便你修改这个默认文件,因为它有些内容是不必要或者可以更改的。不过基本上我们可以保留其原样。复制过来的另一个好处是,避免其被外方更新导致你引用过来后产生变数。总之,proguardFiles 这个配置项(其实是一个 gradle 方法)可以接受无限个 rules 文件路径,它的参数是一个可变字符串参数,不过为了避免代码横向发展,我更愿意使用另一个方法,叫 proguardFile,注意,少了一个 s 有没有,它接受单个参数,相当于 add 一个 rules。对此,提供我的配置以供参考:

release {
    debuggable false
    minifyEnabled true
    zipAlignEnabled true
    shrinkResources true
    signingConfig signingConfigs.release
    proguardFile 'proguard-common.pro'
    proguardFile 'proguard-rules.pro'
    proguardFile 'proguard-rules-google-ads.pro'
}

其中 proguard-common.pro 这个文件就是上述我说的复制过来的官方默认配置文件,它被我放在当前 module 目录之下和 proguard-rules.pro 并列。这么写很清楚而且便于复用。

讲完基本内容之后,我决定再介绍两条特别实用的 Proguard rules:

扫描二维码关注公众号,回复: 2498038 查看本文章

-repackageclasses

-repackageclasses 这条规则配置特别强大,它可以把你的代码以及所使用到的各种第三方库代码统统移动到同一个包下,可能有人知道这条配置,但仅仅知道它还不能发挥它最大的作用,默认情况下,你只要在 rules 文件中写上 -repackageclasses 这一行代码就可以了,它会把上述的代码文件都移动到根包目录下,即在 / 包之下,这样当有人反编译了你的 APK,将会在根包之下看到 成千上万 的类文件并列着,除此之外,由于我们有时不得不 keep 一些类文件,于是你应用的包名层次仍然会存在,有一些没被完全混淆的类将继续存留在你的包名之下,这些类文件就相对得不到很好的保护。于是我要介绍一个小技巧,就是 -repackageclasses 后跟上一个你应用的包名,如:

-repackageclasses com.drakeet.purewriter.debug

安全

有了代码混淆还不够,我们需要更多技巧来保护我们的代码,特别是对于需要做混淆但又需要暴露许多 API 的 SDK 开发者来说。混淆是基础,代码安全是意识。

首先我们要知道我们混淆代码是如何被攻破的,其实对于反编译者来说,最简单的入手点就是字符串搜索,我们硬编码留在代码里的字符串值都会在反编译过程中被原样恢复,因此这是我们首要关注对象。避免被通过字符串攻破,我们应该做到以下几点:

一,不要硬编码写入字符串值,即使你不得不这么做,也至少应该另起一个类,比如叫做 HardStrings,用于静态存放这些硬编码的字符串。这样反编译者只能搜索到你这个常量类,而较难以搜索到这些字符串常量被哪里引用。

二,在 release 混淆过程中删除 Log 代码,使用 -assumenosideeffects 这个配置项可以帮我们在编译成 APK 之前把日志代码全部删掉,这么做不仅有助于提升性能,而且日志代码往往会保留很多我们的意图和许多可被反编译的字符串:

-assumenosideeffects class android.util.Log {
    public static boolean isLoggable(java.lang.String, int);
    public static int d(...);
    public static int w(...);
    public static int v(...);
    public static int i(...);
}

三,对于你不得不留下的一些硬编码和日志内容,可以采用编码形式替换,如 你可以规定 “4001” 代表某种错误,而不是在你的代码里写入这个错误的具体描述字符串。这么做的话,你需要有个地方记下这些编码映射的内容,关于此有个技巧:你可以再创建一个常量类,其内容是一堆静态字符串对象,针对上面那个例子,你可以把真正的错误信息作为一个字符串变量的名字,而把它的值写成一个编码,如下:

public static final String SHOULD_REGISTER_FIRST_ERROR = "ssrrffe";

这样当你在看没混淆的代码引用这个静态变量,你能够一目了然它的意思。而反编译者看到的则是:

public static final String abc = "ssrrffe";

命名看不懂,值也看不懂。

四,把 AppKey 之类特别敏感的字符串内容藏在 native so 文件中。

关于字符串技巧的内容差不多就这样了,能做到这些就不错了,还有一些极端做法不多说,为了阻碍黑客阅读,自己也变得非常麻烦,双刃剑,这不是我们想要的结果。

然后我们讲另一个混淆后代码的软肋,就是一些我们不得不 keep 的内容,如果是闭源 SDK 开发者,需要 keep 的内容将会更多,几乎只要是 public 的类、变量,方法,全部要 keep,那么针对这个问题,我们该怎么办?介绍一个方法:

给这些需要 keep 的内容设置委托者,然后将委托者投入大海之中。

很玄乎吧?哈哈,这么讲有助于记忆。其实和我们在混淆章节说的藏叶于林的思想是一样的。如果一个类不得不 keep,那就把它所做的全部内容都转交给一个 private 或 internal 的类对象去完成,这个委托类对象代码可以完全混淆,然后你再把这个委托类通过混淆工具藏在大量的代码之中,这样就足够给反编译者带来了很大的麻烦,相比直接获取逻辑代码,这么做以后要找到实体的逻辑代码将费劲得多。

因此,如果你知道有这么一个方式,其实你完全可以不使用饿了么提供的那个 Activity 和 View 混淆工具,也能很好地保护你的 Activity 和 View。

不过一般情况我们无需所有内容都保护,只要把关键、核心内容委托出去就可以了。

猜你喜欢

转载自blog.csdn.net/github_37271067/article/details/76020663