current position:Home>Android proguard code obfuscation and decompilation tool

Android proguard code obfuscation and decompilation tool

2023-01-25 11:29:56Someone from Yungu Li

开启混淆

在build.gradle的buildTypesYou can turn on the confusion by adding the following dependencies in ;

    buildTypes {
    
        debug {
    
            // 开启混淆
            minifyEnabled true
            // 开启资源压缩,编译时会自动删除未使用到的res资源
            shrinkResources true
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
        release {
    
            //开启混淆会导致编译速度变慢,debug通常不开启
            minifyEnabled false
            shrinkResources false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }

ProguardConfused Flowchart

在这里插入图片描述
含义解释:

  • 压缩(Shrink): 检测并删除未使用的类,字段,方法和属性.
  • 优化(Optimize): Analyze and optimize the bytecode of the method.
  • 混淆(Obfuscate): Use short meaningless names ega,b,c等,重命名类,字段和方法.
  • 预检(Preveirfy): 主要是在Java平台上对处理后的代码进行预检.

输入/输出配置项

  • @filename

等同于:-include filename,filename 文件名.

  • -include [filename]

从给定文件中读取配置项,filename 文件名.

  • -basedirectory [directoryname]

为后续的相对文件指定基础目录,directoryname 目录名.

  • injars [classPath]

指定要处理的输入jar(等压缩包),包中的class文件会被处理后输出到outjars的指定路径下,非class文件直接输出到outjars指定路径,classpath jar包输入路径.

  • outjars [classPath]

指定输出路径,接收injars的文件输出,classPath 输出路径.

  • libraryjars [classPath]

指定不被混淆的jar,classPath 文件路径.

压缩配置项

  • -dontshrink

不进行代码压缩,默认会进行代码压缩,打开此配置项则不进行压缩.

  • -printusage [fileName]

将被压缩的代码输出到指定路径.

优化配置项

  • -dontoptimize

指定不进行代码优化,默认情况下ProGuard会优化所有代码.

  • -optimizationpasses n

指定代码迭代优化的次数,默认执行一遍.

混淆配置

  • -dontobfuscate
    不进行混淆,默认会进行代码混淆.

  • -printmapping [filename]

将混淆前后映射表输出到指定文件.

  • -dontusemixedcaseclassnames

混淆时不使用大小写混合,混淆后类名为小写.

  • -keepattributes [attribute_filter]

指定要保留的属性,如:-keepattributes Exceptions,InnerClasses

  • -dontpreverify

指定不预先验证已处理的类文件. 默认情况下,如果目标版本是Java Micro Edition或Java 6或更高版本,Class files will be pre-validated. 对于Java Micro Edition,需要进行预验证,因此,如果指定此选项,Then you need to run an external prevalidator on the processed code. 对于Java 6,Pre-authentication is not required yet,但可以提高Java虚拟机中类加载的效率.androidThis option is generally configured in the project.

通用配置项

  • -verbose

指定在处理期间输出更多信息.如果程序因异常终止,此选项将打印出整个堆栈跟踪,而不仅仅是异常消息.

  • -dontnote [class_filter]

指定不打印匹配类的相关异常信息,class_filter为正则表达式,符合表达式的类不打印信息.

  • -dontwarn [class_filter]

指定相关类不发出警告,class_filter为正则表达式.如:-dontwarn androidx.**
Specifies not to warn about unresolved references and other important issues.Optional filter is a regular expression; proguardNo warnings are printed for classes matching about-names.忽视警告可能很危险,If an unprocessed class or class member does need to be processed,则处理后的代码将无法正常运行.Use this option only when we know there is no risk,例如,androidis ignored in the default obfuscation configurationsupport包或androidxWarnings for all classes in the package,因为support包或androidxPackages are usually fine.

  • -dump [filename]

将所有class的内部结构输出到指定文件.如:-dump proguard/class_files.txt

keep配置项

保留内容Prevent from being deleted or renamed防止被重命名
类和类成员-keep-keepnames
仅类成员-keepclassmembers-keepclassmembersnames
If the class member exists,保留类和类成员-keepclasseswithmembers-keepclasseswithmembernames
  • -keep

指定要保留的类和类成员.

//View子类,类名不混淆
- keep public class * extends android.view.View{
    
 		//set开头的方法不混淆
    void set*(***);
  	//构造函数不混淆
    public <init>(android.content.Context);
    public <init>(android.content.Context, android.util.AttributeSet);
    public <init>(android.content.Context, android.util.AttributeSet, int);
}

指定的类名和类成员不被混淆,需要注意的是以下配置只能保证类名不被混淆.

-keep public class * extends android.app.Activity

想要类名和类成员全部不混淆应该使用:

-keep public class * extends android.app.Activity{
    *;}
  • - keepclassmembers

保留指定的类成员.

//指定不混淆的类成员,类名会混淆
-keepclassmembers class * {
    
    //事件监听类(参数符合**On*Event)的方法不混淆
    void *(**On*Event);
}
  • -keepclasseswithmembers

在所有类成员都存在的情况下,指定要保留的类和类成员.

//需要匹配类和所有指定成员都存在的类,类和类成员不混淆
-keepclasseswithmembers class * {
    
    public <init>(android.content.Context, android.util.AttributeSet);
    public <init>(android.content.Context, android.util.AttributeSet, int);
}
  • -keepnames/-keepclassmembernames和-keepclasseswithmembernames

简单来说使用-keep/-keepclassmember和-keepclasseswithmember可能会阻止成员被压缩优化,而使用-keepnames/-keepclassmembernames和-keepclasseswithmembernames而不会.

通配符

名称含义
?匹配名称中的任意单个字符
*匹配名称中任意多个字符,不包含包分隔符和目录分隔符,用在类体中可以匹配任意字段和方法
**匹配名称中任何部分,May contain package separators
< n >在相同选项中匹配第n个匹配的通配符
***匹配任何类型(Primitive or non-primitive,array or non-array)
Matches any number of arguments of any type
Matches any primitive type(“ boolean”,“ int”等,但不匹配“ void”)
< init >matches any constructor
< fields >matches any field
< methods >matches any method

proguard常用配置规则

  • 1.常用配置
-optimizationpasses 5
# 混淆时不使用大小写混合,混淆后的类名为小写
-dontusemixedcaseclassnames
# 指定不去忽略非公共库的类
-dontskipnonpubliclibraryclasses
# 指定不去忽略非公共库的成员
-dontskipnonpubliclibraryclassmembers
# 混淆时不做预校验
-dontpreverify
# 混淆时不记录日志
-verbose
# 代码优化
-dontshrink
# 不优化输入的类文件
-dontoptimize
# 保留注解不混淆
-keepattributes *Annotation*,InnerClasses
# 避免混淆泛型
-keepattributes Signature
# 保留代码行号,方便异常信息的追踪
-keepattributes SourceFile,LineNumberTable
# 混淆采用的算法
-optimizations !code/simplification/cast,!field/*,!class/merging/* # dump.txt文件列出apk包内所有class的内部结构 -dump proguard/class_files.txt # seeds.txt文件列出未混淆的类和成员 -printseeds proguard/seeds.txt # usage.txt文件列出从apk中删除的代码 -printusage proguard/unused.txt # mapping.txt文件列出混淆前后的映射 -printmapping proguard/mapping.txt 
  • 2. Android 系统类

Android类

-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

support包

# support
-keep class android.support.** {
    *;}
-keep public class * extends android.support.**
-dontwarn android.support.**
-keep interface android.support.** {
     *; }

androidx包

# androidx
-keep class androidx.** {
    *;}
-keep interface androidx.** {
    *;}
-keep public class * extends androidx.**
-dontwarn androidx.**

自定义控件get/set和构造

# 自定义控件
-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);
}

R文件

# R文件
-keep class **.R$* {
    
 *;
}

webview

# webview
-keepclassmembers class android.webkit.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, *);
}

android事件方法

# 按键等事件
-keepclassmembers class * {
    
    void *(**On*Event);
}
# onClick
-keepclassmembers class * extends android.app.Activity{
    
    public void *(android.view.View);
}

枚举类型

-keepclassmembers enum * {
    
    public static **[] values();
    public static ** valueOf(java.lang.String);
}

其他类

# native方法
-keepclasseswithmembernames class * {
    
    native <methods>;
}
# View构造方法
-keepclasseswithmembers class * {
    
    public <init>(android.content.Context, android.util.AttributeSet);
    public <init>(android.content.Context, android.util.AttributeSet, int);
}
# Parcelable
-keep class * implements android.os.Parcelable {
    
  public static final android.os.Parcelable$Creator *;
}
# Serializable
-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();
}

反编译工具

  • apk文件的处理

xml文件处理

apktool下载地址:https://ibotpeaches.github.io/Apktool/

xmlFile decompilation command:

apktool.bat d  (apk的路径) -f -o (Unzip to the destination folder)

d : 解码(decode缩写)的意思

-f : Force delete the target directory,Used when trying to decode to a folder that already exists

-o: apkThe name of the folder to be written

构建apk命令:

apktool b (目标文件夹)

Rebuild from the target folderAPK,生成的APK在"目标文件夹"\dist文件夹里

  • dex文件处理

1、dex得到jar 文件

dex2jar.bat下载地址:https://sourceforge.net/projects/dex2jar/

​ 2、jar得到java 代码

jd-gui下载地址:http://jd.benow.ca/

反编译dex文件步骤:

1.dex2jar.bat先解压出来

2.配置dex2jardirectory into the system variable(防止找不到)

3.把apkExtract the directoryclasses.dex到上面的目录中

4.cd (dex2jar的完整路径)进入到目录下面,执行命令

d2j-dex2jar.bat -f D:\dex2jar-2.0\classes.dex(This is my localclass.dex完整路径)

At this time, a similar one will be generatedclasses-dex2jar.jar的压缩文件(在c盘)

Use it directly after downloadingjd-gui打开上面class-dex2jar.jarThe compressed package can view the complete code.

If the above finds it troublesome,You can use the following decompilation artifact:

https://github.com/skylot/jadx/releases/tag/v1.3.1

copyright notice
author[Someone from Yungu Li],Please bring the original link to reprint, thank you.
https://en.cdmana.com/2023/025/202301251120396416.html

Random recommended