4

假设我想要一个 java 类文件,反汇编它,调整 java 字节码输出,然后重新组装它。

我需要重命名常量池表中的符号。我也无权访问源代码,使用反编译器似乎有点矫枉过正。我不想优化任何东西——java 在这方面做得很好。

有没有...一种简单的方法来做到这一点?我找到了几种用于拆卸或重新组装的工具,但两者都没有。或者没有成对的工具似乎使用相同的格式来表示文本中的字节码。

4

5 回答 5

6

你检查过ASM API 吗?

这是一个代码示例(改编自官方文档),解释了如何修改类字节码:

ClasssWriter cw = new ClassWriter();
ClassAdapter ca = new ClassAdapter(cw); // ca forwards all events to cw
// ca should modify the class data
ClassReader cr = new ClassReader("MyClass");
cr.accept(ca, 0);
byte[] b2 = cw.toByteArray(); // b2 represents the same class as MyClass, modified by ca

然后 b2 可以存储在 .class 文件中以供将来使用。ClassLoader.defineClass(String,byte[],int,int)如果您定义自己的类加载器,也可以使用该方法加载它。

于 2010-11-15T16:54:17.170 回答
5

这个问题现在有点老了,但是由于我在stackoverflow上的任何地方都没有找到答案,所以让我记录下来:

我过去成功使用了标准的jasper/jasmin组合:

  • jasper用于反汇编为 jasmin 兼容格式
  • jasmin将重新组装 jasper 的输出

jasper 唯一的烦恼是它忘记为 switch 默认子句创建标签,然后 jasmin 会给你类似的错误

Main.j:391:JAS 错误标签:LABEL0x48 尚未添加到代码中。

这意味着您必须进入 .j 文件并手动修复它。“javap -c”可能会在那里为您提供帮助。对于那个错误,我建议你在进行任何修改之前,立即使用 jasper 和 jasmin,以确保它有效。

您实际上可以通过将此补丁应用于 jasper 来修复该标签错误:

--- Code_Collection.java.orig   1999-06-14 14:10:44.000000000 +0000
+++ Code_Collection.java        2011-02-05 07:23:21.000000000 +0000
@@ -1210,6 +1210,7 @@
     -----------------------------------------------------------------------*/
    void getLabel(Code_Collection code) {
       for (int i = 0; i < count; i++) code.setLabel(pc+branch[i]);
+      code.setLabel(pc+tableDefault);
    }

    /*-----------------------------------------------------------------------

投稿给作者,感觉项目好多年没做,不知道会不会被合并。

编辑:应用了上述补丁的 Jasper 现在可在https://github.com/EugenDueck/Jasper获得

然后是Eclipse Bytecode Outline,如本答案所述: java bytecode editor?

于 2011-02-05T06:33:26.043 回答
4

Krakatau提供了一个开源的反汇编器和汇编器,使这变得非常容易。Krakatau 旨在替代 Jasmin。它使用类似 Jasmin 的语法来实现向后兼容性,但扩展了格式以支持类文件格式中的所有晦涩功能并修复 Jasmin 中的错误。它还使您可以轻松地反汇编、修改和重新组装类。

Krakatau 唯一真正的缺点是它目前没有很好的记录。但是,如果您有任何问题,请随时提出。(披露:我写了 Krakatau)。

于 2013-07-02T14:49:40.447 回答
0

您正在描述现代编译器已经做了什么。除此之外,大多数 JVM 可以(并尝试)在应用程序运行时继续优化字节码。

从研究现有编译器/JVM 对字节码的作用开始。最好的情况是您可以改进 JVM 的优化器,这是可能的,但概率很低,无论哪种方式,您都可能重新发明轮子。最坏的情况是您的更改实际上会干扰运行时优化器并导致整体性能下降。

  1. 研究编译器和 JVM
  2. 基准
  3. 基准
  4. 基准

[编辑] 找到一个相关的帖子:字节码操作模式

于 2010-11-15T17:43:55.573 回答
0

找到原始源代码,修改它,然后重新编译不是更容易吗?或者这是来自您没有源代码的一些二进制代码?

专业提示:内置 Java 类库的源代码作为OpenJDK项目的一部分提供,特别是在OpenJDK 6 Source中。

于 2010-11-15T16:54:14.683 回答