混淆(Proguard R8)和反混淆

news2024/11/26 5:46:59

    本篇来介绍下Android的混淆和反混淆,说起混淆,大家都会很自然地想到Proguard,此外还有R8。事实上,AGP3.3之后,官方默认使用R8做代码优化、混淆和压缩。ProGuard和R8常常用于混淆最终的Android项目,增加项目被反编译的难度。

目录

一、ProGuard

二、R8

三、Proguard和R8对比

四、混淆

五、反混淆

1、mapping文件

2、proguardgui.sh


一、ProGuard

    ProGuard是一个压缩、优化和混淆Java字节码文件的免费的工具。混淆只是ProGuard的其中一项功能,ProGuard能够对Java类中的代码进行压缩(Shrink),优化(Optimize),混淆(Obfuscate),预检(Preveirfy)。以下是Proguard的工作流程:

1、压缩(Shrink)

删除没有使用的类,字段,方法和属性。

2、优化(Optimize)

对字节码进行优化,并且移除无用指令。

3、混淆(Obfuscate)

使用a,b,c等无意义的名称,对类,字段和方法进行重命名。

4、预检(Preveirfy)

在Java平台上对处理后的代码进行预检。

二、R8

    R8是一个将java字节码转换为优化的dex的工具。它遍历整个应用程序,然后对其进行优化,例如删除未使用的类、方法等。它可以帮助我们减少构建的大小并使我们的应用程序更加安全。R8使用Proguard的规则,R8比Proguard更快更强。

1、代码压缩

安全地从App及其库依赖项中删除未使用的类,字段,方法和属性。

2、资源压缩

从打包的App中删除未使用的资源,包括应用程序库依赖项中未使用的资源。它与代码压缩一起使用,这样一旦删除了未使用的代码,也可以安全地删除不再引用的资源。

3、代码混淆

使用简短无意义的名称重命名代码里的类,字段和方法,从而减少DEX文件大小。

4、代码优化

删除未使用的代码或重写代码使其更简洁。

三、Proguard和R8对比

    在使用 Proguard 时,应用程序代码由Java编译器转换为Java字节码.class文件。然后Proguard使用我们编写的规则对其进行优化产出优化后的.class文件,最后将其转换为可执行的Dalvik字节码。编译打包的流程如下:

 R8引入之后,代码的混淆和转换为dex通过R8一步完成,编译打包的流程如下:

1、R8 有效地内联容器类并删除未使用的类、字段和方法,包体积更小。

2、与 Proguard 相比,R8 对 Kotlin 的支持更多。

3、R8比 Proguard 更快,从而减少了整体构建时间。

四、混淆

虽然Android Studio已经默认使用R8作为编译器,但是仍然需要我们在build.gradle(app)中配置一下是否开启代码和资源压缩:

    buildTypes {
        release {
            // 是否开启代码压缩
            minifyEnabled true
            // 是否开启资源压缩
            shrinkResources true
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
            signingConfig signingConfigs.release
            android.applicationVariants.all { variant ->
                variant.outputs.all {
                    outputFileName = "demo_" + defaultConfig.versionName + "_release.apk"
                }
            }
        }
    }

 本篇我们使用如下demo,代码造了一个空指针异常,这是为后面反混淆准备的:

package com.example.proguarddemo;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.View;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {
    private TextView mTextView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mTextView = findViewById(R.id.crash);
        mTextView.setOnClickListener(v -> {
            mTextView = null;
            mTextView.setText("11111");
        });
    }
}

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/crash"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

    既然AS已经默认使用R8作为编译器,那么我们不再去对比Proguard和R8的包体积和编译速度,我们使用本篇博客的demo来对比下开R8和不开R8打release包的体积。

(1)不开R8:

(2)开R8,但不开资源压缩:

(3)开R8,开资源压缩:

 通过对比上面的包体积,可以看到,开了R8 + 资源压缩后,包体积缩减了55.6%。接下来,我们看下代码是否真的混淆了,装上打包后的release包,运行后点击textview,触发了崩溃,我们看下堆栈能不能看到源码:

2023-04-24 16:46:45.163 6037-6037/? E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.proguarddemo, PID: 6037
    java.lang.NullPointerException: throw with null exception
        at a1.a.onClick(SourceFile:5)
        at android.view.View.performClick(View.java:7281)
        at android.view.View.performClickInternal(View.java:7255)
        at android.view.View.access$3600(View.java:828)
        at android.view.View$PerformClick.run(View.java:27925)
        at android.os.Handler.handleCallback(Handler.java:900)
        at android.os.Handler.dispatchMessage(Handler.java:103)
        at android.os.Looper.loop(Looper.java:219)
        at android.app.ActivityThread.main(ActivityThread.java:8393)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:513)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1055)

可以看到,崩溃的堆栈是混淆后的,a1.a.onClick,代码确实是混淆后的,这增强了代码的安全性,让外人不那么容易反编译得到关键代码。

五、反混淆

    承接上文说到的,代码混淆后代码的安全性增强了。正式包发版后,针对线上的crash收集到的崩溃堆栈也是混淆后的,增加了crash问题排查定位的难度。那么,如何反混淆呢?

    混淆的原理是把一些类名、方法名、属性名等修改为无意义的字母等,降低代码可阅读性的同时,压缩代码体积。混淆的同时会生成一个mapping文件,记录的就是映射关系,通过映射关系可以拿到混淆前的类名和方法名。

     

1、mapping文件

打release包后,生成的mapping文件路径:app/build/outputs/mapping/release

2、proguardgui.sh

在sdk中有反混淆的工具:proguardgui.sh,可以帮助我们通过mapping文件解析崩溃堆栈。进入到Android/sdk/tools/proguard/bin,直接运行

./proguardgui.sh

会打开一个gui界面,选择mapping文件,粘贴crash堆栈后,点击Retrace!:

 可以看到,是MainActivity的onClick方法的第三行发生了空指针:

    本篇系统的介绍了Android的Proguard和R8,总结了二者的执行过程和对比,并通过实际的demo去验证R8优化后的包体积和混淆的结果。同时,也介绍了如何通过解析mapping的工具proguardgui.sh去辅助我们解析混淆后的crash堆栈,方便更快速的定位线上问题。如果对你有所帮助或启发,欢迎关注点赞。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/529237.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【加载更多 Objective-C语言】

一、咱们上午就做了两件事儿, 1.把我们的数据,加载起来, 2.实现了下面这个”加载更多“按钮的功能, 3.只不过,我们加载数据的时候,用了一个自定义cell, 那么,基本加载数据的办法,我就不再说了, 基本,就是那些步骤, 只是把我们自定义cell部分,再给大家复习一下…

【C语言】宏实现一个整数的二进制位的奇数位和偶数位交换

要写一个宏实现将一个整数的二进制位的奇数位和偶数位交换&#xff0c;我们首先要分析如何将一个整数的二进制位的奇数位和偶数位交换 以下以整数7为例 7的二进制&#xff1a; 0000 0000 0000 0000 0000 0000 0000 0111 7 奇数位与偶数位交换后为&#xff1a; 0000 0000 0000 …

一周狂赚50万,GPT-4帮你在线“脱单”,AI女友按分钟收费,在线男友数量多达1000+

电影情节照进现实 不知道大家有没有看过一部电影《她》&#xff0c;讲述的是在不远的未来人与人工智能相爱的科幻爱情电影。主人公西奥多和人工智能系统OS1的化身萨曼莎在相处中&#xff0c;发现彼此之间都存在双向的需求与欲望&#xff0c;人机友谊最终发展成为一段不被世俗理…

Zookeeper 分布式应用程序的分布式协调服务

老规矩学习一个新技术首先从它的官网入手&#xff1a;Apache ZooKeeper 概览 一谈到集群&#xff0c; 从结构上看&#xff1a; 主从集群&#xff1a;主从集群就可以做读写分离&#xff0c;写在主、读在从无主集群&#xff08;比如redis cluster&#xff09; 从数据上看&…

10---正则表达式匹配

给你一个字符串 s 和一个字符规律 p&#xff0c;请你来实现一个支持 . 和 * 的正则表达式匹配。 . 匹配任意单个字符* 匹配零个或多个前面的那一个元素 所谓匹配&#xff0c;是要涵盖 整个 字符串 s的&#xff0c;而不是部分字符串。 示例 1&#xff1a; 输入&#xff1a;s…

JavaEE 数据链路层 以太网协议

网络原理补充-数据链路层与以太网协议 文章目录 JavaEE & 网络原理补充-数据链路层 & 以太网协议1. 以太网数据帧1.1 帧头帧尾1.2 类型1.3 载荷 2. IP数据报补充2.1 16位标识2.2 13位片偏移2.3 3位标识 3. DNS3.1 DNS原理3.2 DNS劫持或者污染 JavaEE & 网络原理补…

MongoDB 查询文档中使用文本选择器($text)

之前我们介绍过使用比较选择器、逻辑选择器、元素选择器、数组选择器查询文档&#xff0c;如果您需要进一步了解&#xff0c;可以参考&#xff1a; MongoDB 查询文档中使用比较选择器、逻辑选择器https://blog.csdn.net/m1729339749/article/details/129965699 MongoDB 查询文…

IHS安装ssl证书

1、向专业机构申请证书&#xff0c;或者使用openssl生成自签名证书&#xff0c;openssl生成证书参考以下步骤。 openssl生成证书参考https://blog.51cto.com/longlei/2120718 生成加密私钥 [rootlocalhost test]# openssl genrsa -out test.key 2048 Generating RSA private…

直线模组常见故障的解决方法

直线模组因其具有单体运动速度快、重复定位精度高、本体质量轻、占设备空间小、寿命长等特点&#xff0c;运用的范围一直在扩大&#xff0c;发展至今&#xff0c;已经被广泛应用到各种各样的设备当中。 在直线模组的使用过程中&#xff0c;或多或少都会出现一些问题&#xff0c…

DUBBO 3.x 兼容 invoke 调用

从DUBBO的2.7.22版本升级到了3.x的版本后&#xff0c;发现invoke失灵了 首先是启动报错&#xff0c;注释掉配置 dubbo.protocol.telnetinvoke后程序可运行&#xff0c;但是invoke失效。 通过对比源码 示例&#xff1a; tag-3.0.10 tag-2.7.22 发现3.0.2之后的版本都移除了i…

【网络编程】UDP简单实现翻译软件与网络聊天室

文章目录 一、引入二、翻译软件实现2.1 加载字典2.2 处理数据并传递给用户端2.3 客户端获取结果2.4 结果2.5 执行命名功能 三、网络聊天室实现3.1 管理用户3.2 发送消息3.3 多线程处理3.4 结果 四、源码 一、引入 在上一章【网络编程】demo版UDP网络服务器实现实现了客户端和服…

(1分钟了解)视觉惯性导航初始化方法综述

视觉惯性导航初始化方法综述 ​ 编辑切换为居中 添加图片注释&#xff0c;不超过 140 字&#xff08;可选&#xff09; 初始化相关的简介&#xff0c;在这里知道初始化方法可以分为联合初始化、非联合初始化和半联合初始化三种方法即可。 ​ 编辑切换为居中 添加图片注释&…

VIM学习笔记 正则表达式-(vimgrep/grep)

在UNIX问世的前一年&#xff0c;1969年&#xff0c;Ken Thompson将正则表达式整合入QED文本编辑器。在Linux文本编辑器ed中&#xff0c;如果你希望显示包含字母“re”的行时&#xff0c;需要使用命令g/re/p&#xff0c;而grep也因此得名。可以看作此操作的缩写&#xff1a;g (g…

ARM板上的蓝牙对讲功能

1&#xff09;ARMRTL8723 或RTL8821 RTL8723是USB接口的邮票芯片&#xff0c;集成了wifi和BT。前面已经完成了wifi的处理&#xff0c;这次主要说一下蓝牙语音方面。 蓝牙功能&#xff0c;我们主要是使用Bluez5协议栈.结合alsa使用&#xff08;pulseaudio也是可以的&#xff0c…

JVM学习(四)

1. JAVA IO/NIO 1.1. 阻塞 IO 模型 最传统的一种 IO 模型&#xff0c;即在读写数据过程中会发生阻塞现象。当用户线程发出 IO 请求之后&#xff0c;内 核会去查看数据是否就绪&#xff0c;如果没有就绪就会等待数据就绪&#xff0c;而用户线程就会处于阻塞状态&#xff0c…

Class 02 - R语言Rstudio的安装

Class 02 - R语言&Rstudio的安装 下载和安装R安装前准备下载R语言安装R语言开始使用R语言 下载和安装RStudio安装前准备下载RStudio安装RStudio开始使用RStudio如何编写代码 下载和安装R 在这个部分中&#xff0c;你将完成在计算机上下载和安装R语言程序。当安装完成后&am…

嫌视频背景杂乱或单调?如何去除视频杂乱背景

录制视频时&#xff0c;有时候视频背景会十分杂乱或单调&#xff0c;这会对用户的视觉体验和注意力产生负面影响。 背景杂乱或单调的场景可能会影响您的观感。这种情况通常发生在自然光线不足或拍摄环境不理想的情况下。如果您想改变视频的背景或者是去除视频杂乱的背景&#…

硬件I2C读写MPU6050代码

1、接线图 SDA接在B11,SCL接在B10 &#xff0c;软件IIC的两个引脚可以任意更改的&#xff0c;因为都是开漏输出&#xff0c;硬件接在哪个引脚上&#xff0c;程序中就对应操作哪个引脚 但是硬件IIC&#xff0c;通信引脚是不可以任意指定的&#xff0c;查表&#xff0c;由于PB6、…

2023年Android开发者路线-第4部分

2023年Android开发者路线-第1部分 2023年Android开发者路线-第2部分 2023年Android开发者路线-第3部分 2023年Android开发者路线-第4部分 2023年Android开发者路线-第4部分 在上一篇博文中&#xff0c;我们讨论了现代 Android 开发的基本要素&#xff0c;包括 Fragments、…

2023年Android开发者路线-第3部分

2023年Android开发者路线-第1部分 2023年Android开发者路线-第2部分 2023年Android开发者路线-第3部分 2023年Android开发者路线-第4部分 2023年Android开发者路线-第3部分 在上一篇文章中&#xff0c;我们讨论了 Android 主要组件的重要元素&#xff0c;包括 Intents 和 …