我想用字节码编辑一个jar文件,我创建了一个项目来编辑它.

    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运行时(类文件版本0.0)编译,此版本的Java运行时仅识别高达52.0的类文件版本

我试图找到一种方法来设置类文件的版本,但找不到,有什么 idea 吗?

推荐答案

您的声明

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);将所有信息从类读取器复制到classNode一样,classNode.accept(cw);将修改后的信息从classNode复制到类编写器.

要从字面上回答问题,请致电

Java相关问答推荐

@GetMapping和@GetExchange有什么区别?

使用ExecutorService时在ThreadFactory中触发自定义newThread函数

最小拓Flutter 排序的时间复杂度是多少?

Java .类参数不通过构造函数传递

SpringBootreact 式Web应用程序的Spring Cloud Configer服务器中的资源控制器损坏

在bash中将数组作为Java程序的参数传递

如何调整工作时间日历中的时间

Mapstruct不能正确/完全映射属性

第二次按下按钮后,我需要将按钮恢复到其原始状态,以便它可以再次工作

测试何时使用Mockito强制转换对象会导致ClassCastException

Spring Boot中的应用程序.properties文件中未使用的属性

错误:不兼容的类型:Double不能转换为Float

无法使用Java PreparedStatement在SQLite中的日期之间获取结果

JFree Chart从图表中删除边框

Java 21中泛型的不兼容更改

我该如何为我的类编写getter和setter方法?

如何通过用户ID向用户发送私信

谷歌应用引擎本地服务器赢得';t在eclipse上运行

保持标题窗格的箭头可见,即使设置为不可折叠

PhantomReference无法访问时会发生什么?