diff --git a/src/main/kotlin/app/revanced/patches/youtube/utils/navbarindex/NavBarIndexHookPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/utils/navbarindex/NavBarIndexHookPatch.kt index 52f7b64c2..0023c022c 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/utils/navbarindex/NavBarIndexHookPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/utils/navbarindex/NavBarIndexHookPatch.kt @@ -1,6 +1,7 @@ package app.revanced.patches.youtube.utils.navbarindex import app.revanced.extensions.exception +import app.revanced.extensions.findMutableMethodOf import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.InstructionExtensions.addInstruction import app.revanced.patcher.extensions.InstructionExtensions.addInstructions @@ -8,20 +9,25 @@ import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.fingerprint.MethodFingerprint import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.PatchException +import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod import app.revanced.patches.youtube.utils.fingerprints.OnBackPressedFingerprint +import app.revanced.patches.youtube.utils.navbarindex.fingerprints.DefaultTabsBarFingerprint import app.revanced.patches.youtube.utils.navbarindex.fingerprints.MobileTopBarButtonOnClickFingerprint -import app.revanced.patches.youtube.utils.navbarindex.fingerprints.NavButtonOnClickFingerprint import app.revanced.patches.youtube.utils.navbarindex.fingerprints.OnResumeFragmentsFingerprints import app.revanced.patches.youtube.utils.navbarindex.fingerprints.SettingsActivityOnBackPressedFingerprint import app.revanced.util.integrations.Constants.UTILS_PATH +import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction35c +import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction +import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction +import com.android.tools.smali.dexlib2.iface.reference.Reference @Suppress("unused") object NavBarIndexHookPatch : BytecodePatch( setOf( + DefaultTabsBarFingerprint, MobileTopBarButtonOnClickFingerprint, - NavButtonOnClickFingerprint, OnBackPressedFingerprint, OnResumeFragmentsFingerprints, SettingsActivityOnBackPressedFingerprint @@ -32,22 +38,23 @@ object NavBarIndexHookPatch : BytecodePatch( /** * Change NavBar Index value according to selected Tab */ - NavButtonOnClickFingerprint.result?.let { + DefaultTabsBarFingerprint.result?.let { it.mutableMethod.apply { - val insertIndex = it.scanResult.patternScanResult!!.endIndex - 1 - val targetString = - getInstruction(insertIndex - 2).reference.toString() - if (!targetString.endsWith("Ljava/util/ArrayList;->indexOf(Ljava/lang/Object;)I")) - throw PatchException("Reference not found: $targetString") - val indexRegister = - getInstruction(insertIndex - 1).registerA + val targetIndex = it.scanResult.patternScanResult!!.startIndex + val setTabIndexReference = getInstruction(targetIndex).reference - addInstruction( - insertIndex, - "invoke-static {v$indexRegister}, $INTEGRATIONS_CLASS_DESCRIPTOR->setCurrentNavBarIndex(I)V" - ) + val (onClickMethod, insertIndex) = getOnClickMethod(context, setTabIndexReference) + + onClickMethod.apply { + val indexRegister = getInstruction(insertIndex).registerD + + addInstruction( + insertIndex, + "invoke-static {v$indexRegister}, $INTEGRATIONS_CLASS_DESCRIPTOR->setCurrentNavBarIndex(I)V" + ) + } } - } ?: throw NavButtonOnClickFingerprint.exception + } ?: throw DefaultTabsBarFingerprint.exception /** * Set NavBar index to last index on back press @@ -79,6 +86,31 @@ object NavBarIndexHookPatch : BytecodePatch( private const val INTEGRATIONS_CLASS_DESCRIPTOR = "$UTILS_PATH/NavBarIndexPatch;" + private fun getOnClickMethod( + context: BytecodeContext, + targetReference: Reference + ): Pair { + context.classes.forEach { classDef -> + classDef.methods.forEach { method -> + if (method.name == "onClick") { + method.implementation?.instructions?.forEachIndexed { index, instruction -> + if (instruction.opcode != Opcode.INVOKE_VIRTUAL) + return@forEachIndexed + if ((instruction as ReferenceInstruction).reference != targetReference) + return@forEachIndexed + + val targetMethod = context.proxy(classDef) + .mutableClass + .findMutableMethodOf(method) + + return Pair(targetMethod, index) + } + } + } + } + throw PatchException("OnClickMethod not found!") + } + /** * Hook setLastNavBarIndex method * diff --git a/src/main/kotlin/app/revanced/patches/youtube/utils/navbarindex/fingerprints/DefaultTabsBarFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/utils/navbarindex/fingerprints/DefaultTabsBarFingerprint.kt new file mode 100644 index 000000000..419310202 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/utils/navbarindex/fingerprints/DefaultTabsBarFingerprint.kt @@ -0,0 +1,17 @@ +package app.revanced.patches.youtube.utils.navbarindex.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.MethodFingerprint +import com.android.tools.smali.dexlib2.AccessFlags +import com.android.tools.smali.dexlib2.Opcode + +object DefaultTabsBarFingerprint : MethodFingerprint( + returnType = "V", + accessFlags = AccessFlags.PROTECTED or AccessFlags.FINAL, + parameters = listOf("Landroid/view/View;"), + opcodes = listOf( + Opcode.INVOKE_VIRTUAL, + Opcode.IGET + ), + customFingerprint = { methodDef, _ -> methodDef.definingClass.endsWith("/DefaultTabsBar;") } +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/utils/navbarindex/fingerprints/NavButtonOnClickFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/utils/navbarindex/fingerprints/NavButtonOnClickFingerprint.kt deleted file mode 100644 index a65f29961..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/utils/navbarindex/fingerprints/NavButtonOnClickFingerprint.kt +++ /dev/null @@ -1,50 +0,0 @@ -package app.revanced.patches.youtube.utils.navbarindex.fingerprints - -import app.revanced.patcher.extensions.or -import app.revanced.patcher.fingerprint.MethodFingerprint -import com.android.tools.smali.dexlib2.AccessFlags -import com.android.tools.smali.dexlib2.Opcode -import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction - -object NavButtonOnClickFingerprint : MethodFingerprint( - returnType = "V", - accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, - parameters = listOf("Landroid/view/View;"), - opcodes = listOf( - Opcode.INVOKE_DIRECT, - Opcode.INVOKE_VIRTUAL, - Opcode.RETURN_VOID, - Opcode.IGET_OBJECT, - Opcode.CHECK_CAST, - Opcode.IGET_OBJECT, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT, - Opcode.INVOKE_VIRTUAL, // insert index - Opcode.RETURN_VOID - ), - customFingerprint = custom@{ methodDef, classDef -> - if (classDef.methods.count() != 3) - return@custom false - - if (methodDef.name != "onClick") - return@custom false - - val instructions = methodDef.implementation?.instructions!! - - if (instructions.count() < 20) - return@custom false - - var count = 0 - for (instruction in instructions) { - if (instruction.opcode != Opcode.INVOKE_VIRTUAL) - continue - - val invokeInstruction = instruction as ReferenceInstruction - if (invokeInstruction.reference.toString() != "Ljava/util/ArrayList;->indexOf(Ljava/lang/Object;)I") - continue - - count++ - } - count == 2 - } -) \ No newline at end of file