java - 如何使用ASM进行字节码转换后定义类(类文件版本0.0)

标签 java jvm java-bytecode-asm

我无法加载使用 ASM 库修改字节码后的类。

这里是恒等更改器(mutator),我希望得到与字节一大小相同的修改后的数组,但它短了两倍! (439 比 278)

    String path = SimpleClass.class.getName().replace(".", "/") + ".class";
    ClassLoader classLoader = SimpleClass.class.getClassLoader();
    InputStream is = classLoader.getResourceAsStream(path);

    byte[] bytes = IOUtils.toByteArray(is);

    ClassReader reader = new ClassReader(bytes);
    ClassWriter writer = new ClassWriter(reader, 0);
    byte[] modified = writer.toByteArray();

加载失败没什么奇怪的。 我怀疑 header 被截断,但第一个字节是相同的 两个数组。

-54、-2、-70

static class ByteClassLoader extends ClassLoader {
    public Class define(String name, byte[] body) {
        return defineClass(name, body, 0, body.length);
    }
}

ByteClassLoader myLoader = new ByteClassLoader();
Class myClass = myLoader.define("Ooo", modified);

因错误而失败:

java.lang.UnsupportedClassVersionError: Ooo has been compiled by a more  recent version of the Java Runtime (class file version 0.0), this version of the Java Runtime only recognizes class file versions up to 52.0

at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:763)
at java.lang.ClassLoader.defineClass(ClassLoader.java:642)
at PrintTest$ByteClassLoader.define(PrintTest.java:24)
at PrintTest.x(PrintTest.java:48)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:117)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:42)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:253)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:84)

最佳答案

这些字节对应于 0xcafeba,它与 Java 类文件魔数(Magic Number) 0xcafebabe 相匹配。

这里的问题是 new ClassWriter(reader, 0) 并没有做你可能认为它会做的事情;请参阅API documentation :

classReader - the ClassReader used to read the original class. It will be used to copy the entire constant pool from the original class and also to copy other fragments of original bytecode where applicable.

我们仍然需要让作者通过 ClassReader.accept 访问读者。 ,如下:

reader.accept(writer, 0);
<小时/>

顺便说一句,您不需要 IOUtils.toByteArray 因为 ClassReader 有一个 constructor taking InputStream .

关于java - 如何使用ASM进行字节码转换后定义类(类文件版本0.0),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61881910/

相关文章:

Java 字节码 - ASM - 获取标签偏移量

java - 在 Java 中如何从计数器中减去一个值?

java - 热点何时可以在堆栈上分配对象?

java - JVM 是开源代码吗?

java - 如何使用 ClassVisitor/Java 字节码 (ASM) 向 ByteCode 中的方法添加额外指令

java - 字节码注入(inject)在哪里可能有用?

java - GSON 将 boolean 值序列化为 0 或 1

java - REST API 与 Hadoop 冲突

java - SurfaceView 中的多个 TextView

Python 脚本无法访问 Docker 镜像中的 .jar 文件