Change reflection loading to replace classes in the jar loader instead, pending testing

This commit is contained in:
libraryaddict 2021-05-15 12:31:45 +12:00
parent 44ab504509
commit c8bd25ba57
4 changed files with 71 additions and 34 deletions

View File

@ -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<Map.Entry<String, String>> illegalMethods) throws IOException, InvocationTargetException,
IllegalAccessException, NoSuchFieldException {
ClassReader cr = new ClassReader(
getClass().getClassLoader().getResourceAsStream(className.replace(".", "/") + ".class"));
public void createClassWithoutMethods(String className, ArrayList<Map.Entry<String, String>> 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<String, String> entry = illegalMethods.stream()
.filter(e -> e.getKey().equals(name) && e.getValue().equals(desc)).findFirst().orElse(null);
Map.Entry<String, String> 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<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;
libsJarFile.addClass(className, writer.toByteArray());
}
}

View File

@ -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<Map.Entry<String, String>> illegalMethods) throws IOException, InvocationTargetException,
IllegalAccessException, NoSuchMethodException, NoSuchFieldException;
}

View File

@ -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();
}
}

View File

@ -99,10 +99,10 @@ public class WatcherSanitizer {
}
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());
}
} catch (IOException | IllegalAccessException | InvocationTargetException | NoSuchMethodException | NoSuchFieldException | LinkageError e) {
} catch (Throwable e) {
e.printStackTrace();
LibsDisguises.getInstance().getLogger().severe("Registered: " + new Gson().toJson(mapped));
}