Separate remapping from the write{Pack,Jar} methods

This is a prerequisite for removing dummy arguments - before the methods
are remapped, removing an argument might cause the method to conflict
with another method with the same name and descriptor as the replacement
descriptor.
master
Graham 5 years ago
parent c6d184c5c5
commit 1319295d77
  1. 7
      asm/src/main/java/dev/openrs2/asm/classpath/ClassPath.java
  2. 44
      asm/src/main/java/dev/openrs2/asm/classpath/Library.java
  3. 3
      asm/src/main/java/dev/openrs2/asm/transform/ClassForNameTransformer.java
  4. 52
      deob/src/main/java/dev/openrs2/deob/Deobfuscator.java
  5. 23
      deob/src/main/java/dev/openrs2/deob/remap/ClassNamePrefixer.java

@ -9,6 +9,7 @@ import dev.openrs2.asm.MemberDesc;
import dev.openrs2.asm.MemberRef; import dev.openrs2.asm.MemberRef;
import dev.openrs2.util.collect.DisjointSet; import dev.openrs2.util.collect.DisjointSet;
import dev.openrs2.util.collect.ForestDisjointSet; import dev.openrs2.util.collect.ForestDisjointSet;
import org.objectweb.asm.commons.Remapper;
import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.ClassNode;
public final class ClassPath { public final class ClassPath {
@ -86,6 +87,12 @@ public final class ClassPath {
return null; return null;
} }
public void remap(Remapper remapper) {
for (var library : libraries) {
library.remap(remapper);
}
}
public DisjointSet<MemberRef> createInheritedFieldSets() { public DisjointSet<MemberRef> createInheritedFieldSets() {
var disjointSet = new ForestDisjointSet<MemberRef>(); var disjointSet = new ForestDisjointSet<MemberRef>();
var ancestorCache = new HashMap<ClassMetadata, ImmutableSet<MemberDesc>>(); var ancestorCache = new HashMap<ClassMetadata, ImmutableSet<MemberDesc>>();

@ -5,6 +5,7 @@ import java.io.IOException;
import java.io.SequenceInputStream; import java.io.SequenceInputStream;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.Map; import java.util.Map;
import java.util.TreeMap; import java.util.TreeMap;
@ -14,12 +15,13 @@ import java.util.jar.JarOutputStream;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream; import java.util.zip.GZIPOutputStream;
import dev.openrs2.asm.transform.ClassForNameTransformer;
import dev.openrs2.util.io.DeterministicJarOutputStream; import dev.openrs2.util.io.DeterministicJarOutputStream;
import dev.openrs2.util.io.SkipOutputStream; import dev.openrs2.util.io.SkipOutputStream;
import org.apache.harmony.pack200.Pack200; import org.apache.harmony.pack200.Pack200;
import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter; import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.commons.ClassRemapper; import org.objectweb.asm.commons.ClassRemapper;
import org.objectweb.asm.commons.Remapper; import org.objectweb.asm.commons.Remapper;
import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.ClassNode;
@ -112,33 +114,51 @@ public final class Library implements Iterable<ClassNode> {
return classes.values().iterator(); return classes.values().iterator();
} }
public void writeJar(Path path, Remapper remapper) throws IOException { public void remap(Remapper remapper) {
var transformer = new ClassForNameTransformer(remapper);
var classNames = new HashSet<String>();
for (var clazz : classes.values()) {
for (var method : clazz.methods) {
if ((method.access & (Opcodes.ACC_NATIVE | Opcodes.ACC_ABSTRACT)) == 0) {
transformer.transformCode(clazz, method);
}
}
classNames.add(clazz.name);
}
for (var name : classNames) {
var in = classes.remove(name);
var out = new ClassNode();
in.accept(new ClassRemapper(out, remapper));
classes.put(out.name, out);
}
}
public void writeJar(Path path) throws IOException {
logger.info("Writing jar {}", path); logger.info("Writing jar {}", path);
try (var out = new DeterministicJarOutputStream(Files.newOutputStream(path))) { try (var out = new DeterministicJarOutputStream(Files.newOutputStream(path))) {
for (var clazz : classes.values()) { for (var clazz : classes.values()) {
var name = clazz.name;
var writer = new ClassWriter(0); var writer = new ClassWriter(0);
ClassVisitor visitor = new CheckClassAdapter(writer, true); clazz.accept(new CheckClassAdapter(writer, true));
if (remapper != null) {
visitor = new ClassRemapper(visitor, remapper);
name = remapper.map(name);
}
clazz.accept(visitor);
out.putNextEntry(new JarEntry(name + CLASS_SUFFIX)); out.putNextEntry(new JarEntry(clazz.name + CLASS_SUFFIX));
out.write(writer.toByteArray()); out.write(writer.toByteArray());
} }
} }
} }
public void writePack(Path path, Remapper remapper) throws IOException { public void writePack(Path path) throws IOException {
logger.info("Writing pack {}", path); logger.info("Writing pack {}", path);
var temp = Files.createTempFile(TEMP_PREFIX, JAR_SUFFIX); var temp = Files.createTempFile(TEMP_PREFIX, JAR_SUFFIX);
try { try {
writeJar(temp, remapper); writeJar(temp);
try ( try (
var in = new JarInputStream(Files.newInputStream(temp)); var in = new JarInputStream(Files.newInputStream(temp));

@ -1,9 +1,8 @@
package dev.openrs2.deob.transform; package dev.openrs2.asm.transform;
import java.util.List; import java.util.List;
import dev.openrs2.asm.InsnMatcher; import dev.openrs2.asm.InsnMatcher;
import dev.openrs2.asm.transform.Transformer;
import org.objectweb.asm.commons.Remapper; import org.objectweb.asm.commons.Remapper;
import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.ClassNode;

@ -16,10 +16,9 @@ import dev.openrs2.deob.remap.TypedRemapper;
import dev.openrs2.deob.transform.BitShiftTransformer; import dev.openrs2.deob.transform.BitShiftTransformer;
import dev.openrs2.deob.transform.BitwiseOpTransformer; import dev.openrs2.deob.transform.BitwiseOpTransformer;
import dev.openrs2.deob.transform.CanvasTransformer; import dev.openrs2.deob.transform.CanvasTransformer;
import dev.openrs2.deob.transform.ClassForNameTransformer;
import dev.openrs2.deob.transform.CounterTransformer; import dev.openrs2.deob.transform.CounterTransformer;
import dev.openrs2.deob.transform.DummyLocalTransformer;
import dev.openrs2.deob.transform.DummyArgTransformer; import dev.openrs2.deob.transform.DummyArgTransformer;
import dev.openrs2.deob.transform.DummyLocalTransformer;
import dev.openrs2.deob.transform.ExceptionTracingTransformer; import dev.openrs2.deob.transform.ExceptionTracingTransformer;
import dev.openrs2.deob.transform.FieldOrderTransformer; import dev.openrs2.deob.transform.FieldOrderTransformer;
import dev.openrs2.deob.transform.OpaquePredicateTransformer; import dev.openrs2.deob.transform.OpaquePredicateTransformer;
@ -133,41 +132,30 @@ public final class Deobfuscator {
} }
/* remap all class, method and field names */ /* remap all class, method and field names */
logger.info("Creating remappers"); logger.info("Remapping");
var remapper = TypedRemapper.create(classPath); classPath.remap(TypedRemapper.create(classPath));
var glRemapper = TypedRemapper.create(glClassPath); glClassPath.remap(TypedRemapper.create(glClassPath));
var unsignedRemapper = TypedRemapper.create(unsignedClassPath); unsignedClassPath.remap(TypedRemapper.create(unsignedClassPath));
/* transform Class.forName() calls */
logger.info("Transforming Class.forName() calls");
Transformer transformer = new ClassForNameTransformer(remapper);
transformer.transform(classPath);
transformer = new ClassForNameTransformer(glRemapper);
transformer.transform(glClassPath);
transformer = new ClassForNameTransformer(unsignedRemapper);
transformer.transform(unsignedClassPath);
/* write output jars */ /* write output jars */
logger.info("Writing output jars"); logger.info("Writing output jars");
Files.createDirectories(output); Files.createDirectories(output);
client.writeJar(output.resolve("runescape.jar"), remapper); client.writeJar(output.resolve("runescape.jar"));
loader.writeJar(output.resolve("loader.jar"), remapper); loader.writeJar(output.resolve("loader.jar"));
signLink.writeJar(output.resolve("signlink.jar"), remapper); signLink.writeJar(output.resolve("signlink.jar"));
unpack.writeJar(output.resolve("unpack.jar"), remapper); unpack.writeJar(output.resolve("unpack.jar"));
unpacker.writeJar(output.resolve("unpacker.jar"), remapper); unpacker.writeJar(output.resolve("unpacker.jar"));
gl.writeJar(output.resolve("jaggl.jar"), glRemapper); gl.writeJar(output.resolve("jaggl.jar"));
glDri.writeJar(output.resolve("jaggl_dri.jar"), glRemapper); glDri.writeJar(output.resolve("jaggl_dri.jar"));
glClient.writeJar(output.resolve("runescape_gl.jar"), glRemapper); glClient.writeJar(output.resolve("runescape_gl.jar"));
glLoader.writeJar(output.resolve("loader_gl.jar"), glRemapper); glLoader.writeJar(output.resolve("loader_gl.jar"));
glSignLink.writeJar(output.resolve("signlink_gl.jar"), glRemapper); glSignLink.writeJar(output.resolve("signlink_gl.jar"));
glUnpack.writeJar(output.resolve("unpack_gl.jar"), glRemapper); glUnpack.writeJar(output.resolve("unpack_gl.jar"));
glUnpacker.writeJar(output.resolve("unpacker_gl.jar"), glRemapper); glUnpacker.writeJar(output.resolve("unpacker_gl.jar"));
unsignedClient.writeJar(output.resolve("runescape_unsigned.jar"), unsignedRemapper); unsignedClient.writeJar(output.resolve("runescape_unsigned.jar"));
} }
} }

@ -3,11 +3,7 @@ package dev.openrs2.deob.remap;
import java.util.HashMap; import java.util.HashMap;
import dev.openrs2.asm.classpath.Library; import dev.openrs2.asm.classpath.Library;
import dev.openrs2.deob.transform.ClassForNameTransformer;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.commons.ClassRemapper;
import org.objectweb.asm.commons.SimpleRemapper; import org.objectweb.asm.commons.SimpleRemapper;
import org.objectweb.asm.tree.ClassNode;
public final class ClassNamePrefixer { public final class ClassNamePrefixer {
public static void addPrefix(Library library, String prefix) { public static void addPrefix(Library library, String prefix) {
@ -19,25 +15,8 @@ public final class ClassNamePrefixer {
mapping.put(clazz.name, prefix + clazz.name); mapping.put(clazz.name, prefix + clazz.name);
} }
} }
var remapper = new SimpleRemapper(mapping);
var transformer = new ClassForNameTransformer(remapper); library.remap(new SimpleRemapper(mapping));
for (var clazz : library) {
for (var method : clazz.methods) {
if ((method.access & (Opcodes.ACC_NATIVE | Opcodes.ACC_ABSTRACT)) == 0) {
transformer.transformCode(clazz, method);
}
}
}
for (var name : mapping.keySet()) {
var in = library.remove(name);
var out = new ClassNode();
in.accept(new ClassRemapper(out, remapper));
library.add(out);
}
} }
private ClassNamePrefixer() { private ClassNamePrefixer() {

Loading…
Cancel
Save