Android混淆
一、为什么要混淆
为了避免apk在发布后被用户通过反编译拿到源代码和资源文件,然后修改资源和代码之后就变成一个新的apk。而经过混淆后的APK,即使被反编译,也难以阅读,注意混淆不是让apk不能阅读,而是加大阅读的难度,为了避免劳动成果被窃取,也避免出现安全漏洞和隐患,所以在apk发布之前一定要进行混淆。
二、混淆的原理
Java是一种跨平台、解释型语言,Java源代码编译成的class文件中有大量包含语义的变量名、方法名的信息,很容易被反编译为Java源代码。为了防止这种现象,我们可以对Java字节码进行混淆。混淆不仅能将代码中的类名、字段、方法名变为无意义的名称,保护代码,也由于移除无用的类、方法,并使用简短名称对类、字段、方法进行重命名缩小了程序的大小。
ProGuard由shrink、optimize、obfuscate和preverify四个步骤组成,每个步骤都是可选的,需要哪些步骤都可以在脚本中配置。参见ProGuard官方介绍。
压缩(Shrink):默认开启,侦测并移除代码中无用的类、字段、方法和特性,减少应用体积,并且会在优化动作执行之后再次执行(因为优化后可能会再次暴露一些未使用的类和成员)。
-dontshrink 关闭混淆
优化(Optimize):默认开启,分析和优化字节码,让应用运行的更快。
-dontoptimize 关闭优化,默认混淆配置文件开始
-optimizationpasses n 表示proguard对代码进行迭代优化的次数,Android一般为5
混淆(Obfuscate):默认开启,使用a、b、c、d这样简短而无意义的名称,对类、字段和方法进行重命名,增大反编译难度。
-dontobfuscate 关闭混淆
上面三个步骤使代码大小更小、更高效,也更难被逆向工程。
预检(Preverify):在java平台上对处理后的代码进行预检。
混淆流程图:
Proguard读入input jars(or wars,zip or directories),经过四个步骤生成处理之后的jars(or wars,ears,zips or directories),Optimization步骤可选择多次进行。
为了确定哪些代码应该被保留,哪些代码应该被移除或混淆,需要确定一个或多个Entry Point。Entry Point经常是带有main methods,applets,midlets的classes,它们在混淆过程中会被保留。
Proguard的几个步骤如何处理Entry Points。
(1).在压缩阶段,Proguard从上述Entry Points开始遍历搜索哪些类和类成员被使用。其他没有被使用的类和类成员会移除。
(2).在优化阶段,Proguard进一步设置非Entry Point的类和方法为private、static和final来进行优化,不使用的参数会被移除,某些方法会被标记为内联。
(3).在混淆阶段,Proguard重命名非Entry Points的类和类成员。
(4).预检阶段是唯一没有触及Entry Points的阶段。
三、Android Studio默认的混淆方案及字段解读
1.开启混淆
在build.gradle文件内相应的构建类型中添加minifyEnabled true即可。
除了minifyEnable属性外,还有用于定义ProGuard规则的proguardFiles属性:
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
官方文档介绍:
getDefaultProguardFile('proguard-android.txt')方法可从Android SDK tools/proguard/文件夹获取默认的ProGuard设置。要想做进一步的代码压缩,请尝试使用位于同一位置的proguard-android-optimize.txt文件。它包括相同的Proguard规则,但还包括其他在字节码一级(方法内和方法间)执行分析的优化,以进一步减少APK大小和帮助提高其运行速度。
proguard-rules.pro文件用于添加自定义Proguard规则。默认情况下,该文件位于模块根目录(build.gradle文件旁),内容为空。
在gradle 2.2之后,defaultProguardFile没有使用sdk目录下的proguard-android.txt,而是使用了gradle自带的proguard-android.txt,不同的gradle版本带有不同的默认混淆文件,在项目根目录的build/intermediates/proguard-files/proguard-android.txt-2.3.1。
混淆配置文件不检查规则是否重复,如果两条规则冲突,则采用白名单的,比如设置了开启优化和不优化两个选项后,不论顺序,最终都会执行不优化的操作。
2.构建输出
构建时Proguard都会输出下列文件:(build之后)
(1)dump.txt --- 说明APK中所有类文件的内部结构
(2)mapping.txt --- 提供原始与混淆过的类、方法和字段名称之间的转换
(3)seeds --- 列出未进行混淆的类和成员
(4)usage.txt --- 列出从APK移除的代码
这些文件保存在/build/outputs/mapping/release目录下。
3.解码混淆过的堆栈追踪
使用混淆后,保存好mapping文件,程序csh时通过脚本进行解码。
retrace工具位于/tools/proguard/目录下,解码命令为:
retrace.bat|retrace.sh [-verbose] mapping.txt [<stacktrace_file>]
4.默认的混淆方案及字段解读
(1)不适用大小混写类名
-dontusemixedcaseclassnames
默认情况下混淆的类名可以包含大小写字符的混合
(2)不忽略公共类库
-dontskipnonpubliclibraryclasses
指定不去忽略非public的library classes。从Proguard 4.5开始,是默认的设置。
(3)不优化指定的文件与不预检验
-dontoptimize
-dontpreverify
默认optimize和preverify选项是关闭的,因为Android的dex并不想Java虚拟机需要optimize(优化)和previrify(预检)两个步骤。
(4)指定哪个属性不要混淆,可一次指定多个属性
-keeppattributes [attribute_filter]
通常Exceptions,Signature,Deprecated,SourceFile,SourceDir,LineNumberTable,LocalVariableTable,LocalVariableTypeTable,Synthetic,EnclosingMethod,RuntimeVisibleAnnotations,RuntimeInvisibleAnnotations,RuntimeVisibleParameterAnnotations,RuntimeInvisibleParameterAnnotations,AnnotationDefault属性需要被保留,根据项目具体使用情况保留。
gradle默认的keepattributes属性不全,只保留了Annotations,Signature,InnerClasses,EnclosingMethod,为了混淆之后定位csh代码方便,需要在proguard_rules.pro中手动添加抛出异常时保留代码行号,并且重命名超出异常时的文件名称,这样能方便定位问题:
#抛出异常时保留代码行号
-keeppattributes SourceFile,LineNumberTable
#重命名抛出异常时的文件名称
-renamesourcefileattribute SourceFile
keep选项制定了哪些类,哪些方法不被混淆,从而保证了程序的正常运行。
keep用法有6种:
(1)-keep(names)选项 指定类和类成员(变量和方法)不被混淆
-keep [,modifier,...] class_specification
//指定类名不被改变
-keep public class com.google.vending.licensing.ILicensingService
//指定使用了Keep注解的类和类成员都不被改变
-keep @android.support.annotation.Keep class * {*;}
(2)-keepclassmembers(names) 指定类成员不被混淆,类名会被混淆
//keep setters in views 使得animations仍然能够工作
-keepclassmembers public class * extends android.view.View {
void set*(***);
*** get*();
}
(3)-keepclasseswithmembers(names) 指定类和类成员都不被混淆
-keepclasseswithmembers [,modifier,...] class_specification
//包含native方法的类名和native方法都不能被混淆,如果native方法未被调用,则被移除。由于native方法与对应so库中的方法名称对应,方法名被混淆会导致调用出现问题,所以native方法不能被混淆。
-keepclasseswithmembernames class * {
native <methods>;
}
不带names的选项为From being removed or renames,既不会被移除或重命名,即使类或类成员未被使用。带有names的选项为From being renamed,不会被重命名,如果是无用的类或类成员,会被移除,移除是指在压缩(Shrinking)时是否会被删除。
通用Options:
(1)-verbose 打印混淆详细信息
(2)-dontnote选项:指定不去输出打印该类产生的错误或遗漏
-dontnote com.android.vending.licensing.ILicensingService
-dontnote android.support.**
(3)-dontwarn选项:指定不去warn unresolved references和其他重要的problem
-dontwarn android.support.**
如上面(2)(3)所示,android.support的libraries需要保留。
四、自定义混淆文件
1.Filters
? 匹配一个字符
* 匹配一个名字,除了目录外分隔符外的任意部分
** 匹配任意名,可能包含任意路径分隔符
! 排除
<field> 匹配类中的所有字段
<method> 匹配类中所有的方法
<init> 匹配类中所有的构造函数
-keep class com.lily.test.** 本包和所包含子包下的类名都保持
-keep class com.lily.test.* 保持该包下的类名
-keep class com.lily.test.** {*;} 保持包和子包的类名和里面的内容均不被混淆
如果要保留一个类中的内部类不被混淆则需要用$符号。
2.-assumenosideeffects指令:
assumeosideeffects是Optimization过程中的选项,所以为保证指令的有效,需要开启optimization。这个指令的含义是Proguard会在optimization过程中删除对这些方法的调用,需要注意:当你知道你在做什么的时候才能使用它。
3.一个自定义文件
#代码混淆压缩比,在0~7之间
-optimizationpasses 5#
#混淆时不适用大小写混合,混合后的类名为小写
-dontusemixedcaseclassnames #指定不去忽略非公共库的类
-dontskipnonpubliclibraryclasses #不做预校验,preverify是proguard的四个步骤之一,Android不需要precerify,去掉这一步能够加快混淆速度。
-dontpreverify -verbose #google推荐算法
-optimizations !code/simplification/arithmetic,!code/simplication/cast,!field/*,!class/mergin/* #避免混淆Annotation、内部类、泛型、匿名类
-keepattributes *Annotation*,InnerClasses,Signature,EnclosingMethod #重命名抛出异常时的文件名称
-renamesourcefileattribute SourceFile #抛出异常时保留代码行号
-keepattributes SourceFile,LineNumberTable #处理support包
-dontnote android.support.**
-dontwarn android.support.** #保留四大组件,自定义的Application等这些类不被混淆
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * entends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.preference.Preference
-keep public class com.android.vending.licensing.ILicensingService #保留本地native方法不被混淆
-keepclasseswithmembernames class * {
native <methods>
} #保留枚举类不被混淆
-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
} #第三方jar包不被混淆
-keep class com.github.test.** {*;} #保留自定义的Test类和类成员不被混淆
-keep class class.lily.Test {*;} #保留自定义的xlog文件夹下面的类、类成员和方法不被混淆
-keep class com.text.xlog.** {
<fields>;
<methods>;
} #assume no side effects;删除android.util.Log输出的日志
-assumenosideeffects class android.util.Log {
public static *** v(...);
public static *** d(...);
public static *** i(...);
public static *** w(...);
public static *** e(...);
} #保留keep注解的类名和方法
-keep,allowobfuscation @interface android.support.annotation.Keep
-keep @android.support.annotation.Keep class *
-keepclassmember class * {
@android.support.annotation.Keep *;
}
五、常用到的不混淆
1.jni方法不混淆
jni方法不混淆,因为方法需要和native方法保持一致。
-keepclasseswithmembernames class * {
# 保持native方法不被混淆
native <methods>;
}
2.反射不混淆
反射用到的类不混淆(否则混淆可能出现问题)。
-keepatrributes EnclosingMethod
3.AndroidMainfest中的类不混淆
AndroidMainfest中的类不混淆,所以四大组件和Application的子类和Framework层下所有的类默认不会进行混淆。自定义的View默认也不会被混下,所以排除自定义View,或者四大组件被混淆的规则在ndroid Studio中无需加入的,下面是兼容性比较高的规则:
-keep public class * extends android.app.Fragment
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Service
-keep public class * extends android.content。BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * entends android.app.backup.BackupAgentHelper
-keep public class * entends android.preference.Preference
4.JSON对象类不混淆
与服务器交互时,使用GSON、fastjson等框架解析服务端数据时,所写的JSON对象类不混淆,否则无法将JSON解析成对应的对象。
5.第三方开源或SDK包
使用第三方开源库或者引用其他第三方的SDK包时,如果有特别要求,也需要在混淆文件中加入对应的混淆规则。
6.WebView的JS调用的接口方法不混淆
有用到WebView的JS调用也需要保证写的接口方法不混淆,原则和第一条一样。
-keepclassmembers classs fqcn.of.javascript.interface.for.webview {
public *;
}
7.Parcelable的子类和Creator静态成员变量不混淆
Parcelable的子类和Creator静态成员变量不混淆,否则会产生Android.os.BadParcelableException异常;
-keep class * implements Android.os.Parcelable {
# 保持Parcelable不被混淆
public static final Android.os.Parcelable$Creator *;
}
8.enum类型
使用enum类型时需要注意避免以下两个方法混淆,因为enum类的特殊性,以下两个方法会被反射调用。
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
9.注解不混淆
-keepatrributes *Annotation*
-keep class * extends java.lang.annotation.Annotation {*;}
10.泛型不混淆
-keepattributes Signature
11.内部类不混淆
-keepattributes InnerClasses
六、第三方混淆参考规则
1.Gson
-dontwarn com.google.**
-keep class com.google.gson.** {*;}
2.otto
-keepattributes *Annotation*
-keepclassmembers class ** {
@com.squareup.Subscribe public *;
@com.squareup.otto.Produce public *;
}
3.universal-image-loader
-dontwarn com.nostra13.universalimageloader.**
-keep class com.nostra13.universalimageloader.** {*;}
4.友盟统计
-keepclassmembers class * {
public <init> (org.json.JSONObject);
}
#友盟统计5.0.0以上SDK需要
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
#友盟统计R.java删除问题
-keep public class com.gdhbgh.activity.R$*{
public static final int *;
}
5.OkHttp
-dontwarn com.squareup.okhttp.**
-keep class com.squareup.okhttp.** {*;}
-keep interface com.squareup.okhttp.** {*;}
-dontwarn okio.**
6.nineoldandroids
-dontwarn com.nineoldandroids.*;
-keep class com.nineoldandroids.** {*;}
7.支付宝
-keep class com.alipay.android.app.IAlixPay{*;}
-keep class com.alipay.android.app.IRemoteServiceCallback{*;}
-keep class com.alipay.android.app.IRemoteServiceCallback$Stub{*;}
-keep class com.alipay.sdk.app.PayTask{
public *;
}
-keep class com.alipay.sdk.app.AuthTask{
public *;
}
8.Socket.io
-keep class socket.io-client.
-keepclasswithmembers,allowshrinking class socket.io-client.* {*;}
-keep class io.socket.
-keepclasseswithmembers,allowshrinking class io.socket.* {*;}
9.JPUSH
-dontwarn cn.jpush.**
-keep class cn.jpush.** {*;} # protobuf(jpush依赖)
-dontwarn com.google.**
-keep class com.google.protobuf.** {*;}
10.友盟分享
-dontwarn com.umeng.**
-dontwarn com.tencent.weibo.sdk.** -keep public interface com.tencent.**
-keep public interface com.umeng.socialize.**
-keep public interface com.umeng.socialize.sensor.**
-keep public interface com.umeng.scrshot.** -keep public class com.umeng.socialize.* {*;} -keep class com.umeng.scrshot.**
-keep public class com.tencent.** {*;}
-keep class com.umeng.socialize.sensor.**
-keep class com.umeng.socialize.handler.**
-keep class com.umeng.socialize.handler.*
-keep class com.tencent.mm.sdk.modelmsg.WXMediaMessage {*;}
-keep class com.tencent.mm.sdk.modelmsg.** implements com.tencent.mm.sdk.modelmsg.WXMediaMessage$IMediaObject {*;} -keep class im.yixin.sdk.api.YXMessage {*;}
-keep class im.yixin.sdk.api.** implements im.yixin.sdk.api.YXMessage$YXMessageData{*;} -keep class com.tencent.** {*;}
-dontwarn com.tencent.**
-keep public class com.umeng.soexample.R$*{
public static final int *;
}
-keep class com.tencent.open.TDialog$*
-keep class com.tencent.open.TDialog$* {*;}
-keep class com.tencent.open.PKDialog
-keep class com.tencent.open.PKDialog {*;}
-keep class com.tencent.open.PKDialog$*
-keep class com.tencent.open.PKDialog$* {*;} -keep class com.sina.** {*;}
-dontwarn com.sina.**
-keep class com.alipay.share.sdk.** {*;}
七、常见的一些问题
1.网络层混淆
一般网络层都不进行混淆,可以经过划分包后直接不混淆网络层的包:
-keep class com.xxx.xxx.http.** {*;}
2.数据模型混淆
-keep class * implements java.io.Serializable {*;}
-keepclassmembers class * implements java.io.Serializable {*;}
有时候上面的这种方式可能会导致应用卡住,没有任何错误提示,所以建议采用分包模式,吧所有bean放在同一个包中,直接对该包加白名单。
-keep class com.xxx.xxx.domain.xx {*;}
3.XML映射混淆
如果遇到一些空间无法Inflate,报NullPointException,比如ListView,NavigationView等等
-keep class *.** {*;}
4.混淆规则编写方法
如果混淆后报错,通过retrace后找到错误的问题后可以直接编写规则来去掉混淆,但是如果报的错误莫名其妙,而且报错的类没有混淆,那么可以采用极端的方法,加入下面的规则:
-keep class *.** {*;}
这条规则表示不混淆所有类及其中所有代码,加了这条规则之后,还不能运行表示是其他问题,例如注解,内部类等等,可以运行后,可以通过反编译,寻找所有包名,记录下来,吧上述规则改为:
-keep class android.** {*;}
-keep class com.** {*;}
-keep class org.** {*;}
一个个去掉检查是否有报错,例如查到
-keep class com.** {*;}
加了就没有错误,则可以继续一级级往下检查。
但要注意,有时候可能是几个包混合问题。
参考文章:
http://mp.weixin.qq.com/s/WmJyiA3fDNriw5qXuoA9MA
http://www.jianshu.com/p/7436a1a32891#
http://www.2cto.com/kf/201607/530170.html
Android混淆的更多相关文章
- android混淆那些事
写给Android开发者的混淆使用手册 综述 毫无疑问,混淆是打包过程中最重要的流程之一,在没有特殊原因的情况下,所有 app 都应该开启混淆. 首先,这里说的的混淆其实是包括了代码压缩.代码混淆以及 ...
- Android混淆打包配置总结
Android打包失败出现Proguard returned with error code 1. See console的错误 这个问题是由于代码混淆引起的,找不到引用包. 只需在你的proguar ...
- Android混淆那些事儿
博客: 安卓之家 微博: 追风917 CSDN: 蒋朋的家 简书: 追风917 博客园:追风917 # Android混淆 Android混淆是Android开发者经常使用的一种用于代码防止被反编译的 ...
- Android混淆、反编译以及反破解的简单回顾
=========================================================================虽然反编译很简单,也没下面说的那么复杂,不过还是转了过 ...
- Android 混淆那些事儿
本文来自于腾讯Bugly公众号(weixinBugly),未经作者同意,请勿转载,原文地址:https://mp.weixin.qq.com/s/WmJyiA3fDNriw5qXuoA9MA 作者:l ...
- android -------- 混淆打包报错(warning - InnerClass annotations are missing corresponding EnclosingMember annotations)
最近做Android混淆打包遇到一些问题,Android Sdutio 3.1 版本打包的 错误如下: Android studio warning - InnerClass annotations ...
- Android 混淆代码有关问题总结
Android 混淆代码问题总结 Android 混淆代码: 最快的方式: 1. 首先更新Android的SDK至最新版本,重新建立1个工程,把源码和资源及其他文件拷到新的工程里面. 2. 工程目录底 ...
- Android 混淆[学习笔记]
Android 混淆 Gradle的简介: http://www.flysnow.org/2015/03/30/manage-your-android-project-with-gradle.html ...
- Android混淆代码
Android代码混淆是必须的,java层代码如果不做混淆等于把源代码送人了.那如何做混淆呢? 之前一般都是提到采用proguard.cfg,但使用新版本ADT后没有这个文件了,取而代之的是progu ...
- Android混淆打包
一.理论知识 ProGuard是一款免费的Java类文件压缩器.优化器和混淆器.它能发现并删除无用类.字段(field).方法和属性值(attribute).它也能优化字节码并删除无用的指令.最后 ...
随机推荐
- PHP导出生成CSV文件
composer 用起来是非常方便的 所以我是依赖composer来做的包管理 1.先安装composer 自行百度一下composer安装以及使用 2.用composer下载安装office包即可 ...
- repo版本切换
repo init -u https://android.googlesource.com/platform/manifest repo sync 之后 这样初始化之后,相当于下载了全部的分支, 本想 ...
- 002---第一个Hibernate示例
Hibernate压缩文件结构 下载Hibernate压缩文档,下面为文件结构: Hibernate3.jar:为Hibernate的核心jar包: build.xml:重新打包配置文件 build. ...
- java 与操作系统进程同步问题(二)————经典消费者生产者问题
http://www.cnblogs.com/zyp4614/p/6033757.html (java 与操作系统进程同步问题(一)----互斥问题) 今天写的是最经典的生产者消费者问题,最简单的版本 ...
- DDD理论学习系列(4)-- 领域模型
DDD理论学习系列目录 1.引言 我们还是先来拆词理解,领域模型可以拆为"领域"和"模型"二词. 领域:按照我们之前的文章的理解,DDD中的领域是指软件系统要解 ...
- Redis 小白指南(三)- 事务、过期、消息通知、管道和优化内存空间
Redis 小白指南(三)- 事务.过期.消息通知.管道和优化内存空间 简介 <Redis 小白指南(一)- 简介.安装.GUI 和 C# 驱动介绍> 讲的是 Redis 的介绍,以及如何 ...
- Java对【JSON数据的解析】--Gson解析法
Gson和fastjson分别为谷歌和阿里巴巴对JSON数据进行处理封装的jar包 两者异同点: 相同点:都是根据JSON数据创建相应的类 不同点: 1.调用方式区别 谷歌:方法都是非静态的,需要先创 ...
- 影响国内WinCE7发展的最大障碍是没有D版下载
WinCE红火的时代已经过去,做嵌入式系统时考虑WinCE的越来越少,网络上相关文章也是越来越少. 但真正用过WinCE的应该有体会,它集成了文件系统,tcp/ip,GUI系统,usb驱动,就这些,你 ...
- Windows server 2008 r2 开启Aero
1.右键“计算机”----“管理”----“添加功能”,选上“桌面体验”,一般来说要把服务器系统做成工作 站的话,最好再选上“优质WINDOWS音频视频体验”,如果有无线网卡再选上“无线LAN服务”, ...
- 隐马尔科夫模型HMM(四)维特比算法解码隐藏状态序列
隐马尔科夫模型HMM(一)HMM模型 隐马尔科夫模型HMM(二)前向后向算法评估观察序列概率 隐马尔科夫模型HMM(三)鲍姆-韦尔奇算法求解HMM参数 隐马尔科夫模型HMM(四)维特比算法解码隐藏状态 ...