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/38917284/

相关文章:

java - If 语句检测字符串中的特定单词

java - JVM 如何优化 Fluent api

Java 8 迭代流操作

java - Eclipse RCP应用程序仅以管理员身份启动

java - 在哪里修补程序分析期间收集的信息

java - 加载 web.xml 以使用 jetty 进行集成测试

java - 使用动态生成的类进行 Hazelcast 用户代码部署

java - Java中如何找到方法调用的行号

java - 当一个实例的成员暴露给外界时,它能被垃圾回收吗