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;
}
}