字节码检测的Java代理问题
这是我第一次实现java代理,我正在尝试学习字节码插装。在阅读了几篇介绍和教程之后,我编写了一个包含两个类的小应用程序(Summer和Application)。现在,我想通过premain方法运行java代理,以使用以下代码显示执行路径:
public class TestJavaAgent {
public static void premain(String agentArgument,
Instrumentation instrumentation){
instrumentation.addTransformer(new ClassFileTransformer() {
@Override
public byte[] transform(ClassLoader classLoader, String s, Class<?> aClass, ProtectionDomain protectionDomain, byte[] bytes) throws IllegalClassFormatException {
ClassPool cp = ClassPool.getDefault();
try {
CtClass cc = cp.get("Summer");
CtMethod methods [] = cc.getMethods();
for( CtMethod method : methods){
System.out.println("Entering "+method.getName());
method.addLocalVariable("elapsedTime", CtClass.longType);
method.insertBefore("elapsedTime = System.currentTimeMillis();");
method.insertAfter("{elapsedTime = System.currentTimeMillis() - elapsedTime;"
+ "System.out.println(\"Method Executed in ms: \" + elapsedTime);}");
}
return cc.toBytecode();
} catch (Exception ex) {
return bytes;
}
}
});
}
}
我通过java -javaagent{Agent JAR} -jar {Application Jar}
启动了代理,但它没有打印任何插入的消息。调试完代码后,我意识到“ClassPool.getDefault()”之后的所有内容都无法访问,但我不知道为什么。有人能帮我吗
# 1 楼答案
转换器应该转换作为参数传递的类,而不是您喜欢的任意类。注册后,它将调用所有加载的类,包括您自己使用的类(
ClassPool
)。因此,您正在创建一个循环依赖项必须检查class name参数,并等待为要转换的类调用方法。对于所有其他类,只需返回
null
请注意,如果您没有更改任何内容,那么返回
null
比返回原始数组更可取,因为JVM可以立即识别您没有更改任何内容,而无需查看数组内容