是否有任何Java Decompiler可以正确反编译对重载方法的调用?

时间:2010-05-15 13:01:57

标签: java decompiler jad

考虑这个(恕我直言)简单的例子:

public class DecompilerTest {
    public static void main(String[] args) {
        Object s1 = "The", s2 = "answer";
        doPrint((Object) "You should know:");
        for (int i = 0; i < 2; i++) {
            doPrint(s1);
            doPrint(s2);
            s1 = "is";
            s2 = new Integer(42);
        }
        System.out.println();
    }

    private static void doPrint(String s1) {
        System.out.print("Wrong!");
    }

    private static void doPrint(Object s1) {
        System.out.print(s1 + " ");
    }
}

使用没有调试信息的源/目标级别1.1进行编译(即不应存在局部变量信息)并尝试对其进行反编译。我尝试了Jad,JD-GUI和Fernflower,他们都至少有一个错误的通话(即程序打印“错误!”至少一次)

是否真的没有可以推断出正确的强制转换的java反编译器,以便它不会调用错误的重载?

编辑:目标级别1.1,以便不存在特定于Java6的快速验证信息。这可能会给反编译器一个线索,即s1已被声明为Object而不是String。即使没有这些信息,反编译器也应该能够反编译代码(不一定得到原始变量类型,但显示相同的行为),特别是因为许多混淆器也将它剥离。

反编译器出了什么问题:

  • 他们在第一次通话中错过了演员(Object)
  • 他们将s1的类型推断为String,但忘记在调用doPrint时添加强制转换(以便调用String版本而不是Object版本)
  • 一个糟糕的(我甚至没有列出)甚至将s2的类型推断为String,导致无法编译的代码。

在任何情况下,此代码都不会调用String重载,但反编译的代码会执行。

5 个答案:

答案 0 :(得分:9)

Hallo mihi,

抱歉迟到了。我正在复制http://www.reversed-java.com/fernflower/forum?threadfolder=2_DE

的答案

你的问题实际上是一个众所周知的问题。我们来看看:

1)纯字节码不包含任何有关对象变量类型的信息,因此在第一遍中,s1和s2被声明为Object。

2)反编译器正在努力为每个变量分配最佳类型(=在Fernflower中实现的“最窄类型原则”)。所以s1和s2被正确识别为String的实例。

3)doPrint的调用为我们提供了正确方法的直接链接 private static void doPrint(Object s1)

4)到目前为止一切都还好,对吗?现在我们有一个String变量s1传递给一个函数,它需要一个Object。我们需要施展吗?你不会这么认为,因为Object是一个超类型的String。然而我们这样做 - 因为在同一个类中有另一个具有相同名称和不同参数签名的函数。所以我们需要分析整个班级,找出是否需要演员表。

5)一般来说,这意味着我们需要分析所有库中的所有引用类,包括java运行时。大量的工作!实际上,这个功能是在Fernflower的某些alpha版本中实现的,但由于性能和内存损失而尚未在生产中实现。其他提到的反编译器在设计上缺乏这种能力。

希望我已经澄清了一些事情:)

答案 1 :(得分:4)

Krakatau正确处理所有重载的方法,甚至是在原始类型上重载的方法,大多数反编译器都会出错。它总是将参数强制转换为被调用方法的确切类型,因此代码可能比必要的更混乱,但至少它是正确的。

披露:我是Krakatau的作者。

答案 2 :(得分:3)

用于反编译的JadClipse Eclipse插件还提供了您可能想要尝试的JODE反编译器。我在Jad放弃时使用它。

Dava反编译器也使用了Soot - 我上次看过 - 在重建原始Java代码方面非常雄心勃勃。我没有试过你的例子,但你可能想看看。 http://www.sable.mcgill.ca/dava/

答案 3 :(得分:3)

Procyon应该正确处理重载的方法调用。与Krakatau一样,Procyon最初为每个与目标方法不完全匹配的方法参数插入强制转换。但是,大多数这些将在反编译的后期阶段被删除,以识别和消除冗余的强制转换。如果可以验证这样做不会导致调用绑定到不同的方法,则Procyon将仅删除调用参数上的强制转换。例如,如果无法解析声明方法的.class,则根本不会尝试删除强制转换,因为它无法知道哪些重载可能会发生冲突。

答案 4 :(得分:1)

添加到之前的答案: 以下是截至2015年3月的现代反编译器列表:

  • Procyon
  • CFR
  • JD
  • Fernflower

所有这些都支持重载方法。

您可以在线测试上面提到的反编译器,无需安装,并做出自己的教育选择。 云中的Java反编译器:http://www.javadecompilers.com/