From 5d6626609dcdac36ce530f7627f614f3c2d6de34 Mon Sep 17 00:00:00 2001 From: ZeroZipp Date: Sat, 4 Apr 2026 21:04:10 +0200 Subject: [PATCH] update --- .idea/markdown.xml | 8 ++++ src/main/kotlin/dev/zerozipp/loader/Agent.kt | 20 +-------- src/main/kotlin/dev/zerozipp/loader/Knot.kt | 43 ++++++++++++++++++++ 3 files changed, 52 insertions(+), 19 deletions(-) create mode 100644 .idea/markdown.xml create mode 100644 src/main/kotlin/dev/zerozipp/loader/Knot.kt diff --git a/.idea/markdown.xml b/.idea/markdown.xml new file mode 100644 index 0000000..c61ea33 --- /dev/null +++ b/.idea/markdown.xml @@ -0,0 +1,8 @@ + + + + + + \ No newline at end of file diff --git a/src/main/kotlin/dev/zerozipp/loader/Agent.kt b/src/main/kotlin/dev/zerozipp/loader/Agent.kt index e0b8e11..6a27b56 100644 --- a/src/main/kotlin/dev/zerozipp/loader/Agent.kt +++ b/src/main/kotlin/dev/zerozipp/loader/Agent.kt @@ -10,11 +10,9 @@ import net.bytebuddy.description.method.* import net.bytebuddy.asm.Advice import java.lang.instrument.* import java.util.jar.JarFile -import java.nio.file.Path import java.io.File @Suppress("unused") object Agent { - private const val KNOT = "net.fabricmc.loader.impl.launch.knot" @JvmStatic fun premain(args: String?, inst: Instrumentation?) = attach(inst!!) @JvmStatic fun agentmain(args: String?, inst: Instrumentation?) = attach(inst!!) val injections = listOf(Tick::class, Render::class, Gui::class) @@ -32,27 +30,11 @@ import java.io.File } } - private fun getKnotDelegate(): Any? { - val base = Class.forName("$KNOT.KnotClassLoader") - val delegate = base.getDeclaredField("delegate") - val threads = Thread.getAllStackTraces().keys - val loaders = threads.mapNotNull { it.contextClassLoader } - val knot = loaders.firstOrNull { it.javaClass == base } - return delegate.apply { isAccessible = true }.get(knot) - } - - private fun exposeToKnot(jar: Path) { - val delegate = getKnotDelegate() - val base = Class.forName("$KNOT.KnotClassDelegate") - val source = base.getMethod("addCodeSource", Path::class.java) - source.apply { isAccessible = true }.invoke(delegate, jar) - } - private fun attach(inst: Instrumentation) { val domain = Client::class.java.protectionDomain val location = File(domain.codeSource.location.toURI()) inst.appendToSystemClassLoaderSearch(JarFile(location)) - runCatching { exposeToKnot(location.toPath()) } + Knot(location.toPath()).register(inst) var builder: AgentBuilder = Default() builder = builder.disableClassFormatChanges() diff --git a/src/main/kotlin/dev/zerozipp/loader/Knot.kt b/src/main/kotlin/dev/zerozipp/loader/Knot.kt new file mode 100644 index 0000000..8a2f2ae --- /dev/null +++ b/src/main/kotlin/dev/zerozipp/loader/Knot.kt @@ -0,0 +1,43 @@ +package dev.zerozipp.loader + +import java.lang.instrument.* +import java.security.ProtectionDomain +import java.nio.file.Path + +class Knot(private val jar: Path) : ClassFileTransformer { + private val knot = "net.fabricmc.loader.impl.launch.knot" + private var registry = mutableSetOf() + override fun transform(classLoader: ClassLoader, className: String, + redefined: Class<*>, domain: ProtectionDomain, bytes: ByteArray + ): ByteArray? = null.also { load(classLoader) } + + fun register(inst: Instrumentation) { + val result = runCatching { expose(jar) } + if(result.isSuccess) return + inst.addTransformer(this) + registry.add(inst) + } + + private fun delegate() = run { + val base = Class.forName("$knot.KnotClassLoader") + val delegate = base.getDeclaredField("delegate") + val threads = Thread.getAllStackTraces().keys + val loaders = threads.mapNotNull { it.contextClassLoader } + val knot = loaders.firstOrNull { it.javaClass == base } + delegate.apply { isAccessible = true }.get(knot) + } + + private fun expose(jar: Path) = delegate().let { + val base = Class.forName("$knot.KnotClassDelegate") + val source = base.getMethod("addCodeSource", Path::class.java) + source.apply { isAccessible = true }.invoke(it, jar) + } + + private fun load(loader: ClassLoader) { + val knotLoader = "$knot.KnotClassLoader" + if(loader.javaClass.name != knotLoader) return + registry.forEach { it.removeTransformer(this) } + runCatching { expose(jar) } + registry.clear() + } +} \ No newline at end of file