instrumentation
Java探针技术-instrutment中retransformClasses和redefineClasses - 洛神灬殇 - 博客园
探秘 Java 热部署三(Java agent agentmain) - 莫那-鲁道 - 博客园
1000个字带你一次性搞懂JavaAgent技术,反正我是彻底服了-腾讯云开发者社区-腾讯云
jar包封装方式可参考封装jar包 | Runwu2204
premain
先于main执行
在MANIFEST中插入
1 Premain-Class: xxx.xxx.xxx
对应类中需要带有
1 public static void Agentmain (String agentArgs, Instrumentation inst)
调用方式
在-jar前面加入 -javaagent:xxx.jar
具体类似java -javaagent:agent.jar -jar main.jar
(agent jar指对应带Agent-Class
或者Premain-Class
的jar包 而main.jar
指的是对应带main 也就是需要被hook的jar包)
主要使用transform (相当于加载class前需要调用的函数)来实现加载对应class时调用修改函数
则需要加入
Can-Retransform-Classes: true
Can-Redefine-Classes: true
否则会报unsupported
1 2 3 Premain-Class: xxx.xxx.xxx Can-Retransform-Classes: true Can-Redefine-Classes: true
agentmain
在类加载后执行
在MANIFEST中插入
1 Agent-Class: xxx.xxx.xxx
对应类中需要带有
1 public static void agentmain (String agentArgs, Instrumentation instrumentation)
调用方式
使用
1 2 VirtualMachine vm = VirtualMachine.attach("xxx" );vm.loadAgent("xxx.jar" );
exp: 使用premain修改构造函数,添加新函数 AgentMainTest
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 package org.example;import javassist.*;import java.lang.instrument.ClassDefinition;import java.lang.instrument.ClassFileTransformer;import java.lang.instrument.IllegalClassFormatException;import java.lang.instrument.Instrumentation;import java.security.ProtectionDomain;public class AgentMainTest { static { } public static void premain (String agentArgs, Instrumentation instrumentation) throws Exception { System.out.println("开始代理 Agent" ); instrumentation.addTransformer(new Transformer (),true ); } static class Transformer implements ClassFileTransformer { @Override public byte [] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte [] classfileBuffer) throws IllegalClassFormatException { if (className.contains("java/util/Date" )){ try { System.out.println("IN:" +className); ClassPool classPool=ClassPool.getDefault(); CtClass clazz=classPool.get("java.util.Date" ); CtMethod ctMethod = new CtMethod (CtClass.intType, "test" , new CtClass []{CtClass.intType}, clazz); ctMethod.setModifiers(Modifier.PUBLIC); ctMethod.setBody("{return $1;}" ); clazz.addMethod(ctMethod); CtConstructor ctConstructor=clazz.getDeclaredConstructor(new CtClass []{}); ctConstructor.setBody("this(0L);" ); return clazz.toBytecode(); }catch (Exception e){ System.out.println("error:" +className); } } else { try { ClassPool classPool=ClassPool.getDefault(); CtClass clazz=classPool.get(className); return clazz.toBytecode(); }catch (Exception e){ } } return null ; } } }
Main
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 package org.example;import javassist.*;import java.lang.instrument.Instrumentation;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.util.Date;public class Main { public static void main (String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { Date dt=new Date (); Method nmethod=Date.class.getDeclaredMethod("test" ,new Class []{int .class}); System.out.println(String.valueOf(dt)); System.out.println(nmethod.invoke(dt,1 )); } }
MANIFEST.MF
1 2 3 4 5 6 7 8 Manifest-Version: 1.0 Can-Redefine-Classes: true Premain-Class: org.example.AgentMainTest Can-Retransform-Classes: true Can-Redefine-Classes: true Main-Class: org.example.Main Class-Path: javassist-3.25.0-GA.jar
jar包结构
运行结果
使用agentmain动态补丁 注意需要导入对应版本java的lib下的tools.jar
导入方式类似这样
项目结构
AgentMainTest
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 package org.example;import java.lang.instrument.ClassFileTransformer;import java.lang.instrument.IllegalClassFormatException;import java.lang.instrument.Instrumentation;import java.security.ProtectionDomain;import javassist.ClassPool;import javassist.CtClass;import javassist.CtConstructor;import javassist.CtMethod;public class AgentMainTest { public AgentMainTest () { } public static void premain (String agentArgs, Instrumentation instrumentation) throws Exception { System.out.println("premain 开始代理 Agent" ); instrumentation.addTransformer(new Transformer (), true ); } public static void agentmain (String agentArgs, Instrumentation instrumentation) throws Exception { System.out.println("agentmain 开始代理 Agent" ); instrumentation.addTransformer(new Transformer (), true ); } static class Transformer implements ClassFileTransformer { Transformer() { } public byte [] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte [] classfileBuffer) throws IllegalClassFormatException { ClassPool classPool; CtClass clazz; if (className.contains("java/util/Date" )) { try { System.out.println("IN:" + className); classPool = ClassPool.getDefault(); clazz = classPool.get("java.util.Date" ); CtMethod ctMethod = new CtMethod (CtClass.intType, "test" , new CtClass []{CtClass.intType}, clazz); ctMethod.setModifiers(1 ); ctMethod.setBody("{return $1;}" ); clazz.addMethod(ctMethod); CtConstructor ctConstructor = clazz.getDeclaredConstructor(new CtClass [0 ]); ctConstructor.setBody("this(0L);" ); return clazz.toBytecode(); } catch (Exception var10) { System.out.println("error:" + className); } } else { try { classPool = ClassPool.getDefault(); clazz = classPool.get(className); return clazz.toBytecode(); } catch (Exception var11) { } } return null ; } } }
Main
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 package org.example;import javassist.*;import com.sun.tools.attach.*;import java.lang.instrument.Instrumentation;import java.lang.management.ManagementFactory;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.util.Date;public class Main { public static void main (String[] args) throws Exception { String name = ManagementFactory.getRuntimeMXBean().getName(); String Pid=name.split("@" )[0 ]; VirtualMachine vm = VirtualMachine.attach(Pid); vm.loadAgent("unnamed.jar" ); Date dt=new Date (); Method nmethod=Date.class.getDeclaredMethod("test" ,new Class []{int .class}); System.out.println(String.valueOf(dt)); System.out.println(nmethod.invoke(dt,1 )); } }
MANIFEST.MF
1 2 3 4 5 6 7 8 9 Manifest-Version: 1.0 Can-Redefine-Classes: true Premain-Class: org.example.AgentMainTest Agent-Class: org.example.AgentMainTest Can-Retransform-Classes: true Can-Redefine-Classes: true Main-Class: org.example.Main Class-Path: javassist-3.25.0-GA.jar tools.jar
Class-Path 注意路径就是当前路径的相对地址 此处我直接在unamed文件夹调用的所以直接用这个地址
运行效果