From d2d671ec88409f7822297796a3eb4e9ba986e7eb Mon Sep 17 00:00:00 2001 From: Lucwousin Date: Thu, 7 Nov 2019 15:43:32 +0100 Subject: [PATCH] Make NonloadingClassWriter better at not loading classes --- .../objectwebasm/NonloadingClassWriter.java | 34 ++-- .../runelite/runeloader/CheckMappings.java | 165 ------------------ 2 files changed, 22 insertions(+), 177 deletions(-) delete mode 100644 deobfuscator/src/test/java/net/runelite/runeloader/CheckMappings.java diff --git a/deobfuscator/src/main/java/net/runelite/asm/objectwebasm/NonloadingClassWriter.java b/deobfuscator/src/main/java/net/runelite/asm/objectwebasm/NonloadingClassWriter.java index f0e54d8aff..c22b2e9f42 100644 --- a/deobfuscator/src/main/java/net/runelite/asm/objectwebasm/NonloadingClassWriter.java +++ b/deobfuscator/src/main/java/net/runelite/asm/objectwebasm/NonloadingClassWriter.java @@ -43,8 +43,21 @@ public NonloadingClassWriter(ClassGroup group, int flags) @Override protected String getCommonSuperClass(String type1, String type2) { - ClassFile cf1 = group.findClass(type1), - cf2 = group.findClass(type2); + // Checking more than this wouldn't make any sense + // Object has no super class, and RS api is guaranteed to be interfaces, which always extend from Object + // some rl api classes however ARE actual classes, so we can't just assume interface, for the slim chance + // we've got rl api on classpath. We could check all implemented interfaces in group, but that means you end up + // with Object as super class anyway, just like if you just let the Class.forName call throw. + // (maybe we could if we had a better package structure...) + if (type1.equals("java/lang/Object") + || type2.equals("java/lang/Object") + || type1.startsWith("net/runelite/rs/api/RS") + || type2.startsWith("net/runelite/rs/api/RS") + ) + return "java/lang/Object"; + + ClassFile cf1 = group.findClass(type1); + ClassFile cf2 = group.findClass(type2); if (cf1 == null && cf2 == null) { @@ -62,10 +75,11 @@ protected String getCommonSuperClass(String type1, String type2) if (cf1 != null && cf2 != null) { - for (ClassFile c = cf1; c != null; c = c.getParent()) - for (ClassFile c2 = cf2; c2 != null; c2 = c2.getParent()) - if (c == c2) - return c.getName(); + if (!(cf1.isInterface() || cf2.isInterface())) + for (ClassFile c = cf1; c != null; c = c.getParent()) + for (ClassFile c2 = cf2; c2 != null; c2 = c2.getParent()) + if (c == c2) + return c.getName(); return "java/lang/Object"; } @@ -80,7 +94,6 @@ protected String getCommonSuperClass(String type1, String type2) } else { - assert cf2 == null; found = cf1; other = type2; } @@ -88,13 +101,10 @@ protected String getCommonSuperClass(String type1, String type2) ClassFile prev = null; for (ClassFile c = found; c != null; c = c.getParent()) - { - prev = c; - - if (c.getName().equals(other)) + if ((prev = c).getSuperName().equals(other)) return other; - } + // This should pretty much never be hit, right? return super.getCommonSuperClass(prev.getSuperName(), other); } } diff --git a/deobfuscator/src/test/java/net/runelite/runeloader/CheckMappings.java b/deobfuscator/src/test/java/net/runelite/runeloader/CheckMappings.java deleted file mode 100644 index 06cd68abfc..0000000000 --- a/deobfuscator/src/test/java/net/runelite/runeloader/CheckMappings.java +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Copyright (c) 2016-2017, Adam - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.runelite.runeloader; - -import java.io.File; -import java.io.IOException; -import java.lang.reflect.Field; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLClassLoader; -import java.util.ArrayList; -import java.util.List; -import net.runelite.mapping.Export; -import net.runelite.mapping.ObfuscatedGetter; -import net.runelite.mapping.ObfuscatedName; -import net.runelite.runeloader.inject.GetterInjectInstruction; -import net.runelite.runeloader.inject.Injection; -import net.runelite.runeloader.inject.InjectionModscript; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Test; - -public class CheckMappings -{ - private static final File CLIENT = new File("d:/rs/07/adamout.jar"); - - private final List classes = new ArrayList<>(); - - @Before - public void before() throws MalformedURLException, ClassNotFoundException - { - ClassLoader loader = new URLClassLoader(new URL[]{CLIENT.toURI().toURL()}); - - Class c = loader.loadClass("client"); - classes.add(c); - - for (int i = 0; i < 230; ++i) - { - try - { - c = loader.loadClass("class" + i); - classes.add(c); - } - catch (ClassNotFoundException ex) - { - } - } - } - - @SuppressWarnings("unchecked") - private Class findClassWithObfuscatedName(String name) - { - for (Class c : classes) - { - if (c.getName().equals("net.runelite.rs.client.client") && name.equals("client")) - { - return c; - } - - ObfuscatedName oc = (ObfuscatedName) c.getDeclaredAnnotation(ObfuscatedName.class); - if (oc == null) - { - continue; - } - - if (oc.value().equals(name)) - { - return c; - } - } - return null; - } - - private Field findFieldWithObfuscatedName(Class c, String name) - { - for (Field f : c.getDeclaredFields()) - { - ObfuscatedName oc = f.getDeclaredAnnotation(ObfuscatedName.class); - if (oc == null) - { - continue; - } - - if (oc.value().equals(name)) - { - return f; - } - } - return null; - } - - private Integer getIntegerMultiplier(Field f) - { - ObfuscatedGetter getter = f.getDeclaredAnnotation(ObfuscatedGetter.class); - if (getter == null) - { - return null; - } - return getter.intValue() == 0 ? null : getter.intValue(); - } - - private String getExportedName(Field f) - { - Export e = f.getDeclaredAnnotation(Export.class); - if (e == null) - { - return null; - } - return e.value(); - } - - @Test - @Ignore - public void checkMappings() throws IOException - { - InjectionModscript mod = Injection.load(MappingImporter.class.getResourceAsStream(MappingImporter.RL_INJECTION)); - - for (int i = 0; i < mod.getGetterInjects().size(); ++i) - { - GetterInjectInstruction gii = mod.getGetterInjects().get(i); - - Class c = this.findClassWithObfuscatedName(gii.getGetterClassName()); - Assert.assertNotNull(c); - - Field f = this.findFieldWithObfuscatedName(c, gii.getGetterFieldName()); - Assert.assertNotNull(f); - - String exportedName = this.getExportedName(f); - String attrName = gii.getGetterName(); - attrName = Utils.toExportedName(attrName); - - Integer mul = gii.getMultiplier(), - myMul = this.getIntegerMultiplier(f); - - // XXX Check @Export etc names - - //Assert.assertEquals(exportedName, attrName); - Assert.assertEquals(myMul, mul); - } - } -}