【问题标题】:Java: Strange result after decompilingJava:反编译后的奇怪结果
【发布时间】:2011-05-25 03:27:01
【问题描述】:

我有一个奇怪的 jar 文件,它包含一些类,当我使用 JD Decompiler 时,它会显示如下一段:

public final void a(ak aa) {
    this.jdField_a_of_type_Ak = aa;
}

public final void a(cn ccn) {
  this.jdField_a_of_type_Cn = ccn;
}

public final cN a() {
  return this.jdField_a_of_type_CN;
}

public final void a() {
  super.b();
}

public final boolean a() {
    return this.jdField_a_of_type_Boolean;
}

我只是想知道为什么编译器/混淆器可以产生这样的类字节码,我的意思是方法签名。有人知道混淆器可以做到这一点吗?

【问题讨论】:

  • 您已经展示了 5 个方法 - 哪个方法签名让您感到困扰?
  • 你问的是重载的返回类型(最后三个)吗?
  • 我的意思是最后三个,return类型不包含在方法签名中,所以这些方法是重复的,对吧?
  • 在字节码级别,方法签名包括返回类型。因此,即使在 Java 中无效,它也可以根据返回类型唯一地识别方法。
  • 注意:字节码不限于Java,它可能被Scala等其他语言使用。

标签: java obfuscation decompiler


【解决方案1】:

... 混淆器会产生这样的方法名称/签名,因为这是它的工作。任何混淆器都应该为此目的工作。

【讨论】:

    【解决方案2】:

    Java 字节码支持在 Java 源代码中无效的结构。混淆器通过修改字节码以使用这些结构来利用这一事实(同时仍然给出与未混淆的字节码相同的结果)。

    【讨论】:

    • 你能命名一个java-obfuscator软件来做这个吗?
    • @secmask,ProGuard 会这样做。看我的回答。
    【解决方案3】:

    类已经编译,没有调试信息(至少局部变量信息缺失),后来混淆了。

    一种基本的混淆策略是用新的、毫无意义的名称替换(几乎)所有包、类和方法名,这样人们就无法理解反编译的代码。

    其他策略是混淆字符串并添加无法反编译为 java 代码的字节码结构。

    您仍然可以为经过混淆的类文件创建等效的 java 源代码,但需要付出很大的努力。

    【讨论】:

      【解决方案4】:

      正如@Joachim Sauer correctly points out:JVM 规范对字节码中方法重载的限制比 JLS 对 Java 程序的限制要少。

      来自JVM Specification (Section 4.6, Methods)

      一个类文件中的两个方法不能具有相同的名称和描述符(第 4.3.3 节)。

      并且方法描述符包含返回类型:(4.3.3 Method Descriptors)

      MethodDescriptor:
      ( ParameterDescriptor* ) ReturnDescriptor

      您在问题中提到的方法都有不同的描述符,所以它们都可以:

      public final void a(ak aa)     ->     (Lsomepkg1/ak;)V
      public final void a(cn ccn)    ->     (Lsomepkg2/ccn;)V
      public final cN a()            ->     ()Lsomepkg3/cN;
      public final void a()          ->     ()V
      public final boolean a()       ->     ()Z
      

      混淆器巧妙地利用了这一点。一个有效的字节码程序不再有一个“直接对应的”Java 程序。例如,ProGuard 就是这样做的。这是他们手册中的一个 sn-p:

      -overloadaggressively

      指定在混淆时应用积极的重载。然后,多个字段和方法可以获得相同的名称,只要它们的参数和返回类型不同(不仅仅是它们的参数)

      还有其他类似的技术,例如使用jsr 字节码指令或使用Java 语言中的保留字变量标识符。 Here 是一个列出一些技术的网页。


      回答明显的后续问题:JVM 如何知道在调用点调用哪个方法?

      invoke-instructions 要求您指定对要调用的完整方法签名(包括方法的返回类型)的引用。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-10-28
        • 1970-01-01
        • 2020-07-12
        • 2011-10-16
        • 1970-01-01
        • 2015-07-25
        • 2012-01-14
        相关资源
        最近更新 更多