一、混淆的目的

一款发布到市场的软件原则上都应该做代码混淆。

通过代码混淆可以将项目中的类、方法、变量等信息进行重命名,变成一些无意义的简短名字,同时也可以移除未被使用的类、方法、变量等。所以直观的看,通过混淆可以提高程序的安全性,增加逆向工程的难度,同时也有效缩减了apk的体积。一起来get这个技能吧!

二、开启混淆

在基于Android Studio项目的app module的build.gradle中有如下默认代码片段:

buildTypes {release {minifyEnabled falseproguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'signingConfig signingConfigs.release}
}

代表要发布的release包的混淆配置,默认不开启混淆,要开启混淆首先做如下修改: minifyEnabled true

开启混淆后还可以添加shrinkResourcestrue配置,代表开启资源文件压缩。

这样就在release模式下开启了混淆。一般在debug模式下不开启混淆,因为混淆会导致编译时间变长、无法debug问题,毕竟也是内部测试嘛,没必要!

开启混淆后,接下来就是用混淆配置文件来设置混淆规则:

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

proguard-android.txt代表系统默认的混淆规则配置文件,该文件在<AndroidSDK目录>/tools/proguard下,一般不要更改该配置文件,因为也会作用于其它项目,除非你能确保所做的更改不影响其它项目的混淆。

proguard-rules.pro代码表当前project的混淆配置文件,在app module下,可以通过修改该文件来添加适用当前项目的混淆规则。

三、编写混淆配置文件

为了更好的编写proguard-rules.pro,先学习下系统的proguard-android.txt

# This is a configuration file for ProGuard.
# http://proguard.sourceforge.net/index.html#manual/usage.html
# 混淆时不使用大小写混合类名
-dontusemixedcaseclassnames
# 不跳过library中的非public的类
-dontskipnonpubliclibraryclasses
# 打印混淆的详细信息
-verbose
# Optimization is turned off by default. Dex does not like code run
# through the ProGuard optimize and preverify steps (and performs some
# of these optimizations on its own).
# 关闭优化(原因见上边的原英文注释)
-dontoptimize
# 不进行预校验,可加快混淆速度
-dontpreverify
# Note that if you want to enable optimization, you cannot just
# include optimization flags in your own project configuration file;
# instead you will need to point to the
# "proguard-android-optimize.txt" file instead of this one from your
# project.properties file.
# 保留注解中的参数
-keepattributes *Annotation*
# 不混淆如下两个谷歌服务类
-keep public class com.google.vending.licensing.ILicensingService
-keep public class com.android.vending.licensing.ILicensingService
# For native methods, see http://proguard.sourceforge.net/manual/examples.html#native
# 不混淆包含native方法的类的类名以及native方法名
-keepclasseswithmembernames class * {native <methods>;
}
# keep setters in Views so that animations can still work.
# see http://proguard.sourceforge.net/manual/examples.html#beans
# 不混淆View中的setXxx()和getXxx()方法,以保证属性动画正常工作
-keepclassmembers public class * extends android.view.View {void set*(***);*** get*();
}
# We want to keep methods in Activity that could be used in the XML attribute onClick
# 不混淆Activity中参数是View的方法,例如,一个控件通过android:onClick="clickMethodName"绑定点击事件,混淆后会导致点击事件失效
-keepclassmembers class * extends android.app.Activity {public void *(android.view.View);
}
# For enumeration classes, see http://proguard.sourceforge.net/manual/examples.html#enumerations
# 不混淆枚举类中的values()和valueOf()方法
-keepclassmembers enum * {public static **[] values();public static ** valueOf(java.lang.String);
}
# 不混淆Parcelable实现类中的CREATOR字段,以保证Parcelable机制正常工作
-keepclassmembers class * implements android.os.Parcelable {public static final android.os.Parcelable$Creator CREATOR;
}
# 不混淆R文件中的所有静态字段,以保证正确找到每个资源的id
-keepclassmembers class **.R$* {public static <fields>;
}
# The support library contains references to newer platform versions.
# Don't warn about those in case this app is linking against an older
# platform version.  We know about them, and they are safe.
# 不对android.support包下的代码警告(如果我们打包的版本低于support包下某些类的使用版本,会出现警告的问题)
-dontwarn android.support.**
# Understand the @Keep support annotation.
# 不混淆Keep类
-keep class android.support.annotation.Keep
# 不混淆使用了注解的类及类成员
-keep @android.support.annotation.Keep class * {*;}
# 如果类中有使用了注解的方法,则不混淆类和类成员
-keepclasseswithmembers class * {@android.support.annotation.Keep <methods>;
}
# 如果类中有使用了注解的字段,则不混淆类和类成员
-keepclasseswithmembers class * {@android.support.annotation.Keep <fields>;
}
# 如果类中有使用了注解的构造函数,则不混淆类和类成员
-keepclasseswithmembers class * {@android.support.annotation.Keep <init>(...);
}

可以看出proguard-android.txt主要作用是防止指定内容被混淆,其中使用了以-开头,结合keep类关键字,*、<>等通配符的语法,先get这些语法吧!

·        首先看keep类关键字:

关键字 

含义

keep

保留类和类成员,防止被混淆或移除

Keepnames

保留类和类成员,防止被混淆,但没有被引用的类成员会被移除

keepclassmembers

只保留类成员,防止被混淆或移除

keepclassmembernames 

只保留类成员,防止被混淆,但没有被引用的成员会被移除

keepclasseswithmembers

保留类和类成员,防止被混淆或移除,如果指定的类成员不存在还是会被混淆

keepclasseswithmembernames

保留类和类成员,防止被混淆,如果指定的类成员不存在还是会被混淆,没有被引用的类成员会被移除

相关通配符:

通配符

 含义

*

匹配任意长度字符,但不含包名分隔符.。例如一个类的全包名路径是com.othershe.test.Person,使用com.othershe.test.*、com.othershe.test.*都是可以匹配的,但com.othershe.*就不能匹配

** 

匹配任意长度字符,并包含包名分隔符.。例如要匹配com.othershe.test.**包下的所有内容

***

匹配任意参数类型。例如*** getName(***)可匹配String getName(String)

... 

匹配任意长度的任意类型参数。例如void setName(...)可匹配void setName(String firstName, String secondName)

<fileds>

匹配类、接口中所有字段

<methods>

匹配类、接口中所有方法

<init>

匹配类中所有构造函数

到这里对混淆已经有了基本的了解,系统的proguard-android.txt已经为我们完成了大部分基础的混淆配置工作,至于编写当前appmodule下的proguard-rules.pro,只需要针对当前项目添加一些特有的配置,避免某些重要的东西被混淆掉导致错误,我们主要考虑以下几点:

①、在AndroidManifest.xml中注册的继承四大组件的子类的类名以及重写的方法名都不会被混淆。如果希望项目中android.support.v4.app.Fragment子类的类名和重写父类的方法名不被混淆可以添加如下配置:

# 不混淆Fragment的子类类名以及onCreate()、onCreateView()方法名
-keep public class * extends android.support.v4.app.Fragment {
    public void onCreate(android.os.Bundle);public android.view.View onCreateView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle);
}

②、不混淆某个特定的类和类中所有成员

-keep class com.othershe.test.utils.CommonUtil { *; }

③、不混淆某个目录下的文件,例如使用Gson时,数据bean不能被混淆,需要如下配置:

# com.othershe.test.model代表数据bean所在的全包名目录
-keep class com.othershe.test.model.** { *; }

④、上一条的具体原因是因为Gson用到了反射。如果我们自己使用了反射,例如

Field field = service.getField("BASE_URL");

注:BASE_URL是service所属类的一个字段名,则该字段不能被混淆。

⑤、保留泛型

-keepattributes Signature

⑥、保留用于调试堆栈跟踪的行号信息(为了后期调试方便,建议配置)

-keepattributes SourceFile,LineNumberTable

⑦、如果使用了上一行配置,还需要添加如下配置将源文件重命名为SourceFile,以便通过鼠标点击直达源文件:

-renamesourcefileattribute SourceFile

⑧、 WebView中使用了JS调用,需要添加如下配置:

-keepclassmembers class fqcn.of.javascript.interface.for.webview {
   public *;
}

⑨、项目中使用的第三方library混淆规则,列举了几个常用的:

# okhttp
-dontwarn okhttp3.**
-dontwarn okio.**
-dontwarn javax.annotation.**
-keepnames class okhttp3.internal.publicsuffix.PublicSuffixDatabase# Retrofit
-dontwarn okio.**
-dontwarn javax.annotation.**
-dontnote retrofit2.Platform
-dontwarn retrofit2.Platform$Java8
-keepattributes Signature
-keepattributes Exceptions# RxJava RxAndroid
-dontwarn sun.misc.**
-keepclassmembers class rx.internal.util.unsafe.*ArrayQueue*Field* {long producerIndex;long consumerIndex;
}
-keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueProducerNodeRef {rx.internal.util.atomic.LinkedQueueNode producerNode;
}
-keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueConsumerNodeRef {rx.internal.util.atomic.LinkedQueueNode consumerNode;
}# Gson
-keep class com.google.gson.stream.** { *; }
-keepattributes EnclosingMethod
# xxx代表model类的全包名路径
-keep class xxx.** { *; }# butterknie
-keep class butterknife.** { *; }
-dontwarn butterknife.internal.**
-keep class **$$ViewBinder { *; }
-keepclasseswithmembernames class * {@butterknife.* <fields>;
}
-keepclasseswithmembernames class * {@butterknife.* <methods>;
}# eventbus
-keepattributes *Annotation*
-keepclassmembers class ** {@org.greenrobot.eventbus.Subscribe <methods>;
}
-keep enum org.greenrobot.eventbus.ThreadMode { *; }
# Only required if you use AsyncExecutor
-keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent {<init>(java.lang.Throwable);
}

以上这些可以按需添加到proguard-rules.pro!

四、查看混淆结果

混淆后打包,会在appmodule/build/outputs/mapping/release目录下生成如下文件(动不动就几万行,是在没法看):

dump.txt:描述apk文件中所有类的内部结构

mapping.txt:混淆前后的类、类成员、方法的对照关系(重要,追溯Crash堆栈信息要用到)

resources.txt:资源文件的压缩信息

seeds.txt:未被混淆的类和成员

usage.txt:被移除的代码

混淆后的apk包,需要系统的测试,防止混淆导致的潜在bug。

我们还是有必要看一下混淆后的代码结构,验证混淆是否成功。一个简单的办法,Android Studio的Build菜单下有一个Analyze APK选项,只需要先选择要分析的apk包,在之后的界面点击classes.dex即可看到混淆后的代码结构:

但是这样只能看到一个类的成员变量和方法的结构,如果要看一个类的具体内容,就需要反编译apk包了,具体可参考Android apk反编译及重新打包流程,希望一切顺利!

五、 追溯Crash堆栈信息

代码混淆后,也会导致Crash堆栈信息被混淆,难以阅读,增加定位问题位置的难度,一个混淆后的Crash堆栈信息类似这样,核心的信息都没了:

为了解决这个问题,可以使用<SDK目录>\tools\proguard\bin下的proguardgui.bat脚本将Crash堆栈信息还原到混淆前的状态。步骤如下:

1. 双击打开脚本,选择左边的ReTrace选项

2. 选择Mappingfile文件,也就是混淆后打包后在appmodule/build/outputs/mapping/release下生成的mapping.txt

3. 拷贝混淆后的堆栈信息

4. 点击右下角的ReTrace!按钮,完成Crash堆栈信息的追溯

如下图中间部分就是追溯到的原Crash堆栈信息:

代码混淆常用的内容就这些了,重点还是要理解混淆的相关语法,灵活运用!混淆一定程度增加逆向工程的难度,但还是能被破解的,如果你的代码有价值,也难免被有心的人利用!

除了混淆之外,一些厂商也提供了apk加固的服务来保证软件的安全性,但也是可以被脱壳的!有兴趣的可自行了解!

Android混淆使用详解相关推荐

  1. Android 混淆机制详解

    前言 混淆是增加逆向工程和破解的难度,防止App知识产权被窃取的一个有力手段,高级的代码混淆甚至可以有效地保护存储在客户端的密钥,同时混淆也有很多要注意的地方. 从广义上讲,Android 中的混淆包 ...

  2. 《Android游戏开发详解》——第1章,第1.6节函数(在Java中称为“方法”更好)...

    本节书摘来自异步社区<Android游戏开发详解>一书中的第1章,第1.6节函数(在Java中称为"方法"更好),作者 [美]Jonathan S. Harbour,更 ...

  3. JMessage Android 端开发详解

    JMessage Android 端开发详解 目前越来越多的应用会需要集成即时通讯功能,这里就为大家详细讲一下如何通过集成 JMessage 来为你的 App 增加即时通讯功能. 首先,一个最基础的 ...

  4. 《Java和Android开发实战详解》——2.5节良好的Java程序代码编写风格

    本节书摘来自异步社区<Java和Android开发实战详解>一书中的第2章,第2.5节良好的Java程序代码编写风格,作者 陈会安,更多章节内容可以访问云栖社区"异步社区&quo ...

  5. Android事件流程详解

    Android事件流程详解 网络上有不少博客讲述了android的事件分发机制和处理流程机制,但是看过千遍,总还是觉得有些迷迷糊糊,因此特地抽出一天事件来亲测下,向像我一样的广大入门程序员详细讲述an ...

  6. Android Studio 插件开发详解二:工具类

    转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/78112856 本文出自[赵彦军的博客] 在插件开发过程中,我们按照开发一个正式的项 ...

  7. 《Android游戏开发详解》一2.16 区分类和对象

    本节书摘来异步社区<Android游戏开发详解>一书中的第2章,第2.16节,作者: [美]Jonathan S. Harbour 译者: 李强 责编: 陈冀康,更多章节内容可以访问云栖社 ...

  8. Android Framework系统服务详解

    Android Framework系统服务详解 操作环境 系统:Linux (Ubuntu 12.04) 平台:高通 Android版本:5.1 PS: 符号...为省略N条代码 一.大致原理分析 A ...

  9. android屏幕适配详解

    android屏幕适配详解 官方地址:http://developer.android.com/guide/practices/screens_support.html 一.关于布局适配建议 1.不要 ...

  10. Android LiveData组件详解以及LiveDataBus

    转载请标明出处:https://blog.csdn.net/zhaoyanjun6/article/details/99749323 本文出自[赵彦军的博客] 一.LiveData简介 LiveDat ...

最新文章

  1. 科软2020计算机科学与技术,2020新高考 报考计算机类专业怎么选科
  2. jquery获取元素的值,获取当前对象的父对象等等
  3. 【直播课】图像分类竞赛技巧与多标签分类实战
  4. 保姆式参赛教程全公开,居然还送10万奖金?
  5. knn算法实现电影分类
  6. 爬虫之操作excel
  7. Django讲课笔记04:Django项目的调试
  8. 【转】Nginx服务并发过10万的Linux内核优化配置
  9. 电影票房预测问题:如何使用Python生成词云
  10. 神舟刷蓝天w650dbios_Hasse神舟笔记本卡logo解决,刷BIOS方法,教你修复神船
  11. 51单片机学习:串口通信实验
  12. @开源镜像站(linux系统:Center OS|Ubuntu|Debian)
  13. 2022QS世界大学学科排名出炉,计算机学科有哪些信息值得关注?
  14. TSL2591STM32固件库开发
  15. win7 cmd 无法复制粘贴
  16. post测试+php文件,PHPT – 无法运行使用–POST_RAW–的示例测试
  17. Android知识点 200 —— framework/base/cmds 常见的am命令,input,pm命令
  18. 从0到1搭建大数据平台之调度系统
  19. cocos2d-x 菜鸟学习笔记一(跨平台编译)
  20. 宁芝普拉姆键盘说明书

热门文章

  1. python︱六款中文分词模块尝试:jieba、THULAC、SnowNLP、pynlpir、CoreNLP、pyLTP
  2. 怎么把ide改成ahci_无需重装操作系统,IDE模式轻松改成AHCI模式
  3. UE4 蓝图事件调度器Event Dispatcher
  4. 视频分辨率QCIF、CIF、2CIF、4CIF,D1~D5
  5. imageJ打不开mp4怎么办?
  6. R语言画图——添加数学表达式和R2
  7. 剪贴板是计算机系统,Windows7电脑剪切板在哪?
  8. PCB layout的基本原则
  9. 常见电容器图片_电容的电路符号及图片识别
  10. 计算机一级网页制作教程视频教程,网页制作入门教程(一)