zoukankan      html  css  js  c++  java
  • apk反编译(6)用ProGuard 混淆、压缩代码,压缩资源。

    1.android官方文档

      https://developer.android.com/studio/build/shrink-code  主要内容如下:

    1.1 压缩代码

    • 混淆生成的文件:<module-name>/build/outputs/mapping/release/目录下 
    • 自定义要保留的代码,-keep与@keep
    • 解码混淆,使用 <sdk-root>/tools/proguard/ 下的工具。
    • 通过 Instant Run 启用代码压缩

    1.2 压缩资源

    • shrinkResources
    • 自定义要保留的资源
    • 启用严格引用检查
    • 移除未使用的备用资源
    • 合并重复资源
    • 排查资源压缩问题 

    1.3 官方proguard示例

       Android SDK/tools/proguard/proguard-android.txt 是默认混淆文件,同目录下的proguard-android-optimize.txt 是优化版本。

      在proguard/examples下有很多示例,如android.pro:

      1 #
      2 # This ProGuard configuration file illustrates how to process Android
      3 # applications.
      4 # Usage:
      5 #     java -jar proguard.jar @android.pro
      6 #
      7 # If you're using the Android SDK (version 2.3 or higher), the android tool
      8 # already creates a file like this in your project, called proguard.cfg.
      9 # It should contain the settings of this file, minus the input and output paths
     10 # (-injars, -outjars, -libraryjars, -printmapping, and -printseeds).
     11 # The generated Ant build file automatically sets these paths.
     12 
     13 # Specify the input jars, output jars, and library jars.
     14 # Note that ProGuard works with Java bytecode (.class),
     15 # before the dex compiler converts it into Dalvik code (.dex).
     16 
     17 # -injars  bin/classes
     18 # -injars  libs
     19 # -outjars bin/classes-processed.jar
     20 
     21 # -libraryjars /usr/local/android-sdk/platforms/android-9/android.jar
     22 #-libraryjars /usr/local/android-sdk/add-ons/google_apis-7_r01/libs/maps.jar
     23 # ...
     24 
     25 # Save the obfuscation mapping to a file, so you can de-obfuscate any stack
     26 # traces later on.
     27 
     28 -printmapping bin/classes-processed.map
     29 
     30 # You can print out the seeds that are matching the keep options below.
     31 
     32 #-printseeds bin/classes-processed.seeds
     33 
     34 # Preverification is irrelevant for the dex compiler and the Dalvik VM.
     35 
     36 -dontpreverify
     37 
     38 # Reduce the size of the output some more.
     39 
     40 -repackageclasses ''
     41 -allowaccessmodification
     42 
     43 # Switch off some optimizations that trip older versions of the Dalvik VM.
     44 
     45 -optimizations !code/simplification/arithmetic
     46 
     47 # Keep a fixed source file attribute and all line number tables to get line
     48 # numbers in the stack traces.
     49 # You can comment this out if you're not interested in stack traces.
     50 
     51 -renamesourcefileattribute SourceFile
     52 -keepattributes SourceFile,LineNumberTable
     53 
     54 # RemoteViews might need annotations.
     55 
     56 -keepattributes *Annotation*
     57 
     58 # Preserve all fundamental application classes.
     59 
     60 -keep public class * extends android.app.Activity
     61 -keep public class * extends android.app.Application
     62 -keep public class * extends android.app.Service
     63 -keep public class * extends android.content.BroadcastReceiver
     64 -keep public class * extends android.content.ContentProvider
     65 
     66 # Preserve all View implementations, their special context constructors, and
     67 # their setters.
     68 
     69 -keep public class * extends android.view.View {
     70     public <init>(android.content.Context);
     71     public <init>(android.content.Context, android.util.AttributeSet);
     72     public <init>(android.content.Context, android.util.AttributeSet, int);
     73     public void set*(...);
     74 }
     75 
     76 # Preserve all classes that have special context constructors, and the
     77 # constructors themselves.
     78 
     79 -keepclasseswithmembers class * {
     80     public <init>(android.content.Context, android.util.AttributeSet);
     81 }
     82 
     83 # Preserve all classes that have special context constructors, and the
     84 # constructors themselves.
     85 
     86 -keepclasseswithmembers class * {
     87     public <init>(android.content.Context, android.util.AttributeSet, int);
     88 }
     89 
     90 # Preserve the special fields of all Parcelable implementations.
     91 
     92 -keepclassmembers class * implements android.os.Parcelable {
     93     static android.os.Parcelable$Creator CREATOR;
     94 }
     95 
     96 # Preserve static fields of inner classes of R classes that might be accessed
     97 # through introspection.
     98 
     99 -keepclassmembers class **.R$* {
    100   public static <fields>;
    101 }
    102 
    103 # Preserve the required interface from the License Verification Library
    104 # (but don't nag the developer if the library is not used at all).
    105 
    106 -keep public interface com.android.vending.licensing.ILicensingService
    107 
    108 -dontnote com.android.vending.licensing.ILicensingService
    109 
    110 # The Android Compatibility library references some classes that may not be
    111 # present in all versions of the API, but we know that's ok.
    112 
    113 -dontwarn android.support.**
    114 
    115 # Preserve all native method names and the names of their classes.
    116 
    117 -keepclasseswithmembernames class * {
    118     native <methods>;
    119 }
    120 
    121 # Preserve the special static methods that are required in all enumeration
    122 # classes.
    123 
    124 -keepclassmembers class * extends java.lang.Enum {
    125     public static **[] values();
    126     public static ** valueOf(java.lang.String);
    127 }
    128 
    129 # Explicitly preserve all serialization members. The Serializable interface
    130 # is only a marker interface, so it wouldn't save them.
    131 # You can comment this out if your application doesn't use serialization.
    132 # If your code contains serializable classes that have to be backward 
    133 # compatible, please refer to the manual.
    134 
    135 -keepclassmembers class * implements java.io.Serializable {
    136     static final long serialVersionUID;
    137     static final java.io.ObjectStreamField[] serialPersistentFields;
    138     private void writeObject(java.io.ObjectOutputStream);
    139     private void readObject(java.io.ObjectInputStream);
    140     java.lang.Object writeReplace();
    141     java.lang.Object readResolve();
    142 }
    143 
    144 # Your application may contain more items that need to be preserved; 
    145 # typically classes that are dynamically created using Class.forName:
    146 
    147 # -keep public class mypackage.MyClass
    148 # -keep public interface mypackage.MyInterface
    149 # -keep public class * implements mypackage.MyInterface

    2.proguard官方教程

      https://www.guardsquare.com/en/products/proguard/manual   包含:

    • sdk/tools/proguard/bin/proguardgui.sh 界面工具教程
    • 混淆选项列表
    • 混淆示例
    • 解混淆
    • Gradle plugin 配置教程
    • 等等  

      sdk/tools/proguard/docs/index.html 是官方教程本地版本。

    2.1 混淆选项列表

      官方地址:https://www.guardsquare.com/en/products/proguard/manual/refcard

    @filename Short for '-include filename'.
    -include filename Read configuration options from the given file.
    -basedirectory directoryname Specifies the base directory for subsequent relative file names.
    -injars class_path

    Specifies the program jars (or apks, aabs, aars, wars,

    ears, jmods, zips, or directories).

    -outjars class_path

    Specifies the names of the output jars (or apks, aabs,

    aars, wars, ears, jmods, zips, or directories).

    -libraryjars class_path

    Specifies the library jars (or apks, aabs, aars, wars, ears,

    jmods, zips, or directories)

    -skipnonpubliclibraryclasses Ignore non-public library classes.
    -dontskipnonpubliclibraryclasses Don't ignore non-public library classes (the default).
    -dontskipnonpubliclibraryclassmembers Don't ignore package visible library class members.
    -keepdirectories [directory_filter]

    Keep the specified directories in the output jars (or wars,

    ears, zips, or directories).

    -target version Set the given version number in the processed classes.
    -forceprocessing Process the input, even if the output seems up to date.
    -keep [,modifier,...] class_specification Preserve the specified classes and class members.
    -keepclassmembers [,modifier,...] class_specification

    Preserve the specified class members, if their classes

    are preserved as well.

    -keepclasseswithmembers [,modifier,...] class_specification

    Preserve the specified classes and class members, if all

    of the specified class members are present.

    -keepnames class_specification

    Preserve the names of the specified classes and class

    members (if they aren't removed in the shrinking step).

    -keepclassmembernamesclass_specification

    Preserve the names of the specified class members

    (if they aren't removed in the shrinking step).

    -keepclasseswithmembernamesclass_specification

    Preserve the names of the specified classes and class

    members, if all of the specified class members are present

    (after the shrinking step).

    -if class_specification

    Specify classes and class members that must be present

    to activate the subsequent keep option.

    -printseeds [filename]

    List classes and class members matched by the various -keep options,

    to the standard output or to the given file.

    -dontshrink Don't shrink the input class files.
    -printusage [filename]

    List dead code of the input class files, to the standard output or

    to the given file.

    -whyareyoukeeping class_specification

    Print details on why the given classes and class members are

    being kept in the shrinking step.

    -dontoptimize Don't optimize the input class files.
    -optimizations optimization_filter The optimizations to be enabled and disabled.
    -optimizationpasses n The number of optimization passes to be performed.
    -assumenosideeffects class_specification

    Assume that the specified methods don't have any side effects,

    while optimizing.

    -assumenoexternalsideeffectsclass_specification

    Assume that the specified methods don't have any external side

    effects, while optimizing.

    -assumenoescapingparametersclass_specification

    Assume that the specified methods don't let any reference parameters

    escape to the heap, while optimizing.

    -assumenoexternalreturnvaluesclass_specification

    Assume that the specified methods don't return any external reference

    values, while optimizing.

    -assumevalues class_specification

    Assume fixed values or ranges of values for primitive fields and

    methods, while optimizing.

    -allowaccessmodification

    Allow the access modifiers of classes and class members to be

    modified,while optimizing.

    -mergeinterfacesaggressively Allow any interfaces to be merged, while optimizing.
    -dontobfuscate Don't obfuscate the input class files.
    -printmapping [filename]

    Print the mapping from old names to new names for classes and

    class members that have been renamed, to the standard output

    or to the given file.

    -applymapping filename Reuse the given mapping, for incremental obfuscation.
    -obfuscationdictionary  filename   可自定义混淆字符

    Use the words in the given text file as obfuscated field names and

    method names.

    -classobfuscationdictionary filename Use the words in the given text file as obfuscated class names.
    -packageobfuscationdictionaryfilename Use the words in the given text file as obfuscated package names.
    -overloadaggressively Apply aggressive overloading while obfuscating.
    -useuniqueclassmembernames

    Ensure uniform obfuscated class member names for subsequent

    incremental obfuscation.

    -dontusemixedcaseclassnames Don't generate mixed-case class names while obfuscating.
    -keeppackagenames [package_filter] Keep the specified package names from being obfuscated.
    -flattenpackagehierarchy[package_name]

    Repackage all packages that are renamed into the single given

    parent package.

    -repackageclasses [package_name] Repackage all class files that are renamed into the single given package.
    -keepattributes [attribute_filter]

    Preserve the given optional attributes; typically 可选的属性有:[

    Exceptions,InnerClassesSignatureDeprecated,

    SourceFileSourceDirLineNumberTableLocalVariableTable

    LocalVariableTypeTableSyntheticEnclosingMethod,  *Annotation*].

    -keepparameternames Keep the parameter names and types of methods that are kept.
    -renamesourcefileattribute [string] Put the given constant string in the SourceFileattributes.
    -adaptclassstrings [class_filter]

    Adapt string constants in the specified classes, based on the

    obfuscated names of any corresponding classes.

    -adaptresourcefilenames [file_filter]

    Rename the specified resource files, based on the obfuscated

    names of the corresponding class files.

    -adaptresourcefilecontents [file_filter]

    Update the contents of the specified resource files, based on the

    obfuscated names of the processed classes.

    -dontpreverify Don't preverify the processed class files.
    -microedition Target the processed class files at Java Micro Edition.
    -android Target the processed class files at Android.
    -verbose Write out some more information during processing.
    -dontnote [class_filter] Don't print notes about potential mistakes or omissions in the configuration.
    -dontwarn [class_filter] Don't warn about unresolved references at all.
    -ignorewarnings

    Print warnings about unresolved references, but continue processing

    anyhow.

    -printconfiguration [filename]

    Write out the entire configuration, in traditional ProGuard style,

    to the standard output or to the given file.

    -dump [filename]

    Write out the internal structure of the processed class files,

    to the standard output or to the given file.

    -addconfigurationdebugging

    Instrument the processed code with debugging statements that

    print out suggestions for missing ProGuard configuration.

    2.2 混淆选项通配符

      Keep 选项后面的匹配条件中,经常需要用到通配符,例如上面默认 proguard-android.txt 规则中的 void set*(***);。

      常见的通配符如下:

    通配符描述
    <init> 匹配所有构造函数
    <fields> 匹配所有字段
    <methods> 匹配所有方法,不包括构造函数
    ? 匹配任意单个字符
    % 匹配任意原始数据类型,例如 boolean、int,但是不包括 void
    * 匹配任意长度字符,但是不包括包名分隔符( . ),例如 android.support.* 不匹配 android.support.annotation.Keep
    ** 匹配任意长度字符,包括包名分隔符( . ),例如 android.support.** 匹配 support 包下的所有类
    *** 匹配任意类型,包括原始数据类型、数组
    匹配任意数量的任意参数类型

    2.3 解混淆

    • debug版本

        如果有异常,直接点击行号就可以了。下图第25行。

        

    • release版本:

        找到对应版本的mapping.txt以及对应的异常日志,如果没有日志可以从android studio logcat中复制,

        1.打开ProGuard图形工具,选择左侧ReTrace 栏

        2.在右侧Mapping file中找到对应的mapping.txt

        3.把异常的堆栈信息复制到Obfuscated stack track中,或者点Load stack trace...按钮找到对应的文件。

        4.点右下角ReTrace!按钮。

        

      

    3.哪些不应该混淆

      对于某些情况,ProGuard 会移除所有(并且只会移除)未使用的代码。不过,ProGuard 难以对许多情况进行正确分析,可能会移除应用真正需要的代码。

    不该混淆

    原因
    当应用引用的类只来自 AndroidManifest.xml 文件时

    混淆处理之后,类名就会被篡改,实际使用的类与 manifest 中注册的类并不匹配,出错。

    如android常用4组件和Application类

    当应用调用的方法来自 Java 原生接口 (JNI) 时

     
    混淆后,会找不对对应的方法的实现

    当应用在运行时(例如使用反射或自检)操作代码时

    混淆后,找不到相应的名字,经常发生 NoSuchMethodException 和

     NoSuchFiledException 异常

    序列化的类

    经过混淆的"洗礼"之后,序列化之后的 value 对应的 key 已然变为没有意义的字段。

    同时,反序列化的过程创建对象从根本上来说还是借助于反射,混淆之后 key会被改变,

    所以也会违背我们预期的效果。

    枚举

    枚举类内部存在 values 方法,混淆后该方法会被重新命名,并抛出 NoSuchMethodException

    Android 系统默认的混淆规则文件中已经添加了对于枚举类的处理,无需再去做额外工作。

    自定义控件不需要被混淆

    view的一些回调方法会被修改,导致出错或者显示不正常。 

    JavaScript 调用 Java 的方法不应混淆

    容易找不到方法

    第三方库也不建议混淆

    通常第3库以jar或者so方式存在,工具很难分析其中的调用关系。容易出错。

    注解不能混淆

    很多场景下注解被用作在运行时反射确定一些元素的特征,Android工程默认的混淆配置

    已经包含了保留注解的配置。

    4.自定义混淆字典

    4.1 以自定义混淆字典选项

    • -obfuscationdictionary filename            混淆属性名、方法名参考的字典
    • -classobfuscationdictionary filename      混淆类参考的字典
    • -packageobfuscationdictionary filename  混淆包名参考的字典

    4.2 混淆字典规则

    • 一行一个单词
    • 空行、空格忽略,
    • 标点符号无效
    • 重复的字符被忽略 
    • # 后面的字符忽略
    • 混淆属性和方法时,最好使用类对应的class文件中经存在的字符

    4.3 android提供的字典示例

      在sdk/tools/proguard/examples/dictionaries/ 目录下有字典示例:

      

    4.4 使用混淆字典

      可把一份字典示例文件(如 windows.txt)或者自定义一个字典文件复制到项目中,与proguard-rules.pro同级。

      在proguard-rules.pro中添加混淆选项,然后开始生成apk。

    1 -obfuscationdictionary windows.txt
    2 -classobfuscationdictionary windows.txt
    3 -packageobfuscationdictionary windows.txt

      如:

     

    5.实例

    5.1 自定义要保留的类或包

      打完包后,用android studio分析下它。打开其中的dex文件,选择要保留的类,或者包 -> 右键  -> Generate Proguard keep rule 

      复制其中的内容到 proguard-rules.pro 下。

    5.2 配置默认android混淆选项

      把  sdk/tools/proguard/examples/android.pro 内容复制到 proguard-rules.pro中

      把不必要的选项关掉。

    5.3 打开混淆开关

      在release配置里打开混淆开关

     1     ...
     2     buildTypes {
     3         release {
     4             minifyEnabled true
     5             shrinkResources true
     6             zipAlignEnabled = true
     7             proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
     8         }
     9         debug{
    10             minifyEnabled false
    11             shrinkResources false
    12 //            useProguard false
    13             zipAlignEnabled = true
    14             proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
    15         }
    16     }
    17     ...

    5.4 混淆走掉 Log.e 等

    1 #-dontoptimize
    2 -assumenosideeffects class android.util.Log {
    3    public static boolean isLoggable(java.lang.String, int);
    4    public static int v(...);
    5    public static int i(...);
    6    public static int w(...);
    7    public static int d(...);
    8    public static int e(...);
    9 }
  • 相关阅读:
    nginx:安装成windows服务
    org.aspectj.apache.bcel.classfile.ClassFormatException: Invalid byte tag in constant pool: 18
    数据库中间件
    架构策略
    谈判
    设计模式 总结 常用10种
    08 状态模式 state
    07 策略模式 strategy
    06 命令模式(不用)
    05 观察者模式 Observer
  • 原文地址:https://www.cnblogs.com/mhbs/p/5111513.html
Copyright © 2011-2022 走看看