android-ProGuard混淆

android-ProGuard混淆


前篇

ProGuard 工具是用于压缩,优化,混淆我们的代码,主作用是可以移除代码中的无用类,字段,方法和属性同时可以混淆(类,字段,方法,属性的)命名。最终结果可以使我们的 apk 文件体积更加小,也会让我们的 apk 更加难以被他人逆向工程,这对于那些特别时包含一些安全性功能的apk来说是相当重要的。很抽象,我也这么觉得,结合其他资料,我们把 ProGuard 技术的功能概括为以下4项:

  1. 压缩(shrinks) :检查并移除代码中无用的类,字段,方法,属性。

  2. 优化(optimizes):对字节码进行优化,移除无用的指令。

  3. 混淆(obfuscates):使用a,b,c,d等简短而无意义的名称,对类,字段和方法进行重名,这样即使代码被逆向工程,对方也比较难以读懂。 (就类似 js 里面的 uglify-js, 压缩代码.)

  4. 预检测(Preveirfy):在java平台上对处理后的代码进行再次检测。

ProGuard 混淆技术是集成到 Android 构建系统,所以我们不需要手动调用它。ProGuard 混淆技术只有当我们构建您的应用程序并准备发布应用时才需要使用,所以我们在debug模式下没有必要进行代码混淆。ProGuard 混淆技术也只是一种可选技术,即使不使用 ProGuard 混淆技术,我们的应用程序也可以进行运行,但是强烈建议在发布应用程序时使用该技术。

混淆代码也是防止 app 上传到 Google Play 后代码查重.


对代码进行混淆处理

混淆处理的目的是通过缩短应用的类、方法和字段的名称来减小应用的大小

不过,由于混淆处理会对代码的不同部分进行重命名,因此在执行某些任务(如检查堆栈轨迹)时需要用到额外的工具。 要了解混淆处理后的堆栈轨迹,请参阅下一个部分

AndroidManifest.xml

  • AndroidManifest.xml 中配置的 类 的类名不会被混淆.

输出混淆日志

1
2
3
4
5
6
7
8
9
10
11
# 未混淆的类和成员
-printseeds ../../proguard-log/seeds.txt

# 列出从 apk 中删除的无用代码
-printusage ../../proguard-log/unused.txt

# 混淆前后的映射
-printmapping ../../proguard-log/mapping.txt

# R8 在构建项目时应用的所有规则的完整报告
-printconfiguration ../../proguard-log/full-r8-config.txt

解码经过混淆处理的堆栈轨迹

R8 对您的代码进行混淆处理后,理解堆栈轨迹的难度将会极大增加,因为类和方法的名称可能已发生变化。 除了重命名之外,R8 还可以更改堆栈轨迹中的行号,以在写入 DEX 文件时进一步缩减大小。 幸运的是,R8 在每次运行时都会创建一个 mapping.txt 文件,其中列出了经过混淆处理的类、方法和字段名称与原始名称的映射关系。此映射文件还包含用于将行号映射回原始源文件行号的信息。R8 会将此文件保存在 /build/outputs/mapping// 目录中。

注意 :您每次构建项目时都会覆盖 R8 生成的 mapping.txt 文件,因此您每次发布新版本时都要注意保存一个该文件的副本。 通过为每个发布版本保留一个 mapping.txt 文件的副本,您可以在用户提交来自旧版应用的经过混淆处理的堆栈轨迹时,调试相关问题。


unity Android 混淆

  1. 打开 混淆

  2. 然后生成文件 Assets\Plugins\Android\proguard-user.txt, 在里面添加 混淆规则 即可.

    需要注意的是跨平台 (都是 public 方法) 调用方法需要 keep 住, 否则运行时调用 java 会报错. keep 住 public 方法即可. 如:

    1
    2
    3
    -keep class com.yang.androidaar.MainActivity{
    public <methods>; # 保持该类下所有的共有方法不被混淆
    }

    将入口 MainActivity 类 keep 住.

    接入的第三方 sdk 有要求混淆 keep 的规则, 直接丢到里面即可.

踩坑

在 as 中导出 unity 库模块 的 jar 时, 不能在 库模块 中开启混淆. 否则打包时, 主工程有开启了混淆, 导致二次混淆会报错

1
transformClassesAndResourcesWithR8ForRelease FAILED

打包后实际运行看到, 即使导出 jar 时不混淆, 只要打包时混淆, 库模块 的代码还是可以混淆成功的

库模块 里故意报个错

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class LaunchReport {
public void doReport() {
try {
int a = 123;
if (a > 100) {
Log.d(TAG, "doReport: hello 111");
throw new Exception("my wolegequ exception");
}
} catch (Exception e) {
e(TAG, "--- test exception:" + e.getMessage());
e.printStackTrace();
}
}
}

可以看到代码是混淆的

1
2
3
4
04-21 15:15:42.237 24470-24470/com.rmgstation.rummymon E/LaunchReport: --- test exception:my wolegequ exception
04-21 15:15:42.237 24470-24470/com.rmgstation.rummymon W/System.err: java.lang.Exception: my wolegequ exception
04-21 15:15:42.237 24470-24470/com.rmgstation.rummymon W/System.err: at com.yang.androidaar.c.a(:37)
04-21 15:15:42.237 24470-24470/com.rmgstation.rummymon W/System.err: at com.yang.androidaar.MainActivity.onCreate(:103)

配置了 混淆日志 路径, 但是报错文件找不到

报错: FileNotFoundException

  • 比如混淆文件: proguard-user.txt

    1
    2
    # R8 在构建项目时应用的所有规则的完整报告
    -printconfiguration ../../patch/proguard-log/full-r8-config.txt

    这个 ../../patch/proguard-log 目录一定要存在, 不然就会报错, 打包失败


踩坑

gradle 8 版本构建提示混淆配置缺失

  • 报错:

    1
    2
    3
    > Task :testapp:minifyReleaseWithR8 FAILED
    AGPBI: {"kind":"error","text":"Missing classes detected while running R8. Please add the missing classes or apply additional keep rules that are generated in E:\\its\\longterm_itc-cc\\Rummy_AndroidStudio\\testapp\\build\\outputs\\mapping\\release\\missing_rules.txt.","sources":[{}]}
    AGPBI: {"kind":"error","text":"Missing class org.bouncycastle.jsse.BCSSLParameters (referenced from: void okhttp3.internal.platform.BouncyCastlePlatform.configureTlsExtensions(javax.net.ssl.SSLSocket, java.lang.String, java.util.List))\r\nMissing class org.bouncycastle.jsse.BCSSLSocket (referenced from: void okhttp3.internal.platform.BouncyCastlePlatform.configureTlsExtensions(javax.net.ssl.SSLSocket, java.lang.String, java.util.List) and 1 other context)\r\nMissing class org.bouncycastle.jsse.provider.BouncyCastleJsseProvider (referenced from: void okhttp3.internal.platform.BouncyCastlePlatform.<init>())\r\nMissing class org.conscrypt.Conscrypt$Version (referenced from: boolean okhttp3.internal.platform.ConscryptPlatform$Companion.atLeastVersion(int, int, int))\r\nMissing class org.conscrypt.Conscrypt (referenced from: boolean okhttp3.internal.platform.ConscryptPlatform$Companion.atLeastVersion(int, int, int) and 3 other contexts)\r\nMissing class org.conscrypt.ConscryptHostnameVerifier (referenced from: okhttp3.internal.platform.ConscryptPlatform$configureTrustManager$1)\r\nMissing class org.openjsse.javax.net.ssl.SSLParameters (referenced from: void okhttp3.internal.platform.OpenJSSEPlatform.configureTlsExtensions(javax.net.ssl.SSLSocket, java.lang.String, java.util.List))\r\nMissing class org.openjsse.javax.net.ssl.SSLSocket (referenced from: void okhttp3.internal.platform.OpenJSSEPlatform.configureTlsExtensions(javax.net.ssl.SSLSocket, java.lang.String, java.util.List) and 1 other context)\r\nMissing class org.openjsse.net.ssl.OpenJSSE (referenced from: void okhttp3.internal.platform.OpenJSSEPlatform.<init>())","sources":[{}],"tool":"R8"}
  • 解决办法: 根据提示, 打开路径的 missing_rules.txt 文件, 将里面的内容加入到混淆配置 proguard-rules.pro 中即可

    参考: https://stackoverflow.com/questions/70037537/proguard-missing-classes-detected-while-running-r8-after-adding-package-names-in