update
This commit is contained in:
Generated
+8
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="MarkdownSettings">
|
||||||
|
<option name="previewPanelProviderInfo">
|
||||||
|
<ProviderInfo name="Compose (experimental)" className="com.intellij.markdown.compose.preview.ComposePanelProvider" />
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
@@ -10,11 +10,9 @@ import net.bytebuddy.description.method.*
|
|||||||
import net.bytebuddy.asm.Advice
|
import net.bytebuddy.asm.Advice
|
||||||
import java.lang.instrument.*
|
import java.lang.instrument.*
|
||||||
import java.util.jar.JarFile
|
import java.util.jar.JarFile
|
||||||
import java.nio.file.Path
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
@Suppress("unused") object Agent {
|
@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 premain(args: String?, inst: Instrumentation?) = attach(inst!!)
|
||||||
@JvmStatic fun agentmain(args: String?, inst: Instrumentation?) = attach(inst!!)
|
@JvmStatic fun agentmain(args: String?, inst: Instrumentation?) = attach(inst!!)
|
||||||
val injections = listOf(Tick::class, Render::class, Gui::class)
|
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) {
|
private fun attach(inst: Instrumentation) {
|
||||||
val domain = Client::class.java.protectionDomain
|
val domain = Client::class.java.protectionDomain
|
||||||
val location = File(domain.codeSource.location.toURI())
|
val location = File(domain.codeSource.location.toURI())
|
||||||
inst.appendToSystemClassLoaderSearch(JarFile(location))
|
inst.appendToSystemClassLoaderSearch(JarFile(location))
|
||||||
runCatching { exposeToKnot(location.toPath()) }
|
Knot(location.toPath()).register(inst)
|
||||||
|
|
||||||
var builder: AgentBuilder = Default()
|
var builder: AgentBuilder = Default()
|
||||||
builder = builder.disableClassFormatChanges()
|
builder = builder.disableClassFormatChanges()
|
||||||
|
|||||||
@@ -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<Instrumentation>()
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user