From aa6d0cb6bb8a8e3147f2b9222c72a6eeb979e126 Mon Sep 17 00:00:00 2001 From: Scu11 Date: Tue, 14 Apr 2020 15:12:12 +0100 Subject: [PATCH 1/3] Move Library#write methods to dedicated classes Signed-off-by: Scu11 --- .../java/dev/openrs2/asm/classpath/Library.kt | 84 ------------------- .../dev/openrs2/asm/io/JarLibraryWriter.kt | 45 ++++++++++ .../dev/openrs2/asm/io/Js5LibraryWriter.kt | 12 +++ .../java/dev/openrs2/asm/io/LibraryWriter.kt | 8 ++ .../openrs2/asm/io/Pack200LibraryWriter.kt | 36 ++++++++ .../openrs2/asm/io/SignedJarLibraryWriter.kt | 54 ++++++++++++ .../main/java/dev/openrs2/bundler/Bundler.kt | 26 +++++- .../main/java/dev/openrs2/bundler/Resource.kt | 25 ++++-- .../java/dev/openrs2/deob/Deobfuscator.kt | 34 +++++--- .../util/io/DeterministicJarOutputStream.kt | 28 +------ 10 files changed, 219 insertions(+), 133 deletions(-) create mode 100644 asm/src/main/java/dev/openrs2/asm/io/JarLibraryWriter.kt create mode 100644 asm/src/main/java/dev/openrs2/asm/io/Js5LibraryWriter.kt create mode 100644 asm/src/main/java/dev/openrs2/asm/io/LibraryWriter.kt create mode 100644 asm/src/main/java/dev/openrs2/asm/io/Pack200LibraryWriter.kt create mode 100644 asm/src/main/java/dev/openrs2/asm/io/SignedJarLibraryWriter.kt 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 d7a9a3cb..03a9bc64 100644 --- a/asm/src/main/java/dev/openrs2/asm/classpath/Library.kt +++ b/asm/src/main/java/dev/openrs2/asm/classpath/Library.kt @@ -1,26 +1,16 @@ package dev.openrs2.asm.classpath import com.github.michaelbull.logging.InlineLogger -import dev.openrs2.asm.ClassVersionUtils -import dev.openrs2.asm.NopClassVisitor import dev.openrs2.asm.remap import dev.openrs2.compress.gzip.Gzip -import dev.openrs2.crypto.Pkcs12KeyStore -import dev.openrs2.util.io.DeterministicJarOutputStream import org.objectweb.asm.ClassReader -import org.objectweb.asm.ClassWriter -import org.objectweb.asm.Opcodes import org.objectweb.asm.commons.Remapper import org.objectweb.asm.tree.ClassNode -import org.objectweb.asm.util.CheckClassAdapter -import java.io.OutputStream import java.nio.file.Files import java.nio.file.Path import java.util.TreeMap -import java.util.jar.JarEntry import java.util.jar.JarInputStream import java.util.jar.JarOutputStream -import java.util.jar.Manifest import java.util.jar.Pack200 class Library() : Iterable { @@ -62,80 +52,6 @@ class Library() : Iterable { classes = classes.mapKeysTo(TreeMap()) { (_, clazz) -> clazz.name } } - fun writeJar(classPath: ClassPath, path: Path, manifest: Manifest? = null) { - logger.info { "Writing jar $path" } - - Files.newOutputStream(path).use { - writeJar(classPath, it, manifest) - } - } - - fun writeJar(classPath: ClassPath, out: OutputStream, manifest: Manifest? = null) { - DeterministicJarOutputStream.create(out, manifest).use { jar -> - for (clazz in classes.values) { - val writer = if (ClassVersionUtils.gte(clazz.version, Opcodes.V1_7)) { - StackFrameClassWriter(classPath) - } else { - ClassWriter(ClassWriter.COMPUTE_MAXS) - } - - clazz.accept(writer) - - jar.putNextEntry(JarEntry(clazz.name + CLASS_SUFFIX)) - jar.write(writer.toByteArray()) - - /* - * XXX(gpe): CheckClassAdapter breaks the Label offset - * calculation in the OriginalPcTable's write method, so we do - * a second pass without any attributes to check the class, - * feeding the callbacks into a no-op visitor. - */ - for (method in clazz.methods) { - method.attrs?.clear() - } - clazz.accept(CheckClassAdapter(NopClassVisitor, true)) - } - } - } - - fun writeSignedJar(classPath: ClassPath, path: Path, keyStore: Pkcs12KeyStore, manifest: Manifest? = null) { - logger.info { "Writing signed jar $path" } - - val unsignedPath = Files.createTempFile(TEMP_PREFIX, JAR_SUFFIX) - try { - writeJar(classPath, unsignedPath, manifest) - - val signedPath = Files.createTempFile(TEMP_PREFIX, JAR_SUFFIX) - try { - keyStore.signJar(unsignedPath, signedPath) - DeterministicJarOutputStream.repack(signedPath, path) - } finally { - Files.deleteIfExists(signedPath) - } - } finally { - Files.deleteIfExists(unsignedPath) - } - } - - fun writePack(classPath: ClassPath, out: OutputStream) { - val temp = Files.createTempFile(TEMP_PREFIX, JAR_SUFFIX) - try { - writeJar(classPath, temp) - - JarInputStream(Files.newInputStream(temp)).use { `in` -> - Gzip.createHeaderlessOutputStream(out).use { gzip -> - Pack200.newPacker().pack(`in`, gzip) - } - } - } finally { - Files.deleteIfExists(temp) - } - } - - fun writeJs5(classPath: ClassPath, out: OutputStream) { - // TODO(gpe): implement - } - companion object { private val logger = InlineLogger() private const val CLASS_SUFFIX = ".class" diff --git a/asm/src/main/java/dev/openrs2/asm/io/JarLibraryWriter.kt b/asm/src/main/java/dev/openrs2/asm/io/JarLibraryWriter.kt new file mode 100644 index 00000000..63468157 --- /dev/null +++ b/asm/src/main/java/dev/openrs2/asm/io/JarLibraryWriter.kt @@ -0,0 +1,45 @@ +package dev.openrs2.asm.io + +import dev.openrs2.asm.ClassVersionUtils +import dev.openrs2.asm.NopClassVisitor +import dev.openrs2.asm.classpath.ClassPath +import dev.openrs2.asm.classpath.Library +import dev.openrs2.asm.classpath.StackFrameClassWriter +import org.objectweb.asm.ClassWriter +import org.objectweb.asm.Opcodes +import org.objectweb.asm.util.CheckClassAdapter +import java.util.jar.JarEntry +import java.util.jar.JarOutputStream + +class JarLibraryWriter(private val output: JarOutputStream) : LibraryWriter { + + override fun write(classPath: ClassPath, library: Library) { + for (clazz in library) { + val writer = if (ClassVersionUtils.gte(clazz.version, Opcodes.V1_7)) { + StackFrameClassWriter(classPath) + } else { + ClassWriter(ClassWriter.COMPUTE_MAXS) + } + + clazz.accept(writer) + + output.putNextEntry(JarEntry(clazz.name + CLASS_SUFFIX)) + output.write(writer.toByteArray()) + + /* + * XXX(gpe): CheckClassAdapter breaks the Label offset + * calculation in the OriginalPcTable's write method, so we do + * a second pass without any attributes to check the class, + * feeding the callbacks into a no-op visitor. + */ + for (method in clazz.methods) { + method.attrs?.clear() + } + clazz.accept(CheckClassAdapter(NopClassVisitor, true)) + } + } + + private companion object { + private const val CLASS_SUFFIX = ".class" + } +} diff --git a/asm/src/main/java/dev/openrs2/asm/io/Js5LibraryWriter.kt b/asm/src/main/java/dev/openrs2/asm/io/Js5LibraryWriter.kt new file mode 100644 index 00000000..d5fe1867 --- /dev/null +++ b/asm/src/main/java/dev/openrs2/asm/io/Js5LibraryWriter.kt @@ -0,0 +1,12 @@ +package dev.openrs2.asm.io + +import dev.openrs2.asm.classpath.ClassPath +import dev.openrs2.asm.classpath.Library +import java.io.OutputStream + +class Js5LibraryWriter(private val output: OutputStream) : LibraryWriter { + + override fun write(classPath: ClassPath, library: Library) { + // TODO(gpe): implement + } +} diff --git a/asm/src/main/java/dev/openrs2/asm/io/LibraryWriter.kt b/asm/src/main/java/dev/openrs2/asm/io/LibraryWriter.kt new file mode 100644 index 00000000..b04ee79f --- /dev/null +++ b/asm/src/main/java/dev/openrs2/asm/io/LibraryWriter.kt @@ -0,0 +1,8 @@ +package dev.openrs2.asm.io + +import dev.openrs2.asm.classpath.ClassPath +import dev.openrs2.asm.classpath.Library + +interface LibraryWriter { + fun write(classPath: ClassPath, library: Library) +} diff --git a/asm/src/main/java/dev/openrs2/asm/io/Pack200LibraryWriter.kt b/asm/src/main/java/dev/openrs2/asm/io/Pack200LibraryWriter.kt new file mode 100644 index 00000000..a04573f5 --- /dev/null +++ b/asm/src/main/java/dev/openrs2/asm/io/Pack200LibraryWriter.kt @@ -0,0 +1,36 @@ +package dev.openrs2.asm.io + +import dev.openrs2.asm.classpath.ClassPath +import dev.openrs2.asm.classpath.Library +import dev.openrs2.compress.gzip.Gzip +import dev.openrs2.util.io.DeterministicJarOutputStream +import java.io.OutputStream +import java.nio.file.Files +import java.util.jar.JarInputStream +import java.util.jar.Pack200 + +class Pack200LibraryWriter(private val output: OutputStream) : LibraryWriter { + + override fun write(classPath: ClassPath, library: Library) { + val tempJar = Files.createTempFile(TEMP_PREFIX, JAR_SUFFIX) + + try { + DeterministicJarOutputStream(Files.newOutputStream(tempJar)).use { tempOutput -> + JarLibraryWriter(tempOutput).write(classPath, library) + } + + JarInputStream(Files.newInputStream(tempJar)).use { input -> + Gzip.createHeaderlessOutputStream(output).use { gzip -> + Pack200.newPacker().pack(input, gzip) + } + } + } finally { + Files.deleteIfExists(tempJar) + } + } + + private companion object { + private const val TEMP_PREFIX = "tmp" + private const val JAR_SUFFIX = ".jar" + } +} diff --git a/asm/src/main/java/dev/openrs2/asm/io/SignedJarLibraryWriter.kt b/asm/src/main/java/dev/openrs2/asm/io/SignedJarLibraryWriter.kt new file mode 100644 index 00000000..74beea12 --- /dev/null +++ b/asm/src/main/java/dev/openrs2/asm/io/SignedJarLibraryWriter.kt @@ -0,0 +1,54 @@ +package dev.openrs2.asm.io + +import dev.openrs2.asm.classpath.ClassPath +import dev.openrs2.asm.classpath.Library +import dev.openrs2.crypto.Pkcs12KeyStore +import dev.openrs2.util.io.DeterministicJarOutputStream +import java.io.OutputStream +import java.nio.file.Files +import java.nio.file.Path +import java.util.jar.JarInputStream +import java.util.jar.Manifest + +class SignedJarLibraryWriter( + private val output: OutputStream, + private val manifest: Manifest, + private val keyStore: Pkcs12KeyStore +) : LibraryWriter { + + override fun write(classPath: ClassPath, library: Library) { + val unsignedJar = Files.createTempFile(TEMP_PREFIX, JAR_SUFFIX) + + try { + DeterministicJarOutputStream(Files.newOutputStream(unsignedJar), manifest).use { unsignedOutput -> + JarLibraryWriter(unsignedOutput).write(classPath, library) + } + + val signedJar = Files.createTempFile(TEMP_PREFIX, JAR_SUFFIX) + try { + keyStore.signJar(unsignedJar, signedJar) + repack(signedJar) + } finally { + Files.deleteIfExists(signedJar) + } + } finally { + Files.deleteIfExists(unsignedJar) + } + } + + private fun repack(signedJar: Path) { + JarInputStream(Files.newInputStream(signedJar)).use { input -> + DeterministicJarOutputStream(output, input.manifest).use { output -> + generateSequence { input.nextJarEntry }.forEach { + output.putNextEntry(it) + input.copyTo(output) + } + } + } + } + + private companion object { + private const val TEMP_PREFIX = "tmp" + private const val JAR_SUFFIX = ".jar" + } +} diff --git a/bundler/src/main/java/dev/openrs2/bundler/Bundler.kt b/bundler/src/main/java/dev/openrs2/bundler/Bundler.kt index 7a664f15..1dcf8b95 100644 --- a/bundler/src/main/java/dev/openrs2/bundler/Bundler.kt +++ b/bundler/src/main/java/dev/openrs2/bundler/Bundler.kt @@ -3,6 +3,8 @@ package dev.openrs2.bundler import com.github.michaelbull.logging.InlineLogger import dev.openrs2.asm.classpath.ClassPath import dev.openrs2.asm.classpath.Library +import dev.openrs2.asm.io.JarLibraryWriter +import dev.openrs2.asm.io.SignedJarLibraryWriter import dev.openrs2.bundler.transform.BufferSizeTransformer import dev.openrs2.bundler.transform.CachePathTransformer import dev.openrs2.bundler.transform.HostCheckTransformer @@ -14,6 +16,8 @@ import dev.openrs2.bundler.transform.ResourceTransformer import dev.openrs2.bundler.transform.RightClickTransformer import dev.openrs2.bundler.transform.TypoTransformer import dev.openrs2.crypto.Pkcs12KeyStore +import dev.openrs2.util.io.DeterministicJarOutputStream +import java.nio.file.Files import java.nio.file.Path import java.util.jar.Attributes import java.util.jar.Attributes.Name.MANIFEST_VERSION @@ -109,11 +113,27 @@ class Bundler @Inject constructor(publicKeyTransformer: PublicKeyTransformer) { } // write unsigned client and loaders - client.writeJar(classPath, output.resolve("runescape.jar"), unsignedManifest) + writeJar(classPath, client, output.resolve("runescape.jar")) val keyStore = Pkcs12KeyStore.open(keyStorePath) - loader.writeSignedJar(classPath, output.resolve("loader.jar"), keyStore, signedManifest) - glLoader.writeSignedJar(glClassPath, output.resolve("loader_gl.jar"), keyStore, signedManifest) + writeSignedJar(classPath, loader, output.resolve("loader.jar"), keyStore) + writeSignedJar(glClassPath, glLoader, output.resolve("loader_gl.jar"), keyStore) + } + + private fun writeJar(classPath: ClassPath, library: Library, path: Path) { + logger.info { "Writing jar $path" } + + DeterministicJarOutputStream(Files.newOutputStream(path), unsignedManifest).use { output -> + JarLibraryWriter(output).write(classPath, library) + } + } + + private fun writeSignedJar(classPath: ClassPath, library: Library, path: Path, keyStore: Pkcs12KeyStore) { + logger.info { "Writing signed jar $path" } + + Files.newOutputStream(path).use { + SignedJarLibraryWriter(it, signedManifest, keyStore).write(classPath, library) + } } 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 4ed7e5d6..d49a3b94 100644 --- a/bundler/src/main/java/dev/openrs2/bundler/Resource.kt +++ b/bundler/src/main/java/dev/openrs2/bundler/Resource.kt @@ -3,6 +3,10 @@ package dev.openrs2.bundler import com.github.michaelbull.logging.InlineLogger import dev.openrs2.asm.classpath.ClassPath import dev.openrs2.asm.classpath.Library +import dev.openrs2.asm.io.JarLibraryWriter +import dev.openrs2.asm.io.Js5LibraryWriter +import dev.openrs2.asm.io.Pack200LibraryWriter +import dev.openrs2.util.io.DeterministicJarOutputStream import java.io.ByteArrayOutputStream import java.nio.file.Files import java.nio.file.Path @@ -66,23 +70,26 @@ class Resource( } fun compressJar(source: String, destination: String, classPath: ClassPath, library: Library): Resource { - ByteArrayOutputStream().use { out -> - library.writeJar(classPath, out) - return compress(source, destination, out.toByteArray()) + ByteArrayOutputStream().use { output -> + DeterministicJarOutputStream(output).use { jarOutput -> + JarLibraryWriter(jarOutput).write(classPath, library) + } + + return compress(source, destination, output.toByteArray()) } } fun compressPack(source: String, destination: String, classPath: ClassPath, library: Library): Resource { - ByteArrayOutputStream().use { out -> - library.writePack(classPath, out) - return compress(source, destination, out.toByteArray()) + ByteArrayOutputStream().use { output -> + Pack200LibraryWriter(output).write(classPath, library) + return compress(source, destination, output.toByteArray()) } } fun compressJs5(source: String, destination: String, classPath: ClassPath, library: Library): Resource { - ByteArrayOutputStream().use { out -> - library.writeJs5(classPath, out) - return compress(source, destination, out.toByteArray()) + ByteArrayOutputStream().use { output -> + Js5LibraryWriter(output).write(classPath, library) + return compress(source, destination, output.toByteArray()) } } diff --git a/deob/src/main/java/dev/openrs2/deob/Deobfuscator.kt b/deob/src/main/java/dev/openrs2/deob/Deobfuscator.kt index 338793bd..97e44e67 100644 --- a/deob/src/main/java/dev/openrs2/deob/Deobfuscator.kt +++ b/deob/src/main/java/dev/openrs2/deob/Deobfuscator.kt @@ -5,6 +5,7 @@ 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.asm.io.JarLibraryWriter import dev.openrs2.bundler.Bundler import dev.openrs2.bundler.transform.ResourceTransformer import dev.openrs2.deob.SignedClassUtils.move @@ -36,6 +37,7 @@ import dev.openrs2.deob.transform.UnusedArgTransformer import dev.openrs2.deob.transform.UnusedLocalTransformer import dev.openrs2.deob.transform.UnusedMethodTransformer import dev.openrs2.deob.transform.VisibilityTransformer +import dev.openrs2.util.io.DeterministicJarOutputStream import java.nio.file.Files import java.nio.file.Path @@ -124,20 +126,28 @@ class Deobfuscator(private val input: Path, private val output: Path) { Files.createDirectories(output) - 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")) - unpackClass.writeJar(classPath, output.resolve("unpackclass.jar")) + writeJar(classPath, client, output.resolve("runescape.jar")) + writeJar(classPath, loader, output.resolve("loader.jar")) + writeJar(classPath, signLink, output.resolve("signlink.jar")) + writeJar(classPath, unpack, output.resolve("unpack.jar")) + writeJar(classPath, unpackClass, output.resolve("unpackclass.jar")) - gl.writeJar(glClassPath, output.resolve("jaggl.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")) - glUnpackClass.writeJar(glClassPath, output.resolve("unpackclass_gl.jar")) + writeJar(glClassPath, gl, output.resolve("jaggl.jar")) + writeJar(glClassPath, glClient, output.resolve("runescape_gl.jar")) + writeJar(glClassPath, glLoader, output.resolve("loader_gl.jar")) + writeJar(glClassPath, glSignLink, output.resolve("signlink_gl.jar")) + writeJar(glClassPath, glUnpack, output.resolve("unpack_gl.jar")) + writeJar(glClassPath, glUnpackClass, output.resolve("unpackclass_gl.jar")) - unsignedClient.writeJar(unsignedClassPath, output.resolve("runescape_unsigned.jar")) + writeJar(unsignedClassPath, unsignedClient, output.resolve("runescape_unsigned.jar")) + } + + private fun writeJar(classPath: ClassPath, library: Library, path: Path) { + logger.info { "Writing jar $path" } + + DeterministicJarOutputStream(Files.newOutputStream(path)).use { output -> + JarLibraryWriter(output).write(classPath, library) + } } companion object { diff --git a/util/src/main/java/dev/openrs2/util/io/DeterministicJarOutputStream.kt b/util/src/main/java/dev/openrs2/util/io/DeterministicJarOutputStream.kt index 29b658f2..f128a67d 100644 --- a/util/src/main/java/dev/openrs2/util/io/DeterministicJarOutputStream.kt +++ b/util/src/main/java/dev/openrs2/util/io/DeterministicJarOutputStream.kt @@ -1,17 +1,15 @@ package dev.openrs2.util.io import java.io.OutputStream -import java.nio.file.Files -import java.nio.file.Path import java.nio.file.attribute.FileTime -import java.util.jar.JarInputStream import java.util.jar.JarOutputStream import java.util.jar.Manifest import java.util.zip.ZipEntry class DeterministicJarOutputStream : JarOutputStream { - private constructor(out: OutputStream) : super(out) - private constructor(out: OutputStream, man: Manifest) : super(out, man) + + constructor(out: OutputStream) : super(out) + constructor(out: OutputStream, man: Manifest) : super(out, man) override fun putNextEntry(ze: ZipEntry) { ze.creationTime = UNIX_EPOCH @@ -22,25 +20,5 @@ class DeterministicJarOutputStream : JarOutputStream { companion object { private val UNIX_EPOCH = FileTime.fromMillis(0) - - fun create(out: OutputStream, manifest: Manifest? = null): JarOutputStream { - return if (manifest != null) { - DeterministicJarOutputStream(out, manifest) - } else { - DeterministicJarOutputStream(out) - } - } - - fun repack(src: Path, dest: Path) { - JarInputStream(Files.newInputStream(src)).use { input -> - create(Files.newOutputStream(dest), input.manifest).use { output -> - while (true) { - val entry = input.nextJarEntry ?: break - output.putNextEntry(entry) - input.copyTo(output) - } - } - } - } } } -- 2.30.2 From 9b42b1ff81fdb1600e1e46c6179438fc01689ca9 Mon Sep 17 00:00:00 2001 From: Scu11 Date: Tue, 14 Apr 2020 15:27:21 +0100 Subject: [PATCH 2/3] Move Library#read methods to dedicated classes Signed-off-by: Scu11 --- .../java/dev/openrs2/asm/classpath/Library.kt | 55 ------------------- .../dev/openrs2/asm/io/JarLibraryReader.kt | 33 +++++++++++ .../java/dev/openrs2/asm/io/LibraryReader.kt | 7 +++ .../openrs2/asm/io/Pack200LibraryReader.kt | 35 ++++++++++++ .../main/java/dev/openrs2/bundler/Bundler.kt | 31 +++++++++-- .../java/dev/openrs2/deob/Deobfuscator.kt | 21 ++++++- 6 files changed, 119 insertions(+), 63 deletions(-) create mode 100644 asm/src/main/java/dev/openrs2/asm/io/JarLibraryReader.kt create mode 100644 asm/src/main/java/dev/openrs2/asm/io/LibraryReader.kt create mode 100644 asm/src/main/java/dev/openrs2/asm/io/Pack200LibraryReader.kt 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 03a9bc64..2fb5d281 100644 --- a/asm/src/main/java/dev/openrs2/asm/classpath/Library.kt +++ b/asm/src/main/java/dev/openrs2/asm/classpath/Library.kt @@ -1,17 +1,9 @@ package dev.openrs2.asm.classpath -import com.github.michaelbull.logging.InlineLogger import dev.openrs2.asm.remap -import dev.openrs2.compress.gzip.Gzip -import org.objectweb.asm.ClassReader import org.objectweb.asm.commons.Remapper import org.objectweb.asm.tree.ClassNode -import java.nio.file.Files -import java.nio.file.Path import java.util.TreeMap -import java.util.jar.JarInputStream -import java.util.jar.JarOutputStream -import java.util.jar.Pack200 class Library() : Iterable { private var classes = TreeMap() @@ -51,51 +43,4 @@ class Library() : Iterable { classes = classes.mapKeysTo(TreeMap()) { (_, clazz) -> clazz.name } } - - companion object { - private val logger = InlineLogger() - private const val CLASS_SUFFIX = ".class" - private const val TEMP_PREFIX = "tmp" - private const val JAR_SUFFIX = ".jar" - - fun readJar(path: Path): Library { - logger.info { "Reading jar $path" } - - val library = Library() - - JarInputStream(Files.newInputStream(path)).use { `in` -> - while (true) { - val entry = `in`.nextJarEntry ?: break - if (!entry.name.endsWith(CLASS_SUFFIX)) { - continue - } - - val clazz = ClassNode() - val reader = ClassReader(`in`) - reader.accept(JsrInliner(clazz), ClassReader.SKIP_DEBUG or ClassReader.SKIP_FRAMES) - - library.add(clazz) - } - } - - return library - } - - fun readPack(path: Path): Library { - logger.info { "Reading pack $path" } - - val temp = Files.createTempFile(TEMP_PREFIX, JAR_SUFFIX) - try { - Gzip.createHeaderlessInputStream(Files.newInputStream(path)).use { `in` -> - JarOutputStream(Files.newOutputStream(temp)).use { out -> - Pack200.newUnpacker().unpack(`in`, out) - } - } - - return readJar(temp) - } finally { - Files.deleteIfExists(temp) - } - } - } } diff --git a/asm/src/main/java/dev/openrs2/asm/io/JarLibraryReader.kt b/asm/src/main/java/dev/openrs2/asm/io/JarLibraryReader.kt new file mode 100644 index 00000000..a9754db4 --- /dev/null +++ b/asm/src/main/java/dev/openrs2/asm/io/JarLibraryReader.kt @@ -0,0 +1,33 @@ +package dev.openrs2.asm.io + +import dev.openrs2.asm.classpath.JsrInliner +import dev.openrs2.asm.classpath.Library +import org.objectweb.asm.ClassReader +import org.objectweb.asm.tree.ClassNode +import java.util.jar.JarInputStream + +class JarLibraryReader(private val input: JarInputStream) : LibraryReader { + + override fun read(): Library { + val library = Library() + + while (true) { + val entry = input.nextJarEntry ?: break + if (!entry.name.endsWith(CLASS_SUFFIX)) { + continue + } + + val clazz = ClassNode() + val reader = ClassReader(input) + reader.accept(JsrInliner(clazz), ClassReader.SKIP_DEBUG or ClassReader.SKIP_FRAMES) + + library.add(clazz) + } + + return library + } + + private companion object { + private const val CLASS_SUFFIX = ".class" + } +} diff --git a/asm/src/main/java/dev/openrs2/asm/io/LibraryReader.kt b/asm/src/main/java/dev/openrs2/asm/io/LibraryReader.kt new file mode 100644 index 00000000..05b9638b --- /dev/null +++ b/asm/src/main/java/dev/openrs2/asm/io/LibraryReader.kt @@ -0,0 +1,7 @@ +package dev.openrs2.asm.io + +import dev.openrs2.asm.classpath.Library + +interface LibraryReader { + fun read(): Library +} diff --git a/asm/src/main/java/dev/openrs2/asm/io/Pack200LibraryReader.kt b/asm/src/main/java/dev/openrs2/asm/io/Pack200LibraryReader.kt new file mode 100644 index 00000000..0919640e --- /dev/null +++ b/asm/src/main/java/dev/openrs2/asm/io/Pack200LibraryReader.kt @@ -0,0 +1,35 @@ +package dev.openrs2.asm.io + +import dev.openrs2.asm.classpath.Library +import dev.openrs2.compress.gzip.Gzip +import java.io.InputStream +import java.nio.file.Files +import java.util.jar.JarInputStream +import java.util.jar.JarOutputStream +import java.util.jar.Pack200 + +class Pack200LibraryReader(private val input: InputStream) : LibraryReader { + + override fun read(): Library { + val temp = Files.createTempFile(TEMP_PREFIX, JAR_SUFFIX) + + try { + Gzip.createHeaderlessInputStream(input).use { gzipInput -> + JarOutputStream(Files.newOutputStream(temp)).use { output -> + Pack200.newUnpacker().unpack(gzipInput, output) + } + } + + return JarInputStream(Files.newInputStream(temp)).use { tempInput -> + JarLibraryReader(tempInput).read() + } + } finally { + Files.deleteIfExists(temp) + } + } + + private companion object { + private const val TEMP_PREFIX = "tmp" + private const val JAR_SUFFIX = ".jar" + } +} diff --git a/bundler/src/main/java/dev/openrs2/bundler/Bundler.kt b/bundler/src/main/java/dev/openrs2/bundler/Bundler.kt index 1dcf8b95..264277b3 100644 --- a/bundler/src/main/java/dev/openrs2/bundler/Bundler.kt +++ b/bundler/src/main/java/dev/openrs2/bundler/Bundler.kt @@ -3,7 +3,9 @@ package dev.openrs2.bundler import com.github.michaelbull.logging.InlineLogger import dev.openrs2.asm.classpath.ClassPath import dev.openrs2.asm.classpath.Library +import dev.openrs2.asm.io.JarLibraryReader import dev.openrs2.asm.io.JarLibraryWriter +import dev.openrs2.asm.io.Pack200LibraryReader import dev.openrs2.asm.io.SignedJarLibraryWriter import dev.openrs2.bundler.transform.BufferSizeTransformer import dev.openrs2.bundler.transform.CachePathTransformer @@ -21,6 +23,7 @@ import java.nio.file.Files import java.nio.file.Path import java.util.jar.Attributes import java.util.jar.Attributes.Name.MANIFEST_VERSION +import java.util.jar.JarInputStream import java.util.jar.Manifest import javax.inject.Inject import javax.inject.Singleton @@ -32,12 +35,12 @@ class Bundler @Inject constructor(publicKeyTransformer: PublicKeyTransformer) { fun run(input: Path, output: Path, keyStorePath: Path) { // read input jars/packs logger.info { "Reading input jars" } - val unpacker = Library.readJar(input.resolve("unpackclass.pack")) - val loader = Library.readJar(input.resolve("loader.jar")) - val glLoader = Library.readJar(input.resolve("loader_gl.jar")) - val gl = Library.readPack(input.resolve("jaggl.pack200")) - val client = Library.readJar(input.resolve("runescape.jar")) - val glClient = Library.readPack(input.resolve("runescape_gl.pack200")) + val unpacker = readJar(input.resolve("unpackclass.pack")) + 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")) // bundle libraries together into a common classpath val runtime = ClassLoader.getPlatformClassLoader() @@ -120,6 +123,22 @@ class Bundler @Inject constructor(publicKeyTransformer: PublicKeyTransformer) { writeSignedJar(glClassPath, glLoader, output.resolve("loader_gl.jar"), keyStore) } + private fun readJar(path: Path): Library { + logger.info { "Reading jar $path" } + + return JarInputStream(Files.newInputStream(path)).use { input -> + JarLibraryReader(input).read() + } + } + + private fun readPack(path: Path): Library { + logger.info { "Reading pack $path" } + + return Files.newInputStream(path).use { input -> + Pack200LibraryReader(input).read() + } + } + private fun writeJar(classPath: ClassPath, library: Library, path: Path) { logger.info { "Writing jar $path" } diff --git a/deob/src/main/java/dev/openrs2/deob/Deobfuscator.kt b/deob/src/main/java/dev/openrs2/deob/Deobfuscator.kt index 97e44e67..c380c4e3 100644 --- a/deob/src/main/java/dev/openrs2/deob/Deobfuscator.kt +++ b/deob/src/main/java/dev/openrs2/deob/Deobfuscator.kt @@ -3,9 +3,9 @@ package dev.openrs2.deob import com.github.michaelbull.logging.InlineLogger 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.asm.io.JarLibraryReader import dev.openrs2.asm.io.JarLibraryWriter +import dev.openrs2.asm.io.Pack200LibraryReader import dev.openrs2.bundler.Bundler import dev.openrs2.bundler.transform.ResourceTransformer import dev.openrs2.deob.SignedClassUtils.move @@ -40,6 +40,7 @@ import dev.openrs2.deob.transform.VisibilityTransformer import dev.openrs2.util.io.DeterministicJarOutputStream import java.nio.file.Files import java.nio.file.Path +import java.util.jar.JarInputStream class Deobfuscator(private val input: Path, private val output: Path) { fun run() { @@ -142,6 +143,22 @@ class Deobfuscator(private val input: Path, private val output: Path) { writeJar(unsignedClassPath, unsignedClient, output.resolve("runescape_unsigned.jar")) } + private fun readJar(path: Path): Library { + logger.info { "Reading jar $path" } + + return JarInputStream(Files.newInputStream(path)).use { input -> + JarLibraryReader(input).read() + } + } + + private fun readPack(path: Path): Library { + logger.info { "Reading pack $path" } + + return Files.newInputStream(path).use { input -> + Pack200LibraryReader(input).read() + } + } + private fun writeJar(classPath: ClassPath, library: Library, path: Path) { logger.info { "Writing jar $path" } -- 2.30.2 From fabd5ff22a2148cb78482a48622d938e76abdef0 Mon Sep 17 00:00:00 2001 From: Scu11 Date: Tue, 14 Apr 2020 15:40:54 +0100 Subject: [PATCH 3/3] Reduce mutability in JarLibraryReader Signed-off-by: Scu11 --- .../java/dev/openrs2/asm/classpath/Library.kt | 5 ++-- .../dev/openrs2/asm/io/JarLibraryReader.kt | 28 ++++++++++--------- 2 files changed, 18 insertions(+), 15 deletions(-) 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 2fb5d281..9aee6005 100644 --- a/asm/src/main/java/dev/openrs2/asm/classpath/Library.kt +++ b/asm/src/main/java/dev/openrs2/asm/classpath/Library.kt @@ -5,8 +5,9 @@ import org.objectweb.asm.commons.Remapper import org.objectweb.asm.tree.ClassNode import java.util.TreeMap -class Library() : Iterable { - private var classes = TreeMap() +class Library(classes: Map = emptyMap()) : Iterable { + + private var classes = TreeMap(classes) constructor(library: Library) : this() { for (clazz in library.classes.values) { diff --git a/asm/src/main/java/dev/openrs2/asm/io/JarLibraryReader.kt b/asm/src/main/java/dev/openrs2/asm/io/JarLibraryReader.kt index a9754db4..65b8d71a 100644 --- a/asm/src/main/java/dev/openrs2/asm/io/JarLibraryReader.kt +++ b/asm/src/main/java/dev/openrs2/asm/io/JarLibraryReader.kt @@ -4,27 +4,29 @@ import dev.openrs2.asm.classpath.JsrInliner import dev.openrs2.asm.classpath.Library import org.objectweb.asm.ClassReader import org.objectweb.asm.tree.ClassNode +import java.util.jar.JarEntry import java.util.jar.JarInputStream class JarLibraryReader(private val input: JarInputStream) : LibraryReader { override fun read(): Library { - val library = Library() + val classes = generateSequence { input.nextJarEntry } + .filter(::isClass) + .map { input.readClass() } + .associateBy(ClassNode::name) - while (true) { - val entry = input.nextJarEntry ?: break - if (!entry.name.endsWith(CLASS_SUFFIX)) { - continue - } - - val clazz = ClassNode() - val reader = ClassReader(input) - reader.accept(JsrInliner(clazz), ClassReader.SKIP_DEBUG or ClassReader.SKIP_FRAMES) + return Library(classes) + } - library.add(clazz) - } + private fun isClass(entry: JarEntry): Boolean { + return entry.name.endsWith(CLASS_SUFFIX) + } - return library + private fun JarInputStream.readClass(): ClassNode { + val clazz = ClassNode() + val reader = ClassReader(this) + reader.accept(JsrInliner(clazz), ClassReader.SKIP_DEBUG or ClassReader.SKIP_FRAMES) + return clazz } private companion object { -- 2.30.2