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