refactor: simplify memshell generate map register

This commit is contained in:
ReaJason
2025-02-23 02:33:09 +08:00
parent f27b06fc0b
commit 5084a0b850
177 changed files with 3761 additions and 10859 deletions
@@ -0,0 +1,53 @@
package com.reajason.javaweb.buddy;
import net.bytebuddy.asm.AsmVisitorWrapper;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.implementation.Implementation;
import net.bytebuddy.jar.asm.MethodVisitor;
import net.bytebuddy.jar.asm.Opcodes;
import net.bytebuddy.pool.TypePool;
import org.jetbrains.annotations.NotNull;
import java.util.Set;
import java.util.stream.Collectors;
/**
* @author ReaJason
*/
public class MethodCallReplaceVisitorWrapper implements AsmVisitorWrapper.ForDeclaredMethods.MethodVisitorWrapper {
private final String targetClassName;
private final Set<String> replaceClassNames;
public MethodCallReplaceVisitorWrapper(String targetClassName, Set<String> replaceClassNames) {
this.targetClassName = targetClassName.replace(".", "/");
this.replaceClassNames = replaceClassNames.stream().map(s -> s.replace(".", "/")).collect(Collectors.toSet());
}
@NotNull
@Override
public MethodVisitor wrap(@NotNull TypeDescription instrumentedType,
@NotNull MethodDescription instrumentedMethod,
@NotNull MethodVisitor methodVisitor,
@NotNull Implementation.Context implementationContext,
@NotNull TypePool typePool,
int writerFlags,
int readerFlags) {
return new MethodVisitor(Opcodes.ASM9, methodVisitor) {
@Override
public void visitMethodInsn(int opcode, String owner, String name, String descriptor, boolean isInterface) {
if (opcode == Opcodes.INVOKESTATIC
&& replaceClassNames.contains(owner)) {
super.visitMethodInsn(Opcodes.INVOKESTATIC,
targetClassName,
name,
descriptor,
false);
} else {
super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
}
}
};
}
}
@@ -1,76 +0,0 @@
package com.reajason.javaweb.buddy;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.asm.AsmVisitorWrapper;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.jar.asm.MethodVisitor;
import net.bytebuddy.jar.asm.Opcodes;
import java.nio.file.Files;
import java.nio.file.Paths;
import static net.bytebuddy.matcher.ElementMatchers.named;
public class MethodSubstitutionExample {
public static class MethodReplacementMethodVisitor extends MethodVisitor {
private final String targetClassName;
public MethodReplacementMethodVisitor(MethodVisitor mv, String targetClassName) {
super(Opcodes.ASM9, mv);
this.targetClassName = targetClassName;
}
@Override
public void visitMethodInsn(int opcode, String owner, String name, String descriptor, boolean isInterface) {
if (opcode == Opcodes.INVOKESTATIC
&& owner.endsWith("ExternalClass")
&& name.equals("replacementMethod")) {
super.visitMethodInsn(Opcodes.INVOKESTATIC,
targetClassName.replace(".", "/"),
name,
descriptor,
false);
} else {
super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
}
}
}
public static class ExternalClass {
public static String externalMethod(String input) {
return "External: " + input;
}
public static String replacementMethod(String input) {
return "Replaced: " + input;
}
}
public static class TargetClass {
public String targetMethod(String input) {
System.out.println("targetMethod");
return ExternalClass.replacementMethod(input);
}
public static String replacementMethod(String input) {
return "Replaced: " + input;
}
}
public static void main(String[] args) throws Exception {
String oldClassName = TargetClass.class.getName();
String newClassName = oldClassName + "Redefinition";
DynamicType.Unloaded<TargetClass> dynamicType = new ByteBuddy()
.redefine(TargetClass.class)
.name(newClassName)
.visit(new AsmVisitorWrapper.ForDeclaredMethods().method(named("targetMethod"), (typeDescription, methodDescription, methodVisitor, context, typePool, i, i1) -> new MethodReplacementMethodVisitor(methodVisitor, newClassName)))
.make();
Files.write(Paths.get("xixi.class"), dynamicType.getBytes());
Class<?> redefinedClass = dynamicType.load(MethodSubstitutionExample.class.getClassLoader())
.getLoaded();
}
}
@@ -0,0 +1,62 @@
package com.reajason.javaweb.buddy;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.asm.AsmVisitorWrapper;
import net.bytebuddy.dynamic.DynamicType;
import org.junit.jupiter.api.Test;
import java.util.Collections;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static org.junit.jupiter.api.Assertions.assertEquals;
/**
* @author ReaJason
* @since 2025/2/22
*/
class MethodCallReplaceVisitorWrapperTest {
public static class ExternalClass {
public static String externalMethod(String input) {
return "External: " + input;
}
public static String replacementMethod(String input) {
return "Replaced: " + input;
}
}
public static class TargetClass {
public String targetMethod(String input) {
System.out.println("targetMethod");
return ExternalClass.replacementMethod(input);
}
public static String replacementMethod(String input) {
return "Replaced: " + input;
}
}
@Test
void test() throws Exception {
String newClassName = TargetClass.class.getName() + "Redefinition";
DynamicType.Unloaded<TargetClass> dynamicType = new ByteBuddy()
.redefine(TargetClass.class)
.name(newClassName)
.visit(new AsmVisitorWrapper
.ForDeclaredMethods()
.method(named("targetMethod"),
new MethodCallReplaceVisitorWrapper(
newClassName,
Collections.singleton(ExternalClass.class.getName())
)
)
)
.make();
Class<?> redefinedClass = dynamicType.load(MethodCallReplaceVisitorWrapperTest.class.getClassLoader())
.getLoaded();
Object object = redefinedClass.newInstance();
Object result = object.getClass().getMethod("targetMethod", String.class).invoke(object, "xixi");
assertEquals("Replaced: xixi", result);
}
}