diff --git a/src/main/kotlin/app/revanced/patches/all/connectivity/wifi/spoof/patch/SpoofWifiPatch.kt b/src/main/kotlin/app/revanced/patches/all/connectivity/wifi/spoof/patch/SpoofWifiPatch.kt index 00b05c1ff..f6637c439 100644 --- a/src/main/kotlin/app/revanced/patches/all/connectivity/wifi/spoof/patch/SpoofWifiPatch.kt +++ b/src/main/kotlin/app/revanced/patches/all/connectivity/wifi/spoof/patch/SpoofWifiPatch.kt @@ -15,7 +15,7 @@ import java.util.* @Name("Spoof wifi connection") @Description("Spoofs an existing Wi-Fi connection.") @RequiresIntegrations -internal class SpoofWifiPatch : AbstractTransformInstructionsPatch() { +class SpoofWifiPatch : AbstractTransformInstructionsPatch() { private companion object { const val INTEGRATIONS_CLASS_DESCRIPTOR_PREFIX = "Lapp/revanced/all/connectivity/wifi/spoof/SpoofWifiPatch" diff --git a/src/main/kotlin/app/revanced/patches/all/screencapture/removerestriction/bytecode/patch/RemoveCaptureRestrictionPatch.kt b/src/main/kotlin/app/revanced/patches/all/screencapture/removerestriction/bytecode/patch/RemoveCaptureRestrictionPatch.kt index 7b49d360a..7e372798b 100644 --- a/src/main/kotlin/app/revanced/patches/all/screencapture/removerestriction/bytecode/patch/RemoveCaptureRestrictionPatch.kt +++ b/src/main/kotlin/app/revanced/patches/all/screencapture/removerestriction/bytecode/patch/RemoveCaptureRestrictionPatch.kt @@ -7,7 +7,10 @@ import app.revanced.patcher.patch.annotations.Patch import app.revanced.patcher.patch.annotations.RequiresIntegrations import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod import app.revanced.patches.all.screencapture.removerestriction.resource.patch.RemoveCaptureRestrictionResourcePatch -import app.revanced.util.patch.* +import app.revanced.util.patch.AbstractTransformInstructionsPatch +import app.revanced.util.patch.IMethodCall +import app.revanced.util.patch.Instruction35cInfo +import app.revanced.util.patch.filterMapInstruction35c import com.android.tools.smali.dexlib2.iface.ClassDef import com.android.tools.smali.dexlib2.iface.Method import com.android.tools.smali.dexlib2.iface.instruction.Instruction @@ -17,7 +20,7 @@ import com.android.tools.smali.dexlib2.iface.instruction.Instruction @Description("Removes the restriction of capturing audio from apps that normally wouldn't allow it.") @DependsOn([RemoveCaptureRestrictionResourcePatch::class]) @RequiresIntegrations -internal class RemoveCaptureRestrictionPatch : AbstractTransformInstructionsPatch() { +class RemoveCaptureRestrictionPatch : AbstractTransformInstructionsPatch() { // Information about method calls we want to replace enum class MethodCall( override val definedClassName: String, diff --git a/src/main/kotlin/app/revanced/patches/all/screenshot/removerestriction/patch/RemoveScreenshotRestrictionPatch.kt b/src/main/kotlin/app/revanced/patches/all/screenshot/removerestriction/patch/RemoveScreenshotRestrictionPatch.kt index 97bbb445a..05c49282b 100644 --- a/src/main/kotlin/app/revanced/patches/all/screenshot/removerestriction/patch/RemoveScreenshotRestrictionPatch.kt +++ b/src/main/kotlin/app/revanced/patches/all/screenshot/removerestriction/patch/RemoveScreenshotRestrictionPatch.kt @@ -5,17 +5,19 @@ import app.revanced.patcher.annotation.Name import app.revanced.patcher.patch.annotations.Patch import app.revanced.patcher.patch.annotations.RequiresIntegrations import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod -import app.revanced.util.patch.* +import app.revanced.util.patch.AbstractTransformInstructionsPatch +import app.revanced.util.patch.IMethodCall +import app.revanced.util.patch.Instruction35cInfo +import app.revanced.util.patch.filterMapInstruction35c import com.android.tools.smali.dexlib2.iface.ClassDef import com.android.tools.smali.dexlib2.iface.Method import com.android.tools.smali.dexlib2.iface.instruction.Instruction -import java.util.* @Patch(false) @Name("Remove screenshot restriction") @Description("Removes the restriction of taking screenshots in apps that normally wouldn't allow it.") @RequiresIntegrations -internal class RemoveScreenshotRestrictionPatch : AbstractTransformInstructionsPatch() { +class RemoveScreenshotRestrictionPatch : AbstractTransformInstructionsPatch() { private companion object { const val INTEGRATIONS_CLASS_DESCRIPTOR_PREFIX = diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/fingerprints/ConvertElementToFlatBufferFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/fingerprints/ConvertElementToFlatBufferFingerprint.kt deleted file mode 100644 index 584bb664b..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/fingerprints/ConvertElementToFlatBufferFingerprint.kt +++ /dev/null @@ -1,9 +0,0 @@ -package app.revanced.patches.youtube.layout.hide.general.fingerprints - -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import com.android.tools.smali.dexlib2.Opcode - -object ConvertElementToFlatBufferFingerprint : MethodFingerprint( - strings = listOf("Failed to convert Element to Flatbuffers: %s"), - opcodes = listOf(Opcode.IGET_OBJECT) // Patched at this opcodes index -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/fingerprints/ParseElementFromBufferFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/fingerprints/ParseElementFromBufferFingerprint.kt new file mode 100644 index 000000000..525346c57 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/fingerprints/ParseElementFromBufferFingerprint.kt @@ -0,0 +1,10 @@ +package app.revanced.patches.youtube.layout.hide.general.fingerprints + +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import com.android.tools.smali.dexlib2.Opcode + +object ParseElementFromBufferFingerprint : MethodFingerprint( + parameters = listOf("L","L","[B", "L","L"), + opcodes = listOf(Opcode.INVOKE_INTERFACE, Opcode.MOVE_RESULT_OBJECT), + strings = listOf("Failed to parse Element") +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/patch/HideLayoutComponentsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/patch/HideLayoutComponentsPatch.kt index 27877de6e..8ca4278b2 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/patch/HideLayoutComponentsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/patch/HideLayoutComponentsPatch.kt @@ -4,9 +4,9 @@ import app.revanced.extensions.exception import app.revanced.patcher.annotation.Description import app.revanced.patcher.annotation.Name import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.InstructionExtensions.addInstruction import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels import app.revanced.patcher.extensions.InstructionExtensions.getInstruction +import app.revanced.patcher.extensions.InstructionExtensions.getInstructions import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.annotations.DependsOn import app.revanced.patcher.patch.annotations.Patch @@ -15,10 +15,12 @@ import app.revanced.patches.shared.settings.preference.impl.StringResource import app.revanced.patches.shared.settings.preference.impl.SwitchPreference import app.revanced.patches.shared.settings.preference.impl.TextPreference import app.revanced.patches.youtube.layout.hide.general.annotations.HideLayoutComponentsCompatibility -import app.revanced.patches.youtube.layout.hide.general.fingerprints.ConvertElementToFlatBufferFingerprint +import app.revanced.patches.youtube.layout.hide.general.fingerprints.ParseElementFromBufferFingerprint import app.revanced.patches.youtube.misc.litho.filter.patch.LithoFilterPatch import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch.PreferenceScreen +import com.android.tools.smali.dexlib2.Opcode +import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction @Patch @Name("Hide layout components") @@ -26,7 +28,7 @@ import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch.P @DependsOn([LithoFilterPatch::class, SettingsPatch::class]) @HideLayoutComponentsCompatibility class HideLayoutComponentsPatch : BytecodePatch( - listOf(ConvertElementToFlatBufferFingerprint) + listOf(ParseElementFromBufferFingerprint) ) { override fun execute(context: BytecodeContext) { PreferenceScreen.LAYOUT.addPreferences( @@ -249,30 +251,26 @@ class HideLayoutComponentsPatch : BytecodePatch( // region Mix playlists - ConvertElementToFlatBufferFingerprint.result?.let { - val returnEmptyComponentIndex = it.scanResult.stringsScanResult!!.matches.first().index + 2 + ParseElementFromBufferFingerprint.result?.let { result -> + val returnEmptyComponentInstruction = result.mutableMethod.getInstructions() + .last { it.opcode == Opcode.INVOKE_STATIC } - it.mutableMethod.apply { - // The last virtual register (not parameter). Used to store the byte array - // that may contain information about a mix playlist. - val freeRegister = (implementation!!.registerCount - 1) - parameterTypes.size - 1 + result.mutableMethod.apply { + val consumeByteBufferIndex = result.scanResult.patternScanResult!!.startIndex + val byteBufferRegister = getInstruction(consumeByteBufferIndex).registerD - // Check if the byte array contains anything about a mix playlist. addInstructionsWithLabels( - it.scanResult.patternScanResult!!.startIndex, + result.scanResult.patternScanResult!!.startIndex, """ - invoke-static {v$freeRegister}, $FILTER_CLASS_DESCRIPTOR->filterMixPlaylists([B)Z - move-result v$freeRegister - if-nez v$freeRegister, :return_empty_component + invoke-static {v$byteBufferRegister}, $FILTER_CLASS_DESCRIPTOR->filterMixPlaylists([B)Z + move-result v0 # Conveniently same register happens to be free. + if-nez v0, :return_empty_component """, - ExternalLabel("return_empty_component", getInstruction(returnEmptyComponentIndex)) + ExternalLabel("return_empty_component", returnEmptyComponentInstruction) ) - - // Move the byte array to a free register. - addInstruction(0, "move-object/from16 v$freeRegister, p3") } - } ?: throw ConvertElementToFlatBufferFingerprint.exception + } ?: throw ParseElementFromBufferFingerprint.exception // endregion } diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/bytecode/fingerprints/CreateShortsButtonsFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/bytecode/fingerprints/CreateShortsButtonsFingerprint.kt index fd4b08508..4412d8796 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/bytecode/fingerprints/CreateShortsButtonsFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/bytecode/fingerprints/CreateShortsButtonsFingerprint.kt @@ -1,13 +1,13 @@ package app.revanced.patches.youtube.layout.hide.shorts.bytecode.fingerprints import app.revanced.patcher.extensions.or -import app.revanced.util.patch.LiteralValueFingerprint import app.revanced.patches.youtube.layout.hide.shorts.resource.patch.HideShortsComponentsResourcePatch +import app.revanced.util.patch.LiteralValueFingerprint import com.android.tools.smali.dexlib2.AccessFlags object CreateShortsButtonsFingerprint : LiteralValueFingerprint( accessFlags = AccessFlags.PRIVATE or AccessFlags.FINAL, returnType = "V", parameters = listOf("Z", "Z", "L"), - literal = HideShortsComponentsResourcePatch.reelPlayerRightLargeIconSize + literal = HideShortsComponentsResourcePatch.reelPlayerRightCellButtonHeight ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/resource/patch/HideShortsComponentsResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/resource/patch/HideShortsComponentsResourcePatch.kt index 5fe2678bb..bc8197055 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/resource/patch/HideShortsComponentsResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/resource/patch/HideShortsComponentsResourcePatch.kt @@ -91,11 +91,11 @@ class HideShortsComponentsResourcePatch : ResourcePatch { fun String.getId() = ResourceMappingPatch.resourceMappings.single { it.name == this }.id reelMultipleItemShelfId = "reel_multiple_items_shelf".getId() - reelPlayerRightLargeIconSize = "reel_player_right_large_icon_size".getId() + reelPlayerRightCellButtonHeight = "reel_player_right_cell_button_height".getId() } companion object { - var reelMultipleItemShelfId: Long = -1 - var reelPlayerRightLargeIconSize = -1L + var reelMultipleItemShelfId = -1L + var reelPlayerRightCellButtonHeight = -1L } } \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/TextComponentAtomicReferenceFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/TextComponentAtomicReferenceFingerprint.kt index 0879f52ca..069ec8bb6 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/TextComponentAtomicReferenceFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/TextComponentAtomicReferenceFingerprint.kt @@ -13,19 +13,17 @@ object TextComponentAtomicReferenceFingerprint : MethodFingerprint( accessFlags = AccessFlags.PROTECTED or AccessFlags.FINAL, parameters = listOf("L"), opcodes = listOf( - Opcode.MOVE_OBJECT_FROM16, // available unused register - Opcode.MOVE_OBJECT_FROM16, - null, // move-object/from16 or move/from16 - Opcode.MOVE_OBJECT_FROM16, - Opcode.INVOKE_VIRTUAL, // CharSequence atomic reference - Opcode.MOVE_RESULT_OBJECT, + Opcode.MOVE_OBJECT, // Register A and B is context, use B as context, reuse A as free register + Opcode.INVOKE_VIRTUAL, // Register C is atomic reference + Opcode.MOVE_RESULT_OBJECT, // Register A is char sequence + Opcode.MOVE_OBJECT, Opcode.CHECK_CAST, - Opcode.MOVE_OBJECT, // CharSequence reference, and control flow label. Insert code here. - null, // invoke-interface or invoke-virtual + Opcode.MOVE_OBJECT, + Opcode.INVOKE_INTERFACE, // Insert hook here Opcode.MOVE_RESULT, Opcode.IF_EQZ, - null, // invoke-interface or invoke-virtual + Opcode.INVOKE_INTERFACE, Opcode.MOVE_RESULT_OBJECT, - Opcode.GOTO, + Opcode.GOTO ) ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/patch/ReturnYouTubeDislikePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/patch/ReturnYouTubeDislikePatch.kt index 9214dd56c..34c22181f 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/patch/ReturnYouTubeDislikePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/patch/ReturnYouTubeDislikePatch.kt @@ -83,10 +83,8 @@ class ReturnYouTubeDislikePatch : BytecodePatch( // since the underlying (likes only) text did not change. // This hook handles all situations, as it's where the created Spans are stored and later reused. TextComponentContextFingerprint.also { - it.resolve( - context, - TextComponentConstructorFingerprint.result!!.classDef - ) + if (!it.resolve(context, TextComponentConstructorFingerprint.result!!.classDef)) + throw it.exception }.result?.also { result -> if (!TextComponentAtomicReferenceFingerprint.resolve(context, result.method, result.classDef)) throw TextComponentAtomicReferenceFingerprint.exception @@ -96,33 +94,46 @@ class ReturnYouTubeDislikePatch : BytecodePatch( val atomicReferenceStartIndex = TextComponentAtomicReferenceFingerprint.result!! .scanResult.patternScanResult!!.startIndex - val insertIndex = atomicReferenceStartIndex + 7 + val insertIndex = atomicReferenceStartIndex + 6 textComponentContextFingerprintResult.mutableMethod.apply { // Get the conversion context obfuscated field name, and the registers for the AtomicReference and CharSequence val conversionContextFieldReference = getInstruction(conversionContextIndex).reference - // any free register - val contextRegister = + // Reuse the free register to make room for the atomic reference register. + val freeRegister = getInstruction(atomicReferenceStartIndex).registerB val atomicReferenceRegister = - getInstruction(atomicReferenceStartIndex + 4).registerC + getInstruction(atomicReferenceStartIndex + 1).registerC - val moveCharSequenceInstruction = getInstruction(insertIndex) - val charSequenceRegister = moveCharSequenceInstruction.registerB + val moveCharSequenceInstruction = getInstruction(insertIndex - 1) + val charSequenceSourceRegister = moveCharSequenceInstruction.registerB + val charSequenceTargetRegister = moveCharSequenceInstruction.registerA - // Insert as first instructions at the control flow label. - // Must replace the existing instruction to preserve the label, and then insert the remaining instructions. - replaceInstruction(insertIndex, "move-object/from16 v$contextRegister, p0") + // In order to preserve the atomic reference register, because it is overwritten, + // use another free register to store it. + replaceInstruction( + atomicReferenceStartIndex + 2, + "move-result-object v$freeRegister" + ) + replaceInstruction( + atomicReferenceStartIndex + 3, + "move-object v$charSequenceSourceRegister, v$freeRegister" + ) + + // Move the current instance to the free register, and get the conversion context from it. + replaceInstruction(insertIndex - 1, "move-object/from16 v$freeRegister, p0") addInstructions( - insertIndex + 1, + insertIndex, """ - iget-object v$contextRegister, v$contextRegister, $conversionContextFieldReference # copy obfuscated context field into free register - invoke-static {v$contextRegister, v$atomicReferenceRegister, v$charSequenceRegister}, $INTEGRATIONS_CLASS_DESCRIPTOR->onLithoTextLoaded(Ljava/lang/Object;Ljava/util/concurrent/atomic/AtomicReference;Ljava/lang/CharSequence;)Ljava/lang/CharSequence; - move-result-object v$charSequenceRegister - move-object v${moveCharSequenceInstruction.registerA}, v${charSequenceRegister} # original instruction at the insertion point + # Move context to free register + iget-object v$freeRegister, v$freeRegister, $conversionContextFieldReference + invoke-static {v$freeRegister, v$atomicReferenceRegister, v$charSequenceSourceRegister}, $INTEGRATIONS_CLASS_DESCRIPTOR->onLithoTextLoaded(Ljava/lang/Object;Ljava/util/concurrent/atomic/AtomicReference;Ljava/lang/CharSequence;)Ljava/lang/CharSequence; + move-result-object v$freeRegister + # Replace the original char sequence with the modified one. + move-object v${charSequenceTargetRegister}, v${freeRegister} """ ) } diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/links/open/annotations/OpenLinksExternallyCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/links/annotations/OpenLinksExternallyCompatibility.kt similarity index 83% rename from src/main/kotlin/app/revanced/patches/youtube/misc/links/open/annotations/OpenLinksExternallyCompatibility.kt rename to src/main/kotlin/app/revanced/patches/youtube/misc/links/annotations/OpenLinksExternallyCompatibility.kt index 2a241e89d..c2e83c1c2 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/links/open/annotations/OpenLinksExternallyCompatibility.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/links/annotations/OpenLinksExternallyCompatibility.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.misc.links.open.annotations +package app.revanced.patches.youtube.misc.links.annotations import app.revanced.patcher.annotation.Compatibility import app.revanced.patcher.annotation.Package diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/links/open/fingerprints/BindSessionServiceFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/links/open/fingerprints/BindSessionServiceFingerprint.kt deleted file mode 100644 index 09f6e01c5..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/links/open/fingerprints/BindSessionServiceFingerprint.kt +++ /dev/null @@ -1,17 +0,0 @@ -package app.revanced.patches.youtube.misc.links.open.fingerprints - -import app.revanced.patcher.extensions.or -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import com.android.tools.smali.dexlib2.AccessFlags -import com.android.tools.smali.dexlib2.Opcode - -object BindSessionServiceFingerprint : MethodFingerprint( - returnType = "L", - accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, - opcodes = listOf( - Opcode.IPUT_OBJECT, - Opcode.NEW_INSTANCE, - Opcode.CONST_STRING - ), - strings = listOf("android.support.customtabs.action.CustomTabsService") -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/links/open/fingerprints/GetCustomTabPackageNameFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/links/open/fingerprints/GetCustomTabPackageNameFingerprint.kt deleted file mode 100644 index 8aaecfdca..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/links/open/fingerprints/GetCustomTabPackageNameFingerprint.kt +++ /dev/null @@ -1,18 +0,0 @@ -package app.revanced.patches.youtube.misc.links.open.fingerprints - -import app.revanced.patcher.extensions.or -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import com.android.tools.smali.dexlib2.AccessFlags -import com.android.tools.smali.dexlib2.Opcode - -object GetCustomTabPackageNameFingerprint : MethodFingerprint( - returnType = "L", - accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC, - opcodes = listOf( - Opcode.CHECK_CAST, - Opcode.NEW_INSTANCE, - Opcode.INVOKE_DIRECT, - Opcode.CONST_STRING - ), - strings = listOf("android.support.customtabs.action.CustomTabsService") -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/links/open/fingerprints/InitializeCustomTabSupportFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/links/open/fingerprints/InitializeCustomTabSupportFingerprint.kt deleted file mode 100644 index 314dc8e4d..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/links/open/fingerprints/InitializeCustomTabSupportFingerprint.kt +++ /dev/null @@ -1,18 +0,0 @@ -package app.revanced.patches.youtube.misc.links.open.fingerprints - -import app.revanced.patcher.extensions.or -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import com.android.tools.smali.dexlib2.AccessFlags -import com.android.tools.smali.dexlib2.Opcode - -object InitializeCustomTabSupportFingerprint : MethodFingerprint( - returnType = "V", - accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, - opcodes = listOf( - Opcode.CHECK_CAST, - Opcode.NEW_INSTANCE, - Opcode.INVOKE_DIRECT, - Opcode.CONST_STRING - ), - strings = listOf("android.support.customtabs.action.CustomTabsService") -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/links/open/patch/OpenLinksExternallyPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/links/open/patch/OpenLinksExternallyPatch.kt deleted file mode 100644 index ebcd823b3..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/links/open/patch/OpenLinksExternallyPatch.kt +++ /dev/null @@ -1,59 +0,0 @@ -package app.revanced.patches.youtube.misc.links.open.patch - -import app.revanced.extensions.exception -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.InstructionExtensions.addInstructions -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference -import app.revanced.patches.youtube.misc.links.open.annotations.OpenLinksExternallyCompatibility -import app.revanced.patches.youtube.misc.links.open.fingerprints.BindSessionServiceFingerprint -import app.revanced.patches.youtube.misc.links.open.fingerprints.GetCustomTabPackageNameFingerprint -import app.revanced.patches.youtube.misc.links.open.fingerprints.InitializeCustomTabSupportFingerprint -import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch -import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction21c - -@Patch -@Name("Open links externally") -@Description("Open links outside of the app directly in your browser.") -@OpenLinksExternallyCompatibility -class OpenLinksExternallyPatch : BytecodePatch( - listOf( - GetCustomTabPackageNameFingerprint, - BindSessionServiceFingerprint, - InitializeCustomTabSupportFingerprint - ) -) { - override fun execute(context: BytecodeContext) { - SettingsPatch.PreferenceScreen.MISC.addPreferences( - SwitchPreference( - "revanced_external_browser", - StringResource("revanced_external_browser_title", "Open links in browser"), - StringResource("revanced_external_browser_summary_on", "Opening links externally"), - StringResource("revanced_external_browser_summary_off", "Opening links in app") - ) - ) - - arrayOf( - GetCustomTabPackageNameFingerprint, - BindSessionServiceFingerprint, - InitializeCustomTabSupportFingerprint - ).forEach { - val result = it.result ?: throw it.exception - val insertIndex = result.scanResult.patternScanResult!!.endIndex + 1 - with(result.mutableMethod) { - val register = (implementation!!.instructions[insertIndex - 1] as Instruction21c).registerA - addInstructions( - insertIndex, - """ - invoke-static {v$register}, Lapp/revanced/integrations/patches/OpenLinksExternallyPatch;->enableExternalBrowser(Ljava/lang/String;)Ljava/lang/String; - move-result-object v$register - """ - ) - } - } - } -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/links/patch/OpenLinksExternallyPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/links/patch/OpenLinksExternallyPatch.kt new file mode 100644 index 000000000..347b5ba41 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/links/patch/OpenLinksExternallyPatch.kt @@ -0,0 +1,63 @@ +package app.revanced.patches.youtube.misc.links.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.InstructionExtensions.addInstructions +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod +import app.revanced.patches.shared.settings.preference.impl.StringResource +import app.revanced.patches.shared.settings.preference.impl.SwitchPreference +import app.revanced.patches.youtube.misc.links.annotations.OpenLinksExternallyCompatibility +import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch +import app.revanced.util.patch.AbstractTransformInstructionsPatch +import com.android.tools.smali.dexlib2.iface.ClassDef +import com.android.tools.smali.dexlib2.iface.Method +import com.android.tools.smali.dexlib2.iface.instruction.Instruction +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.StringReference + +@Patch +@Name("Open links externally") +@Description("Open links outside of the app directly in your browser.") +@OpenLinksExternallyCompatibility +class OpenLinksExternallyPatch : AbstractTransformInstructionsPatch>( +) { + override fun filterMap( + classDef: ClassDef, method: Method, instruction: Instruction, instructionIndex: Int + ): Pair? { + if (instruction !is ReferenceInstruction) return null + val reference = instruction.reference as? StringReference ?: return null + + if (reference.string != "android.support.customtabs.action.CustomTabsService") return null + + return instructionIndex to (instruction as OneRegisterInstruction).registerA + } + + override fun transform(mutableMethod: MutableMethod, entry: Pair) { + val (intentStringIndex, register) = entry + + // Hook the intent string. + mutableMethod.addInstructions( + intentStringIndex + 1, + """ + invoke-static {v$register}, Lapp/revanced/integrations/patches/OpenLinksExternallyPatch;->getIntent(Ljava/lang/String;)Ljava/lang/String; + move-result-object v$register + """ + ) + } + + override fun execute(context: BytecodeContext) { + SettingsPatch.PreferenceScreen.MISC.addPreferences( + SwitchPreference( + "revanced_external_browser", + StringResource("revanced_external_browser_title", "Open links in browser"), + StringResource("revanced_external_browser_summary_on", "Opening links externally"), + StringResource("revanced_external_browser_summary_off", "Opening links in app") + ) + ) + + super.execute(context) + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/util/patch/AbstractTransformInstructionsPatch.kt b/src/main/kotlin/app/revanced/util/patch/AbstractTransformInstructionsPatch.kt index bf2e58a43..54123cb3b 100644 --- a/src/main/kotlin/app/revanced/util/patch/AbstractTransformInstructionsPatch.kt +++ b/src/main/kotlin/app/revanced/util/patch/AbstractTransformInstructionsPatch.kt @@ -8,7 +8,7 @@ import com.android.tools.smali.dexlib2.iface.ClassDef import com.android.tools.smali.dexlib2.iface.Method import com.android.tools.smali.dexlib2.iface.instruction.Instruction -internal abstract class AbstractTransformInstructionsPatch : BytecodePatch() { +abstract class AbstractTransformInstructionsPatch : BytecodePatch() { abstract fun filterMap( classDef: ClassDef, diff --git a/src/main/kotlin/app/revanced/util/patch/MethodCall.kt b/src/main/kotlin/app/revanced/util/patch/MethodCall.kt index 6d3a3e069..48a38ad07 100644 --- a/src/main/kotlin/app/revanced/util/patch/MethodCall.kt +++ b/src/main/kotlin/app/revanced/util/patch/MethodCall.kt @@ -8,9 +8,9 @@ import com.android.tools.smali.dexlib2.iface.instruction.Instruction import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction35c import com.android.tools.smali.dexlib2.iface.reference.MethodReference -internal typealias Instruction35cInfo = Triple +typealias Instruction35cInfo = Triple -internal interface IMethodCall { +interface IMethodCall { val definedClassName: String val methodName: String val methodParams: Array @@ -62,14 +62,14 @@ internal interface IMethodCall { } } -internal inline fun fromMethodReference(methodReference: MethodReference) +inline fun fromMethodReference(methodReference: MethodReference) where E : Enum, E : IMethodCall = enumValues().firstOrNull { search -> search.definedClassName == methodReference.definingClass && search.methodName == methodReference.name && methodReference.parameterTypes.toTypedArray().contentEquals(search.methodParams) } -internal inline fun filterMapInstruction35c( +inline fun filterMapInstruction35c( integrationsClassDescriptorPrefix: String, classDef: ClassDef, instruction: Instruction,