混淆

作者: 闫鹏飞写字的地方 | 来源:发表于2021-10-28 16:17 被阅读0次
    学单词
    Pro

    美 /proʊ/
    n. 职业选手;益处;妓女;赞成者;赞成的意见
    adj. (非正式)专业的,职业的
    prep. 赞成的
    adv. 赞成地
    n. (Pro)(俄、美、意、印、西)普罗(人名)

    Guard

    美 /ɡɑːrd/
    n. 卫兵,警卫;看守,守卫;列车长;保护装置;(英国的)禁卫军;(篮球)后卫;(拳击运动员的)防御姿势
    v. 守卫,保卫;看守,监视;警惕,防范;保护,维护
    【名】(Guard)(英)格尔德(人名)
    n. (Guard)人名;(英)格尔德

    1.简介

    Android Studio自身集成Java语言的ProGuard作为压缩,优化和混淆工具,配合Gradle构建工具使用很简单,只需要在工程应用目录的gradle文件中设置minifyEnabledtrue即可。然后我们就可以到proguard-rules.pro文件中加入我们的混淆规则了。

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

    美 /ˈʃrɪŋkɪŋ/
    v. 缩水,收缩;变小,缩小;萎缩;退缩;回避,离开(shrink 的现在分词)

    Shrink

    美 /ʃrɪŋk/
    v. (使)缩小,减少;(通常指布料、衣服等洗后)缩水,皱缩;退缩,畏缩;畏避,回避(工作、责任等)
    n. <非正式> 精神病学家,心理学家;收缩;畏缩

    Optimization

    美 /,ɑptəmɪ'zeʃən/
    n. 最佳化,最优化

    Obfuscation

    英 /ˌɒbfʌsˈkeɪʃn/
    n. 困惑;模糊;昏迷

    2.ProGuard作用

    2.1压缩(Shrinking):默认开启,用以减小应用体积,移除未被使用的类和成员,并且会在优化动作执行之后再次执行(因为优化后可能会再次暴露一些未被使用的类和成员)。

    -dontshrink 关闭压缩
    

    2.2优化(Optimization):默认开启,在字节码级别执行优化,让应用运行的更快。

    -dontoptimize  关闭优化
    

    -optimizationpasses n 表示proguard对代码进行迭代优化的次数,Android一般为5

    2.3混淆(Obfuscation):默认开启,增大反编译难度,类和类成员会被随机命名,除非用keep保护。

    -dontobfuscate 关闭混淆
    

    混淆后默认会在工程目录app/build/outputs/mapping/release下生成一个mapping.txt文件,这就是混淆规则,我们可以根据这个文件把混淆后的代码反推回源本的代码,所以这个文件很重要,注意保护好。原则上,代码混淆后越乱越无规律越好,但有些地方我们是要避免混淆的,否则程序运行就会出错,所以就有了下面我们要教大家的,如何让自己的部分代码避免混淆从而防止出错。

    2.查看混淆后的代码

    2.1工具包
    dex2jar 0.0.9.15JD-GUIapktool
    https://pan.baidu.com/s/12ZApUf_7q0IZIK-x2C34VQ
    提取码w000

    2.2下载并解压


    image.png

    2.3使用dex2jar反编译dex文件
    将需要反编译的APK后缀名改为.rar或则.zip,解压看到目录

    image.png

    得到其中的classes.dex文件(它就是java文件编译再通过dx工具打包而成的)

    2.4将获取到的classes.dex复制到解压出来的工具dex2jar文件夹内,

    image.png

    2.5在命令行下,进入到dex2jar.bat所在目录,输入命令:
    dex2jar 0.0.9.15输入dex2jar.bat classes.dex
    dex2jar-2.0输入:d2j-dex2jar.bat classes.dex

    image.png

    简单命令

    //打开D盘
    d: 
    //查看当前文件列表
    dir
    //打开软件目录
    cd 软件
    

    2.6运行结束后,在该目录下会生成一个classes_dex2jar.jar的文件

    image.png

    2.7然后打开工具jd-gui文件夹里的jd-gui.exe,用该工具打开生成的classes_dex2jar.jar文件,便可以看到源码

    image.png

    tip:如果打开找不到自己写的源码,可以解压classes_dex2jar.jar文件,可看到要找的源码,拖拽代码到jd-gui中即可查看代码

    3.混淆基本规则

    3.1

    -keep class com.example.myapplication.*
    -keep class com.example.myapplication.**
    

    *一颗星表示只是保持该包下的类名,而子包下的类名还是会被混淆;
    **两颗星表示把本包和所含子包下的类名都保持;
    用以上方法保持类后,你会发现类名虽然未混淆,但里面的具体方法和变量命名还是变了

    eg:
    混淆前

    image.png

    混淆后
    *一颗星

    image.png

    **两颗星

    image.png

    3.2
    如果既想保持类名,又想保持里面的内容不被混淆,我们就需要以下方法了

    -keep class com.example.myapplication.* {*;}
    -keep class com.example.myapplication.** {*;}
    

    混淆后
    * {*;}一颗星

    image.png

    ** {*;}两颗星

    image.png image.png

    3.3
    在此基础上,我们也可以使用Java的基本规则来保护特定类不被混淆,比如我们可以用extendimplement等这些Java规则。如下例子就避免所有继承Activity的类被混淆

    -keep public class * extends android.app.Activity
    

    混淆后

    image.png

    3.4
    如果我们要保留一个类中的内部类不被混淆则需要用$符号,如下例子表示保持MainActivity内部类User中的所有public内容不被混淆。

    -keepclassmembers class com.example.myapplication.MainActivity$User {
       public *;
    }
    

    eg

    混淆前


    image.png

    没有对内部类处理的


    image.png

    对内部类处理的


    image.png

    3.5
    再者,如果一个类中你不希望保持全部内容不被混淆,而只是希望保护类下的特定内容,就可以使用

    <init>;     //匹配所有构造器
    <fields>;   //匹配所有域
    <methods>;  //匹配所有方法方法
    

    你还可以在<fields><methods>前面加上privatepublicnative等来进一步指定不被混淆的内容,如

    -keep class com.example.myapplication.entity.Person {
        public <methods>;
    }
    

    表示Person类下的所有public方法都不会被混淆,当然你还可以加入参数,比如以下表示用java.lang.Stringint作为入参的构造函数不会被混淆

    -keep class com.example.myapplication.entity.Person {
       public <init>(java.lang.String, int);
    }
    

    有时候你是不是还想着,我不需要保持类名,我只需要把该类下的特定方法保持不被混淆就好,那你就不能用keep方法了,keep方法会保持类名,而需要用keepclassmembers ,如此类名就不会被保持,为了便于对这些规则进行理解,官网给出了以下表格

    保留 防止被移除或者被重命名 防止被重命名
    类和类成员 -keep -keepnames
    仅类成员 -keepclassmembers -keepclassmembernames
    如果拥有某成员,保留类和类成员 -keepclasseswithmembers -keepclasseswithmembernames

    移除是指在压缩(Shrinking)时是否会被删除。

    4.注意事项

    1.jni方法不可混淆,因为这个方法需要和native方法保持一致;

    -keepclasseswithmembernames class * { # 保持native方法不被混淆    
        native <methods>;
    }
    

    2.反射用到的类不混淆(否则反射可能出现问题);
    3.AndroidMainfest中的类不混淆,所以四大组件和Application的子类和Framework层下所有的类默认不会进行混淆。自定义的View默认也不会被混淆;所以像网上贴的很多排除自定义View,或四大组件被混淆的规则在Android Studio中是无需加入的;
    4.与服务端交互时,使用GSONfastjson等框架解析服务端数据时,所写的JSON对象类不混淆,否则无法将JSON解析成对应的对象;
    5.使用第三方开源库或者引用其他第三方的SDK包时,如果有特别要求,也需要在混淆文件中加入对应的混淆规则;
    6.有用到WebViewJS调用也需要保证写的接口方法不混淆,原因和第一条一样;
    7.Parcelable的子类和Creator静态成员变量不混淆,否则会产生Android.os.BadParcelableException异常;

    -keep class * implements Android.os.Parcelable { # 保持Parcelable不被混淆           
        public static final Android.os.Parcelable$Creator *;
    }
    

    8.使用enum类型时需要注意避免以下两个方法混淆,因为enum类的特殊性,以下两个方法会被反射调用,见第二条规则。

    -keepclassmembers enum * {  
        public static **[] values();  
        public static ** valueOf(java.lang.String);  
    }
    
    4.出错后如何排查问题

    4.1开启调试模式下混淆代码

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

    4.2查看mapping.txt文件
    它里面存放着源码到混淆之后的代码的映射信息,这个文件是在我们执行proguard之后产生的

    image.png

    4.3制造一个混淆代码的Crash

    public class TestProGuard {
    
        private static final String TAG = "TestProGuard";
    
        public static void beforeProGuard(){
            Log.d(TAG, "beforeProGuard");
            createAnCrash();
        }
    
        private static void createAnCrash() {
            throw new IllegalArgumentException("IllegalArgumentException");
        }
    
    }
    
    public class MainActivity extends AppCompatActivity {
    
    
        private Person person;
        private User user;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            TestProGuard.beforeProGuard();
    ...
    

    运行之后Logcat日志:

    image.png

    4.3如何还原

    mapping文件位置

    image.png

    我们来到sdk/tools/proguard/bin目录下,打开proguardgui.bat文件

    image.png

    双击打开后


    image.png

    到这里即可排查出问题

    tip:如果你还没有看到行号可在混淆文件中放入

    -keepattributes SourceFile,LineNumberTable
    
    image.png

    完结

    相关文章

      网友评论

          本文标题:混淆

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