是否有任何 Java 反编译器可以正确反编译对重载方法的调用?[关闭]

StackOverflow https://stackoverflow.com/questions/2840183

  •  27-09-2019
  •  | 
  •  

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

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,它们都至少有一个调用错误(即。e.该程序打印了“错误!”至少一次)

难道真的没有java反编译器可以推断出正确的强制转换,这样就不会调用错误的重载吗?

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

反编译器出错的地方:

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

无论如何,这段代码永远不会调用 String 重载,但反编译的代码却重载了。

有帮助吗?

解决方案

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

披露:我是《喀拉喀托》的作者。

其他提示

你好,米希,

回复晚了非常抱歉。我正在复制我的答案 http://www.reversed-java.com/fernflower/forum?threadfolder=2_DE

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

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

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

3) 调用 doPrint 为我们提供了正确方法的直接链接
私有静态无效 doPrint(对象 s1)

4)到目前为止一切都还好,对吧?现在我们有一个字符串变量 s1 传递给一个函数,该函数需要一个对象。我们需要投射它吗?您可能会认为并非如此,因为 Object 是 String 的超类型。但我们确实这样做了 - 因为同一个类中还有另一个函数具有相同的名称和不同的参数签名。所以我们需要分析整个类来确定是否需要强制转换。

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

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

用于反编译的 JadClipse Eclipse 插件还提供了 JODE 反编译器,您可能想尝试一下。当贾德放弃时我会使用它。

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

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

补充一下之前的答案:以下是截至 2015 年 3 月的现代反编译器列表:

  • 南河三族
  • 病死率
  • 京东
  • 蕨花

它们都支持重载方法。

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

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top