Skip to content

Commit

Permalink
Make it all work.
Browse files Browse the repository at this point in the history
  • Loading branch information
Hallowizer committed Aug 2, 2019
1 parent 37cf960 commit 2348a3f
Show file tree
Hide file tree
Showing 7 changed files with 82 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ private void swapClassFinder() {
Function<String, URL> oldFinder = ReflectUtil.readField(TransformingClassLoader.class, "classBytesFinder", CoremodClassLoader.gameLoader);
Function<String, URL> newFinder = oldFinder.andThen(url -> (isDescript(url) ? null : url));

ClassLoader oldParent = ReflectUtil.readField(ClassLoader.class, "parent", CoremodClassLoader.gameLoader);
ReflectUtil.writeField(ClassLoader.class, "parent", CoremodClassLoader.gameLoader, new DescriptClassLoader(oldParent));

ReflectUtil.writeField(TransformingClassLoader.class, "classBytesFinder", CoremodClassLoader.gameLoader, newFinder);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package net.theopalgames.descript.coremods;

public final class DescriptClassLoader extends ClassLoader {
public DescriptClassLoader(ClassLoader parent) {
super(parent);
}

@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
return getClass().getClassLoader().loadClass(name);
}
}
14 changes: 12 additions & 2 deletions src/main/java/net/theopalgames/descript/init/DescriptInit.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.FileSystem;
import java.nio.file.Path;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
Expand All @@ -25,7 +27,7 @@
import net.minecraftforge.fml.loading.FMLLoader;
import net.minecraftforge.fml.loading.moddiscovery.CoreModFile;

// WARNING: If you make any changes to this file, you need to recompile it and put the bytes into src/main/js/core-plugin.js
// WARNING: No warning anymore lol

@UtilityClass
public class DescriptInit {
Expand All @@ -46,14 +48,22 @@ private File findDescriptJar() throws Exception {

List<CoreMod> coreMods = readField(CoreModEngine.class, "coreMods", engine);
CoreModFile fileWrapper;
Path path;
FileSystem fs;
File file = null;
JarEntry entry;
byte[] bytes;
ClassNode clazz;

for (CoreMod coreMod : coreMods) {
fileWrapper = readField(CoreMod.class, "file", coreMod);
file = fileWrapper.getPath().toFile();
path = fileWrapper.getPath();
fs = path.getFileSystem();

if (fs.getClass().getName().endsWith(".ZipFileSystem"))
path = readField(fs.getClass(), "zfpath", fs);

file = path.toFile();

if (file.isFile()) {
if (file.getName().endsWith(".jar"))
Expand Down
23 changes: 20 additions & 3 deletions src/main/java/net/theopalgames/descript/init/UclClassLoader.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,21 @@

import org.apache.commons.lang3.tuple.Pair;

import lombok.SneakyThrows;
import net.theopalgames.descript.reflect.ReflectUtil;
import net.theopalgames.descript.transformers.UclTransformer;

public final class UclClassLoader extends SecureClassLoader {
private final Map<String, Pair<byte[], ProtectionDomain>> loadedClasses = new HashMap<>();

@SneakyThrows
public IClassLoaderDelegate getDelegate() {
// System.out.println("Defining ClassLoaderDelegate...");

byte[] uclBytes = UclTransformer.getUclLoader(this);
Class<?> clazz = defineClass("net.theopalgames.descript.ucl.ClassLoaderDelegate", uclBytes, 0, uclBytes.length);
createClass("net.theopalgames.descript.ucl.ClassLoaderDelegate", uclBytes, null);

Class<?> clazz = Class.forName("net.theopalgames.descript.ucl.ClassLoaderDelegate", true, this);
Class<? extends IClassLoaderDelegate> cast = clazz.asSubclass(IClassLoaderDelegate.class);
return ReflectUtil.findConstructor(cast, URL[].class, ClassLoader.class).newInstance((Object) new URL[0], getClass().getClassLoader());
}
Expand All @@ -27,10 +33,21 @@ public void createClass(String name, byte[] bytes, ProtectionDomain domain) {
}

@Override
public Class<?> findClass(String name) {
public Class<?> findClass(String name) throws ClassNotFoundException {
if (name.equals("net.theopalgames.descript.init.IClassLoaderDelegate") || name.equals("net.theopalgames.descript.transformers.UclTransformer"))
return getClass().getClassLoader().loadClass(name);

// System.out.println("Loading UCL class " + name);

Pair<byte[], ProtectionDomain> pair = loadedClasses.get(name);
return defineClass(name, pair.getLeft(), 0, pair.getLeft().length, pair.getRight());

// if (pair == null)
// throw new ClassNotFoundException(name, new NullPointerException("pair"));

try {
return defineClass(name, pair.getLeft(), 0, pair.getLeft().length, pair.getRight());
} catch (NullPointerException e) {
throw new ClassNotFoundException(name, e);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@

import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.ClassNode;
Expand All @@ -23,7 +22,7 @@
@UtilityClass
public class InnerUclTransformer {
@SuppressWarnings("unchecked")
public void loadBytes(String name, UclClassLoader classLoader, String clPackage) throws Exception {
public void loadBytes(String name, UclClassLoader classLoader, String clPackage, String descAccess100) throws Exception {
// System.out.println("Transforming inner class: " + name);

if (!name.startsWith("java/net/"))
Expand All @@ -50,6 +49,7 @@ public void loadBytes(String name, UclClassLoader classLoader, String clPackage)
for (MethodNode method : clazz.methods) {
Type type = Type.getMethodType(method.desc);
Type[] args = type.getArgumentTypes();
boolean descChanged = false;

for (int i = 0; i < args.length; i++) {
if (args[i].getDescriptor().equals("Ljava/net/URLClassLoader;"))
Expand All @@ -58,6 +58,11 @@ public void loadBytes(String name, UclClassLoader classLoader, String clPackage)

// System.out.println("\n" + clazz.name + "" + method.name + method.desc);

if (clazz.name.equals("net/theopalgames/descript/ucl/ClassLoaderDelegate$1") && method.name.equals("run") && method.desc.equals("()Ljava/lang/Class;")) {
method.desc = "()Lorg/apache/commons/lang3/tuple/Pair;";
descChanged = true;
}

for (AbstractInsnNode insn : (Iterable<AbstractInsnNode>) () -> method.instructions.iterator()) {
// System.out.println(insn.getOpcode());

Expand All @@ -69,6 +74,10 @@ public void loadBytes(String name, UclClassLoader classLoader, String clPackage)

if (cast.name.equals("defineClass"))
cast.desc = "(Ljava/lang/String;L" + clPackage + "/Resource;)Lorg/apache/commons/lang3/tuple/Pair;";
else if (cast.name.equals("access$100"))
cast.desc = descAccess100;
else if (cast.name.equals("run"))
cast.desc = "()Lorg/apache/commons/lang3/tuple/Pair;";
}

Type calleeType = Type.getMethodType(cast.desc);
Expand All @@ -81,8 +90,8 @@ public void loadBytes(String name, UclClassLoader classLoader, String clPackage)

cast.desc = Type.getMethodType(calleeType.getReturnType(), calleeargs).getDescriptor();

if (cast.getOpcode() == Opcodes.INVOKEVIRTUAL)
System.out.println(clazz.name + "/" + method.name + method.desc + " -> " + cast.owner + "/" + cast.name + cast.desc);
// if (cast.getOpcode() == Opcodes.INVOKEVIRTUAL)
// System.out.println(clazz.name + "/" + method.name + method.desc + " -> " + cast.owner + "/" + cast.name + cast.desc);
} else if (insn instanceof FieldInsnNode) {
FieldInsnNode cast = (FieldInsnNode) insn;

Expand All @@ -106,8 +115,10 @@ public void loadBytes(String name, UclClassLoader classLoader, String clPackage)
}
}

Type newType = Type.getMethodType(type.getReturnType(), args);
method.desc = newType.getDescriptor();
if (!descChanged) {
Type newType = Type.getMethodType(type.getReturnType(), args);
method.desc = newType.getDescriptor();
}
}

ClassWriter cw = new ClassWriter(0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,12 @@ public byte[] getUclLoader(UclClassLoader classLoader) {
List<MethodNode> toRemove = new ArrayList<>();
boolean descChanged;

String descAccess100 = null;

for (MethodNode method : clazz.methods) {
Type type = Type.getMethodType(method.desc);
Type[] args = type.getArgumentTypes();
Type ret = type.getReturnType();
descChanged = false;

for (int i = 0; i < args.length; i++) {
Expand Down Expand Up @@ -151,6 +154,16 @@ public byte[] getUclLoader(UclClassLoader classLoader) {
} else if (method.name.equals("addURL")) {
method.access &= ~Opcodes.ACC_PROTECTED;
method.access |= Opcodes.ACC_PUBLIC;
} else if (method.name.equals("access$100")) {
ret = Type.getType("Lorg/apache/commons/lang3/tuple/Pair;");

for (AbstractInsnNode insn : (Iterable<AbstractInsnNode>) () -> method.instructions.iterator())
if (insn instanceof MethodInsnNode) {
MethodInsnNode cast = (MethodInsnNode) insn;

if (cast.name.equals("defineClass"))
cast.desc = "(Ljava/lang/String;L" + clPackage + "/Resource;)Lorg/apache/commons/lang3/tuple/Pair;";
}
}

for (AbstractInsnNode insn : (Iterable<AbstractInsnNode>) () -> method.instructions.iterator())
Expand Down Expand Up @@ -183,20 +196,22 @@ public byte[] getUclLoader(UclClassLoader classLoader) {
}

if (!descChanged) {
Type ret = type.getReturnType();
if (ret.getDescriptor().equals("Ljava/lang/ClassLoader;"))
ret = Type.getType("Lnet/theopalgames/descript/ucl/ClassLoaderDelegate;");

Type newType = Type.getMethodType(ret, args);
method.desc = newType.getDescriptor();
}

if (method.name.equals("access$100"))
descAccess100 = method.desc;
}

// toRemove.stream().map(method -> method.name + method.desc).forEach(System.out::println);
clazz.methods.removeAll(toRemove);

for (InnerClassNode inner : clazz.innerClasses) {
InnerUclTransformer.loadBytes(inner.name, classLoader, clPackage);
InnerUclTransformer.loadBytes(inner.name, classLoader, clPackage, descAccess100);
inner.name = inner.name.replace("java/net/URLClassLoader", "net/theopalgames/descript/ucl/ClassLoaderDelegate");
}

Expand Down
2 changes: 1 addition & 1 deletion src/main/js/core-plugin.js

Large diffs are not rendered by default.

0 comments on commit 2348a3f

Please sign in to comment.