diff --git a/src/main/java/me/libraryaddict/disguise/utilities/reflection/asm/Asm13.java b/src/main/java/me/libraryaddict/disguise/utilities/reflection/asm/Asm13.java index 8ff01844..4a613cfc 100644 --- a/src/main/java/me/libraryaddict/disguise/utilities/reflection/asm/Asm13.java +++ b/src/main/java/me/libraryaddict/disguise/utilities/reflection/asm/Asm13.java @@ -3,10 +3,11 @@ package me.libraryaddict.disguise.utilities.reflection.asm; import lombok.Getter; import org.objectweb.asm.*; +import java.io.File; import java.io.IOException; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; +import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Map; @@ -15,25 +16,38 @@ import java.util.Map; */ public class Asm13 implements IAsm { @Getter - private Method defineMethod; + private final LibsJarFile libsJarFile; - public Asm13() throws NoSuchMethodException { - defineMethod = getDefineClassMethod(); + public Asm13() throws Throwable { + ClassLoader pluginClassLoader = getClass().getClassLoader(); + Class c = Class.forName("org.bukkit.plugin.java.PluginClassLoader"); + Field file = c.getDeclaredField("file"); + file.setAccessible(true); + + libsJarFile = new LibsJarFile((File) file.get(pluginClassLoader)); + + Field field = c.getDeclaredField("jar"); + field.setAccessible(true); + + Field modifiersField = Field.class.getDeclaredField("modifiers"); + modifiersField.setAccessible(true); + modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL); + + field.set(pluginClassLoader, libsJarFile); } - public Class createClassWithoutMethods(String className, - ArrayList> illegalMethods) throws IOException, InvocationTargetException, - IllegalAccessException, NoSuchFieldException { - ClassReader cr = new ClassReader( - getClass().getClassLoader().getResourceAsStream(className.replace(".", "/") + ".class")); + public void createClassWithoutMethods(String className, ArrayList> illegalMethods) + throws IOException, InvocationTargetException, IllegalAccessException, NoSuchFieldException { + className = className.replace(".", "/") + ".class"; + + ClassReader cr = new ClassReader(getClass().getClassLoader().getResourceAsStream(className)); ClassWriter writer = new ClassWriter(cr, 0); cr.accept(new ClassVisitor(Opcodes.ASM5, writer) { - public MethodVisitor visitMethod(int access, String name, String desc, String signature, - String[] exceptions) { + public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { - Map.Entry entry = illegalMethods.stream() - .filter(e -> e.getKey().equals(name) && e.getValue().equals(desc)).findFirst().orElse(null); + Map.Entry entry = + illegalMethods.stream().filter(e -> e.getKey().equals(name) && e.getValue().equals(desc)).findFirst().orElse(null); if (entry != null) { return null; @@ -43,23 +57,6 @@ public class Asm13 implements IAsm { } }, 0); - byte[] bytes = writer.toByteArray(); - - ClassLoader loader = getClass().getClassLoader(); - Field field = loader.getClass().getDeclaredField("classes"); - field.setAccessible(true); - Map> map = (Map>) field.get(loader); - Class newClass = (Class) defineMethod.invoke(getClass().getClassLoader(), className, bytes, 0, bytes.length); - - map.put(className, newClass); - return newClass; - } - - private Method getDefineClassMethod() throws NoSuchMethodException { - Method defineClass = ClassLoader.class - .getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class); - defineClass.setAccessible(true); - - return defineClass; + libsJarFile.addClass(className, writer.toByteArray()); } } diff --git a/src/main/java/me/libraryaddict/disguise/utilities/reflection/asm/IAsm.java b/src/main/java/me/libraryaddict/disguise/utilities/reflection/asm/IAsm.java index b8096d84..cbf1cdc6 100644 --- a/src/main/java/me/libraryaddict/disguise/utilities/reflection/asm/IAsm.java +++ b/src/main/java/me/libraryaddict/disguise/utilities/reflection/asm/IAsm.java @@ -9,7 +9,7 @@ import java.util.Map; * Created by libraryaddict on 17/02/2020. */ public interface IAsm { - Class createClassWithoutMethods(String className, + void createClassWithoutMethods(String className, ArrayList> illegalMethods) throws IOException, InvocationTargetException, IllegalAccessException, NoSuchMethodException, NoSuchFieldException; } diff --git a/src/main/java/me/libraryaddict/disguise/utilities/reflection/asm/LibsJarFile.java b/src/main/java/me/libraryaddict/disguise/utilities/reflection/asm/LibsJarFile.java new file mode 100644 index 00000000..ed120723 --- /dev/null +++ b/src/main/java/me/libraryaddict/disguise/utilities/reflection/asm/LibsJarFile.java @@ -0,0 +1,40 @@ +package me.libraryaddict.disguise.utilities.reflection.asm; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.zip.ZipEntry; + +/** + * Created by libraryaddict on 15/05/2021. + */ +public class LibsJarFile extends JarFile { + private final HashMap customFiles = new HashMap<>(); + + public LibsJarFile(File file) throws IOException { + super(file); + } + + @Override + public synchronized InputStream getInputStream(ZipEntry ze) throws IOException { + if (customFiles.containsKey(ze.getName())) { + return new ByteArrayInputStream(customFiles.get(ze.getName())); + } + + return super.getInputStream(ze); + } + + public void addClass(String name, byte[] bytes) { + customFiles.put(name, bytes); + } + + @Override + public void close() throws IOException { + customFiles.clear(); + super.close(); + } +} diff --git a/src/main/java/me/libraryaddict/disguise/utilities/reflection/asm/WatcherSanitizer.java b/src/main/java/me/libraryaddict/disguise/utilities/reflection/asm/WatcherSanitizer.java index 1f56fbba..fcbc457f 100644 --- a/src/main/java/me/libraryaddict/disguise/utilities/reflection/asm/WatcherSanitizer.java +++ b/src/main/java/me/libraryaddict/disguise/utilities/reflection/asm/WatcherSanitizer.java @@ -99,10 +99,10 @@ public class WatcherSanitizer { } for (Map.Entry>> entry : toRemove.entrySet()) { - Class result = asm.createClassWithoutMethods(entry.getKey(), entry.getValue()); + asm.createClassWithoutMethods(entry.getKey(), entry.getValue()); mapped.add(entry.getKey()); } - } catch (IOException | IllegalAccessException | InvocationTargetException | NoSuchMethodException | NoSuchFieldException | LinkageError e) { + } catch (Throwable e) { e.printStackTrace(); LibsDisguises.getInstance().getLogger().severe("Registered: " + new Gson().toJson(mapped)); }