Convert Deobfuscator to Kotlin

pull/48/head
Graham 4 years ago
parent 0f78c9582c
commit 0db3d979c9
  1. 160
      deob/src/main/java/dev/openrs2/deob/Deobfuscator.java
  2. 156
      deob/src/main/java/dev/openrs2/deob/Deobfuscator.kt

@ -1,160 +0,0 @@
package dev.openrs2.deob;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import com.google.common.collect.ImmutableList;
import dev.openrs2.asm.classpath.ClassPath;
import dev.openrs2.asm.classpath.Library;
import dev.openrs2.asm.transform.Transformer;
import dev.openrs2.bundler.Bundler;
import dev.openrs2.deob.remap.PrefixRemapper;
import dev.openrs2.deob.transform.AccessTransformer;
import dev.openrs2.deob.transform.BitShiftTransformer;
import dev.openrs2.deob.transform.BitwiseOpTransformer;
import dev.openrs2.deob.transform.CanvasTransformer;
import dev.openrs2.deob.transform.CounterTransformer;
import dev.openrs2.deob.transform.DummyArgTransformer;
import dev.openrs2.deob.transform.DummyLocalTransformer;
import dev.openrs2.deob.transform.ExceptionTracingTransformer;
import dev.openrs2.deob.transform.FieldOrderTransformer;
import dev.openrs2.deob.transform.OpaquePredicateTransformer;
import dev.openrs2.deob.transform.OriginalNameTransformer;
import dev.openrs2.deob.transform.RemapTransformer;
import dev.openrs2.deob.transform.ResetTransformer;
import dev.openrs2.deob.transform.UnusedArgTransformer;
import org.objectweb.asm.tree.analysis.AnalyzerException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public final class Deobfuscator {
private static final Logger logger = LoggerFactory.getLogger(Deobfuscator.class);
private static final ImmutableList<Transformer> TRANSFORMERS = ImmutableList.<Transformer>builder()
.add(new OriginalNameTransformer())
.addAll(Bundler.TRANSFORMERS)
.add(new OpaquePredicateTransformer())
.add(new ExceptionTracingTransformer())
.add(new BitShiftTransformer())
.add(new CounterTransformer())
.add(new CanvasTransformer())
.add(new FieldOrderTransformer())
.add(new BitwiseOpTransformer())
.add(new RemapTransformer())
.add(new DummyArgTransformer())
.add(new DummyLocalTransformer())
.add(new UnusedArgTransformer())
.add(new ResetTransformer())
.add(new AccessTransformer())
.build();
public static void main(String[] args) throws IOException, AnalyzerException {
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, AnalyzerException {
/* 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 gl = Library.readPack(input.resolve("jaggl.pack200"));
var client = Library.readJar(input.resolve("runescape.jar"));
var glClient = Library.readPack(input.resolve("runescape_gl.pack200"));
// TODO(gpe): it'd be nice to have separate signlink.jar and
// signlink-unsigned.jar files so we don't (effectively) deobfuscate
// runescape.jar twice with different sets of names, but thinking about
// how this would work is tricky (as the naming must match)
var unsignedClient = new Library(client);
/* overwrite client's classes with signed classes from the loader */
logger.info("Moving signed classes from loader");
var signLink = new Library();
SignedClassUtils.move(loader, client, signLink);
logger.info("Moving signed classes from loader_gl");
var glSignLink = new Library();
SignedClassUtils.move(glLoader, glClient, glSignLink);
/* 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 DRI classes out of jaggl (so we can place javah-generated headers in a separate directory) */
logger.info("Moving DRI classes from jaggl to jaggl_dri");
var glDri = new Library();
glDri.add(gl.remove("com/sun/opengl/impl/x11/DRIHack"));
glDri.add(gl.remove("com/sun/opengl/impl/x11/DRIHack$1"));
glDri.add(gl.remove("jaggl/X11/dri"));
/* 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");
loader.remap(PrefixRemapper.create(loader, "loader_"));
glLoader.remap(PrefixRemapper.create(glLoader, "loader_"));
unpacker.remap(PrefixRemapper.create(unpacker, "unpacker_"));
glUnpacker.remap(PrefixRemapper.create(glUnpacker, "unpacker_"));
/* bundle libraries together into a common classpath */
var runtime = ClassLoader.getPlatformClassLoader();
var classPath = new ClassPath(runtime, ImmutableList.of(), ImmutableList.of(client, loader, signLink, unpack, unpacker));
var glClassPath = new ClassPath(runtime, ImmutableList.of(gl, glDri), ImmutableList.of(glClient, glLoader, glSignLink, glUnpack, glUnpacker));
var unsignedClassPath = new ClassPath(runtime, ImmutableList.of(), ImmutableList.of(unsignedClient));
/* deobfuscate */
logger.info("Transforming client");
for (var transformer : TRANSFORMERS) {
logger.info("Running transformer {}", transformer.getClass().getSimpleName());
transformer.transform(classPath);
}
logger.info("Transforming client_gl");
for (var transformer : TRANSFORMERS) {
logger.info("Running transformer {}", transformer.getClass().getSimpleName());
transformer.transform(glClassPath);
}
logger.info("Transforming client_unsigned");
for (var transformer : TRANSFORMERS) {
logger.info("Running transformer {}", transformer.getClass().getSimpleName());
transformer.transform(unsignedClassPath);
}
/* write output jars */
logger.info("Writing output jars");
Files.createDirectories(output);
client.writeJar(output.resolve("runescape.jar"));
loader.writeJar(output.resolve("loader.jar"));
signLink.writeJar(output.resolve("signlink.jar"));
unpack.writeJar(output.resolve("unpack.jar"));
unpacker.writeJar(output.resolve("unpacker.jar"));
gl.writeJar(output.resolve("jaggl.jar"));
glDri.writeJar(output.resolve("jaggl_dri.jar"));
glClient.writeJar(output.resolve("runescape_gl.jar"));
glLoader.writeJar(output.resolve("loader_gl.jar"));
glSignLink.writeJar(output.resolve("signlink_gl.jar"));
glUnpack.writeJar(output.resolve("unpack_gl.jar"));
glUnpacker.writeJar(output.resolve("unpacker_gl.jar"));
unsignedClient.writeJar(output.resolve("runescape_unsigned.jar"));
}
}

@ -0,0 +1,156 @@
package dev.openrs2.deob
import com.github.michaelbull.logging.InlineLogger
import com.google.common.collect.ImmutableList
import dev.openrs2.asm.classpath.ClassPath
import dev.openrs2.asm.classpath.Library
import dev.openrs2.asm.classpath.Library.Companion.readJar
import dev.openrs2.asm.classpath.Library.Companion.readPack
import dev.openrs2.bundler.Bundler
import dev.openrs2.deob.SignedClassUtils.move
import dev.openrs2.deob.remap.PrefixRemapper.create
import dev.openrs2.deob.transform.*
import org.objectweb.asm.tree.analysis.AnalyzerException
import java.io.IOException
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.Paths
class Deobfuscator(private val input: Path, private val output: Path) {
@Throws(IOException::class, AnalyzerException::class)
fun run() {
// read input jars/packs
logger.info { "Reading input jars" }
val unpacker = readJar(input.resolve("game_unpacker.dat"))
val glUnpacker = Library(unpacker)
val loader = readJar(input.resolve("loader.jar"))
val glLoader = readJar(input.resolve("loader_gl.jar"))
val gl = readPack(input.resolve("jaggl.pack200"))
val client = readJar(input.resolve("runescape.jar"))
val glClient = readPack(input.resolve("runescape_gl.pack200"))
// TODO(gpe): it'd be nice to have separate signlink.jar and
// signlink-unsigned.jar files so we don't (effectively) deobfuscate
// runescape.jar twice with different sets of names, but thinking about
// how this would work is tricky (as the naming must match)
val unsignedClient = Library(client)
// overwrite client's classes with signed classes from the loader
logger.info { "Moving signed classes from loader" }
val signLink = Library()
move(loader, client, signLink)
logger.info { "Moving signed classes from loader_gl" }
val glSignLink = Library()
move(glLoader, glClient, glSignLink)
// 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" }
val unpack = Library()
unpack.add(loader.remove("unpack")!!)
logger.info { "Moving unpack from loader_gl to unpack_gl" }
val glUnpack = Library()
glUnpack.add(glLoader.remove("unpack")!!)
// move DRI classes out of jaggl (so we can place javah-generated headers in a separate directory)
logger.info { "Moving DRI classes from jaggl to jaggl_dri" }
val glDri = Library()
glDri.add(gl.remove("com/sun/opengl/impl/x11/DRIHack")!!)
glDri.add(gl.remove("com/sun/opengl/impl/x11/DRIHack$1")!!)
glDri.add(gl.remove("jaggl/X11/dri")!!)
// 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" }
loader.remap(create(loader, "loader_"))
glLoader.remap(create(glLoader, "loader_"))
unpacker.remap(create(unpacker, "unpacker_"))
glUnpacker.remap(create(glUnpacker, "unpacker_"))
// bundle libraries together into a common classpath
val runtime = ClassLoader.getPlatformClassLoader()
val classPath = ClassPath(
runtime,
ImmutableList.of(),
ImmutableList.of(client, loader, signLink, unpack, unpacker)
)
val glClassPath = ClassPath(
runtime,
ImmutableList.of(gl, glDri),
ImmutableList.of(glClient, glLoader, glSignLink, glUnpack, glUnpacker)
)
val unsignedClassPath = ClassPath(
runtime,
ImmutableList.of(),
ImmutableList.of(unsignedClient)
)
// deobfuscate
logger.info { "Transforming client" }
for (transformer in TRANSFORMERS) {
logger.info { "Running transformer ${transformer.javaClass.simpleName} " }
transformer.transform(classPath)
}
logger.info { "Transforming client_gl" }
for (transformer in TRANSFORMERS) {
logger.info { "Running transformer ${transformer.javaClass.simpleName} " }
transformer.transform(glClassPath)
}
logger.info { "Transforming client_unsigned" }
for (transformer in TRANSFORMERS) {
logger.info { "Running transformer ${transformer.javaClass.simpleName} " }
transformer.transform(unsignedClassPath)
}
// write output jars
logger.info { "Writing output jars" }
Files.createDirectories(output)
client.writeJar(output.resolve("runescape.jar"))
loader.writeJar(output.resolve("loader.jar"))
signLink.writeJar(output.resolve("signlink.jar"))
unpack.writeJar(output.resolve("unpack.jar"))
unpacker.writeJar(output.resolve("unpacker.jar"))
gl.writeJar(output.resolve("jaggl.jar"))
glDri.writeJar(output.resolve("jaggl_dri.jar"))
glClient.writeJar(output.resolve("runescape_gl.jar"))
glLoader.writeJar(output.resolve("loader_gl.jar"))
glSignLink.writeJar(output.resolve("signlink_gl.jar"))
glUnpack.writeJar(output.resolve("unpack_gl.jar"))
glUnpacker.writeJar(output.resolve("unpacker_gl.jar"))
unsignedClient.writeJar(output.resolve("runescape_unsigned.jar"))
}
companion object {
private val logger = InlineLogger()
private val TRANSFORMERS = listOf(
OriginalNameTransformer(),
*Bundler.TRANSFORMERS.toTypedArray(),
OpaquePredicateTransformer(),
ExceptionTracingTransformer(),
BitShiftTransformer(),
CounterTransformer(),
CanvasTransformer(),
FieldOrderTransformer(),
BitwiseOpTransformer(),
RemapTransformer(),
DummyArgTransformer(),
DummyLocalTransformer(),
UnusedArgTransformer(),
ResetTransformer(),
AccessTransformer()
)
@Throws(IOException::class, AnalyzerException::class)
@JvmStatic
fun main(args: Array<String>) {
val deobfuscator = Deobfuscator(Paths.get("nonfree/code"), Paths.get("nonfree/code/deob"))
deobfuscator.run()
}
}
}
Loading…
Cancel
Save