package com.deer.agent;import com.deer.agent.sandbox.AgentClazzTransformer;import java.lang.instrument.Instrumentation;import java.util.Arrays;public class AgentMain { public static void premain(String agentArgs, Instrumentation inst) { System.out.println("premain"); } public static void agentmain(String agentArgs, Instrumentation inst){ System.out.println("load agent..."); Class[] clazzList = inst.getAllLoadedClasses(); Arrays.stream(clazzList).forEach(clazz->{ if(clazz.getName().startsWith("com.deer.base.service.impl")){ // try { inst.addTransformer(new AgentClazzTransformer(), true); inst.retransformClasses(clazz); }catch (Exception e){ // } } }); }}
package com.deer.agent.sandbox;import org.objectweb.asm.ClassReader;import org.objectweb.asm.ClassWriter;import java.lang.instrument.ClassFileTransformer;import java.lang.instrument.IllegalClassFormatException;import java.security.ProtectionDomain;public class AgentClazzTransformer implements ClassFileTransformer { @Override public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { ClassReader cr = new ClassReader(classfileBuffer); ClassWriter cw = new ClassWriter(cr,ClassWriter.COMPUTE_MAXS); TraceClassVisitor traceClassVisitor = new TraceClassVisitor(cw); cr.accept(traceClassVisitor,ClassReader.EXPAND_FRAMES); return cw.toByteArray(); }}
package com.deer.agent.sandbox;import org.objectweb.asm.*;import org.objectweb.asm.commons.AdviceAdapter;public class TraceClassVisitor extends ClassVisitor implements Opcodes { private String clazzName; private String methodName; public TraceClassVisitor(ClassVisitor classVisitor) { super(ASM7, classVisitor); } private static int[] computeLvtSlotIndices(boolean isStatic, Type[] paramTypes) { int[] lvtIndex = new int[paramTypes.length]; int nextIndex = isStatic ? 0 : 1; for (int i = 0; i < paramTypes.length; ++i) { lvtIndex[i] = nextIndex; if (isWideType(paramTypes[i])) { nextIndex += 2; } else { ++nextIndex; } } return lvtIndex; } private static boolean isWideType(Type aType) { return aType == Type.LONG_TYPE || aType == Type.DOUBLE_TYPE; } private static boolean isStatic(int access) { return (access & 8) > 0; } @Override public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { super.visit(version, access, name, signature, superName, interfaces); clazzName = name; } @Override public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { MethodVisitor mv = cv.visitMethod(access, name, descriptor, signature, exceptions); //跳过java原生相关的类 if (!clazzName.startsWith("com/deer/base")) { return mv; } mv = new AdviceAdapter(ASM7, mv, access, name, descriptor) { private Type[] methodArgs; private String[] parameterNames; private int[] lvtSlotIndex; @Override protected void onMethodEnter() { //记录关键参数 methodName = name; this.methodArgs = Type.getArgumentTypes(descriptor); this.parameterNames = new String[this.methodArgs.length]; this.lvtSlotIndex =computeLvtSlotIndices(isStatic(access),this.methodArgs); super.onMethodEnter(); } @Override protected void onMethodExit(int opcode) { if (methodName .equals("<init>") || methodName.equals("<clinit>")){ return; } if (opcode == RETURN) { push((Type) null); } else if (opcode == LRETURN || opcode == DRETURN) { dup2(); box(Type.getReturnType(methodDesc)); } else { dup(); box(Type.getReturnType(methodDesc)); } Type objectType = Type.getObjectType("java/lang/Object"); push(lvtSlotIndex.length); newArray(objectType); for (int j = 0; j < lvtSlotIndex.length; j++) { int index = lvtSlotIndex[j]; Type type = methodArgs[j]; dup(); push(j); mv.visitVarInsn(ALOAD, index); box(type); arrayStore(objectType); } visitLdcInsn(clazzName); visitLdcInsn(methodName); mv.visitMethodInsn(INVOKESTATIC, "com/deer/agent/sandbox/Sender", "send", "(Ljava/lang/Object;[Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;)V", false); } @Override public void visitLocalVariable(String name, String descriptor, String signature, Label start, Label end, int index) { for (int i=0;i<this.lvtSlotIndex.length;i++){ if(this.lvtSlotIndex[i] == index){ this.parameterNames[i]=name; } } } }; return mv; }}