mirror of
https://github.com/ReaJason/MemShellParty.git
synced 2026-09-21 22:50:42 +08:00
fix: method body write failed with jakarta renamed
ByteBuddy Advice cache the class method list at first, the method signature will be changed when use jakarta rename, if follow advice need enhance the javax method, it will not find method signature. because ByteBuddy cached javax method, but follow advice need find the jakarta method, boom~
This commit is contained in:
+1
-1
@@ -17,11 +17,11 @@ public final class ProcessorRegistry {
|
||||
private static final List<Processor<DynamicType.Builder<?>>> BUILDER_PROCESSORS = Arrays.asList(
|
||||
new ListenerBuilderModifier(),
|
||||
new ValveBuilderModifier(),
|
||||
new JakartaBuilderModifier(),
|
||||
new DebugOffBuilderModifier()
|
||||
);
|
||||
|
||||
private static final List<Processor<byte[]>> BYTE_PROCESSORS = Arrays.asList(
|
||||
new JakartaPostProcessor(),
|
||||
new JettyHandlerPostProcessor(),
|
||||
new ShrinkPostProcessor()
|
||||
);
|
||||
|
||||
-22
@@ -1,22 +0,0 @@
|
||||
package com.reajason.javaweb.memshell.generator.processors;
|
||||
|
||||
import com.reajason.javaweb.buddy.ServletRenameVisitorWrapper;
|
||||
import com.reajason.javaweb.memshell.config.ShellConfig;
|
||||
import com.reajason.javaweb.memshell.config.ShellToolConfig;
|
||||
import com.reajason.javaweb.memshell.generator.Processor;
|
||||
import net.bytebuddy.dynamic.DynamicType;
|
||||
|
||||
/**
|
||||
* @author ReaJason
|
||||
* @since 2025/12/7
|
||||
*/
|
||||
public class JakartaBuilderModifier implements Processor<DynamicType.Builder<?>> {
|
||||
|
||||
@Override
|
||||
public DynamicType.Builder<?> process(DynamicType.Builder<?> builder, ShellConfig shellConfig, ShellToolConfig shellToolConfig) {
|
||||
if (shellConfig.isJakarta()) {
|
||||
builder = builder.visit(ServletRenameVisitorWrapper.INSTANCE);
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
package com.reajason.javaweb.memshell.generator.processors;
|
||||
|
||||
import com.reajason.javaweb.asm.ClassRenameUtils;
|
||||
import com.reajason.javaweb.memshell.config.ShellConfig;
|
||||
import com.reajason.javaweb.memshell.config.ShellToolConfig;
|
||||
import com.reajason.javaweb.memshell.generator.Processor;
|
||||
|
||||
public class JakartaPostProcessor implements Processor<byte[]> {
|
||||
@Override
|
||||
public byte[] process(byte[] input, ShellConfig shellConfig, ShellToolConfig shellToolConfig) {
|
||||
if (shellConfig.isJakarta()) {
|
||||
return ClassRenameUtils.relocateJakarta(input);
|
||||
}
|
||||
return input;
|
||||
}
|
||||
}
|
||||
+6
-10
@@ -17,6 +17,7 @@ import net.bytebuddy.description.modifier.Visibility;
|
||||
import net.bytebuddy.description.type.TypeDescription;
|
||||
import net.bytebuddy.dynamic.DynamicType;
|
||||
import net.bytebuddy.implementation.FixedValue;
|
||||
import net.bytebuddy.implementation.StubMethod;
|
||||
import net.bytebuddy.matcher.ElementMatchers;
|
||||
|
||||
import static net.bytebuddy.matcher.ElementMatchers.named;
|
||||
@@ -46,12 +47,9 @@ public class ListenerBuilderModifier implements Processor<DynamicType.Builder<?>
|
||||
TypeDescription typeDefinition, String newClassName) {
|
||||
MethodList<MethodDescription.InDefinedShape> methods = typeDefinition.getDeclaredMethods();
|
||||
|
||||
if (methods.filter(ElementMatchers.named("getResponseFromRequest")
|
||||
.and(ElementMatchers.takesArguments(Object.class))
|
||||
.and(ElementMatchers.returns(Object.class)))
|
||||
.isEmpty()) {
|
||||
throw new GenerationException("[public Object getResponseFromRequest(Object request)] method not found" +
|
||||
" make sure arg and return type is Object.class");
|
||||
if (methods.filter(named("getResponseFromRequest").and(takesArguments(1))).isEmpty()) {
|
||||
throw new GenerationException("please add [getResponseFromRequest(Object request)] method," +
|
||||
" the method body will be auto adapted for multi server");
|
||||
} else {
|
||||
builder = builder
|
||||
.visit(MethodCallReplaceVisitorWrapper.newInstance(
|
||||
@@ -59,13 +57,11 @@ public class ListenerBuilderModifier implements Processor<DynamicType.Builder<?>
|
||||
.visit(Advice.to(implInterceptor).on(named("getResponseFromRequest")));
|
||||
}
|
||||
|
||||
if (methods.filter(named("getFieldValue")
|
||||
.and(takesArguments(Object.class, String.class)))
|
||||
.isEmpty()) {
|
||||
if (methods.filter(named("getFieldValue").and(takesArguments(Object.class, String.class))).isEmpty()) {
|
||||
builder = builder.defineMethod("getFieldValue", Object.class, Visibility.PUBLIC, Ownership.STATIC)
|
||||
.withParameters(Object.class, String.class)
|
||||
.throwing(Exception.class)
|
||||
.intercept(FixedValue.nullValue())
|
||||
.intercept(StubMethod.INSTANCE)
|
||||
.visit(Advice.to(ShellCommonUtil.GetFieldValueInterceptor.class).on(named("getFieldValue")));
|
||||
}
|
||||
return builder;
|
||||
|
||||
-12
@@ -28,12 +28,6 @@ class ListenerGeneratorTest {
|
||||
}
|
||||
}
|
||||
|
||||
public static class J {
|
||||
public HttpServletResponse getResponseFromRequest(HttpServletRequest request) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static class FakeRequest {
|
||||
public Object response = "i'm a good boy";
|
||||
}
|
||||
@@ -44,12 +38,6 @@ class ListenerGeneratorTest {
|
||||
Assertions.assertThrows(GenerationException.class, () -> ListenerBuilderModifier.modifier(builder, Tomcat.ListenerInterceptor.class, TypeDescription.ForLoadedType.of(Object.class), "hello.world"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetResponseFromRequestSignatureError() {
|
||||
DynamicType.Builder<?> builder = new ByteBuddy().redefine(J.class);
|
||||
Assertions.assertThrows(GenerationException.class, () -> ListenerBuilderModifier.modifier(builder, Tomcat.ListenerInterceptor.class, TypeDescription.ForLoadedType.of(J.class), "hello.world"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@SneakyThrows
|
||||
void test() {
|
||||
|
||||
+31
-12
@@ -1,5 +1,6 @@
|
||||
package com.reajason.javaweb.asm;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
@@ -14,12 +15,7 @@ import org.objectweb.asm.commons.SimpleRemapper;
|
||||
public class ClassRenameUtils {
|
||||
|
||||
public static byte[] renameClass(byte[] classBytes, String newName) {
|
||||
ClassReader reader = null;
|
||||
try {
|
||||
reader = new ClassReader(classBytes);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("invalid class bytes");
|
||||
}
|
||||
ClassReader reader = getClassReader(classBytes);
|
||||
String oldClassName = reader.getClassName();
|
||||
String newClassName = newName.replace('.', '/');
|
||||
ClassWriter writer = new ClassWriter(reader, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
|
||||
@@ -29,12 +25,7 @@ public class ClassRenameUtils {
|
||||
}
|
||||
|
||||
public static byte[] relocateClass(byte[] classBytes, String relocateClassPackage, String relocatePrefix) {
|
||||
ClassReader reader = null;
|
||||
try {
|
||||
reader = new ClassReader(classBytes);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("invalid class bytes");
|
||||
}
|
||||
ClassReader reader = getClassReader(classBytes);
|
||||
String oldClassName = relocateClassPackage.replace('.', '/');
|
||||
String newClassName = relocatePrefix.replace('.', '/');
|
||||
ClassWriter writer = new ClassWriter(reader, ClassWriter.COMPUTE_MAXS);
|
||||
@@ -51,4 +42,32 @@ public class ClassRenameUtils {
|
||||
reader.accept(adapter, 0);
|
||||
return writer.toByteArray();
|
||||
}
|
||||
|
||||
public static byte[] relocateJakarta(byte[] classBytes) {
|
||||
ClassReader reader = getClassReader(classBytes);
|
||||
ClassWriter writer = new ClassWriter(reader, ClassWriter.COMPUTE_MAXS);
|
||||
ClassRemapper adapter = new ClassRemapper(writer, new Remapper(Opcodes.ASM9) {
|
||||
@Override
|
||||
public String map(String typeName) {
|
||||
if (typeName.startsWith("javax/servlet/")
|
||||
|| typeName.startsWith("javax/websocket/")) {
|
||||
return typeName.replaceFirst("javax", "jakarta");
|
||||
} else {
|
||||
return typeName;
|
||||
}
|
||||
}
|
||||
});
|
||||
reader.accept(adapter, 0);
|
||||
return writer.toByteArray();
|
||||
}
|
||||
|
||||
private static @NotNull ClassReader getClassReader(byte[] classBytes) {
|
||||
ClassReader reader = null;
|
||||
try {
|
||||
reader = new ClassReader(classBytes);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("invalid class bytes");
|
||||
}
|
||||
return reader;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user