【问题标题】:Class compiled by a more recent version of the Java Runtime (0.0), this version of the Java Runtime only recognizes class file versions up to 52.0由更新版本的 Java Runtime (0.0) 编译的类,此版本的 Java Runtime 仅识别最高 52.0 的类文件版本
【发布时间】:2022-06-15 21:36:23
【问题描述】:

我想编辑一个带有字节码的 jar 文件,我创建了一个项目来编辑它。 我有 2 个功能:

    public static byte[] transform(byte[] buf){
    ClassNode classNode = new ClassNode();
    ClassReader classReader = new ClassReader(buf);
    classReader.accept(classNode, ClassReader.EXPAND_FRAMES);

    for (MethodNode method : classNode.methods) {
        if(method.name.equals(shouldSideBeRenderedMethod) && method.desc.startsWith("(L") && method.desc.endsWith(";IIII)Z")){
            System.out.println("[*] Patching bytecode of shouldSideBeRendered...");
            InsnList insnList = new InsnList();

            Label label0 = new Label();
            insnList.add(new LabelNode(label0));
            insnList.add(new VarInsnNode(ALOAD, 0));
            insnList.add(new FieldInsnNode(GETFIELD, blockClass.replaceAll("\\.", "/"), unlocalizedNameField, "Ljava/lang/String;"));
            insnList.add(new LdcInsnNode("stone"));
            insnList.add(new MethodInsnNode(INVOKEVIRTUAL, "java/lang/String", "equals", "(Ljava/lang/Object;)Z", false));
            Label label1 = new Label();
            insnList.add(new JumpInsnNode(IFNE, new LabelNode(label1)));
            insnList.add(new InsnNode(ICONST_1));
            Label label2 = new Label();
            insnList.add(new JumpInsnNode(GOTO, new LabelNode(label2)));
            insnList.add(new LabelNode(label1));
            insnList.add(new FrameNode(Opcodes.F_SAME, 0, null, 0, null));
            insnList.add(new InsnNode(ICONST_0));
            insnList.add(new LabelNode(label2));
            insnList.add(new FrameNode(Opcodes.F_SAME1, 0, null, 1, new Object[]{Opcodes.INTEGER}));
            insnList.add(new InsnNode(IRETURN));
            Label label3 = new Label();
            insnList.add(new LabelNode(label3));

            method.instructions.insertBefore(method.instructions.getFirst(), insnList);
        }
    }

    return new ClassWriter(classReader, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES).toByteArray();
}

JarFile jarFile = new JarFile(jarPath);
    List<JarEntry> entries = Collections.list(jarFile.entries());
    HashMap<String, byte[]> classMap = new HashMap<>();
    entries.forEach(jarEntry -> {
        try {
            if(jarEntry.getName().equals(blockClass.replaceAll("\\.", "/") + ".class")){
                classMap.put(jarEntry.getName(), transform(IOUtils.toByteArray(jarFile.getInputStream(jarEntry))));
            }else{
                classMap.put(jarEntry.getName(), IOUtils.toByteArray(jarFile.getInputStream(jarEntry)));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    });
    System.out.println("[+] Jar loaded !");

    System.out.println("[*] Writing patched jar...");
    try {
        JarOutputStream jarOutputStream = new JarOutputStream(new FileOutputStream("output.jar"));
        for (Map.Entry<String, byte[]> entry : classMap.entrySet()) {
            JarEntry jarEntry = new JarEntry(entry.getKey());
            jarOutputStream.putNextEntry(jarEntry);
            jarOutputStream.write(entry.getValue());
            jarOutputStream.closeEntry();
        }
        jarOutputStream.close();

        System.out.println("[+] Patched jar successfully written to output.jar !");
    } catch (Exception e) {
        e.printStackTrace();
    }

代码有效,我得到了 jar,但是当我启动它时:线程“main”java.lang.UnsupportedClassVersionError 中的异常:net/minecraft/m/d 已由 Java 运行时的更新版本编译( class 文件版本 0.0),此版本的 Java Runtime 仅识别最高 52.0 的 class 文件版本

我试图找到一种方法来设置类文件版本,但找不到,请知道吗?

【问题讨论】:

    标签: java bytecode


    【解决方案1】:

    你的陈述

    return new ClassWriter(classReader,
            ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES).toByteArray();
    

    创建一个新的ClassWriter,但在请求生成的字节码之前不向其写入任何内容。

    您必须使用类信息填充它。在您的具体情况下:

    ClassWriter cw = new ClassWriter(classReader,
                                     ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
    classNode.accept(cw);
    return cw.toByteArray();
    

    就像classReader.accept(classNode, ClassReader.EXPAND_FRAMES); 将所有信息从类阅读器复制到classNodeclassNode.accept(cw); 会将修改后的信息从classNode 复制到类编写器。

    要从字面上回答这个问题,请致电 visit​(int version, int access, java.lang.String name, java.lang.String signature, java.lang.String superName, java.lang.String[] interfaces)会指定类的主要信息,包括版本号,但是使用Visitor Pattern时会自动调用该方法。

    【讨论】:

    • 它似乎工作,我要测试运行它,谢谢
    猜你喜欢
    • 2019-10-07
    • 2020-12-26
    • 2021-01-07
    • 2020-01-27
    • 2021-12-31
    • 1970-01-01
    • 2020-03-27
    • 2022-01-23
    • 1970-01-01
    相关资源
    最近更新 更多