forked from openrs2/openrs2
parent
0f78c9582c
commit
0db3d979c9
@ -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…
Reference in new issue