Remap in reflect calls to defineClass

This commit is contained in:
IzzelAliz 2020-12-11 14:00:33 +08:00
parent dd5be5a46d
commit df6517ee6e
3 changed files with 79 additions and 2 deletions

View File

@ -2,6 +2,7 @@ package io.izzel.arclight.common.mod.util.remapper;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import cpw.mods.modlauncher.api.LamdbaExceptionUtils;
import io.izzel.arclight.common.mod.ArclightMod;
import io.izzel.arclight.common.mod.util.remapper.generated.RemappingURLClassLoader;
import org.apache.logging.log4j.Marker;
@ -21,11 +22,14 @@ import org.objectweb.asm.tree.MethodNode;
import org.objectweb.asm.tree.TypeInsnNode;
import org.objectweb.asm.tree.VarInsnNode;
import java.lang.invoke.MethodType;
import java.net.URLClassLoader;
import java.nio.ByteBuffer;
import java.security.SecureClassLoader;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
public class ClassLoaderAdapter implements PluginTransformer {
@ -44,6 +48,27 @@ public class ClassLoaderAdapter implements PluginTransformer {
private final Map<String, String> classLoaderTypes = ImmutableMap.<String, String>builder()
.put(Type.getInternalName(URLClassLoader.class), Type.getInternalName(RemappingURLClassLoader.class))
.build();
private final Set<ClassLoaderRemapper.WrappedMethod> defineClassMethods = defineClassTypes.entrySet().stream()
.map(LamdbaExceptionUtils.rethrowFunction(entry -> {
MethodType type = MethodType.fromMethodDescriptorString(entry.getKey().getDescriptor(), getClass().getClassLoader());
return new ClassLoaderRemapper.WrappedMethod("defineClass", type.parameterArray());
})).collect(Collectors.toSet());
public static boolean isDefineClassMethod(Class<?> cl, String bukkitName, Class<?>[] pTypes) {
if (bukkitName.equals("defineClass") && ClassLoader.class.isAssignableFrom(cl)) {
return INSTANCE.defineClassMethods.contains(new ClassLoaderRemapper.WrappedMethod(bukkitName, pTypes));
} else {
return false;
}
}
public static boolean isDefineClassMethod(Class<?> cl, String bukkitName, MethodType methodType) {
if (bukkitName.equals("defineClass") && ClassLoader.class.isAssignableFrom(cl)) {
return INSTANCE.defineClassMethods.contains(new ClassLoaderRemapper.WrappedMethod(bukkitName, methodType.parameterArray()));
} else {
return false;
}
}
@Override
public void handleClass(ClassNode node, ClassLoaderRemapper remapper) {

View File

@ -359,7 +359,7 @@ public class ClassLoaderRemapper extends JarRemapper {
}
private static class WrappedMethod {
static class WrappedMethod {
private final String name;
private final Class<?>[] pTypes;

View File

@ -1,5 +1,7 @@
package io.izzel.arclight.common.mod.util.remapper.generated;
import io.izzel.arclight.api.Unsafe;
import io.izzel.arclight.common.mod.util.remapper.ClassLoaderAdapter;
import io.izzel.arclight.common.mod.util.remapper.ClassLoaderRemapper;
import org.objectweb.asm.Type;
@ -8,9 +10,13 @@ import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.nio.ByteBuffer;
import java.security.CodeSource;
import java.security.Permissions;
import java.security.ProtectionDomain;
@SuppressWarnings("unused")
public class ArclightReflectionHandler {
public class ArclightReflectionHandler extends ClassLoader {
private static final String PREFIX = "net.minecraft.";
@ -46,6 +52,12 @@ public class ArclightReflectionHandler {
// bukkit -> srg
public static Method redirectGetMethod(Class<?> cl, String bukkitName, Class<?>... pTypes) throws NoSuchMethodException {
if (ClassLoaderAdapter.isDefineClassMethod(cl, bukkitName, pTypes)) {
Class<?>[] classes = new Class<?>[pTypes.length + 1];
classes[0] = ClassLoader.class;
System.arraycopy(pTypes, 0, classes, 1, pTypes.length);
return ArclightReflectionHandler.class.getMethod(bukkitName, classes);
}
Method method = remapper.tryMapMethodToSrg(cl, bukkitName, pTypes);
if (method != null) {
return method;
@ -56,6 +68,12 @@ public class ArclightReflectionHandler {
// bukkit -> srg
public static Method redirectGetDeclaredMethod(Class<?> cl, String bukkitName, Class<?>... pTypes) throws NoSuchMethodException {
if (ClassLoaderAdapter.isDefineClassMethod(cl, bukkitName, pTypes)) {
Class<?>[] classes = new Class<?>[pTypes.length + 1];
classes[0] = ClassLoader.class;
System.arraycopy(pTypes, 0, classes, 1, pTypes.length);
return ArclightReflectionHandler.class.getDeclaredMethod(bukkitName, classes);
}
Method method = remapper.tryMapMethodToSrg(cl, bukkitName, pTypes);
if (method != null) {
return method;
@ -147,6 +165,13 @@ public class ArclightReflectionHandler {
// bukkit -> srg
public static MethodHandle redirectFindVirtual(MethodHandles.Lookup lookup, Class<?> cl, String name, MethodType methodType) throws NoSuchMethodException, IllegalAccessException {
if (ClassLoaderAdapter.isDefineClassMethod(cl, name, methodType)) {
Class<?>[] pTypes = methodType.parameterArray();
Class<?>[] classes = new Class<?>[pTypes.length + 1];
classes[0] = ClassLoader.class;
System.arraycopy(pTypes, 0, classes, 1, pTypes.length);
return lookup.findStatic(ArclightReflectionHandler.class, name, MethodType.methodType(Class.class, classes));
}
Method method = remapper.tryMapMethodToSrg(cl, name, methodType.parameterArray());
if (method != null) {
return lookup.findVirtual(cl, method.getName(), methodType);
@ -197,4 +222,31 @@ public class ArclightReflectionHandler {
String replace = remapper.mapType(canonicalName.replace('.', '/')).replace('/', '.');
return loader.loadClass(replace);
}
public static Class<?> defineClass(ClassLoader loader, byte[] b, int off, int len) {
return defineClass(loader, null, b, off, len);
}
public static Class<?> defineClass(ClassLoader loader, String name, byte[] b, int off, int len) {
return defineClass(loader, name, b, off, len, (ProtectionDomain) null);
}
public static Class<?> defineClass(ClassLoader loader, String name, byte[] b, int off, int len, ProtectionDomain pd) {
byte[] bytes = remapper.remapClass(b);
return Unsafe.defineClass(name, bytes, 0, bytes.length, loader, pd);
}
public static Class<?> defineClass(ClassLoader loader, String name, ByteBuffer b, ProtectionDomain pd) {
byte[] bytes = new byte[b.remaining()];
b.get(bytes);
return defineClass(loader, name, bytes, 0, bytes.length, pd);
}
public static Class<?> defineClass(ClassLoader loader, String name, byte[] b, int off, int len, CodeSource cs) {
return defineClass(loader, name, b, off, len, new ProtectionDomain(cs, new Permissions()));
}
public static Class<?> defineClass(ClassLoader loader, String name, ByteBuffer b, CodeSource cs) {
return defineClass(loader, name, b, new ProtectionDomain(cs, new Permissions()));
}
}