diff --git a/asm/src/main/java/dev/openrs2/asm/classpath/ClassMetadata.kt b/asm/src/main/java/dev/openrs2/asm/classpath/ClassMetadata.kt index 0a3b80be..e82a85a7 100644 --- a/asm/src/main/java/dev/openrs2/asm/classpath/ClassMetadata.kt +++ b/asm/src/main/java/dev/openrs2/asm/classpath/ClassMetadata.kt @@ -38,6 +38,28 @@ abstract class ClassMetadata { return false } + fun isAssignableFrom(type: ClassMetadata): Boolean { + return type == this || isSuperClassOf(type) || isSuperInterfaceOf(type) + } + + private tailrec fun isSuperClassOf(type: ClassMetadata): Boolean { + val superClass = type.superClass ?: return false + if (superClass == this) { + return true + } + return isSuperClassOf(superClass) + } + + private fun isSuperInterfaceOf(type: ClassMetadata): Boolean { + for (superInterface in type.superInterfaces) { + if (superInterface == this || isSuperInterfaceOf(superInterface)) { + return true + } + } + + return false + } + override fun equals(other: Any?): Boolean { if (this === other) return true if (other !is ClassMetadata) return false diff --git a/asm/src/main/java/dev/openrs2/asm/classpath/Library.kt b/asm/src/main/java/dev/openrs2/asm/classpath/Library.kt index a3218a98..212c3eeb 100644 --- a/asm/src/main/java/dev/openrs2/asm/classpath/Library.kt +++ b/asm/src/main/java/dev/openrs2/asm/classpath/Library.kt @@ -7,7 +7,6 @@ import dev.openrs2.common.crypto.Pkcs12KeyStore import dev.openrs2.common.io.DeterministicJarOutputStream import dev.openrs2.common.io.SkipOutputStream import org.objectweb.asm.ClassReader -import org.objectweb.asm.ClassWriter import org.objectweb.asm.commons.Remapper import org.objectweb.asm.tree.ClassNode import org.objectweb.asm.util.CheckClassAdapter @@ -64,18 +63,18 @@ class Library constructor() : Iterable { classes = classes.mapKeysTo(TreeMap()) { (_, clazz) -> clazz.name } } - fun writeJar(path: Path, manifest: Manifest? = null) { + fun writeJar(classPath: ClassPath, path: Path, manifest: Manifest? = null) { logger.info { "Writing jar $path" } Files.newOutputStream(path).use { - writeJar(it, manifest) + writeJar(classPath, it, manifest) } } - fun writeJar(out: OutputStream, manifest: Manifest? = null) { + fun writeJar(classPath: ClassPath, out: OutputStream, manifest: Manifest? = null) { DeterministicJarOutputStream.create(out, manifest).use { jar -> for (clazz in classes.values) { - val writer = ClassWriter(0) + val writer = StackFrameClassWriter(classPath) clazz.accept(writer) @@ -96,12 +95,12 @@ class Library constructor() : Iterable { } } - fun writeSignedJar(path: Path, keyStore: Pkcs12KeyStore, manifest: Manifest? = null) { + fun writeSignedJar(classPath: ClassPath, path: Path, keyStore: Pkcs12KeyStore, manifest: Manifest? = null) { logger.info { "Writing signed jar $path" } val unsignedPath = Files.createTempFile("tmp", ".jar") try { - writeJar(unsignedPath, manifest) + writeJar(classPath, unsignedPath, manifest) keyStore.signJar(unsignedPath) DeterministicJarOutputStream.repack(unsignedPath, path) } finally { @@ -109,10 +108,10 @@ class Library constructor() : Iterable { } } - fun writePack(out: OutputStream) { + fun writePack(classPath: ClassPath, out: OutputStream) { val temp = Files.createTempFile(TEMP_PREFIX, JAR_SUFFIX) try { - writeJar(temp) + writeJar(classPath, temp) JarInputStream(Files.newInputStream(temp)).use { `in` -> val headerSize = GZIP_HEADER.size.toLong() @@ -126,7 +125,7 @@ class Library constructor() : Iterable { } } - fun writeJs5(out: OutputStream) { + fun writeJs5(classPath: ClassPath, out: OutputStream) { // TODO(gpe): implement } @@ -151,7 +150,7 @@ class Library constructor() : Iterable { val clazz = ClassNode() val reader = ClassReader(`in`) - reader.accept(JsrInliner(clazz), ClassReader.SKIP_DEBUG) + reader.accept(JsrInliner(clazz), ClassReader.SKIP_DEBUG or ClassReader.SKIP_FRAMES) library.add(clazz) } diff --git a/asm/src/main/java/dev/openrs2/asm/classpath/StackFrameClassWriter.kt b/asm/src/main/java/dev/openrs2/asm/classpath/StackFrameClassWriter.kt new file mode 100644 index 00000000..2f6ce2dc --- /dev/null +++ b/asm/src/main/java/dev/openrs2/asm/classpath/StackFrameClassWriter.kt @@ -0,0 +1,21 @@ +package dev.openrs2.asm.classpath + +import org.objectweb.asm.ClassWriter + +class StackFrameClassWriter(private val classPath: ClassPath) : ClassWriter(COMPUTE_FRAMES) { + override fun getCommonSuperClass(type1: String, type2: String): String { + var c = classPath[type1]!! + val d = classPath[type2]!! + return when { + c.isAssignableFrom(d) -> type1 + d.isAssignableFrom(c) -> type2 + c.`interface` || d.`interface` -> "java/lang/Object" + else -> { + do { + c = c.superClass!! + } while (!c.isAssignableFrom(d)) + c.name + } + } + } +} diff --git a/bundler/src/main/java/dev/openrs2/bundler/Bundler.kt b/bundler/src/main/java/dev/openrs2/bundler/Bundler.kt index da353305..595443c9 100644 --- a/bundler/src/main/java/dev/openrs2/bundler/Bundler.kt +++ b/bundler/src/main/java/dev/openrs2/bundler/Bundler.kt @@ -72,13 +72,13 @@ class Bundler @Inject constructor(publicKeyTransformer: PublicKeyTransformer) { // compress resources logger.info { "Compressing resources" } - val unpackerJar = Resource.compressJar("unpackclass.pack", "game_unpacker.dat", unpacker) - val clientPack = Resource.compressPack("runescape.pack200", "main_file_cache.dat0", client) - val clientJs5 = Resource.compressJs5("runescape.js5", "main_file_cache.dat1", client) - val glClientPack = Resource.compressPack("runescape_gl.pack200", "main_file_cache.dat3", glClient) - val glClientJs5 = Resource.compressJs5("runescape_gl.js5", "main_file_cache.dat4", glClient) - val glPack = Resource.compressPack("jaggl.pack200", "main_file_cache.dat5", gl) - val glJs5 = Resource.compressJs5("jaggl.js5", "main_file_cache.dat6", gl) + val unpackerJar = Resource.compressJar("unpackclass.pack", "game_unpacker.dat", classPath, unpacker) + val clientPack = Resource.compressPack("runescape.pack200", "main_file_cache.dat0", classPath, client) + val clientJs5 = Resource.compressJs5("runescape.js5", "main_file_cache.dat1", classPath, client) + val glClientPack = Resource.compressPack("runescape_gl.pack200", "main_file_cache.dat3", glClassPath, glClient) + val glClientJs5 = Resource.compressJs5("runescape_gl.js5", "main_file_cache.dat4", glClassPath, glClient) + val glPack = Resource.compressPack("jaggl.pack200", "main_file_cache.dat5", glClassPath, gl) + val glJs5 = Resource.compressJs5("jaggl.js5", "main_file_cache.dat6", glClassPath, gl) val glNatives = Resource.compressGlNatives() val miscNatives = Resource.compressMiscNatives() @@ -117,11 +117,11 @@ class Bundler @Inject constructor(publicKeyTransformer: PublicKeyTransformer) { } // write unsigned client and loaders - client.writeJar(output.resolve("runescape.jar"), unsignedManifest) + client.writeJar(classPath, output.resolve("runescape.jar"), unsignedManifest) val keyStore = Pkcs12KeyStore.open(keyStorePath) - loader.writeSignedJar(output.resolve("loader.jar"), keyStore, signedManifest) - glLoader.writeSignedJar(output.resolve("loader_gl.jar"), keyStore, signedManifest) + loader.writeSignedJar(classPath, output.resolve("loader.jar"), keyStore, signedManifest) + glLoader.writeSignedJar(glClassPath, output.resolve("loader_gl.jar"), keyStore, signedManifest) } companion object { diff --git a/bundler/src/main/java/dev/openrs2/bundler/Resource.kt b/bundler/src/main/java/dev/openrs2/bundler/Resource.kt index 83c2589a..4ed7e5d6 100644 --- a/bundler/src/main/java/dev/openrs2/bundler/Resource.kt +++ b/bundler/src/main/java/dev/openrs2/bundler/Resource.kt @@ -1,6 +1,7 @@ package dev.openrs2.bundler import com.github.michaelbull.logging.InlineLogger +import dev.openrs2.asm.classpath.ClassPath import dev.openrs2.asm.classpath.Library import java.io.ByteArrayOutputStream import java.nio.file.Files @@ -64,23 +65,23 @@ class Resource( return Resource(source, destination, crc.value.toInt(), digest.digest(), uncompressed.size, content) } - fun compressJar(source: String, destination: String, library: Library): Resource { + fun compressJar(source: String, destination: String, classPath: ClassPath, library: Library): Resource { ByteArrayOutputStream().use { out -> - library.writeJar(out) + library.writeJar(classPath, out) return compress(source, destination, out.toByteArray()) } } - fun compressPack(source: String, destination: String, library: Library): Resource { + fun compressPack(source: String, destination: String, classPath: ClassPath, library: Library): Resource { ByteArrayOutputStream().use { out -> - library.writePack(out) + library.writePack(classPath, out) return compress(source, destination, out.toByteArray()) } } - fun compressJs5(source: String, destination: String, library: Library): Resource { + fun compressJs5(source: String, destination: String, classPath: ClassPath, library: Library): Resource { ByteArrayOutputStream().use { out -> - library.writeJs5(out) + library.writeJs5(classPath, out) return compress(source, destination, out.toByteArray()) } } diff --git a/deob/src/main/java/dev/openrs2/deob/Deobfuscator.kt b/deob/src/main/java/dev/openrs2/deob/Deobfuscator.kt index fc5d6223..c220fab4 100644 --- a/deob/src/main/java/dev/openrs2/deob/Deobfuscator.kt +++ b/deob/src/main/java/dev/openrs2/deob/Deobfuscator.kt @@ -133,21 +133,21 @@ class Deobfuscator(private val input: Path, private val output: Path) { 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")) + client.writeJar(classPath, output.resolve("runescape.jar")) + loader.writeJar(classPath, output.resolve("loader.jar")) + signLink.writeJar(classPath, output.resolve("signlink.jar")) + unpack.writeJar(classPath, output.resolve("unpack.jar")) + unpacker.writeJar(classPath, output.resolve("unpacker.jar")) + + gl.writeJar(glClassPath, output.resolve("jaggl.jar")) + glDri.writeJar(glClassPath, output.resolve("jaggl_dri.jar")) + glClient.writeJar(glClassPath, output.resolve("runescape_gl.jar")) + glLoader.writeJar(glClassPath, output.resolve("loader_gl.jar")) + glSignLink.writeJar(glClassPath, output.resolve("signlink_gl.jar")) + glUnpack.writeJar(glClassPath, output.resolve("unpack_gl.jar")) + glUnpacker.writeJar(glClassPath, output.resolve("unpacker_gl.jar")) + + unsignedClient.writeJar(unsignedClassPath, output.resolve("runescape_unsigned.jar")) } companion object {