如何混淆我用 kotlin 编码的 sdk(并摆脱元数据)

Posted

技术标签:

【中文标题】如何混淆我用 kotlin 编码的 sdk(并摆脱元数据)【英文标题】:How can I obfuscate my sdk coded with kotlin (and get rid of Metadata) 【发布时间】:2018-02-23 11:34:18 【问题描述】:

我正在开发一个 SDK(android 库),我必须对我的大部分代码进行模糊处理,这样客户就不会尝试使用内部代码。 我的库是用 kotlin 编码的,我使用 proguard 来混淆代码。问题是编译和混淆后代码内部仍然有@kotlin.Metadata(运行时)注释。使用这些注释,很容易检索产生这个“(不那么)混淆”字节码的 java 代码。

我一开始以为是我的错,我的项目有太多的熵源可能会导致这种行为,所以我做了一个示例项目来证明问题不是来自我的 sdk 实现。 我用 AS 创建了一个新项目,然后是一个包含 2 个文件的 lib 模块:

facade.kt 是我的外观类,我不想混淆,所以客户可以使用它:

package com.example.mylibrary

class MyFacade(val internalClass:InternalClass) 

   fun doSomething() 
      internalClass.doSomething(
             firstArgument=1,
             secondArgument=2
      )
    
 

在这个示例中,internal.kt 包含我想要混淆的类:

package com.example.mylibrary

class InternalClass 
    fun doSomething(firstArgument: Int, secondArgument: Int) 
        System.out.println("Arguments are : $firstArgument, $secondArgument")
    

proguard 规则通过此发布关闭注入到 gradle 项目中:

buildTypes 
    release 
        minifyEnabled true
        proguardFiles 'proguard-rules.pro'
    

这里是proguard-rules.pro(只有一行,仅此而已):

-keep class com.example.mylibrary.MyFacade *;

结果:当我./gradlew clean myLib:assembleRelease 时,我确实获得了一个aar,其中保留了我的外观,并且我的内部类已重命名为'a',使用一个方法'a',除了该类仍被注释使用 kotlin @Metadata,它包含帮助反编译器检索原始类名、方法、属性和参数名称等的所有信息…… 所以我的代码根本没有那么模糊......

@Metadata(
   mv = 1, 1, 7,
   bv = 1, 0, 2,
   k = 1,
   d1 = "\u0000\u001a\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0002\b\u0002\n\u0002\u0010\u0002\n\u0000\n\u0002\u0010\b\n\u0002\b\u0002\u0018\u00002\u00020\u0001B\u0005¢\u0006\u0002\u0010\u0002J\u0016\u0010\u0003\u001a\u00020\u00042\u0006\u0010\u0005\u001a\u00020\u00062\u0006\u0010\u0007\u001a\u00020\u0006¨\u0006\b",
   d2 = "Lcom/example/mylibrary/InternalClass;", "", "()V", "doSomething", "", "firstArgument", "", "secondArgument", "mylibrary_release"
)
public final class a 
    ...

所以我的问题是:是否有可能摆脱这些注释,我是唯一面临这个问题的人,还是我错过了什么?

【问题讨论】:

这太糟糕了……因为你已经从proguardFiles 中删除了 (?) 默认的 Android *.pro 文件,我怀疑 Kotlin Gradle 插件会强制以某种方式保留注释。您可能必须使用单独的 Proguard 通道从您的 jar 中删除它们,- Proguard 只是 Java 库/Ant 任务,因此您可以声明 classpath 对它的依赖,并在自定义 Gradle 任务/Android 插件转换中自己使用它。跨度> @user1643723 感谢您的建议,我没有怀疑这可能来自 kotlin-gradle 插件,我将尝试分离的 proguard 调用技巧。 我检查了这个解决方案,确实删除了注释。然而,这不是工业的,我不得不修改我的 proguard 文件才能让它工作,而且我还没有尝试在运行时使用 AAR... 所以现在我在运行时进行了检查,这正是我所期望的...java.lang.AbstractMethodError: abstract method "java.lang.Object kotlin.jvm.functions.Function0.invoke()" 我遇到了类似这样的神秘错误,这似乎与 java 与 kotlin 字节码交互的方式有关。 . 我注定要失败。 您可能希望使用您最近尝试的描述来更新问题。使用 Proguard 手动处理库文件是一项艰巨的任务,你可能得到了 -libraryjars 列表错误或类似的东西。确保你在 Proguard 配置中有两个“-dontskip*”选项! 【参考方案1】:

最后,我找到了删除 Kotlin 元数据注释的方法。

为了隐藏 Kotlin 元数据注释,您需要启用 R8 完整模式。

这是关于我的环境的信息。

环境

OS: macOS 10.15.1
Android Studio: 3.5.1
Gradle: 5.4.1
Android Gradle Tool: 3.5.2

您只需向gradle.properties 添加属性,如下所示

gradle.properties

android.enableR8.fullMode=true

这是我的 Proguard 规则

proguard-rules.pro

-dontwarn kotlin.**
-assumenosideeffects class kotlin.jvm.internal.Intrinsics 
    static void checkParameterIsNotNull(java.lang.Object, java.lang.String);

仅供参考,R8 完整模式现在仍在测试中,所以有时它不能正常工作。但是,对我来说,它现在可以完美运行。

【讨论】:

以上是关于如何混淆我用 kotlin 编码的 sdk(并摆脱元数据)的主要内容,如果未能解决你的问题,请参考以下文章

如何摆脱 Android-Kotlin 中的 `Unresolved reference: NavController` 错误?

怎么样编写地道的Kotlin代码

怎么样编写地道的Kotlin代码

怎么样编写地道的Kotlin代码

怎么样编写地道的Kotlin代码

怎么样编写地道的Kotlin代码