java - 以可读格式打开 Java 字节代码并对其进行编辑

标签 java jvm javac bytecode .class-file

我想使用某种编辑器打开 Java 编译器生成的字节码(Java 二进制文件),这允许我查看字节码(原始的,但人类可以理解的,采用定义的格式 here )并修改内容直接在 .class文件。

我已经尝试过javap公用事业。但通过javap ,我无法更改我的 .class 文件,而且它似乎没有显示原始字节代码

另外,我见过类似 JD Decompiler 的反编译器这给了我 .class 中的代码文件。但我对源代码不感兴趣,我想查看字节码。

另外,我尝试过名为 dirtyJOE 的 GUI 编辑器& JBE 。这个编辑器相当不错,达到了我一半的目的。我可以在 .class 中看到各个字段文件并编辑我的 .class文件也是如此。但这似乎也像一个翻译器,它解码字节码并将其显示在 UI 上以便于理解。它没有向我显示原始字节代码。

是否有可能转到原始字节码?

我可能听起来很愚蠢,但我想确认这一点,正确理解 Java 编译器和 JVM。

最佳答案

可以使用javap -v转储原始字节代码,但要以您可以编辑的格式获取类文件中的所有信息,我使用ASM。您不会使用它进行编辑的原因是;

  • 它不允许您做很多 Java 无法做的事情。
  • 使用起来非常非常困难。
  • 如果你破坏了它,你不会得到太多关于哪里出了问题的反馈。

字节码只是 Java 代码的编译版本,这毫无值(value),这就是为什么它们做同样的事情。 JVM 可以通过多种方式自由地对其进行优化,如果您想了解 JVM 的工作原理或代码的运行方式,那么理解字节码就不是很有用。

<小时/>

感谢@Antimony 提出手动编写字节代码的使用建议。虽然其中一些是有效的,但它们要么相当先进,要么晦涩难懂,或者有实现相同目标的替代方法。

一些想法

throw checked exceptions without declaring them,

Thread.currentThread().stop(checkedException);

catch checked exceptions without declaring them,

   if (false) throw new CheckedException();
} catch(CheckedException ce) {

use identifiers invalid in Java

有很多有效但不太有用的字符可供使用,我会使用其中一个

if( ⁀ ‿ ⁀ == ⁀ ⁔ ⁀ || ¢ + ¢== ₡)

for (char c‮h = 0; c‮h < Character.MAX_VALUE; c‮h++)
    if (Character.isJavaIdentifierPart(c‮h) && !Character.isJavaIdentifierStart(c‮h))
        System.out.printf("%04x <%s>%n", (int) c‮h, "" + c‮h);

由于标识符中的不可见字符导致文本向后打印,因此是有效代码。

http://vanillajava.blogspot.co.uk/2012/09/hidden-code.html

http://vanillajava.blogspot.co.uk/2012/08/uses-for-special-characters-in-java-code.html

access fields before constructor call

我很确定这会导致VerifyError(或者当我尝试时确实如此)。相反,您可以使用

Object o = Unsafe.allocateInstance(clazz); // create without calling a constructor.

call different constructors conditionally

我再次能够在对象创建和实例调用之间放置代码,但可能有一种方法可以让它工作。在 Java 中你可以这样写

MyClass mc = condition ? new MyClass(a) : new MyClass(a, b);

do exception handling on constructors.

不确定你在这里的意思,因为你可以在构造函数中捕获或抛出异常。

assign final fields more than once or not at all

您可以使用反射来代替,并为最终字段指定默认值。即字段不可能没有值。

have a strictfp constructor with nonstrictfp methods

这是一个有趣的,但不是我需要的。

use laxer type checking

字节码确实允许不同的类型检查规则,但它们很容易与不太有用的VerifyErrors发生冲突。你可以做到这一点,但恕我直言,很难做到正确。

throw exceptions from static initializer

您已经可以抛出未检查的异常,并且要抛出已检查的异常,您可以使用上面的技巧,但是我通常用 AssertionError 等包装。

use invokedynamic

您可以使用 MethodHandles,但它们在 Java 7 中相当笨重。我希望在 Java 8 中它们使用起来会更自然。

use subroutines

有趣,我还没有尝试过这个,但我不确定它们比方法调用有什么优势。

use unusual control flow

确实如此,但这更有可能使 JIT 优化器感到困惑,因此代码可能会变慢,因此可能无法为您提供您可能希望的优势。

use old super call semantics

你可以,但我不确定这有多大用处。

use thread monitors

你可以使用

Unsafe.enterMonitor();
Unsafe.exitMonitor();
Unsafe.tryMonitorEnter();

initial values for fields.

我同意编译器没有像我预期的那样使用这些,但我再次不确定如果这样做会产生什么区别。

关于java - 以可读格式打开 Java 字节代码并对其进行编辑,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13118851/

相关文章:

java - 我可以使用java中的收集器从文档列表中查找具有最大键值的文档吗

java 。如何允许用户使用字符串输入跳过提示的数字要求?

java - 有多少种方法可以解决java中的堆空间问题?

JAVA:静态方法在执行过程中对性能有很大影响吗?

带有 JDK 7/8 的 java 编译器目标版本 "jsr14"

java - 使用 IOFileFilter 的问题

Java JSTL 错误 java.lang.NoClassDefFoundError : javax/servlet/jsp/jSTL/core/LoopTag

java - 在Java中,PrintStream如何最终将文本打印到控制台?

Java:如何从包中编译可运行的 jar?

Java命令行编译问题和依赖关系