Open-source multiplayer game server compatible with the RuneScape client
https://www.openrs2.org/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
171 lines
6.1 KiB
171 lines
6.1 KiB
package dev.openrs2.deob;
|
|
|
|
import java.io.IOException;
|
|
import java.net.URL;
|
|
import java.net.URLClassLoader;
|
|
import java.nio.file.Files;
|
|
import java.nio.file.Path;
|
|
import java.nio.file.Paths;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
|
|
import dev.openrs2.asm.Library;
|
|
import dev.openrs2.asm.Transformer;
|
|
import dev.openrs2.deob.classpath.ClassPath;
|
|
import dev.openrs2.deob.classpath.TypedRemapper;
|
|
import dev.openrs2.deob.transform.ClassForNameTransformer;
|
|
import dev.openrs2.deob.transform.ExceptionTracingTransformer;
|
|
import dev.openrs2.deob.transform.OpaquePredicateTransformer;
|
|
import dev.openrs2.deob.transform.OriginalNameTransformer;
|
|
import org.slf4j.Logger;
|
|
import org.slf4j.LoggerFactory;
|
|
|
|
public final class Deobfuscator {
|
|
private static final Logger logger = LoggerFactory.getLogger(Deobfuscator.class);
|
|
|
|
private static final List<Transformer> TRANSFORMERS = List.of(
|
|
new OpaquePredicateTransformer(),
|
|
new ExceptionTracingTransformer()
|
|
);
|
|
|
|
public static void main(String[] args) throws IOException {
|
|
var deobfuscator = new Deobfuscator(Paths.get("nonfree/code"), Paths.get("nonfree/code/deob"));
|
|
deobfuscator.run();
|
|
}
|
|
|
|
private final Path input, output;
|
|
|
|
public Deobfuscator(Path input, Path output) {
|
|
this.input = input;
|
|
this.output = output;
|
|
}
|
|
|
|
public void run() throws IOException {
|
|
/* read input jars/packs */
|
|
logger.info("Reading input jars");
|
|
var unpacker = Library.readJar(input.resolve("game_unpacker.dat"));
|
|
var glUnpacker = new Library(unpacker);
|
|
var loader = Library.readJar(input.resolve("loader.jar"));
|
|
var glLoader = Library.readJar(input.resolve("loader_gl.jar"));
|
|
var client = Library.readJar(input.resolve("runescape.jar"));
|
|
var glClient = Library.readPack(input.resolve("runescape_gl.pack200"));
|
|
var unsignedClient = new Library(client);
|
|
|
|
/* read dependencies */
|
|
var runtime = ClassLoader.getPlatformClassLoader();
|
|
var jogl = new URLClassLoader(new URL[] {
|
|
input.resolve("jogl.jar").toUri().toURL()
|
|
}, runtime);
|
|
|
|
/* overwrite client's classes with signed classes from the loader */
|
|
logger.info("Moving signed classes from loader to runescape");
|
|
var signedClasses = SignedClassSet.create(loader, client);
|
|
|
|
logger.info("Moving signed classes from loader_gl to runescape_gl");
|
|
var glSignedClasses = SignedClassSet.create(glLoader, glClient);
|
|
|
|
/* deobfuscate */
|
|
var allLibraries = Map.of(
|
|
"unpacker", unpacker,
|
|
"unpacker_gl", glUnpacker,
|
|
"loader", loader,
|
|
"loader_gl", glLoader,
|
|
"runescape", client,
|
|
"runescape_gl", glClient,
|
|
"runescape_unsigned", unsignedClient
|
|
);
|
|
|
|
for (var entry : allLibraries.entrySet()) {
|
|
logger.info("Transforming library {}", entry.getKey());
|
|
|
|
for (var transformer : TRANSFORMERS) {
|
|
logger.info("Running transformer {}", transformer.getClass().getSimpleName());
|
|
transformer.transform(entry.getValue());
|
|
}
|
|
}
|
|
|
|
/* move unpack class out of the loader (so the unpacker and loader can both depend on it) */
|
|
logger.info("Moving unpack from loader to unpack");
|
|
var unpack = new Library();
|
|
unpack.add(loader.remove("unpack"));
|
|
|
|
logger.info("Moving unpack from loader_gl to unpack_gl");
|
|
var glUnpack = new Library();
|
|
glUnpack.add(glLoader.remove("unpack"));
|
|
|
|
/* move signed classes out of the client (so the client and loader can both depend on them) */
|
|
logger.info("Moving signed classes from runescape to signlink");
|
|
var signLink = new Library();
|
|
signedClasses.move(client, signLink);
|
|
|
|
logger.info("Moving signed classes from runescape_gl to signlink_gl");
|
|
var glSignLink = new Library();
|
|
glSignedClasses.move(glClient, glSignLink);
|
|
|
|
/* prefix remaining loader/unpacker classes (to avoid conflicts when we rename in the same classpath as the client) */
|
|
logger.info("Prefixing loader and unpacker class names");
|
|
ClassNamePrefixer.addPrefix(loader, "loader_");
|
|
ClassNamePrefixer.addPrefix(glLoader, "loader_");
|
|
ClassNamePrefixer.addPrefix(unpacker, "unpacker_");
|
|
ClassNamePrefixer.addPrefix(glUnpacker, "unpacker_");
|
|
|
|
/* remap all class, method and field names */
|
|
logger.info("Creating remappers");
|
|
var libraries = new Library[] { client, loader, signLink, unpack, unpacker };
|
|
var remapper = TypedRemapper.create(new ClassPath(runtime, libraries));
|
|
|
|
var glLibraries = new Library[] { glClient, glLoader, glSignLink, glUnpack, glUnpacker };
|
|
var glRemapper = TypedRemapper.create(new ClassPath(jogl, glLibraries));
|
|
|
|
var unsignedRemapper = TypedRemapper.create(new ClassPath(runtime, unsignedClient));
|
|
|
|
/* transform Class.forName() calls */
|
|
logger.info("Transforming Class.forName() calls");
|
|
Transformer transformer = new ClassForNameTransformer(remapper);
|
|
for (var library : libraries) {
|
|
transformer.transform(library);
|
|
}
|
|
|
|
transformer = new ClassForNameTransformer(glRemapper);
|
|
for (var library : glLibraries) {
|
|
transformer.transform(library);
|
|
}
|
|
|
|
transformer = new ClassForNameTransformer(unsignedRemapper);
|
|
transformer.transform(unsignedClient);
|
|
|
|
/* add @OriginalName annotations */
|
|
logger.info("Annotating classes and members with original names");
|
|
transformer = new OriginalNameTransformer(remapper);
|
|
for (var library : libraries) {
|
|
transformer.transform(library);
|
|
}
|
|
|
|
transformer = new OriginalNameTransformer(glRemapper);
|
|
for (var library : glLibraries) {
|
|
transformer.transform(library);
|
|
}
|
|
|
|
transformer = new OriginalNameTransformer(unsignedRemapper);
|
|
transformer.transform(unsignedClient);
|
|
|
|
/* write output jars */
|
|
logger.info("Writing output jars");
|
|
|
|
Files.createDirectories(output);
|
|
|
|
client.writeJar(output.resolve("runescape.jar"), remapper);
|
|
loader.writeJar(output.resolve("loader.jar"), remapper);
|
|
signLink.writeJar(output.resolve("signlink.jar"), remapper);
|
|
unpack.writeJar(output.resolve("unpack.jar"), remapper);
|
|
unpacker.writeJar(output.resolve("unpacker.jar"), remapper);
|
|
|
|
glClient.writeJar(output.resolve("runescape_gl.jar"), glRemapper);
|
|
glLoader.writeJar(output.resolve("loader_gl.jar"), glRemapper);
|
|
glSignLink.writeJar(output.resolve("signlink_gl.jar"), glRemapper);
|
|
glUnpack.writeJar(output.resolve("unpack_gl.jar"), glRemapper);
|
|
glUnpacker.writeJar(output.resolve("unpacker_gl.jar"), glRemapper);
|
|
|
|
unsignedClient.writeJar(output.resolve("runescape_unsigned.jar"), unsignedRemapper);
|
|
}
|
|
}
|
|
|