Android混淆总结

在了解混淆之前,先来了解一下反编译。

反编译

Android程序打完包之后得到的是一个APK文件,这个文件是可以直接安装到任何Android手机上的,我们反编译其实也就是对这个APK文件进行反编译。Android的反编译主要又分为两个部分,一个是对代码的反编译,一个是对资源的反编译。

代码反编译

要想将APK文件中的代码反编译出来,我们需要用到以下两款工具:
dex2jar 这个工具用于将dex文件转换成jar文件 下载地址:http://sourceforge.net/projects/dex2jar/files/
jd-gui 这个工具用于将jar文件转换成java代码 下载地址:http://jd.benow.ca/

将这两个工具都下载好并解压,然后我们就开始对Demo程序进行反编译。解压dex2jar压缩包后,你会发现有很多个文件,如下图所示:

Paste_Image.png

其中我们要用到的是d2j-dex2jar.bat这个文件,如果是linux或mac系统的话就要用d2j-dex2jar.sh这个文件。

接下来可以将要反编译的apk进行解压,先将后缀的“.apk”改为“.zip”,再进行解压,可以看到里面有一个文件classes.dex文件(这里还有一个classes2.dex是因为源apk方法数超过了65k,实行分包了),如下图:

Paste_Image.png

这个classes.dex文件就是存放所有java代码的地方了,我们将它拷贝到dex2jar解压后的目录下,并在cmd中也进入到同样的目录,然后执行:
d2j-dex2jar classes.dex
结果如下:

Paste_Image.png

执行成功后,在目录下会多一个文件classes-dex2jar.jar

Paste_Image.png

接下来再借助jd-gui.exe进行查看这个jar文件,如下图

Paste_Image.png

至此,代码反编译的工作就完成了。

资源反编译

原先解压出的apk里面,在res文件夹里面,其实已经有了大部分的资源了,但也仅仅是图片资源可以直接查看到,其余的xml打开都是被编译过的,无法直接读取到铭文,所以还需进行资源反编译。

要想将APK文件中的资源反编译出来,又要用到另外一个工具了:
apktool 这个工具用于最大幅度地还原APK文件中的9-patch图片、布局、字符串等等一系列的资源。 下载地址:http://ibotpeaches.github.io/Apktool/install/

这里只需要apktool.bat和apktool.jar这两个文件,将这两个文件放到同一个文件夹即可,如下图:

Paste_Image.png

同样通过cmd执行语句
apktool d demo.apk
执行结果如下图所示,表示反编译资源已经成功

Paste_Image.png

混淆

混淆的好处

1、减少apk文件大小,我尝试着把微博的apk资源进行混淆,apk文件由36.5M减少到35.6M;
2、增加反编译和二次打包的难度,混淆之后的apk不能用apktool之类的工具直接反编译。当然只是增加了难度,毕竟没有绝对安全;
3、减少运行时内存占用,在运行时各个res的key都是以String形式加载到内存中的,混淆之后key变短了很多内存占用肯定会变少。

混淆的原理

简单来说就是把方法,字段,包和类这些java 元素的名称改成无意义的名称,这样代码结构没有变化,还可以运行,但是想弄懂代码的架构却很难。 proguard 就是这样的混淆工具,它可以分析一组class 的结构,根据用户的配置,然后把这些class 文件的可以混淆java 元素名混淆掉。

常用语法

关键字

关键字 描述
keep 保留类和类中的成员,防止它们被混淆或移除。
keepnames 保留类和类中的成员,防止它们被混淆,但当成员没有被引用时会被移除。
keepclassmembers 只保留类中的成员,防止它们被混淆或移除。
keepclassmembernames 只保留类中的成员,防止它们被混淆,但当成员没有被引用时会被移除。
keepclasseswithmembers 保留类和类中的成员,防止它们被混淆或移除,前提是指名的类中的成员必须存在,如果不存在则还是会混淆。
keepclasseswithmembernames 保留类和类中的成员,防止它们被混淆,但当成员没有被引用时会被移除,前提是指名的类中的成员必须存在,如果不存在则还是会混淆。

通配符

通配符 描述
<field> 匹配类中的所有字段
<method> 匹配类中的所有方法
<init> 匹配类中的所有构造函数
* 匹配任意长度字符,但不含包名分隔符(.)。比如说我们的完整类名是com.example.test.MyActivity,使用com.*,或者com.exmaple.*都是无法匹配的,因为*无法匹配包名中的分隔符,正确的匹配方式是com.exmaple.*.*,或者com.exmaple.test.*,这些都是可以的。但如果你不写任何其它内容,只有一个*,那就表示匹配所有的东西。
** 匹配任意长度字符,并且包含包名分隔符(.)。比如proguard-android.txt中使用的-dontwarn android.support.**就可以匹配android.support包下的所有内容,包括任意长度的子包。
*** 匹配任意参数类型。比如void set*(***)就能匹配任意传入的参数类型,*** get*()就能匹配任意返回值的类型。
匹配任意长度的任意类型参数。比如void test(…)就能匹配任意void test(String a)或者是void test(int a, String b)这些方法。

其它常用语法

-libraryjars class_path 应用的依赖包,如android-support-v4  
-assumenosideeffects class_specification 假设调用不产生任何影响,在proguard代码优化时会将该调用remove掉。如system.out.println和Log.v等等  
-dontwarn [class_filter] 不提示warnning  

配置指令

代码压缩配置 shrinker配置

-dontshrink 声明不压缩文件.默认情况下,除了-keep相关指定的类,其它所有的**没有被引用到的类**都会被删除,每次优化(optimizate)操作之后也会执行一次压缩操作,因为每次优化操作可能删除一部分**不在需要的类**.
-printusage{filename} 将被删除的元素输出到文件,或者打印到保准输出流
whyareyoukeeping {class_specification} 打印为什么吗一个类或类的成员被保护,这对检查一个输出文件中的类的结果有帮助.

代码优化配置 optimizate配置

-dontoptimize 声明不优化的文件.默认情况下,优化选项是开启的,并且所有的优化都是在字节码层进行的.
-optimizations 更加细粒度的声明优化开启或者关闭.
**-optimizationpasses n **指定执行几次优化,默认情况只执行一次优化,执行多次优化可以提高优化的效果.但是如果执行一次优化之后没有效果,就会停止优化,剩下的设置次数不在执行.

其它配置

-dontusemixedcaseclassnames 表示混淆时不使用大小写混合类名。
-dontskipnonpubliclibraryclasses表示不跳过library中的非public的类。
-verbose表示打印混淆的详细信息。
-dontpreverify表示不进行预校验。这个预校验是作用在Java平台上的,Android平台上不需要这项功能,去掉之后还可以加快混淆速度。
-keepattributes *Annotation*表示对注解中的参数进行保留。

举例说明

1.不混淆某个类的构造函数

例如不混淆Test类的构造函数

-keepcalssmembers clsss com.freezing.example.Text{
    public <init>(int,int)
}

2.不混淆某个包下所有的类或者指定的类

例如不混淆package com.freezing.example下的所有的类/接口
-keep class com.freezing.example.**{*;}

例如不混淆com.freezing.example.Text类
-keep class com.freezing.example.Text{*;}

如果希望不混淆某个接口,则把上述命令的class替换为interface即可.

3.不混淆某个类的特定的函数

例如不混淆com.freezing.example.Test类中的setTestString函数

-keepclassmembers class com.freezing.example.Test{
    public void setTestString(java.lang.String);
}

4.不混淆某个类的子类,某个接口的实现

例如不混淆com.freezing.example.Test的子类
-keep public class * extend com.freezing.example.Test
例如不混淆com.freezing.example.TestInterface的实现

-keep class * implements com.freezing.example.TestInterface{
    public static final com.freezing.example.TestInterface$Creator *;
}

5.注意第三方依赖包

例如添加android-support-v4.jar依赖包

-libraryjars libs/android-support-v4.jar
-dontwarn android.support.v4.**{*;}
-keep class android.support.v4.**{*;}
-keep interface android.support.v4.**{*;}

注意添加dontwarn,因为默认情况下proguard会检查每一个引用是否正确,但是第三方库里往往有些不会用到的类,没有正确引用,所有如果不配置的话,系统会报错.

使用混淆文件

在项目的module.gradle里面有一段配置混淆的代码,如下:

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

其中minifyEnabled 设置为true则打包后的apk就会是混淆过的,并且只有正式版的apk会混淆,debug版的apk是不会被混淆的。

最后介绍一个通用的混淆配置,有需要可以直接拿来用

# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in E:\android\sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
#   http://developer.android.com/guide/developing/tools/proguard.html

# Add any project specific keep options here:

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
#   public *;
#}

#-------------------------------------------定制化区域----------------------------------------------
#---------------------------------1.实体类---------------------------------



#-------------------------------------------------------------------------

#---------------------------------2.第三方包-------------------------------




#-------------------------------------------------------------------------

#---------------------------------3.与js互相调用的类------------------------



#-------------------------------------------------------------------------

#---------------------------------4.反射相关的类和方法-----------------------



#----------------------------------------------------------------------------
#---------------------------------------------------------------------------------------------------

#-------------------------------------------基本不用动区域--------------------------------------------
#---------------------------------基本指令区----------------------------------
-optimizationpasses 5
-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-dontskipnonpubliclibraryclassmembers
-dontpreverify
-verbose
-printmapping proguardMapping.txt
-optimizations !code/simplification/cast,!field/*,!class/merging/*
-keepattributes *Annotation*,InnerClasses
-keepattributes Signature
-keepattributes SourceFile,LineNumberTable
#----------------------------------------------------------------------------

#---------------------------------默认保留区---------------------------------
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.app.backup.BackupAgentHelper
-keep public class * extends android.preference.Preference
-keep public class * extends android.view.View
-keep public class com.android.vending.licensing.ILicensingService
-keep class android.support.** {*;}

-keepclasseswithmembernames class * {
    native <methods>;
}
-keepclassmembers class * extends android.app.Activity{
    public void *(android.view.View);
}
-keepclassmembers enum * {
    public static **[] values();
    public static ** valueOf(java.lang.String);
}
-keep public class * extends android.view.View{
    *** get*();
    void set*(***);
    public <init>(android.content.Context);
    public <init>(android.content.Context, android.util.AttributeSet);
    public <init>(android.content.Context, android.util.AttributeSet, int);
}
-keepclasseswithmembers class * {
    public <init>(android.content.Context, android.util.AttributeSet);
    public <init>(android.content.Context, android.util.AttributeSet, int);
}
-keep class * implements android.os.Parcelable {
  public static final android.os.Parcelable$Creator *;
}
-keepclassmembers class * implements java.io.Serializable {
    static final long serialVersionUID;
    private static final java.io.ObjectStreamField[] serialPersistentFields;
    private void writeObject(java.io.ObjectOutputStream);
    private void readObject(java.io.ObjectInputStream);
    java.lang.Object writeReplace();
    java.lang.Object readResolve();
}
-keep class **.R$* {
 *;
}
-keepclassmembers class * {
    void *(**On*Event);
}
#----------------------------------------------------------------------------

#---------------------------------webview------------------------------------
-keepclassmembers class fqcn.of.javascript.interface.for.Webview {
   public *;
}
-keepclassmembers class * extends android.webkit.WebViewClient {
    public void *(android.webkit.WebView, java.lang.String, android.graphics.Bitmap);
    public boolean *(android.webkit.WebView, java.lang.String);
}
-keepclassmembers class * extends android.webkit.WebViewClient {
    public void *(android.webkit.WebView, jav.lang.String);
}
#----------------------------------------------------------------------------
#------------------------------------------------

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

推荐阅读更多精彩内容

  • 如何开启混淆 eclipse 只需要在工程中找到projiect.properties文件,在这个文件中修改下面一...
    mymdeep阅读 403评论 0 1
  • 混淆 关于混淆的概念请移步郭霖大神博客:Android安全攻防战,反编译与混淆技术完全解析(下)。小白必看,全面易...
    _戏_梦阅读 1,555评论 0 3
  • layout: wikititle: Android逆向分析笔记categories: Reverse_Engin...
    超哥__阅读 10,694评论 1 17
  • 图 文/钟意阅读 小悠悠是一只刚刚出生的毛毛虫。 清晨,当第一缕阳光洒满树梢的时候,小悠悠悄悄地探出头来,她有些好...
    叶听雨阅读 2,329评论 20 39
  • 【Week10周六小组会20170930】 🥇组会前集体打卡时间:5:20 组会时间:周日早上5:20-6:00(...
    平凡高杰阅读 346评论 0 0