From 422b10b419eb010b612931e8b250b9dd1b7424ed Mon Sep 17 00:00:00 2001 From: Runemoro Date: Sat, 2 Nov 2019 17:23:14 -0400 Subject: Check protected method/field target in visibility index (#157) --- .../enigma/analysis/IndexSimpleVerifier.java | 153 +++++++++++++++++++++ 1 file changed, 153 insertions(+) create mode 100644 src/main/java/cuchaz/enigma/analysis/IndexSimpleVerifier.java (limited to 'src/main/java/cuchaz/enigma/analysis/IndexSimpleVerifier.java') diff --git a/src/main/java/cuchaz/enigma/analysis/IndexSimpleVerifier.java b/src/main/java/cuchaz/enigma/analysis/IndexSimpleVerifier.java new file mode 100644 index 0000000..da2b5ef --- /dev/null +++ b/src/main/java/cuchaz/enigma/analysis/IndexSimpleVerifier.java @@ -0,0 +1,153 @@ +package cuchaz.enigma.analysis; + +import cuchaz.enigma.analysis.index.EntryIndex; +import cuchaz.enigma.analysis.index.InheritanceIndex; +import cuchaz.enigma.translation.representation.AccessFlags; +import cuchaz.enigma.translation.representation.entry.ClassDefEntry; +import cuchaz.enigma.translation.representation.entry.ClassEntry; +import org.objectweb.asm.Type; +import org.objectweb.asm.tree.analysis.BasicValue; +import org.objectweb.asm.tree.analysis.SimpleVerifier; + +import java.util.Set; + +public class IndexSimpleVerifier extends SimpleVerifier { + private static final Type OBJECT_TYPE = Type.getType("Ljava/lang/Object;"); + private final EntryIndex entryIndex; + private final InheritanceIndex inheritanceIndex; + + public IndexSimpleVerifier(EntryIndex entryIndex, InheritanceIndex inheritanceIndex) { + super(ASM7, null, null, null, false); + this.entryIndex = entryIndex; + this.inheritanceIndex = inheritanceIndex; + } + + @Override + protected boolean isSubTypeOf(BasicValue value, BasicValue expected) { + Type expectedType = expected.getType(); + Type type = value.getType(); + switch (expectedType.getSort()) { + case Type.INT: + case Type.FLOAT: + case Type.LONG: + case Type.DOUBLE: + return type.equals(expectedType); + case Type.ARRAY: + case Type.OBJECT: + if (type.equals(NULL_TYPE)) { + return true; + } else if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) { + if (isAssignableFrom(expectedType, type)) { + return true; + } else if (isInterface(expectedType)) { + return isAssignableFrom(OBJECT_TYPE, type); + } else { + return false; + } + } else { + return false; + } + default: + throw new AssertionError(); + } + } + + @Override + protected boolean isInterface(Type type) { + AccessFlags classAccess = entryIndex.getClassAccess(new ClassEntry(type.getInternalName())); + if (classAccess != null) { + return classAccess.isInterface(); + } + + Class clazz = getClass(type); + if (clazz != null) { + return clazz.isInterface(); + } + + return false; + } + + @Override + protected Type getSuperClass(Type type) { + ClassDefEntry definition = entryIndex.getDefinition(new ClassEntry(type.getInternalName())); + if (definition != null) { + return Type.getType('L' + definition.getSuperClass().getFullName() + ';'); + } + + Class clazz = getClass(type); + if (clazz != null) { + return Type.getType(clazz.getSuperclass()); + } + + return OBJECT_TYPE; + } + + @Override + protected boolean isAssignableFrom(Type type1, Type type2) { + if (type1.equals(type2)) { + return true; + } + + if (type2.equals(NULL_TYPE)) { + return true; + } + + if (type1.getSort() == Type.ARRAY) { + return type2.getSort() == Type.ARRAY && isAssignableFrom(Type.getType(type1.getDescriptor().substring(1)), Type.getType(type2.getDescriptor().substring(1))); + } + + if (type2.getSort() == Type.ARRAY) { + return type1.equals(OBJECT_TYPE); + } + + if (type1.getSort() == Type.OBJECT && type2.getSort() == Type.OBJECT) { + if (type1.equals(OBJECT_TYPE)) { + return true; + } + + ClassEntry class1 = new ClassEntry(type1.getInternalName()); + ClassEntry class2 = new ClassEntry(type2.getInternalName()); + + if (entryIndex.hasClass(class1) && entryIndex.hasClass(class2)) { + return inheritanceIndex.getAncestors(class2).contains(class1); + } + + Class class1Class = getClass(Type.getType('L' + class1.getFullName() + ';')); + Class class2Class = getClass(Type.getType('L' + class2.getFullName() + ';')); + + if (class1Class == null) { + return true; // missing classes to find out + } + + if (class2Class != null) { + return class1Class.isAssignableFrom(class2Class); + } + + if (entryIndex.hasClass(class2)) { + Set ancestors = inheritanceIndex.getAncestors(class2); + + for (ClassEntry ancestorEntry : ancestors) { + Class ancestor = getClass(Type.getType('L' + ancestorEntry.getFullName() + ';')); + if (ancestor == null || class1Class.isAssignableFrom(ancestor)) { + return true; // assignable, or missing classes to find out + } + } + + return false; + } + + return true; // missing classes to find out + } + + return false; + } + + @Override + protected final Class getClass(Type type) { + try { + return Class.forName(type.getSort() == Type.ARRAY ? type.getDescriptor().replace('/', '.') : type.getClassName(), false, null); + } catch (ClassNotFoundException e) { + return null; + } + } +} -- cgit v1.2.3