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

Java Agent执行字节码替换时卡住无响应,寻求问题排查方案

问题分析与解决方案

卡住的根本原因

你遇到的程序卡死问题,核心在于在ClassFileTransformer的transform方法中调用ClassPool.get("Defender")会触发目标类的加载流程,而此时Defender类正处于加载过程中,会再次回调transform方法,形成无限循环,导致程序无法继续执行。

从你的输出可以看到,程序停在了"I'm here"之后,说明卡在了CtClass cc = cp.get("Defender");这一行——这行代码会触发类加载器去加载Defender类,而类加载的过程又会调用你的transform方法,陷入死循环。

修复后的Agent代码

修改核心逻辑:直接使用传入的classfileBuffer创建CtClass,避免触发额外的类加载;同时处理完后释放CtClass资源防止内存泄漏。

import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;

import java.io.ByteArrayInputStream;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.Instrumentation;
import java.security.ProtectionDomain;

public class AgentMain {

    public static void premain(String agentArgs, Instrumentation inst) {
        System.out.println("Ha, ha! This program was hacked ;-)");
        inst.addTransformer(new ClassFileTransformer() {
            @Override
            public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,
                                    ProtectionDomain protectionDomain, byte[] classfileBuffer) {

                if ("Defender".equals(className)) {
                    try {
                        System.out.println("I'm here");
                        ClassPool cp = ClassPool.getDefault();
                        System.out.println("Class pool created");
                        // 直接使用传入的类字节码创建CtClass,避免触发类加载
                        CtClass cc = cp.makeClass(new ByteArrayInputStream(classfileBuffer)); 

                        CtMethod method = cc.getDeclaredMethod("checkSign");

                        String newBody = "{" +
                                "    System.out.println(\"Verification successfully!\");" +
                                "    return;" + // 显式return,和原方法的void返回一致
                                "}";

                        method.setBody(newBody);
                        
                        byte[] modifiedBytecode = cc.toBytecode();
                        // 释放CtClass资源,避免内存泄漏
                        cc.detach();
                        
                        return modifiedBytecode;
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
               
                return classfileBuffer;
            }
        });
    }
}

额外注意点

  1. 显式添加return语句:原方法是void类型,虽然Javassist会自动补全,但显式添加return能让逻辑更清晰,避免潜在的字节码验证问题。
  2. 释放CtClass资源:调用cc.detach()可以将CtClass从ClassPool中移除,防止内存泄漏,这在Agent这类长期运行的代码中很重要。
  3. 异常处理:如果后续仍有异常,可以考虑将异常信息输出到更明确的位置(比如文件),避免因为类加载过程中的异常无法在控制台显示。

内容的提问来源于stack exchange,提问作者Артем Лебідь

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 06:24:49