Change reflection loading to replace classes in the jar loader instead, pending testing
This commit is contained in:
parent
44ab504509
commit
c8bd25ba57
@ -3,10 +3,11 @@ package me.libraryaddict.disguise.utilities.reflection.asm;
|
|||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import org.objectweb.asm.*;
|
import org.objectweb.asm.*;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Modifier;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@ -15,25 +16,38 @@ import java.util.Map;
|
|||||||
*/
|
*/
|
||||||
public class Asm13 implements IAsm {
|
public class Asm13 implements IAsm {
|
||||||
@Getter
|
@Getter
|
||||||
private Method defineMethod;
|
private final LibsJarFile libsJarFile;
|
||||||
|
|
||||||
public Asm13() throws NoSuchMethodException {
|
public Asm13() throws Throwable {
|
||||||
defineMethod = getDefineClassMethod();
|
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,
|
public void createClassWithoutMethods(String className, ArrayList<Map.Entry<String, String>> illegalMethods)
|
||||||
ArrayList<Map.Entry<String, String>> illegalMethods) throws IOException, InvocationTargetException,
|
throws IOException, InvocationTargetException, IllegalAccessException, NoSuchFieldException {
|
||||||
IllegalAccessException, NoSuchFieldException {
|
className = className.replace(".", "/") + ".class";
|
||||||
ClassReader cr = new ClassReader(
|
|
||||||
getClass().getClassLoader().getResourceAsStream(className.replace(".", "/") + ".class"));
|
ClassReader cr = new ClassReader(getClass().getClassLoader().getResourceAsStream(className));
|
||||||
ClassWriter writer = new ClassWriter(cr, 0);
|
ClassWriter writer = new ClassWriter(cr, 0);
|
||||||
|
|
||||||
cr.accept(new ClassVisitor(Opcodes.ASM5, writer) {
|
cr.accept(new ClassVisitor(Opcodes.ASM5, writer) {
|
||||||
public MethodVisitor visitMethod(int access, String name, String desc, String signature,
|
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
|
||||||
String[] exceptions) {
|
|
||||||
|
|
||||||
Map.Entry<String, String> entry = illegalMethods.stream()
|
Map.Entry<String, String> entry =
|
||||||
.filter(e -> e.getKey().equals(name) && e.getValue().equals(desc)).findFirst().orElse(null);
|
illegalMethods.stream().filter(e -> e.getKey().equals(name) && e.getValue().equals(desc)).findFirst().orElse(null);
|
||||||
|
|
||||||
if (entry != null) {
|
if (entry != null) {
|
||||||
return null;
|
return null;
|
||||||
@ -43,23 +57,6 @@ public class Asm13 implements IAsm {
|
|||||||
}
|
}
|
||||||
}, 0);
|
}, 0);
|
||||||
|
|
||||||
byte[] bytes = writer.toByteArray();
|
libsJarFile.addClass(className, writer.toByteArray());
|
||||||
|
|
||||||
ClassLoader loader = getClass().getClassLoader();
|
|
||||||
Field field = loader.getClass().getDeclaredField("classes");
|
|
||||||
field.setAccessible(true);
|
|
||||||
Map<String, Class<?>> map = (Map<String, Class<?>>) 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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ import java.util.Map;
|
|||||||
* Created by libraryaddict on 17/02/2020.
|
* Created by libraryaddict on 17/02/2020.
|
||||||
*/
|
*/
|
||||||
public interface IAsm {
|
public interface IAsm {
|
||||||
Class<?> createClassWithoutMethods(String className,
|
void createClassWithoutMethods(String className,
|
||||||
ArrayList<Map.Entry<String, String>> illegalMethods) throws IOException, InvocationTargetException,
|
ArrayList<Map.Entry<String, String>> illegalMethods) throws IOException, InvocationTargetException,
|
||||||
IllegalAccessException, NoSuchMethodException, NoSuchFieldException;
|
IllegalAccessException, NoSuchMethodException, NoSuchFieldException;
|
||||||
}
|
}
|
||||||
|
@ -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<String, byte[]> 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();
|
||||||
|
}
|
||||||
|
}
|
@ -99,10 +99,10 @@ public class WatcherSanitizer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (Map.Entry<String, ArrayList<Map.Entry<String, String>>> entry : toRemove.entrySet()) {
|
for (Map.Entry<String, ArrayList<Map.Entry<String, String>>> entry : toRemove.entrySet()) {
|
||||||
Class result = asm.createClassWithoutMethods(entry.getKey(), entry.getValue());
|
asm.createClassWithoutMethods(entry.getKey(), entry.getValue());
|
||||||
mapped.add(entry.getKey());
|
mapped.add(entry.getKey());
|
||||||
}
|
}
|
||||||
} catch (IOException | IllegalAccessException | InvocationTargetException | NoSuchMethodException | NoSuchFieldException | LinkageError e) {
|
} catch (Throwable e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
LibsDisguises.getInstance().getLogger().severe("Registered: " + new Gson().toJson(mapped));
|
LibsDisguises.getInstance().getLogger().severe("Registered: " + new Gson().toJson(mapped));
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user