diff --git a/src/main/java/moe/yushi/authlibinjector/AuthlibInjector.java b/src/main/java/moe/yushi/authlibinjector/AuthlibInjector.java index 46a33b4..053ad01 100644 --- a/src/main/java/moe/yushi/authlibinjector/AuthlibInjector.java +++ b/src/main/java/moe/yushi/authlibinjector/AuthlibInjector.java @@ -57,7 +57,6 @@ import moe.yushi.authlibinjector.transform.MainArgumentsTransformer; import moe.yushi.authlibinjector.transform.SkinWhitelistTransformUnit; import moe.yushi.authlibinjector.transform.YggdrasilKeyTransformUnit; import moe.yushi.authlibinjector.transform.support.CitizensTransformer; -import moe.yushi.authlibinjector.transform.support.LaunchWrapperTransformer; import moe.yushi.authlibinjector.transform.support.MC52974Workaround; import moe.yushi.authlibinjector.transform.support.MC52974_1710Workaround; import moe.yushi.authlibinjector.util.Logging; @@ -356,7 +355,6 @@ public final class AuthlibInjector { transformer.units.add(new MainArgumentsTransformer()); transformer.units.add(new ConstantURLTransformUnit(urlProcessor)); transformer.units.add(new CitizensTransformer()); - transformer.units.add(new LaunchWrapperTransformer()); transformer.units.add(new SkinWhitelistTransformUnit(config.getSkinDomains().toArray(new String[0]))); diff --git a/src/main/java/moe/yushi/authlibinjector/transform/AuthlibLogInterceptor.java b/src/main/java/moe/yushi/authlibinjector/transform/AuthlibLogInterceptor.java index 08d404c..36fd244 100644 --- a/src/main/java/moe/yushi/authlibinjector/transform/AuthlibLogInterceptor.java +++ b/src/main/java/moe/yushi/authlibinjector/transform/AuthlibLogInterceptor.java @@ -17,7 +17,6 @@ package moe.yushi.authlibinjector.transform; import static org.objectweb.asm.Opcodes.ASM7; -import static org.objectweb.asm.Opcodes.INVOKESTATIC; import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL; import java.lang.annotation.Annotation; @@ -44,6 +43,7 @@ public class AuthlibLogInterceptor implements TransformUnit { private static Set interceptedClassloaders = Collections.newSetFromMap(new WeakHashMap<>()); + @CallbackMethod public static void onClassLoading(ClassLoader classLoader) { Class classLogManager; try { @@ -212,7 +212,7 @@ public class AuthlibLogInterceptor implements TransformUnit { } @Override - public Optional transform(ClassLoader classLoader, String className, ClassVisitor writer, Runnable modifiedCallback) { + public Optional transform(ClassLoader classLoader, String className, ClassVisitor writer, TransformContext ctx) { if (className.startsWith("com.mojang.authlib.")) { synchronized (interceptedClassloaders) { if (interceptedClassloaders.contains(classLoader)) { @@ -223,14 +223,20 @@ public class AuthlibLogInterceptor implements TransformUnit { @Override public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { - MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions); if ("".equals(name)) { - mv.visitLdcInsn(Type.getType("L" + className.replace('.', '/') + ";")); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getClassLoader", "()Ljava/lang/ClassLoader;", false); - mv.visitMethodInsn(INVOKESTATIC, AuthlibLogInterceptor.class.getName().replace('.', '/'), "onClassLoading", "(Ljava/lang/ClassLoader;)V", false); - modifiedCallback.run(); + return new MethodVisitor(ASM7, super.visitMethod(access, name, descriptor, signature, exceptions)) { + @Override + public void visitCode() { + super.visitCode(); + super.visitLdcInsn(Type.getType("L" + className.replace('.', '/') + ";")); + super.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getClassLoader", "()Ljava/lang/ClassLoader;", false); + CallbackSupport.invoke(ctx, mv, AuthlibLogInterceptor.class, "onClassLoading"); + ctx.markModified(); + } + }; + } else { + return super.visitMethod(access, name, descriptor, signature, exceptions); } - return mv; } }); } diff --git a/src/main/java/moe/yushi/authlibinjector/transform/CallbackEntryPoint.java b/src/main/java/moe/yushi/authlibinjector/transform/CallbackEntryPoint.java new file mode 100644 index 0000000..933c5c8 --- /dev/null +++ b/src/main/java/moe/yushi/authlibinjector/transform/CallbackEntryPoint.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2019 Haowei Wen and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package moe.yushi.authlibinjector.transform; + +import java.lang.invoke.CallSite; +import java.lang.invoke.ConstantCallSite; +import java.lang.invoke.MethodHandles.Lookup; +import java.lang.invoke.MethodType; + +public final class CallbackEntryPoint { + private CallbackEntryPoint() { + } + + public static CallSite bootstrap(Lookup lookup, String name, MethodType type, String owner) throws ReflectiveOperationException { + return new ConstantCallSite( + lookup.findStatic( + ClassLoader.getSystemClassLoader().loadClass(owner), + name, + type)); + } +} diff --git a/src/main/java/moe/yushi/authlibinjector/transform/CallbackMethod.java b/src/main/java/moe/yushi/authlibinjector/transform/CallbackMethod.java new file mode 100644 index 0000000..9167968 --- /dev/null +++ b/src/main/java/moe/yushi/authlibinjector/transform/CallbackMethod.java @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2019 Haowei Wen and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package moe.yushi.authlibinjector.transform; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface CallbackMethod { +} diff --git a/src/main/java/moe/yushi/authlibinjector/transform/CallbackSupport.java b/src/main/java/moe/yushi/authlibinjector/transform/CallbackSupport.java new file mode 100644 index 0000000..00cf9f1 --- /dev/null +++ b/src/main/java/moe/yushi/authlibinjector/transform/CallbackSupport.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2019 Haowei Wen and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package moe.yushi.authlibinjector.transform; + +import static org.objectweb.asm.Opcodes.H_INVOKESTATIC; + +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; + +import org.objectweb.asm.Handle; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Type; + +import moe.yushi.authlibinjector.transform.TransformUnit.TransformContext; + +public final class CallbackSupport { + private CallbackSupport() { + } + + private static Method findCallbackMethod(Class owner, String methodName) { + for (Method method : owner.getDeclaredMethods()) { + int modifiers = method.getModifiers(); + if (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers) && + methodName.equals(method.getName()) && + method.getAnnotation(CallbackMethod.class) != null) { + return method; + } + } + throw new IllegalArgumentException("No such method: " + methodName); + } + + private static final Handle BOOTSTRAP_METHOD = new Handle( + H_INVOKESTATIC, + Type.getInternalName(CallbackEntryPoint.class), + "bootstrap", + "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;", + false); + + public static void invoke(TransformContext ctx, MethodVisitor mv, Class owner, String methodName) { + ctx.requireMinimumClassVersion(50); + ctx.upgradeClassVersion(51); + + String descriptor = Type.getMethodDescriptor(findCallbackMethod(owner, methodName)); + mv.visitInvokeDynamicInsn(methodName, descriptor, BOOTSTRAP_METHOD, owner.getName()); + } +} diff --git a/src/main/java/moe/yushi/authlibinjector/transform/ClassTransformer.java b/src/main/java/moe/yushi/authlibinjector/transform/ClassTransformer.java index 1cd6580..44b504f 100644 --- a/src/main/java/moe/yushi/authlibinjector/transform/ClassTransformer.java +++ b/src/main/java/moe/yushi/authlibinjector/transform/ClassTransformer.java @@ -17,6 +17,7 @@ package moe.yushi.authlibinjector.transform; import static java.util.Collections.emptyList; +import static org.objectweb.asm.Opcodes.ASM7; import java.lang.instrument.ClassFileTransformer; import java.lang.instrument.IllegalClassFormatException; @@ -34,6 +35,7 @@ import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.ClassWriter; import moe.yushi.authlibinjector.AuthlibInjector; +import moe.yushi.authlibinjector.transform.TransformUnit.TransformContext; import moe.yushi.authlibinjector.util.Logging; public class ClassTransformer implements ClassFileTransformer { @@ -46,12 +48,71 @@ public class ClassTransformer implements ClassFileTransformer { private static class TransformHandle { + private static class TransformContextImpl implements TransformContext { + public boolean modifiedMark; + public int minVersionMark = -1; + public int upgradedVersionMark = -1; + + @Override + public void markModified() { + modifiedMark = true; + } + + @Override + public void requireMinimumClassVersion(int version) { + if (this.minVersionMark < version) { + this.minVersionMark = version; + } + } + + @Override + public void upgradeClassVersion(int version) { + if (this.upgradedVersionMark < version) { + this.upgradedVersionMark = version; + } + } + } + + private static class ClassVersionException extends RuntimeException { + public ClassVersionException(String message) { + super(message); + } + } + + private class ClassVersionTransformUnit implements TransformUnit { + @Override + public Optional transform(ClassLoader classLoader, String className, ClassVisitor writer, TransformContext context) { + return Optional.of(new ClassVisitor(ASM7, writer) { + @Override + public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { + int major = version & 0xffff; + + if (minVersion != -1 && major < minVersion) { + throw new ClassVersionException("class version (" + major + ") is lower than required(" + minVersion + ")"); + } + + if (upgradedVersion != -1 && major < upgradedVersion) { + Logging.TRANSFORM.fine("Upgrading class version from " + major + " to " + upgradedVersion); + version = upgradedVersion; + context.markModified(); + } + super.visit(version, access, name, signature, superName, interfaces); + } + }); + } + + @Override + public String toString() { + return "Class File Version Transformer"; + } + } + private List appliedTransformers; - private boolean currentModified; private String className; private byte[] classBuffer; - private ClassWriter pooledClassWriter; private ClassLoader classLoader; + private int minVersion = -1; + private int upgradedVersion = -1; public TransformHandle(ClassLoader classLoader, String className, byte[] classBuffer) { this.className = className; @@ -60,37 +121,45 @@ public class ClassTransformer implements ClassFileTransformer { } public void accept(TransformUnit unit) { - ClassWriter writer; - if (pooledClassWriter == null) { - writer = new ClassWriter(ClassWriter.COMPUTE_MAXS); - } else { - writer = pooledClassWriter; - pooledClassWriter = null; - } + ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS); + TransformContextImpl ctx = new TransformContextImpl(); - Optional optionalVisitor = unit.transform(classLoader, className, writer, () -> currentModified = true); + Optional optionalVisitor = unit.transform(classLoader, className, writer, ctx); if (optionalVisitor.isPresent()) { - currentModified = false; ClassReader reader = new ClassReader(classBuffer); reader.accept(optionalVisitor.get(), 0); - if (currentModified) { + if (ctx.modifiedMark) { Logging.TRANSFORM.info("Transformed [" + className + "] with [" + unit + "]"); if (appliedTransformers == null) { appliedTransformers = new ArrayList<>(); } appliedTransformers.add(unit); classBuffer = writer.toByteArray(); + if (ctx.minVersionMark > this.minVersion) { + this.minVersion = ctx.minVersionMark; + } + if (ctx.upgradedVersionMark > this.upgradedVersion) { + this.upgradedVersion = ctx.upgradedVersionMark; + } } - } else { - pooledClassWriter = writer; } } - public Optional getTransformResult() { + public Optional finish() { if (appliedTransformers == null || appliedTransformers.isEmpty()) { return Optional.empty(); } else { - return Optional.of(classBuffer); + if (minVersion == -1 && upgradedVersion == -1) { + return Optional.of(classBuffer); + } else { + try { + accept(new ClassVersionTransformUnit()); + return Optional.of(classBuffer); + } catch (ClassVersionException e) { + Logging.TRANSFORM.warning("Skipping [" + className + "], " + e.getMessage()); + return Optional.empty(); + } + } } } @@ -119,7 +188,7 @@ public class ClassTransformer implements ClassFileTransformer { units.forEach(handle::accept); listeners.forEach(it -> it.onClassLoading(loader, className, handle.getFinalResult(), handle.getAppliedTransformers())); - Optional transformResult = handle.getTransformResult(); + Optional transformResult = handle.finish(); if (PRINT_UNTRANSFORMED_CLASSES && !transformResult.isPresent()) { Logging.TRANSFORM.fine("No transformation is applied to [" + className + "]"); } diff --git a/src/main/java/moe/yushi/authlibinjector/transform/LdcTransformUnit.java b/src/main/java/moe/yushi/authlibinjector/transform/LdcTransformUnit.java index eefda6f..50d6726 100644 --- a/src/main/java/moe/yushi/authlibinjector/transform/LdcTransformUnit.java +++ b/src/main/java/moe/yushi/authlibinjector/transform/LdcTransformUnit.java @@ -24,7 +24,7 @@ import org.objectweb.asm.MethodVisitor; public abstract class LdcTransformUnit implements TransformUnit { @Override - public Optional transform(ClassLoader classLoader, String className, ClassVisitor writer, Runnable modifiedCallback) { + public Optional transform(ClassLoader classLoader, String className, ClassVisitor writer, TransformContext ctx) { return Optional.of(new ClassVisitor(ASM7, writer) { @Override @@ -36,7 +36,7 @@ public abstract class LdcTransformUnit implements TransformUnit { if (cst instanceof String) { Optional transformed = transformLdc((String) cst); if (transformed.isPresent() && !transformed.get().equals(cst)) { - modifiedCallback.run(); + ctx.markModified(); super.visitLdcInsn(transformed.get()); } else { super.visitLdcInsn(cst); diff --git a/src/main/java/moe/yushi/authlibinjector/transform/MainArgumentsTransformer.java b/src/main/java/moe/yushi/authlibinjector/transform/MainArgumentsTransformer.java index 5ae164a..02011e2 100644 --- a/src/main/java/moe/yushi/authlibinjector/transform/MainArgumentsTransformer.java +++ b/src/main/java/moe/yushi/authlibinjector/transform/MainArgumentsTransformer.java @@ -20,7 +20,6 @@ import static java.util.stream.Collectors.joining; import static org.objectweb.asm.Opcodes.ALOAD; import static org.objectweb.asm.Opcodes.ASM7; import static org.objectweb.asm.Opcodes.ASTORE; -import static org.objectweb.asm.Opcodes.INVOKESTATIC; import java.util.List; import java.util.Optional; @@ -31,14 +30,13 @@ import java.util.stream.Stream; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Type; import moe.yushi.authlibinjector.util.Logging; public class MainArgumentsTransformer implements TransformUnit { @Override - public Optional transform(ClassLoader classLoader, String className, ClassVisitor writer, Runnable modifiedCallback) { + public Optional transform(ClassLoader classLoader, String className, ClassVisitor writer, TransformContext ctx) { if ("net.minecraft.client.main.Main".equals(className)) { return Optional.of(new ClassVisitor(ASM7, writer) { @Override @@ -48,10 +46,10 @@ public class MainArgumentsTransformer implements TransformUnit { @Override public void visitCode() { super.visitCode(); - modifiedCallback.run(); + ctx.markModified(); super.visitVarInsn(ALOAD, 0); - super.visitMethodInsn(INVOKESTATIC, Type.getInternalName(MainArgumentsTransformer.class), "processMainArguments", "([Ljava/lang/String;)[Ljava/lang/String;", false); + CallbackSupport.invoke(ctx, mv, MainArgumentsTransformer.class, "processMainArguments"); super.visitVarInsn(ASTORE, 0); } }; @@ -73,6 +71,7 @@ public class MainArgumentsTransformer implements TransformUnit { // ==== Main arguments processing ==== private static final List> ARGUMENTS_LISTENERS = new CopyOnWriteArrayList<>(); + @CallbackMethod public static String[] processMainArguments(String[] args) { Logging.TRANSFORM.fine(() -> "Main arguments: " + Stream.of(args).collect(joining(" "))); diff --git a/src/main/java/moe/yushi/authlibinjector/transform/SkinWhitelistTransformUnit.java b/src/main/java/moe/yushi/authlibinjector/transform/SkinWhitelistTransformUnit.java index ebd7062..6f0e789 100644 --- a/src/main/java/moe/yushi/authlibinjector/transform/SkinWhitelistTransformUnit.java +++ b/src/main/java/moe/yushi/authlibinjector/transform/SkinWhitelistTransformUnit.java @@ -37,7 +37,7 @@ public class SkinWhitelistTransformUnit implements TransformUnit { } @Override - public Optional transform(ClassLoader classLoader, String className, ClassVisitor writer, Runnable modifiedCallback) { + public Optional transform(ClassLoader classLoader, String className, ClassVisitor writer, TransformContext ctx) { if ("com.mojang.authlib.yggdrasil.YggdrasilMinecraftSessionService".equals(className)) { return Optional.of(new ClassVisitor(ASM7, writer) { @@ -59,7 +59,7 @@ public class SkinWhitelistTransformUnit implements TransformUnit { } else if ((status == 5 || status == 9) && opcode == AASTORE) { status++; if (status == 10) { - modifiedCallback.run(); + ctx.markModified(); super.visitIntInsn(SIPUSH, skinWhitelist.length + 2); super.visitTypeInsn(ANEWARRAY, "java/lang/String"); super.visitInsn(DUP); diff --git a/src/main/java/moe/yushi/authlibinjector/transform/TransformUnit.java b/src/main/java/moe/yushi/authlibinjector/transform/TransformUnit.java index c6001d5..993a471 100644 --- a/src/main/java/moe/yushi/authlibinjector/transform/TransformUnit.java +++ b/src/main/java/moe/yushi/authlibinjector/transform/TransformUnit.java @@ -21,6 +21,16 @@ import org.objectweb.asm.ClassVisitor; public interface TransformUnit { - Optional transform(ClassLoader classLoader, String className, ClassVisitor writer, Runnable modifiedCallback); + public interface TransformContext { + + void markModified(); + + void requireMinimumClassVersion(int version); + + void upgradeClassVersion(int version); + + } + + Optional transform(ClassLoader classLoader, String className, ClassVisitor writer, TransformContext context); } diff --git a/src/main/java/moe/yushi/authlibinjector/transform/YggdrasilKeyTransformUnit.java b/src/main/java/moe/yushi/authlibinjector/transform/YggdrasilKeyTransformUnit.java index e4df851..fdcec91 100644 --- a/src/main/java/moe/yushi/authlibinjector/transform/YggdrasilKeyTransformUnit.java +++ b/src/main/java/moe/yushi/authlibinjector/transform/YggdrasilKeyTransformUnit.java @@ -43,18 +43,18 @@ import java.util.concurrent.CopyOnWriteArrayList; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Type; public class YggdrasilKeyTransformUnit implements TransformUnit { private static final List PUBLIC_KEYS = new CopyOnWriteArrayList<>(); + @CallbackMethod public static List getPublicKeys() { return PUBLIC_KEYS; } @Override - public Optional transform(ClassLoader classLoader, String className, ClassVisitor writer, Runnable modifiedCallback) { + public Optional transform(ClassLoader classLoader, String className, ClassVisitor writer, TransformContext ctx) { if ("com.mojang.authlib.yggdrasil.YggdrasilMinecraftSessionService".equals(className)) { return Optional.of(new ClassVisitor(ASM7, writer) { @@ -76,7 +76,7 @@ public class YggdrasilKeyTransformUnit implements TransformUnit { mv.visitInsn(IRETURN); mv.visitLabel(l0); mv.visitFrame(F_SAME, 0, null, 0, null); - mv.visitMethodInsn(INVOKESTATIC, Type.getInternalName(YggdrasilKeyTransformUnit.class), "getPublicKeys", "()Ljava/util/List;", false); + CallbackSupport.invoke(ctx, mv, YggdrasilKeyTransformUnit.class, "getPublicKeys"); mv.visitMethodInsn(INVOKEINTERFACE, "java/util/List", "iterator", "()Ljava/util/Iterator;", true); mv.visitVarInsn(ASTORE, 2); Label l1 = new Label(); @@ -117,7 +117,7 @@ public class YggdrasilKeyTransformUnit implements TransformUnit { && "com/mojang/authlib/properties/Property".equals(owner) && "isSignatureValid".equals(name) && "(Ljava/security/PublicKey;)Z".equals(descriptor)) { - modifiedCallback.run(); + ctx.markModified(); super.visitMethodInsn(INVOKESTATIC, "com/mojang/authlib/yggdrasil/YggdrasilMinecraftSessionService", "authlib_injector_isSignatureValid", diff --git a/src/main/java/moe/yushi/authlibinjector/transform/support/CitizensTransformer.java b/src/main/java/moe/yushi/authlibinjector/transform/support/CitizensTransformer.java index abcba96..5114151 100644 --- a/src/main/java/moe/yushi/authlibinjector/transform/support/CitizensTransformer.java +++ b/src/main/java/moe/yushi/authlibinjector/transform/support/CitizensTransformer.java @@ -42,7 +42,7 @@ import moe.yushi.authlibinjector.transform.TransformUnit; public class CitizensTransformer implements TransformUnit { @Override - public Optional transform(ClassLoader classLoader, String className, ClassVisitor writer, Runnable modifiedCallback) { + public Optional transform(ClassLoader classLoader, String className, ClassVisitor writer, TransformContext ctx) { if ("net.citizensnpcs.Settings$Setting".equals(className)) { return Optional.of(new ClassVisitor(ASM7, writer) { @Override @@ -62,7 +62,7 @@ public class CitizensTransformer implements TransformUnit { super.visitInsn(RETURN); super.visitLabel(lbl); super.visitFrame(F_SAME, 0, null, 0, null); - modifiedCallback.run(); + ctx.markModified(); } }; } diff --git a/src/main/java/moe/yushi/authlibinjector/transform/support/LaunchWrapperTransformer.java b/src/main/java/moe/yushi/authlibinjector/transform/support/LaunchWrapperTransformer.java deleted file mode 100644 index 5af75b8..0000000 --- a/src/main/java/moe/yushi/authlibinjector/transform/support/LaunchWrapperTransformer.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2019 Haowei Wen and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package moe.yushi.authlibinjector.transform.support; - -import static org.objectweb.asm.Opcodes.ALOAD; -import static org.objectweb.asm.Opcodes.ASM7; -import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL; -import static org.objectweb.asm.Opcodes.RETURN; - -import java.util.Optional; - -import org.objectweb.asm.ClassVisitor; -import org.objectweb.asm.MethodVisitor; - -import moe.yushi.authlibinjector.transform.TransformUnit; - -public class LaunchWrapperTransformer implements TransformUnit { - - @Override - public Optional transform(ClassLoader classLoader, String className, ClassVisitor writer, Runnable modifiedCallback) { - if ("net.minecraft.launchwrapper.LaunchClassLoader".equals(className)) { - return Optional.of(new ClassVisitor(ASM7, writer) { - @Override - public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { - if ("".equals(name)) { - return new MethodVisitor(ASM7, super.visitMethod(access, name, descriptor, signature, exceptions)) { - @Override - public void visitInsn(int opcode) { - if (opcode == RETURN) { - modifiedCallback.run(); - super.visitVarInsn(ALOAD, 0); - super.visitLdcInsn("moe.yushi.authlibinjector."); - super.visitMethodInsn(INVOKEVIRTUAL, "net/minecraft/launchwrapper/LaunchClassLoader", "addClassLoaderExclusion", "(Ljava/lang/String;)V", false); - } - super.visitInsn(opcode); - } - }; - } else { - return super.visitMethod(access, name, descriptor, signature, exceptions); - } - } - }); - } else { - return Optional.empty(); - } - } - - @Override - public String toString() { - return "LaunchWrapper Support"; - } -} diff --git a/src/main/java/moe/yushi/authlibinjector/transform/support/MC52974Workaround.java b/src/main/java/moe/yushi/authlibinjector/transform/support/MC52974Workaround.java index 60aef98..032b103 100644 --- a/src/main/java/moe/yushi/authlibinjector/transform/support/MC52974Workaround.java +++ b/src/main/java/moe/yushi/authlibinjector/transform/support/MC52974Workaround.java @@ -60,7 +60,7 @@ public class MC52974Workaround implements TransformUnit { } @Override - public Optional transform(ClassLoader classLoader, String className, ClassVisitor writer, Runnable modifiedCallback) { + public Optional transform(ClassLoader classLoader, String className, ClassVisitor writer, TransformContext ctx) { if ("com.mojang.authlib.yggdrasil.YggdrasilMinecraftSessionService".equals(className)) { return Optional.of(new ClassVisitor(ASM7, writer) { @Override @@ -70,7 +70,7 @@ public class MC52974Workaround implements TransformUnit { @Override public void visitCode() { super.visitCode(); - modifiedCallback.run(); + ctx.markModified(); super.visitLdcInsn(1); super.visitVarInsn(ISTORE, 2); } diff --git a/src/main/java/moe/yushi/authlibinjector/transform/support/MC52974_1710Workaround.java b/src/main/java/moe/yushi/authlibinjector/transform/support/MC52974_1710Workaround.java index 4ce0970..abd5f5d 100644 --- a/src/main/java/moe/yushi/authlibinjector/transform/support/MC52974_1710Workaround.java +++ b/src/main/java/moe/yushi/authlibinjector/transform/support/MC52974_1710Workaround.java @@ -31,9 +31,10 @@ import java.util.logging.Level; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Type; import moe.yushi.authlibinjector.AuthlibInjector; +import moe.yushi.authlibinjector.transform.CallbackMethod; +import moe.yushi.authlibinjector.transform.CallbackSupport; import moe.yushi.authlibinjector.transform.MainArgumentsTransformer; import moe.yushi.authlibinjector.transform.TransformUnit; import moe.yushi.authlibinjector.util.Logging; @@ -57,12 +58,14 @@ public class MC52974_1710Workaround { // Empty GameProfile -> Filled GameProfile? private static final Map> markedGameProfiles = new WeakIdentityHashMap<>(); + @CallbackMethod public static void markGameProfile(Object gp) { synchronized (markedGameProfiles) { markedGameProfiles.putIfAbsent(gp, Optional.empty()); } } + @CallbackMethod public static Object accessGameProfile(Object gp, Object minecraftServer, boolean isNotchName) { synchronized (markedGameProfiles) { Optional value = markedGameProfiles.get(gp); @@ -105,7 +108,7 @@ public class MC52974_1710Workaround { private static class SessionTransformer implements TransformUnit { @Override - public Optional transform(ClassLoader classLoader, String className, ClassVisitor writer, Runnable modifiedCallback) { + public Optional transform(ClassLoader classLoader, String className, ClassVisitor writer, TransformContext ctx) { return detectNotchName(className, "bbs", "net.minecraft.util.Session", isNotchName -> new ClassVisitor(ASM7, writer) { @Override public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { @@ -117,9 +120,9 @@ public class MC52974_1710Workaround { @Override public void visitInsn(int opcode) { if (opcode == ARETURN) { - modifiedCallback.run(); + ctx.markModified(); super.visitInsn(DUP); - super.visitMethodInsn(INVOKESTATIC, Type.getInternalName(MC52974_1710Workaround.class), "markGameProfile", "(Ljava/lang/Object;)V", false); + CallbackSupport.invoke(ctx, mv, MC52974_1710Workaround.class, "markGameProfile"); } super.visitInsn(opcode); } @@ -139,7 +142,7 @@ public class MC52974_1710Workaround { private static class S0CPacketSpawnPlayerTransformer implements TransformUnit { @Override - public Optional transform(ClassLoader classLoader, String className, ClassVisitor writer, Runnable modifiedCallback) { + public Optional transform(ClassLoader classLoader, String className, ClassVisitor writer, TransformContext ctx) { return detectNotchName(className, "gb", "net.minecraft.network.play.server.S0CPacketSpawnPlayer", isNotchName -> new ClassVisitor(ASM7, writer) { @Override public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { @@ -155,14 +158,14 @@ public class MC52974_1710Workaround { if (opcode == GETFIELD && (isNotchName ? "gb".equals(owner) && "b".equals(name) && "Lcom/mojang/authlib/GameProfile;".equals(descriptor) : "net/minecraft/network/play/server/S0CPacketSpawnPlayer".equals(owner) && "field_148955_b".equals(name) && "Lcom/mojang/authlib/GameProfile;".equals(descriptor))) { - modifiedCallback.run(); + ctx.markModified(); if (isNotchName) { super.visitMethodInsn(INVOKESTATIC, "net/minecraft/server/MinecraftServer", "I", "()Lnet/minecraft/server/MinecraftServer;", false); } else { super.visitMethodInsn(INVOKESTATIC, "net/minecraft/server/MinecraftServer", "func_71276_C", "()Lnet/minecraft/server/MinecraftServer;", false); } super.visitLdcInsn(isNotchName ? 1 : 0); - super.visitMethodInsn(INVOKESTATIC, Type.getInternalName(MC52974_1710Workaround.class), "accessGameProfile", "(Ljava/lang/Object;Ljava/lang/Object;Z)Ljava/lang/Object;", false); + CallbackSupport.invoke(ctx, mv, MC52974_1710Workaround.class, "accessGameProfile"); super.visitTypeInsn(CHECKCAST, "com/mojang/authlib/GameProfile"); } }