Android代码混淆

最近在研究apk瘦身时,发现代码混淆有很大作用,所以就去简单研究了一下。

我认为,代码混淆可以保护核心功能不泄漏以及apk瘦身;但是也有个缺点:就是人为的可能会把不能混淆的代码混淆,导致crash。

经过整理发现代码混淆可以分为三部分:

  • 基本指令以及一些固定不混淆的代码;
  • 某些第三方包;
  • 自己书写的一些不要混淆的代码。
    注:其中第二部分,可以根据情况扩展或去掉某些未曾用到的指令;第三部分需要根据自己的情况去添加;

代码混淆

俗话说,授人以鱼不如授人以渔,但是先有鱼总是好的,所以接下来就会先介绍一下代码混淆的基本使用。

1. 开启混淆代码
在app module下的gradle文件中

android {
    ...
  
    buildTypes {
        release {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

默认minifyEnable是false,我们只需要改为true就开启了混淆。这里只需要在release的时候开启混淆即可,代码混淆会加长APK的生成时间,而且android studio2.0以后使用instance run会停用ProGuard。

这时候打包,安装,如果引入了其他第三方的代码的话,不出意外时会crash的,虽然proguard-android.txt文件中已经包含了一些不混淆的指令了,那些事系统常规的指令,对于自定义的一些指令就需要自己在app下的proguard-rules.pro文件中去定义。
2. PROGUARD模板

proguard-rules.pro

我看这个库里边的内容也用分割线做了一下简单的分割,包含的也是上文说到的三部分,下面简单介绍一下具体包含的内容。

  • 基本指令:包含了压缩级别,忽略警告,混淆警告等;

  • 固定不混淆的代码:包含继承四大组件中的内容,support包,view相关、序列化相关、R文件、枚举、native方法等;

  • 第三方包:这一部分需要根据项目情况去处理,这里支持了我们公司常用框架里边的第三方包;

  • 自己书写的不需要混淆的代码:这里就需要根据自己的情况去书写了,而我们只需要知道哪些东西是不能混淆的就能编写了。
    下面来说一下,混淆的规则:

  • 第三方库。一般都会提供混淆规则,如果没有提供,报错后,我们就可以保护报错的类,不让其混淆,实在不行就用最暴力的解决办法,把其全部代码都不混淆。

  • 运行时动态改变代码。一般例如反射,实体类。

  • 被JNI中调用的类。

  • WebView中Js调用的方法。

  • View相关的类和事件。
    这两步过后,基本就完成了代码混淆,运行后发现问题再解决即可,下面就开始介绍一些混淆中的语法。

1、常用命令

命令 作用
-keep 防止该类所有内容被移除或重命名
-keepnames 防止类和成员被重命名
-keepclassmembers 防止成员被移除或者被重命名
-keepclasseswithmembers 防止拥有该成员的类和成员被移除或者被重命名
-keepclasseswithmembernames 防止拥有该成员的类和成员被重命名

2. 常用规则

  • 类:需要使用完全限定名;

  • *:通配符,任意字符串,不包含包名分隔符(.);

  • **:通配符,任意字符串,包含包名分隔符(.);

  • extends:继承某类的类;

  • implement:实现某接口的类;

  • $:内部类;

  • <init>:所有构造方法;

  • <fields>:所有成员变量;

  • <methods>:所有方法;

  • …:任意参数;

  • 修饰符:public private protected

3. 例子

含义 指令语句
不混淆某个类 -keep public class packageName.className{ *; }
不混淆某个包的所有类 -keep class packageName.**{ *; }
不混淆某个类的子类 -keep public class * extends packageName.className{ *; }
不混淆某个接口的子类 -keep public class * implements packageName.className{ *; }
不混淆某个类的构造方法 -keepclassmembers class packageName.className{ public <init style="box-sizing: border-box;">(); }</init>
不混淆某个类的某个方法 -keepclassmembers class packageName.className{ public void methodName(…); }
不混淆某个类的内部类 -keep class packageName.className$*{ *; }

混淆的步骤

上文中介绍了代码的混淆,其实Android的混淆中还包括了资源压缩,整个过程包括:压缩、优化、混淆、以及预校验,其中第四步在Android中可不要,默认是去掉了的,另外三个都是默认开启的。

  • 压缩:会移除未被使用的类和成员变量,会在优化后再次被执行;
  • 优化:在字节码级别执行优化,让应用运行的更快;
  • 混淆:增大反编译难度,类和类成员会被随机命名,除非用keep保护。
    下面再简单介绍一下再开启资源压缩,和开启代码混淆在一起加上shrinkResources true即可。但是这时候所有未被使用的资源都会被移除,但是有的资源我们可能是动态使用的,就需要保留。
    那么就可以创建一个包含标签的XML文件,并使用tools:keep属性指定保留的资源,使用tools:discard属性指定要删除的资源;多个就使用逗号隔开即可,还可以使用*通配符。例如:
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools"
    tools:keep="@layout/l_used*_c,@layout/l_used_a,@layout/l_used_b*"
    tools:discard="@layout/unused2" />

对于资源的保留,还有一个严格应用的检查,开启后,在使用Resources.getIdentifier()就可以根据动态生成的字符串查询资源名字,例如:

String name = String.format("img_%1d", angle + 1);
res = getResources().getIdentifier(name, "drawable", getPackageName());

使用方式也很简单,如下:

<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools"
    tools:shrinkMode="strict" />

到这里,混淆相关的就基本上介绍完了,然后再总结一下需要注意的东西:

  • 一定要根据混淆规则判断自己的代码是否需要混淆;
  • 测试的版本一定需要打包后的apk;

还遗留的问题是:错误日志的定位问题?思路是根据输出的mapping文件去对应,没有详细的去落实,实际遇到了再补上具体的解决方案。

本文章参考文章

还遗留的问题是:错误日志的定位问题?思路是根据输出的mapping文件去对应,没有详细的去落实,实际遇到了再补上具体的解决方案。

参考

压缩代码和资源

写给Android开发者的混淆使用手册

Android Studio代码混淆插件

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,463评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,868评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,213评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,666评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,759评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,725评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,716评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,484评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,928评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,233评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,393评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,073评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,718评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,308评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,538评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,338评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,260评论 2 352

推荐阅读更多精彩内容

  • 本篇文章:自己在混淆的时候整理出比较全面的混淆方法,比较实用,自己走过的坑,淌出来的路。请大家不要再走回头路,可能...
    Zane_Samuel阅读 55,350评论 8 93
  • 声明 这篇文章更多的是做一个整理,内容来自于ProGuard官方文档以及各种博客等,相关文章的链接在参考目录里,感...
    夷陵小祖阅读 3,677评论 0 23
  • Android知识总结[https://www.jianshu.com/p/01b1de0504d2] 一、配置(...
    涛涛123759阅读 453评论 0 1
  • 混淆代码能有效防止被反编译,防止自己的劳动成果被别人窃取; ProGuard是一个开源的Java代码混淆器。它可以...
    appzy阅读 2,294评论 2 18
  • 久违的晴天,家长会。 家长大会开好到教室时,离放学已经没多少时间了。班主任说已经安排了三个家长分享经验。 放学铃声...
    飘雪儿5阅读 7,519评论 16 22