You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用ASM修改Jar字节码后报类版本0.0不兼容错误如何解决

问题根因

报错里的类版本为0.0不是需要手动配置类版本号,是字节码生成逻辑完全写错了:你将原始类字节码读入ClassNode完成了方法修改,但最后生成字节码时,仅创建了传入原始ClassReader的ClassWriter对象,既没有把修改后的ClassNode写入ClassWriter,也没有触发原始类内容到ClassWriter的写入流程,最终输出的class文件结构残缺,JVM解析类版本字段时读到空值0,才抛出版本不兼容异常。

修复方案
  • 初始化ClassWriter时不需要传入原始ClassReader作为优化参数,直接传入自动计算栈帧、本地变量数的标志位即可
  • 将修改完成的ClassNode通过accept方法写入ClassWriter,再输出字节数组,ASM会自动沿用原类的版本号,不需要手动设置
  • 额外处理:输出Jar包时记得剔除META-INF目录下的.SF、.DSA、.RSA签名文件,否则类字节码修改后签名校验失败会导致启动报错
修复后的transform方法代码
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);
        }
    }

    // 修复核心逻辑:将修改后的classNode写入ClassWriter再输出
    ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
    classNode.accept(cw);
    return cw.toByteArray();
}

补充:Jar写入逻辑里可以加个判断,遇到META-INF目录下的签名文件直接跳过不写入输出包,避免签名校验报错。

内容的提问来源于stack exchange,提问作者Sysy's

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 00:27:19