mitigation: Mitigate AE1 bug

AE1 mistakenly passes in `1` as an ASM api version when it uses
`SignatureVisitor`. This is valid in ASM4 because it never checks if the
Opcode is valid, this is fixed in ASM5, which we override ASM4 with due
to compatibility issues with the Java 8 JRE we use
This commit is contained in:
alexytomi
2025-12-06 15:04:35 +08:00
parent 79e88cf6d5
commit ea571a968d
4 changed files with 97 additions and 1 deletions

View File

@@ -1 +1 @@
b35956195a536dfa5895ca6d40d13c718de4d7fa
59b2f04b91fb2c8c20148554f1388007c2265bd8

View File

@@ -0,0 +1,89 @@
package org.angelauramc.lwjgl2_methods_injector;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.Instrumentation;
import java.security.ProtectionDomain;
/**
* Used to forcibly run asm 5.0.4 without any pesky detection scheme stopping us.
* We can't run ASM 4 and lower because JRE incompatibility.
*/
public class ASM5OverrideInjector extends ClassVisitor {
protected ASM5OverrideInjector(int api, ClassVisitor classVisitor) {
super(api, classVisitor);
}
public static void premain(String args, Instrumentation inst) {
inst.addTransformer(new ClassFileTransformer() {
public byte[] transform(ClassLoader l, String name, Class c, ProtectionDomain d, byte[] b) {
if (name.endsWith("ClassVisitor") ||
name.endsWith("MethodVisitor") ||
name.endsWith("FieldVisitor") ||
name.endsWith("AnnotationVisitor") ||
name.endsWith("SignatureVisitor")) {
try { // Minecraft makes it ugly if we use println
System.out.print("Amethyst-Android: Modifying ASM classes for ASM4 comaptibility...\n");
} catch (Exception ignored) {}
ClassReader cr = new ClassReader(b);
ClassWriter cw = new ClassWriter(cr, 0);
ClassVisitor cv = new disableApiVersionDetection(cw);
cr.accept(cv, 0);
return cw.toByteArray();
} else return null;
}
});
}
/**
* Removes the code causing an IllegalArgumentException if the api version passed is invalid.
* We don't need it, we aren't using ASM properly anyway.
*/
public static class disableApiVersionDetection extends ClassVisitor {
public disableApiVersionDetection(ClassVisitor cv) {
super(Opcodes.ASM4, cv);
}
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
if ("<init>".equals(name)) {
return getMethodVisitor(mv);
}
return mv;
}
private MethodVisitor getMethodVisitor(MethodVisitor mv) {
return new MethodVisitor(this.api, mv) {
@Override
public void visitTypeInsn(int opcode, String type) {
if (opcode == Opcodes.NEW && "java/lang/IllegalArgumentException".equals(type)) {
super.visitInsn(Opcodes.NOP);
} else {
super.visitTypeInsn(opcode, type);
}
}
@Override
public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
if (opcode == Opcodes.INVOKESPECIAL && "java/lang/IllegalArgumentException".equals(owner) && "<init>".equals(name)) {
super.visitInsn(Opcodes.NOP);
} else {
super.visitMethodInsn(opcode, owner, name, desc, itf);
}
}
@Override
public void visitInsn(int opcode) {
if (opcode == Opcodes.ATHROW || opcode == Opcodes.DUP) {
super.visitInsn(Opcodes.NOP);
} else {
super.visitInsn(opcode);
}
}
};
}
}
}

View File

@@ -11,7 +11,14 @@ public class startInjectors {
Class.forName("org.objectweb.asm.ClassWriter");
Class.forName("org.objectweb.asm.MethodVisitor");
Class.forName("org.objectweb.asm.Opcodes");
Package asmPackage = org.objectweb.asm.Opcodes.class.getPackage();
String implVersion = asmPackage.getImplementationVersion();
if (implVersion == null) implVersion = "not found";
System.out.println("Amethyst-Android: Detected ASM version: " + implVersion);
ALC10Injector.premain(args, inst);
// This is the version we override old asm vers with. So we add the patches
// so the older version bugs are ported.
if (implVersion.equals("5.0.4")) ASM5OverrideInjector.premain(args, inst);
} catch (ClassNotFoundException | NoClassDefFoundError ignored) {
}
}