diff --git a/deobfuscator/build.gradle b/deobfuscator/build.gradle index 3142757b1c..5a7f4af7a4 100644 --- a/deobfuscator/build.gradle +++ b/deobfuscator/build.gradle @@ -6,9 +6,9 @@ plugins { description = 'Deobfuscator' -def rootPath = project.rootDir.toString().replace('\\', '/') -def deobfuscatedJar = "${rootPath}/runescape-client/build/libs/rs-client-${project.version}.jar" -def vanillaJar = "${rootPath}/injector-plugin/vanilla-${rsversion}.jar" +configurations { + deobjars +} dependencies { implementation project(':runelite-api') @@ -19,18 +19,28 @@ dependencies { implementation group: 'com.google.code.gson', name: 'gson', version: '2.8.5' implementation group: 'org.ow2.asm', name: 'asm-debug-all', version: '5.2' runtime group: 'org.slf4j', name: 'slf4j-simple', version: '1.7.26' - testImplementation project(':rs-client') - testImplementation group: 'net.runelite.rs', name: 'vanilla', version: '181' + deobjars project(':rs-client') + deobjars group: 'net.runelite.rs', name: 'vanilla', version: '181' + testImplementation configurations.deobjars.dependencies testImplementation group: 'junit', name: 'junit', version: '4.12' testImplementation group: 'org.mockito', name: 'mockito-core', version: '3.0.0' } +processResources { + from file("src/main/resources/deob.properties"), { + filter(ReplaceTokens, tokens: [ + "rs.version": rsversion.toString(), + "vanilla.jar": configurations.deobjars.find {it.name.startsWith("vanilla")}.toString().replace('\\', "/"), + "rs.client": configurations.deobjars.find {it.name.startsWith("rs-client")}.toString().replace('\\', "/") + ]) + } +} processTestResources { from file("src/test/resources/deob-test.properties"), { filter(ReplaceTokens, tokens: [ - "rs.client": deobfuscatedJar.toString(), + "rs.client": configurations.deobjars.find {it.name.startsWith("rs-client")}.toString().replace('\\', "/"), "rs.version": rsversion.toString(), - "vanilla.jar": vanillaJar.toString() + "vanilla.jar": configurations.deobjars.find {it.name.startsWith("vanilla")}.toString().replace('\\', "/") ]) } } \ No newline at end of file diff --git a/deobfuscator/src/main/java/net/runelite/asm/ClassFile.java b/deobfuscator/src/main/java/net/runelite/asm/ClassFile.java index 6d9110a3b3..a5f3a6ecb6 100644 --- a/deobfuscator/src/main/java/net/runelite/asm/ClassFile.java +++ b/deobfuscator/src/main/java/net/runelite/asm/ClassFile.java @@ -30,6 +30,7 @@ import net.runelite.asm.attributes.Annotations; import net.runelite.asm.attributes.annotation.Annotation; import net.runelite.asm.pool.Class; import net.runelite.asm.signature.Signature; +import static net.runelite.deob.DeobAnnotations.*; import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.FieldVisitor; @@ -308,6 +309,20 @@ public class ClassFile return null; } + public Method findObfStaticMethod(String name, Signature type) + { + for (Method m : methods) + { + if (m.isStatic() && + name.equals(getObfuscatedName(m.getAnnotations())) && + type.equals(getObfuscatedSignature(m))) + { + return m; + } + } + return findMethodDeepStatic(name, type); + } + public Method findMethod(String name) { for (Method m : methods) diff --git a/deobfuscator/src/main/java/net/runelite/asm/ClassGroup.java b/deobfuscator/src/main/java/net/runelite/asm/ClassGroup.java index 416281c305..33ab161acc 100644 --- a/deobfuscator/src/main/java/net/runelite/asm/ClassGroup.java +++ b/deobfuscator/src/main/java/net/runelite/asm/ClassGroup.java @@ -31,6 +31,7 @@ import java.util.List; import java.util.Map; import net.runelite.asm.attributes.Code; import net.runelite.asm.signature.Signature; +import static net.runelite.deob.DeobAnnotations.*; public class ClassGroup { @@ -142,4 +143,17 @@ public class ClassGroup return m; } + + public ClassFile findObfuscatedName(String name) + { + for (ClassFile cf : classes) + { + if (name.equals(getObfuscatedName(cf.getAnnotations()))) + { + return cf; + } + } + + return findClass(name); + } } diff --git a/deobfuscator/src/main/java/net/runelite/asm/Field.java b/deobfuscator/src/main/java/net/runelite/asm/Field.java index 8d70053adb..39590b021c 100644 --- a/deobfuscator/src/main/java/net/runelite/asm/Field.java +++ b/deobfuscator/src/main/java/net/runelite/asm/Field.java @@ -26,6 +26,7 @@ package net.runelite.asm; import net.runelite.asm.attributes.Annotations; import net.runelite.asm.attributes.annotation.Annotation; +import net.runelite.deob.DeobAnnotations; import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.FieldVisitor; import org.objectweb.asm.Opcodes; @@ -131,6 +132,17 @@ public class Field this.type = type; } + public Type getObfuscatedType() + { + Type type = DeobAnnotations.getObfuscatedType(this); + if (type == null) + { + type = getType(); + } + + return type; + } + public Object getValue() { return value; diff --git a/deobfuscator/src/main/java/net/runelite/asm/Method.java b/deobfuscator/src/main/java/net/runelite/asm/Method.java index e8cbdef92b..ad7394c7be 100644 --- a/deobfuscator/src/main/java/net/runelite/asm/Method.java +++ b/deobfuscator/src/main/java/net/runelite/asm/Method.java @@ -35,6 +35,7 @@ import net.runelite.asm.attributes.code.LocalVariable; import net.runelite.asm.attributes.code.Parameter; import net.runelite.asm.attributes.code.instruction.types.LVTInstruction; import net.runelite.asm.signature.Signature; +import net.runelite.deob.DeobAnnotations; import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; @@ -193,6 +194,17 @@ public class Method this.arguments = signature; } + public Signature getObfuscatedSignature() + { + Signature sig = DeobAnnotations.getObfuscatedSignature(this); + if (sig == null) + { + sig = arguments; + } + + return sig; + } + public boolean isNative() { return (accessFlags & ACC_NATIVE) != 0; diff --git a/deobfuscator/src/main/java/net/runelite/asm/attributes/Code.java b/deobfuscator/src/main/java/net/runelite/asm/attributes/Code.java index 2a3f08126c..b20c183fea 100644 --- a/deobfuscator/src/main/java/net/runelite/asm/attributes/Code.java +++ b/deobfuscator/src/main/java/net/runelite/asm/attributes/Code.java @@ -25,10 +25,13 @@ package net.runelite.asm.attributes; +import java.util.ArrayList; +import java.util.List; import net.runelite.asm.Method; import net.runelite.asm.attributes.code.Exceptions; import net.runelite.asm.attributes.code.Instruction; import net.runelite.asm.attributes.code.Instructions; +import net.runelite.asm.attributes.code.Label; import net.runelite.asm.attributes.code.instruction.types.LVTInstruction; import net.runelite.asm.signature.Signature; @@ -110,4 +113,28 @@ public class Code { return instructions; } + + public List getLineNumbers() + { + final List lineNumbers = new ArrayList<>(); + + for (Instruction i : instructions.getInstructions()) + { + if (!(i instanceof Label)) + { + continue; + } + + Integer lineNumber = ((Label) i).getLineNumber(); + if (lineNumber == null) + { + continue; + } + + lineNumbers.add(lineNumber); + } + + lineNumbers.sort(Integer::compareTo); + return lineNumbers; + } } diff --git a/deobfuscator/src/main/java/net/runelite/asm/attributes/code/Label.java b/deobfuscator/src/main/java/net/runelite/asm/attributes/code/Label.java index 7f2cd70ffd..095f9ddb15 100644 --- a/deobfuscator/src/main/java/net/runelite/asm/attributes/code/Label.java +++ b/deobfuscator/src/main/java/net/runelite/asm/attributes/code/Label.java @@ -109,6 +109,11 @@ public class Label extends NOP this.lineNumber = lineNumber; } + public Integer getLineNumber() + { + return this.lineNumber; + } + public Instruction next() { Instructions ins = this.getInstructions(); diff --git a/deobfuscator/src/main/java/net/runelite/asm/pool/Field.java b/deobfuscator/src/main/java/net/runelite/asm/pool/Field.java index a63a3d762e..ca24bb33af 100644 --- a/deobfuscator/src/main/java/net/runelite/asm/pool/Field.java +++ b/deobfuscator/src/main/java/net/runelite/asm/pool/Field.java @@ -45,7 +45,7 @@ public class Field @Override public String toString() { - return "Field{" + "clazz=" + clazz + ", name=" + name + ", type=" + type + '}'; + return clazz.getName() + '.' + name + " " + type; } @Override diff --git a/deobfuscator/src/main/java/net/runelite/asm/pool/Method.java b/deobfuscator/src/main/java/net/runelite/asm/pool/Method.java index 510868d191..4585655f2e 100644 --- a/deobfuscator/src/main/java/net/runelite/asm/pool/Method.java +++ b/deobfuscator/src/main/java/net/runelite/asm/pool/Method.java @@ -43,7 +43,7 @@ public class Method @Override public String toString() { - return clazz + "." + name + type; + return clazz.getName() + "." + name + type; } @Override diff --git a/deobfuscator/src/main/java/net/runelite/deob/Deob.java b/deobfuscator/src/main/java/net/runelite/deob/Deob.java index 2dfeae9e6b..6efdfe3500 100644 --- a/deobfuscator/src/main/java/net/runelite/deob/Deob.java +++ b/deobfuscator/src/main/java/net/runelite/deob/Deob.java @@ -75,7 +75,7 @@ public class Deob System.exit(-1); } - //logger.info("Deobfuscator revision {}", DeobProperties.getRevision()); + logger.info("Deobfuscator revision {}", DeobProperties.getRevision()); Stopwatch stopwatch = Stopwatch.createStarted(); diff --git a/deobfuscator/src/main/java/net/runelite/deob/DeobProperties.java b/deobfuscator/src/main/java/net/runelite/deob/DeobProperties.java index f25cd2bd01..979c7bb41f 100644 --- a/deobfuscator/src/main/java/net/runelite/deob/DeobProperties.java +++ b/deobfuscator/src/main/java/net/runelite/deob/DeobProperties.java @@ -24,18 +24,39 @@ */ package net.runelite.deob; +import java.io.File; import java.io.IOException; import java.io.InputStream; import java.util.Properties; public class DeobProperties { - public static String getRevision() throws IOException + private static final Properties properties; + static { - Properties properties = new Properties(); - InputStream resourceAsStream = DeobProperties.class.getResourceAsStream("/deob.properties"); - properties.load(resourceAsStream); + properties = new Properties(); + try (InputStream resourceAsStream = DeobProperties.class.getResourceAsStream("/deob.properties")) + { + properties.load(resourceAsStream); + } + catch (IOException e) + { + //yes + } + } - return "420"; + public static String getRevision() + { + return properties.getProperty("rs.version"); + } + + public static File getVanilla() + { + return new File(properties.getProperty("vanilla.jar")); + } + + public static File getRsClient() + { + return new File(properties.getProperty("rs.client")); } } diff --git a/deobfuscator/src/main/java/net/runelite/deob/updater/MappingDumper.java b/deobfuscator/src/main/java/net/runelite/deob/updater/MappingDumper.java new file mode 100644 index 0000000000..275b3dca74 --- /dev/null +++ b/deobfuscator/src/main/java/net/runelite/deob/updater/MappingDumper.java @@ -0,0 +1,130 @@ +package net.runelite.deob.updater; + +import com.google.common.base.Stopwatch; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.stream.JsonWriter; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; +import net.runelite.asm.ClassFile; +import net.runelite.asm.ClassGroup; +import net.runelite.asm.pool.Field; +import net.runelite.asm.pool.Method; +import net.runelite.deob.DeobProperties; +import net.runelite.deob.updater.mappingdumper.MappedClass; +import net.runelite.deob.updater.mappingdumper.MappedField; +import net.runelite.deob.updater.mappingdumper.MappedMethod; +import net.runelite.deob.updater.mappingdumper.MappingDump; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class MappingDumper +{ + private static ClassGroup group; + private final Logger log = LoggerFactory.getLogger(MappingDumper.class); + private static final Map classMap = new HashMap<>(); + private static final Map fieldMap = new HashMap<>(); + private static final Map methodMap = new HashMap<>(); + + public MappingDumper(ClassGroup group) + { + MappingDumper.group = group; + } + + public void dump(final File outputFile) + { + Stopwatch st = Stopwatch.createStarted(); + group.buildClassGraph(); + + // MappingDump.of(ClassGroup) dumps everything completely + final MappingDump dump = new MappingDump().visitGroup(group); + dump.revision = Integer.parseInt(DeobProperties.getRevision()); + + log.info("RS version {}. Dump took {}", dump.revision, st.toString()); + log.info("Total classes: {}. Total mapped classes: {}. ({}%)", dump.totalClasses, dump.totalNamedClasses, dump.totalNamedClasses * 100 / dump.totalClasses); + log.info("Total non static methods: {}. Total mapped non static methods: {}. ({}%)", dump.totalNonStaticMethods, dump.totalNamedNonStaticMethods, dump.totalNamedNonStaticMethods * 100 / dump.totalNamedMethods); + log.info("Total methods: {}. Total mapped methods: {}. ({}%)", dump.totalMethods, dump.totalNamedMethods, dump.totalNamedMethods * 100 / dump.totalMethods); + log.info("Total fields: {}. Total mapped fields: {}. ({}%)", dump.totalFields, dump.totalNamedFields, dump.totalNamedFields * 100 / dump.totalFields); + log.info("Total non static fields: {}. Total mapped non static fields: {}. ({}%)", dump.totalNonStaticFields, dump.totalNamedNonStaticFields, dump.totalNamedNonStaticFields * 100 / dump.totalNamedFields); + writeJson(dump, outputFile); + } + + // Without this stack'll overflow :P + private void writeJson(MappingDump dump, File outputFile) + { + final Gson gson = new GsonBuilder().setPrettyPrinting().create(); + try (JsonWriter writer = new JsonWriter(new OutputStreamWriter(new FileOutputStream(outputFile), StandardCharsets.UTF_8))) + { + writer.setIndent(" "); + writer.beginObject(); + writer.name("revision").value(dump.revision); + writer.name("totalClasses").value(dump.totalClasses); + writer.name("totalNamedClasses").value(dump.totalNamedClasses); + writer.name("totalFields").value(dump.totalFields); + writer.name("totalNamedFields").value(dump.totalNamedFields); + writer.name("totalNonStaticFields").value(dump.totalNonStaticFields); + writer.name("totalNamedNonStaticFields").value(dump.totalNamedNonStaticFields); + writer.name("totalStaticFields").value(dump.totalStaticFields); + writer.name("totalNamedStaticFields").value(dump.totalNamedStaticFields); + writer.name("totalMethods").value(dump.totalMethods); + writer.name("totalNamedMethods").value(dump.totalNamedMethods); + writer.name("totalNonStaticMethods").value(dump.totalNonStaticMethods); + writer.name("totalNamedNonStaticMethods").value(dump.totalNamedNonStaticMethods); + writer.name("totalStaticMethods").value(dump.totalStaticMethods); + writer.name("totalNamedStaticMethods").value(dump.totalNamedStaticMethods); + writer.name("mappedClasses"); + writer.beginArray(); + for (MappedClass mc : dump.classes) + { + gson.toJson(mc, MappedClass.class, writer); + } + writer.endArray(); + writer.endObject(); + } + catch (IOException e) + { + log.error("Error saving json: ", e); + } + } + + public static ClassGroup getGroup() + { + return group; + } + + public static void putMap(ClassFile clazz, MappedClass mc) + { + classMap.put(clazz, mc); + } + + public static MappedClass getMap(ClassFile clazz) + { + return classMap.get(clazz); + } + + public static void putMap(Field field, MappedField mf) + { + fieldMap.put(field, mf); + } + + public static MappedField getMap(Field field) + { + return fieldMap.get(field); + } + + public static void putMap(Method method, MappedMethod mm) + { + methodMap.put(method, mm); + } + + public static MappedMethod getMap(Method method) + { + return methodMap.get(method); + } + +} diff --git a/deobfuscator/src/main/java/net/runelite/deob/updater/mappingdumper/MappedClass.java b/deobfuscator/src/main/java/net/runelite/deob/updater/mappingdumper/MappedClass.java new file mode 100644 index 0000000000..9a0a6e7511 --- /dev/null +++ b/deobfuscator/src/main/java/net/runelite/deob/updater/mappingdumper/MappedClass.java @@ -0,0 +1,68 @@ +package net.runelite.deob.updater.mappingdumper; + +import com.google.gson.annotations.SerializedName; +import java.util.List; +import java.util.stream.Collectors; +import net.runelite.asm.ClassFile; +import net.runelite.deob.DeobAnnotations; +import net.runelite.deob.updater.MappingDumper; + +public class MappedClass +{ + @SerializedName("class") + public String implementingName; + @SerializedName("name") + public String obfuscatedName; + @SerializedName("super") + public String superClass; + public int access; + public List interfaces; + public List fields; + public List methods; + public List constructors; + + public MappedClass visitClass(final ClassFile c, final MappingDump dump) + { + MappingDumper.putMap(c, this); + + implementingName = DeobAnnotations.getImplements(c); + + obfuscatedName = DeobAnnotations.getObfuscatedName(c.getAnnotations()); + if (obfuscatedName == null) + { + obfuscatedName = c.getName(); + } + + ClassFile parent = c.getParent(); + if (parent != null) + { + superClass = DeobAnnotations.getObfuscatedName(parent.getAnnotations()); + } + + access = c.getAccess(); + + interfaces = c.getInterfaces() + .getMyInterfaces() + .stream() + .map(ClassFile::getAnnotations) + .map(DeobAnnotations::getObfuscatedName) + .collect(Collectors.toList()); + + fields = c.getFields() + .stream() + .map(f -> new MappedField().visitField(f, dump)) + .collect(Collectors.toList()); + + methods = c.getMethods() + .stream() + .map(m -> new MappedMethod().visitMethod(m, dump)) + .collect(Collectors.toList()); + + constructors = methods + .stream() + .filter(m -> m.obfuscatedName.endsWith("init>")) + .collect(Collectors.toList()); + + return this; + } +} diff --git a/deobfuscator/src/main/java/net/runelite/deob/updater/mappingdumper/MappedField.java b/deobfuscator/src/main/java/net/runelite/deob/updater/mappingdumper/MappedField.java new file mode 100644 index 0000000000..dc2b7a7242 --- /dev/null +++ b/deobfuscator/src/main/java/net/runelite/deob/updater/mappingdumper/MappedField.java @@ -0,0 +1,47 @@ +package net.runelite.deob.updater.mappingdumper; + +import com.google.gson.annotations.SerializedName; +import java.util.HashMap; +import java.util.Map; +import net.runelite.asm.Field; +import net.runelite.asm.pool.Method; +import net.runelite.deob.DeobAnnotations; +import net.runelite.deob.updater.MappingDumper; + +public class MappedField +{ + @SerializedName("field") + public String exportedName; + public String owner; + @SerializedName("name") + public String obfuscatedName; + public int access; + public String descriptor; + public Number decoder; + // method name, amt of times + public Map puts = new HashMap<>(); + public Map gets = new HashMap<>(); + + public MappedField visitField(final Field f, final MappingDump dump) + { + MappingDumper.putMap(f.getPoolField(), this); + + exportedName = DeobAnnotations.getExportedName(f.getAnnotations()); + + owner = MappingDumper.getMap(f.getClassFile()).obfuscatedName; + + obfuscatedName = DeobAnnotations.getObfuscatedName(f.getAnnotations()); + if (obfuscatedName == null) + { + obfuscatedName = f.getName(); + } + + access = f.getAccessFlags(); + + descriptor = f.getObfuscatedType().toString(); + + decoder = DeobAnnotations.getObfuscatedGetter(f); + + return this; + } +} diff --git a/deobfuscator/src/main/java/net/runelite/deob/updater/mappingdumper/MappedMethod.java b/deobfuscator/src/main/java/net/runelite/deob/updater/mappingdumper/MappedMethod.java new file mode 100644 index 0000000000..8131ecd1f6 --- /dev/null +++ b/deobfuscator/src/main/java/net/runelite/deob/updater/mappingdumper/MappedMethod.java @@ -0,0 +1,112 @@ +package net.runelite.deob.updater.mappingdumper; + +import com.google.gson.annotations.SerializedName; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import net.runelite.asm.Method; +import net.runelite.asm.attributes.Code; +import net.runelite.asm.attributes.code.Instruction; +import net.runelite.asm.attributes.code.Instructions; +import net.runelite.asm.attributes.code.Parameter; +import net.runelite.asm.attributes.code.instruction.types.GetFieldInstruction; +import net.runelite.asm.attributes.code.instruction.types.InvokeInstruction; +import net.runelite.asm.attributes.code.instruction.types.SetFieldInstruction; +import net.runelite.asm.pool.Class; +import net.runelite.asm.pool.Field; +import net.runelite.deob.DeobAnnotations; +import net.runelite.deob.updater.MappingDumper; + +public class MappedMethod +{ + @SerializedName("method") + public String exportedName; + public String owner; + @SerializedName("name") + public String obfuscatedName; + public int access; + public List parameters; + public String descriptor; + public String garbageValue; + public List lineNumbers; + public Map fieldGets = new HashMap<>(); + public Map fieldPuts = new HashMap<>(); + public Map dependencies = new HashMap<>(); + + public MappedMethod visitMethod(final Method m, final MappingDump dump) + { + MappingDumper.putMap(m.getPoolMethod(), this); + exportedName = DeobAnnotations.getExportedName(m.getAnnotations()); + + owner = MappingDumper.getMap(m.getClassFile()).obfuscatedName; + + obfuscatedName = DeobAnnotations.getObfuscatedName(m.getAnnotations()); + if (obfuscatedName == null) + { + obfuscatedName = m.getName(); + } + + access = m.getAccessFlags(); + + parameters = m.getParameters() + .stream() + .map(Parameter::getName) + .collect(Collectors.toList()); + + descriptor = m.getObfuscatedSignature().toString(); + + garbageValue = DeobAnnotations.getDecoder(m); + + Code c = m.getCode(); + if (c != null) + { + visitCode(c); + } + + return this; + } + + private void visitCode(Code c) + { + lineNumbers = c.getLineNumbers(); + + Instructions ins = c.getInstructions(); + for (Instruction i : ins.getInstructions()) + { + if (i instanceof GetFieldInstruction) + { + Field k = ((GetFieldInstruction) i).getField(); + int v = fieldGets.getOrDefault(k, 0) + 1; + fieldGets.put(k, v); + } + else if (i instanceof SetFieldInstruction) + { + Field k = ((SetFieldInstruction) i).getField(); + int v = fieldPuts.getOrDefault(k, 0) + 1; + fieldPuts.put(k, v); + } + else if (i instanceof InvokeInstruction) + { + List met = ((InvokeInstruction) i).getMethods(); + net.runelite.asm.pool.Method k; + if (met.size() > 0) + { + Method mme = met.get(0); + k = new net.runelite.asm.pool.Method( + new Class(DeobAnnotations.getObfuscatedName(mme.getClassFile().getAnnotations())), + DeobAnnotations.getObfuscatedName(mme.getAnnotations()), + mme.getObfuscatedSignature() != null ? mme.getObfuscatedSignature() : mme.getDescriptor() + ); + } + else + { + k = ((InvokeInstruction) i).getMethod(); + } + + int v = dependencies.getOrDefault(k, 0) + 1; + dependencies.put(k, v); + } + } + } +} diff --git a/deobfuscator/src/main/java/net/runelite/deob/updater/mappingdumper/MappingDump.java b/deobfuscator/src/main/java/net/runelite/deob/updater/mappingdumper/MappingDump.java new file mode 100644 index 0000000000..adcf228893 --- /dev/null +++ b/deobfuscator/src/main/java/net/runelite/deob/updater/mappingdumper/MappingDump.java @@ -0,0 +1,148 @@ +package net.runelite.deob.updater.mappingdumper; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import net.runelite.asm.ClassFile; +import net.runelite.asm.ClassGroup; +import net.runelite.asm.pool.Class; +import net.runelite.asm.pool.Field; +import net.runelite.asm.pool.Method; +import net.runelite.asm.signature.Signature; +import net.runelite.deob.updater.MappingDumper; +import static org.objectweb.asm.Opcodes.ACC_STATIC; + +public class MappingDump +{ + public int revision; + + public int totalClasses = 0; + public int totalNamedClasses = 0; + + public int totalFields = 0; + public int totalNamedFields = 0; + + public int totalNonStaticFields = 0; + public int totalNamedNonStaticFields = 0; + + public int totalStaticFields = 0; + public int totalNamedStaticFields = 0; + + public int totalMethods = 0; + public int totalNamedMethods = 0; + + public int totalNonStaticMethods = 0; + public int totalNamedNonStaticMethods = 0; + + public int totalStaticMethods = 0; + public int totalNamedStaticMethods = 0; + + public List classes; + + private ClassGroup group; + + public MappingDump visitGroup(ClassGroup group) + { + this.group = group; + classes = new ArrayList<>(); + + for (ClassFile c : group.getClasses()) + { + if (c.getName().contains("runelite")) + { + continue; + } + + final MappedClass mc = new MappedClass(); + classes.add(mc.visitClass(c, this)); + } + + totalClasses = classes.size(); + + for (MappedClass c : classes) + { + if (c.implementingName != null) + { + totalNamedClasses++; + } + + for (MappedMethod mm : c.methods) + { + for (Map.Entry entry : mm.fieldGets.entrySet()) + { + MappedField mf = MappingDumper.getMap(entry.getKey()); + if (mf == null) + { + continue; + } + mf.gets.put( + new Method( + new Class(mm.owner), + mm.obfuscatedName, + new Signature(mm.descriptor)), + entry.getValue()); + } + for (Map.Entry entry : mm.fieldPuts.entrySet()) + { + MappedField mf = MappingDumper.getMap(entry.getKey()); + if (mf == null) + { + continue; + } + mf.puts.put( + new Method( + new Class(mm.owner), + mm.obfuscatedName, + new Signature(mm.descriptor)), + entry.getValue()); + } + } + + grabAmountInfo(c); + } + totalNonStaticFields = totalFields - totalStaticFields; + totalNamedNonStaticFields = totalNamedFields - totalNamedStaticFields; + totalNonStaticMethods = totalMethods - totalStaticMethods; + totalNamedNonStaticMethods = totalNamedMethods - totalNamedStaticMethods; + + return this; + } + + private void grabAmountInfo(MappedClass c) + { + totalFields += c.fields.size(); + totalNamedFields += c.fields + .stream() + .filter(f -> f.exportedName != null) + .count(); + totalStaticFields += c.fields + .stream() + .filter(f -> (f.access & ACC_STATIC) != 0) + .count(); + totalNamedStaticFields += c.fields + .stream() + .filter(f -> f.exportedName != null + && (f.access & ACC_STATIC) != 0) + .count(); + + totalMethods += c.methods.size(); + totalNamedMethods += c.methods + .stream() + .filter(f -> f.exportedName != null) + .count(); + totalStaticMethods += c.methods + .stream() + .filter(f -> (f.access & ACC_STATIC) != 0) + .count(); + totalNamedStaticMethods += c.methods + .stream() + .filter(f -> f.exportedName != null + && (f.access & ACC_STATIC) != 0) + .count(); + } + + ClassGroup getGroup() + { + return group; + } +} diff --git a/deobfuscator/src/main/resources/deob.properties b/deobfuscator/src/main/resources/deob.properties new file mode 100644 index 0000000000..0ce0372f8e --- /dev/null +++ b/deobfuscator/src/main/resources/deob.properties @@ -0,0 +1,3 @@ +rs.version=@rs.version@ +vanilla.jar=@vanilla.jar@ +rs.client=@rs.client@ \ No newline at end of file diff --git a/deobfuscator/src/test/java/net/runelite/deob/deobfuscators/mapping/MappingDumper.java b/deobfuscator/src/test/java/net/runelite/deob/deobfuscators/mapping/MappingDumper.java index 262e7bce2e..d43ffbfe6d 100644 --- a/deobfuscator/src/test/java/net/runelite/deob/deobfuscators/mapping/MappingDumper.java +++ b/deobfuscator/src/test/java/net/runelite/deob/deobfuscators/mapping/MappingDumper.java @@ -24,266 +24,47 @@ */ package net.runelite.deob.deobfuscators.mapping; -import com.google.common.io.Files; import java.io.File; import java.io.IOException; -import java.nio.charset.Charset; import java.time.Instant; - import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonArray; import com.google.gson.JsonObject; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Map; import net.runelite.asm.ClassFile; import net.runelite.asm.ClassGroup; import net.runelite.asm.Field; import net.runelite.asm.Method; import net.runelite.asm.Type; -import net.runelite.asm.attributes.code.Parameter; import net.runelite.asm.signature.Signature; -import net.runelite.deob.Deob; import net.runelite.deob.DeobAnnotations; import net.runelite.deob.DeobTestProperties; -import net.runelite.deob.deobfuscators.mapping.mappingdumper.MappedClass; -import net.runelite.deob.deobfuscators.mapping.mappingdumper.MappedField; -import net.runelite.deob.deobfuscators.mapping.mappingdumper.MappedMethod; -import net.runelite.deob.deobfuscators.mapping.mappingdumper.MappingDump; import net.runelite.deob.util.JarUtil; import org.junit.Before; import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; public class MappingDumper { @Rule public DeobTestProperties properties = new DeobTestProperties(); - private final Logger log = LoggerFactory.getLogger(MappingDumper.class); - - private MappingDump dump; - private Map classMap; + private ClassGroup group; private static final String OUTDIR = ""; private final File OUTFILE = new File(OUTDIR, "rlplushooks.json"); @Before - public void before() + public void before() throws IOException { - dump = new MappingDump(); - dump.revision = properties.getRsVersion(); - dump.classes = new ArrayList<>(); - dump.staticFields = new ArrayList<>(); - dump.staticMethods = new ArrayList<>(); - classMap = new HashMap<>(); + group = JarUtil.loadJar(new File(properties.getRsClient())); } @Test @Ignore - public void newDump() throws IOException + public void newDump() { - final ClassGroup group = JarUtil.loadJar(new File(properties.getRsClient())); - - - // First create all the mappedclasses, so we can add static methods to their lists - for (ClassFile c : group.getClasses()) - { - if (c.getName().contains("runelite")) - { - continue; - } - - final MappedClass mc = new MappedClass(); - - mc.obfuscatedName = DeobAnnotations.getObfuscatedName(c.getAnnotations()); - mc.implementingName = DeobAnnotations.getImplements(c); - mc.superClass = c.getSuperName(); - mc.interfaces = c.getInterfaces().getIntfNames(); - mc.constructors = new ArrayList<>(); - mc.fields = new ArrayList<>(); - mc.methods = new ArrayList<>(); - mc.access = c.getAccess(); - mc.staticMethods = new ArrayList<>(); - mc.staticFields = new ArrayList<>(); - - dump.classes.add(mc); - classMap.put(c.getName(), mc); - - dump.totalClasses++; - if (mc.implementingName != null) - { - dump.totalNamedClasses++; - } - } - - for (ClassFile c : group.getClasses()) - { - if (c.getName().contains("runelite")) - { - continue; - } - - final MappedClass mc = classMap.get(c.getName()); - - getFields(c, mc); - - getMethods(c, mc); - } - - dump.totalNonStaticFields = dump.totalFields - dump.totalStaticFields; - dump.totalNamedNonStaticFields = dump.totalNamedFields - dump.totalNamedStaticFields; - dump.totalNonStaticMethods = dump.totalMethods - dump.totalStaticMethods; - dump.totalNamedNonStaticMethods = dump.totalNamedMethods - dump.totalNamedStaticMethods; - - final Gson gson = new GsonBuilder().setPrettyPrinting().create(); - Files.asCharSink(OUTFILE, Charset.defaultCharset()).write(gson.toJson(dump)); - - log.info("Dumped current mappings. revision {}", dump.revision); - log.info("Total classes: {}. Total mapped classes: {}. ({}%)", dump.totalClasses, dump.totalNamedClasses, dump.totalNamedClasses * 100 / dump.totalClasses); - log.info("Total non static methods: {}. Total mapped non static methods: {}. ({}%)", dump.totalNonStaticMethods, dump.totalNamedNonStaticMethods, dump.totalNamedNonStaticMethods * 100 / dump.totalNamedMethods); - log.info("Total methods: {}. Total mapped methods: {}. ({}%)", dump.totalMethods, dump.totalNamedMethods, dump.totalNamedMethods * 100 / dump.totalMethods); - log.info("Total fields: {}. Total mapped fields: {}. ({}%)", dump.totalFields, dump.totalNamedFields, dump.totalNamedFields * 100 / dump.totalFields); - log.info("Total non static fields: {}. Total mapped non static fields: {}. ({}%)", dump.totalNonStaticFields, dump.totalNamedNonStaticFields, dump.totalNamedNonStaticFields * 100 / dump.totalNamedFields); - - } - - private void getFields(final ClassFile c, final MappedClass mc) - { - for (Field f : c.getFields()) - { - dump.totalFields++; - - if (f.isStatic()) - { - dump.totalStaticFields++; - } - - if (Deob.isObfuscated(f.getName())) - { - continue; - } - - dump.totalNamedFields++; - - final MappedField mf = new MappedField(); - - mf.exportedName = f.getName(); - mf.owner = mc.obfuscatedName; - mf.obfuscatedName = DeobAnnotations.getObfuscatedName(f.getAnnotations()); - mf.access = f.getAccessFlags(); - mf.descriptor = DeobAnnotations.getAnnotationValue(f.getAnnotations(), DeobAnnotations.OBFUSCATED_SIGNATURE); - - Number decoder = DeobAnnotations.getObfuscatedGetter(f); - if (decoder != null) - { - mf.decoder = decoder.longValue(); - } - - if (mf.descriptor == null) - { - mf.descriptor = f.getType().toString(); - } - - if (f.isStatic()) - { - dump.staticFields.add(mf); - dump.totalNamedStaticFields++; - - int _index = mf.exportedName.indexOf('_'); - - if (_index != -1) - { - String className = mf.exportedName.substring(0, _index); - MappedClass staticOwner = classMap.get(className); - - if (staticOwner != null) - { - staticOwner.staticFields.add(mf); - } - } - } - else - { - mc.fields.add(mf); - } - } - } - - private void getMethods(final ClassFile c, final MappedClass mc) - { - for (Method m : c.getMethods()) - { - dump.totalMethods++; - - if (m.isStatic()) - { - dump.totalStaticMethods++; - } - - if (Deob.isObfuscated(m.getName()) || m.getName().equals("")) - { - continue; - } - - dump.totalNamedMethods++; - - final MappedMethod mm = new MappedMethod(); - - mm.exportedName = m.getName(); - mm.owner = mc.obfuscatedName; - mm.obfuscatedName = DeobAnnotations.getObfuscatedName(m.getAnnotations()); - mm.access = m.getAccessFlags(); - mm.parameters = new ArrayList<>(); - mm.descriptor = DeobAnnotations.getObfuscatedSignature(m) != null ? DeobAnnotations.getObfuscatedSignature(m).toString() : m.getDescriptor().toString(); - - try - { - mm.garbageValue = Long.parseLong(DeobAnnotations.getDecoder(m)); - } - catch (NumberFormatException e) - { - mm.garbageValue = null; - } - - for (Parameter p : m.getParameters()) - { - mm.parameters.add(p.getName()); - } - - if (m.getName().equals("")) - { - mm.exportedName = null; - mc.constructors.add(mm); - continue; - } - - if (m.isStatic()) - { - dump.staticMethods.add(mm); - dump.totalNamedStaticMethods++; - - int _index = mm.exportedName.indexOf('_'); - - if (_index != -1) - { - String className = mm.exportedName.substring(0, _index - 1); - MappedClass staticOwner = classMap.get(className); - - if (staticOwner != null) - { - staticOwner.staticMethods.add(mm); - } - } - } - else - { - mc.methods.add(mm); - } - } + new net.runelite.deob.updater.MappingDumper(group).dump(OUTFILE); } @Test diff --git a/deobfuscator/src/test/java/net/runelite/deob/deobfuscators/mapping/mappingdumper/MappedClass.java b/deobfuscator/src/test/java/net/runelite/deob/deobfuscators/mapping/mappingdumper/MappedClass.java deleted file mode 100644 index 329d16415f..0000000000 --- a/deobfuscator/src/test/java/net/runelite/deob/deobfuscators/mapping/mappingdumper/MappedClass.java +++ /dev/null @@ -1,22 +0,0 @@ -package net.runelite.deob.deobfuscators.mapping.mappingdumper; - -import com.google.gson.annotations.SerializedName; -import java.util.List; - -public class MappedClass -{ - @SerializedName("class") - public String implementingName; - @SerializedName("name") - public String obfuscatedName; - @SerializedName("super") - public String superClass; - public int access; - public List interfaces; - public List fields; - public List methods; - public List constructors; - // Static fields/methods belonging to this class (ClassName_name) - public List staticFields; - public List staticMethods; -} diff --git a/deobfuscator/src/test/java/net/runelite/deob/deobfuscators/mapping/mappingdumper/MappedField.java b/deobfuscator/src/test/java/net/runelite/deob/deobfuscators/mapping/mappingdumper/MappedField.java deleted file mode 100644 index b690c0d805..0000000000 --- a/deobfuscator/src/test/java/net/runelite/deob/deobfuscators/mapping/mappingdumper/MappedField.java +++ /dev/null @@ -1,15 +0,0 @@ -package net.runelite.deob.deobfuscators.mapping.mappingdumper; - -import com.google.gson.annotations.SerializedName; - -public class MappedField -{ - @SerializedName("field") - public String exportedName; - public String owner; - @SerializedName("name") - public String obfuscatedName; - public int access; - public String descriptor; - public Long decoder; -} diff --git a/deobfuscator/src/test/java/net/runelite/deob/deobfuscators/mapping/mappingdumper/MappedMethod.java b/deobfuscator/src/test/java/net/runelite/deob/deobfuscators/mapping/mappingdumper/MappedMethod.java deleted file mode 100644 index b2f0c15345..0000000000 --- a/deobfuscator/src/test/java/net/runelite/deob/deobfuscators/mapping/mappingdumper/MappedMethod.java +++ /dev/null @@ -1,17 +0,0 @@ -package net.runelite.deob.deobfuscators.mapping.mappingdumper; - -import com.google.gson.annotations.SerializedName; -import java.util.List; - -public class MappedMethod -{ - @SerializedName("method") - public String exportedName; - public String owner; - @SerializedName("name") - public String obfuscatedName; - public int access; - public List parameters; - public String descriptor; - public Long garbageValue; -} diff --git a/deobfuscator/src/test/java/net/runelite/deob/deobfuscators/mapping/mappingdumper/MappingDump.java b/deobfuscator/src/test/java/net/runelite/deob/deobfuscators/mapping/mappingdumper/MappingDump.java deleted file mode 100644 index bd3f089bd3..0000000000 --- a/deobfuscator/src/test/java/net/runelite/deob/deobfuscators/mapping/mappingdumper/MappingDump.java +++ /dev/null @@ -1,35 +0,0 @@ -package net.runelite.deob.deobfuscators.mapping.mappingdumper; - -import java.util.List; - -public class MappingDump -{ - public int revision; - - public int totalClasses; - public int totalNamedClasses; - - public int totalFields; - public int totalNamedFields; - - public int totalNonStaticFields; - public int totalNamedNonStaticFields; - - public int totalStaticFields; - public int totalNamedStaticFields; - - public int totalMethods; - public int totalNamedMethods; - - public int totalNonStaticMethods; - public int totalNamedNonStaticMethods; - - public int totalStaticMethods; - public int totalNamedStaticMethods; - - public List classes; - - // Static things belonging to a certain class will be in both these lists and in the classes - public List staticFields; - public List staticMethods; -}