美文网首页
Android混淆总结

Android混淆总结

作者: 聽媽媽的话 | 来源:发表于2017-05-07 22:26 被阅读23次

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

    反编译

    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);
    }
    #----------------------------------------------------------------------------
    #------------------------------------------------
    
    

    相关文章

      网友评论

          本文标题:Android混淆总结

          本文链接:https://www.haomeiwen.com/subject/wnxptxtx.html