diff --git a/src/main/kotlin/app/revanced/patches/discord/misc/plugin/PluginLoaderPatch.kt b/src/main/kotlin/app/revanced/patches/discord/misc/plugin/PluginLoaderPatch.kt new file mode 100644 index 0000000000..fe7c2d6ef7 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/discord/misc/plugin/PluginLoaderPatch.kt @@ -0,0 +1,13 @@ +package app.revanced.patches.discord.misc.plugin + +import app.revanced.patches.discord.misc.plugin.fingerprints.MainActivityOnCreateFingerprint +import app.revanced.patches.shared.misc.react.BaseReactPreloadScriptBootstrapperPatch + +@Suppress("unused") +object PluginLoaderPatch : BaseReactPreloadScriptBootstrapperPatch( + name = "Plugin loader", + description = "Bootstraps a plugin loader.", + mainActivityOnCreateFingerprintInsertIndexPair = MainActivityOnCreateFingerprint to 2, +) { + override val integrationsClassDescriptor = "Lapp/revanced/integrations/discord/plugin/BunnyBootstrapperPatch;" +} diff --git a/src/main/kotlin/app/revanced/patches/discord/misc/plugin/fingerprints/MainActivityOnCreateFingerprint.kt b/src/main/kotlin/app/revanced/patches/discord/misc/plugin/fingerprints/MainActivityOnCreateFingerprint.kt new file mode 100644 index 0000000000..14e9f6a7bc --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/discord/misc/plugin/fingerprints/MainActivityOnCreateFingerprint.kt @@ -0,0 +1,7 @@ +package app.revanced.patches.discord.misc.plugin.fingerprints + +import app.revanced.patcher.fingerprint.MethodFingerprint + +internal object MainActivityOnCreateFingerprint : MethodFingerprint( + customFingerprint = { method, classDef -> method.name == "onCreate" && classDef.endsWith("ReactActivity;") }, +) diff --git a/src/main/kotlin/app/revanced/patches/shared/misc/react/BaseReactPreloadScriptBootstrapperPatch.kt b/src/main/kotlin/app/revanced/patches/shared/misc/react/BaseReactPreloadScriptBootstrapperPatch.kt new file mode 100644 index 0000000000..44be527b33 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/shared/misc/react/BaseReactPreloadScriptBootstrapperPatch.kt @@ -0,0 +1,63 @@ +package app.revanced.patches.shared.misc.react + +import app.revanced.patcher.PatchClass +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.InstructionExtensions.addInstructions +import app.revanced.patcher.fingerprint.MethodFingerprint +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable +import app.revanced.patches.shared.misc.react.fingerprints.LoadScriptFromAssetFingerprint +import app.revanced.patches.shared.misc.react.fingerprints.LoadScriptFromFileFingerprint +import app.revanced.util.resultOrThrow + +abstract class BaseReactPreloadScriptBootstrapperPatch( + name: String? = null, + description: String? = null, + compatiblePackages: Set? = null, + dependencies: Set? = null, + use: Boolean = true, + fingerprints: Set = emptySet(), + private val mainActivityOnCreateFingerprintInsertIndexPair: Pair, +) : BytecodePatch( + name = name, + description = description, + compatiblePackages = compatiblePackages, + dependencies = dependencies, + use = use, + requiresIntegrations = true, + fingerprints = setOf( + LoadScriptFromAssetFingerprint, + LoadScriptFromFileFingerprint, + mainActivityOnCreateFingerprintInsertIndexPair.first, + ) + fingerprints, +) { + abstract val integrationsClassDescriptor: String + + override fun execute(context: BytecodeContext) { + val (mainActivityOnCreateFingerprint, insertIndex) = mainActivityOnCreateFingerprintInsertIndexPair + val loadScriptFromAssetMethod = LoadScriptFromAssetFingerprint.resultOrThrow().mutableMethod + val (catalystInstanceImplClassDef, loadScriptFromFileMethod) = LoadScriptFromFileFingerprint.resultOrThrow() + .let { it.mutableClass to it.mutableMethod } + + // Create preload script on main activity creation. + mainActivityOnCreateFingerprint.resultOrThrow().mutableMethod.addInstructions( + insertIndex, // Skip super call. + "invoke-static { p0 }, " + + "$integrationsClassDescriptor->startWritePreloadScripts(Landroid/app/Activity;)V", + ) + + // Copy of loadScriptFromFile method acts as a preload script loader. + loadScriptFromFileMethod.toMutable().apply { + name = "loadPreloadScriptFromFile" + }.let(catalystInstanceImplClassDef.methods::add) + + // Load preload script. + listOf(loadScriptFromFileMethod, loadScriptFromAssetMethod).forEach { loadScriptMethod -> + loadScriptMethod.addInstructions( + 0, + "invoke-virtual { p0 }, $integrationsClassDescriptor->" + + "hookLoadScriptFromFile($catalystInstanceImplClassDef)V", + ) + } + } +} diff --git a/src/main/kotlin/app/revanced/patches/shared/misc/react/fingerprints/CatalystInstanceImplFingerprint.kt b/src/main/kotlin/app/revanced/patches/shared/misc/react/fingerprints/CatalystInstanceImplFingerprint.kt new file mode 100644 index 0000000000..485d557dd5 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/shared/misc/react/fingerprints/CatalystInstanceImplFingerprint.kt @@ -0,0 +1,10 @@ +package app.revanced.patches.shared.misc.react.fingerprints + +import app.revanced.patcher.fingerprint.MethodFingerprint + +internal abstract class CatalystInstanceImplFingerprint(methodName: String) : + MethodFingerprint( + customFingerprint = { method, classDef -> + method.name == methodName && classDef.endsWith("CatalystInstanceImpl;") + }, + ) diff --git a/src/main/kotlin/app/revanced/patches/shared/misc/react/fingerprints/LoadScriptFromAssetFingerprint.kt b/src/main/kotlin/app/revanced/patches/shared/misc/react/fingerprints/LoadScriptFromAssetFingerprint.kt new file mode 100644 index 0000000000..f009b8b4ce --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/shared/misc/react/fingerprints/LoadScriptFromAssetFingerprint.kt @@ -0,0 +1,3 @@ +package app.revanced.patches.shared.misc.react.fingerprints + +internal object LoadScriptFromAssetFingerprint : CatalystInstanceImplFingerprint("loadScriptFromAsset") diff --git a/src/main/kotlin/app/revanced/patches/shared/misc/react/fingerprints/LoadScriptFromFileFingerprint.kt b/src/main/kotlin/app/revanced/patches/shared/misc/react/fingerprints/LoadScriptFromFileFingerprint.kt new file mode 100644 index 0000000000..dfd656cbd8 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/shared/misc/react/fingerprints/LoadScriptFromFileFingerprint.kt @@ -0,0 +1,3 @@ +package app.revanced.patches.shared.misc.react.fingerprints + +internal object LoadScriptFromFileFingerprint : CatalystInstanceImplFingerprint("loadScriptFromFile")