From 1598306eb58ae8f8dc38b472628b237e55ec0f1b Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Sat, 28 Jan 2023 06:24:24 +0100 Subject: [PATCH] fix(youtube): reliably resolve fingerprints Signed-off-by: oSumAtrIX --- .../PivotBarCreateButtonViewFingerprint.kt | 5 +- .../patch/CreateButtonRemoverPatch.kt | 24 ++++++--- .../EngagementPanelControllerFingerprint.kt | 29 ++--------- .../patch/PlayerPopupPanelsPatch.kt | 8 +-- .../InvokeMaxBufferFingerprint.kt | 12 +++++ .../fingerprints/MaxBufferFingerprint.kt | 13 +---- .../patch/CustomVideoBufferPatch.kt | 49 ++++++++++++++----- 7 files changed, 76 insertions(+), 64 deletions(-) create mode 100644 src/main/kotlin/app/revanced/patches/youtube/misc/videobuffer/fingerprints/InvokeMaxBufferFingerprint.kt diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/pivotbar/createbutton/fingerprints/PivotBarCreateButtonViewFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/pivotbar/createbutton/fingerprints/PivotBarCreateButtonViewFingerprint.kt index 8be27c38a..02cc2a8dd 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/pivotbar/createbutton/fingerprints/PivotBarCreateButtonViewFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/pivotbar/createbutton/fingerprints/PivotBarCreateButtonViewFingerprint.kt @@ -5,10 +5,7 @@ import org.jf.dexlib2.Opcode object PivotBarCreateButtonViewFingerprint : MethodFingerprint( opcodes = listOf( + Opcode.MOVE_OBJECT, Opcode.INVOKE_DIRECT_RANGE, // unique instruction anchor - Opcode.CONST_4, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_OBJECT, - Opcode.INVOKE_STATIC ) ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/pivotbar/createbutton/patch/CreateButtonRemoverPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/pivotbar/createbutton/patch/CreateButtonRemoverPatch.kt index f3b70d54a..4fc76ae4a 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/pivotbar/createbutton/patch/CreateButtonRemoverPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/pivotbar/createbutton/patch/CreateButtonRemoverPatch.kt @@ -22,6 +22,7 @@ import app.revanced.patches.youtube.layout.pivotbar.utils.InjectionUtils.REGISTE import app.revanced.patches.youtube.layout.pivotbar.utils.InjectionUtils.injectHook import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch +import org.jf.dexlib2.Opcode @Patch @DependsOn([IntegrationsPatch::class, ResourceMappingPatch::class, SettingsPatch::class, ResolvePivotBarFingerprintsPatch::class]) @@ -54,17 +55,24 @@ class CreateButtonRemoverPatch : BytecodePatch() { return PivotBarCreateButtonViewFingerprint.toErrorResult() } - val createButtonResult = PivotBarCreateButtonViewFingerprint.result!! - val insertIndex = createButtonResult.scanResult.patternScanResult!!.endIndex + PivotBarCreateButtonViewFingerprint.result!!.apply { + val insertIndex = mutableMethod.implementation!!.instructions.let { + val scanStart = scanResult.patternScanResult!!.endIndex - /* - * Inject hooks - */ + scanStart + it.subList(scanStart, it.size - 1).indexOfFirst { instruction -> + instruction.opcode == Opcode.INVOKE_STATIC + } + } - val hook = "invoke-static { v$REGISTER_TEMPLATE_REPLACEMENT }, " + - "$INTEGRATIONS_CLASS_DESCRIPTOR->hideCreateButton(Landroid/view/View;)V" + /* + * Inject hooks + */ + val hook = "invoke-static { v$REGISTER_TEMPLATE_REPLACEMENT }, " + + "$INTEGRATIONS_CLASS_DESCRIPTOR->hideCreateButton(Landroid/view/View;)V" + + mutableMethod.injectHook(hook, insertIndex) + } - createButtonResult.mutableMethod.injectHook(hook, insertIndex) return PatchResultSuccess() } diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/playerpopuppanels/fingerprints/EngagementPanelControllerFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/playerpopuppanels/fingerprints/EngagementPanelControllerFingerprint.kt index 4b9636f56..396863a60 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/playerpopuppanels/fingerprints/EngagementPanelControllerFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/playerpopuppanels/fingerprints/EngagementPanelControllerFingerprint.kt @@ -4,33 +4,14 @@ import app.revanced.patcher.extensions.or import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import org.jf.dexlib2.AccessFlags -import org.jf.dexlib2.Opcode @FuzzyPatternScanMethod(3) object EngagementPanelControllerFingerprint : MethodFingerprint( - "L", AccessFlags.PRIVATE or AccessFlags.FINAL, listOf("L", "L", "Z", "Z", "Z"), listOf( - Opcode.MOVE_OBJECT_FROM16, - Opcode.MOVE_OBJECT_FROM16, - Opcode.MOVE_FROM16, - Opcode.IGET_BOOLEAN, - Opcode.CONST_4, - Opcode.IF_NEZ, - Opcode.CONST_STRING, - Opcode.INVOKE_STATIC, - Opcode.SGET_OBJECT, - Opcode.SGET_OBJECT, - Opcode.CONST_STRING, - Opcode.INVOKE_STATIC, - Opcode.RETURN_OBJECT, - Opcode.IGET_OBJECT, - Opcode.IGET_OBJECT, - Opcode.INVOKE_VIRTUAL, - Opcode.CONST_4, - Opcode.CONST_4, - Opcode.CONST_4, - Opcode.CONST_4, - Opcode.CONST_4, - Opcode.CONST_4, + returnType = "L", + access = AccessFlags.PRIVATE or AccessFlags.FINAL, + strings = listOf( + "EngagementPanelController: cannot show EngagementPanel before EngagementPanelController.init() has been called.", + "[EngagementPanel] Cannot show EngagementPanel before EngagementPanelController.init() has been called." ) ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/playerpopuppanels/patch/PlayerPopupPanelsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/playerpopuppanels/patch/PlayerPopupPanelsPatch.kt index 9aca33f4f..5115529ab 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/playerpopuppanels/patch/PlayerPopupPanelsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/playerpopuppanels/patch/PlayerPopupPanelsPatch.kt @@ -1,5 +1,6 @@ package app.revanced.patches.youtube.layout.playerpopuppanels.patch +import app.revanced.extensions.toErrorResult import app.revanced.patcher.annotation.Description import app.revanced.patcher.annotation.Name import app.revanced.patcher.annotation.Version @@ -10,12 +11,12 @@ import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.annotations.DependsOn 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.layout.playerpopuppanels.annotations.PlayerPopupPanelsCompatibility import app.revanced.patches.youtube.layout.playerpopuppanels.fingerprints.EngagementPanelControllerFingerprint import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference @Patch @DependsOn([IntegrationsPatch::class, SettingsPatch::class]) @@ -39,7 +40,8 @@ class PlayerPopupPanelsPatch : BytecodePatch( ) ) - val engagementPanelControllerMethod = EngagementPanelControllerFingerprint.result!!.mutableMethod + val engagementPanelControllerMethod = EngagementPanelControllerFingerprint + .result?.mutableMethod ?: return EngagementPanelControllerFingerprint.toErrorResult() engagementPanelControllerMethod.addInstructions( 0, """ diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/videobuffer/fingerprints/InvokeMaxBufferFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/videobuffer/fingerprints/InvokeMaxBufferFingerprint.kt new file mode 100644 index 000000000..1d00997a9 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/videobuffer/fingerprints/InvokeMaxBufferFingerprint.kt @@ -0,0 +1,12 @@ +package app.revanced.patches.youtube.misc.videobuffer.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.Opcode + +object InvokeMaxBufferFingerprint : MethodFingerprint( + "Z", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf("J", "J", "F"), + listOf(Opcode.CONST_WIDE_16), + strings = listOf("scl.") +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/videobuffer/fingerprints/MaxBufferFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/videobuffer/fingerprints/MaxBufferFingerprint.kt index 9f194e951..556d35d15 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/videobuffer/fingerprints/MaxBufferFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/videobuffer/fingerprints/MaxBufferFingerprint.kt @@ -1,19 +1,8 @@ package app.revanced.patches.youtube.misc.videobuffer.fingerprints -import app.revanced.patcher.extensions.or import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.Opcode -import org.jf.dexlib2.iface.instruction.NarrowLiteralInstruction object MaxBufferFingerprint : MethodFingerprint( - "I", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf(), - listOf(Opcode.SGET_OBJECT, Opcode.IGET, Opcode.IF_EQZ, Opcode.RETURN), - customFingerprint = { methodDef -> - methodDef.definingClass == "Lcom/google/android/libraries/youtube/innertube/model/media/PlayerConfigModel;" - && methodDef.implementation!!.instructions.any { - ((it as? NarrowLiteralInstruction)?.narrowLiteral == 120000) - && methodDef.name == "r" - } - } + opcodes = listOf(Opcode.SGET_OBJECT, Opcode.IGET, Opcode.IF_EQZ, Opcode.RETURN), ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/videobuffer/patch/CustomVideoBufferPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/videobuffer/patch/CustomVideoBufferPatch.kt index c01f935ac..7b5f572c1 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/videobuffer/patch/CustomVideoBufferPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/videobuffer/patch/CustomVideoBufferPatch.kt @@ -1,12 +1,15 @@ package app.revanced.patches.youtube.misc.videobuffer.patch +import app.revanced.extensions.toErrorResult import app.revanced.patcher.annotation.Description import app.revanced.patcher.annotation.Name import app.revanced.patcher.annotation.Version import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.data.toMethodWalker import app.revanced.patcher.extensions.addInstructions import app.revanced.patcher.extensions.instruction import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResultSuccess @@ -19,6 +22,7 @@ import app.revanced.patches.shared.settings.preference.impl.StringResource import app.revanced.patches.shared.settings.preference.impl.TextPreference import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch import app.revanced.patches.youtube.misc.videobuffer.annotations.CustomVideoBufferCompatibility +import app.revanced.patches.youtube.misc.videobuffer.fingerprints.InvokeMaxBufferFingerprint import app.revanced.patches.youtube.misc.videobuffer.fingerprints.MaxBufferFingerprint import app.revanced.patches.youtube.misc.videobuffer.fingerprints.PlaybackBufferFingerprint import app.revanced.patches.youtube.misc.videobuffer.fingerprints.ReBufferFingerprint @@ -32,7 +36,9 @@ import org.jf.dexlib2.iface.instruction.OneRegisterInstruction @Version("0.0.1") class CustomVideoBufferPatch : BytecodePatch( listOf( - MaxBufferFingerprint, PlaybackBufferFingerprint, ReBufferFingerprint + InvokeMaxBufferFingerprint, + PlaybackBufferFingerprint, + ReBufferFingerprint, ) ) { override fun execute(context: BytecodeContext): PatchResult { @@ -103,8 +109,26 @@ class CustomVideoBufferPatch : BytecodePatch( MaxBufferFingerprint, "getMaxBuffer", PatchInfo.UnwrapInfo(true, -1) - ) - ); + ), + preparation@{ + InvokeMaxBufferFingerprint.result?.apply { + val maxBufferMethodCallOffset = 2 + + val maxBufferMethod = this@preparation.toMethodWalker(method) + .nextMethod(scanResult.patternScanResult!!.endIndex + maxBufferMethodCallOffset) + .getMethod() + + if (!MaxBufferFingerprint.resolve( + this@preparation, + maxBufferMethod, + // This is inefficient because toMethodWalker technically already has context about this. + // Alternatively you can iterate manually over all classes + // instead of relying on toMethodWalker. + this@preparation.findClass(maxBufferMethod.definingClass)!!.immutableClass, + ) + ) throw MaxBufferFingerprint.toErrorResult() + } ?: throw InvokeMaxBufferFingerprint.toErrorResult() + }); /** * Information about a patch. @@ -121,11 +145,11 @@ class CustomVideoBufferPatch : BytecodePatch( /** * Information on how to treat a [MethodFingerprint]. * - * @param forEndIndex Whether to retrieve information from the [MethodFingerprint] - * from the end or start index of its pattern scan result. - * @param offset An additional offset to [forEndIndex]. + * @param useEndIndex Whether to retrieve information of the [MethodFingerprint] + * from the end index of its pattern scan result. + * @param offset An additional offset to [useEndIndex]. */ - class UnwrapInfo(val forEndIndex: Boolean = false, val offset: Int = 0) + class UnwrapInfo(val useEndIndex: Boolean = false, val offset: Int = 0) } fun hook(context: BytecodeContext) { @@ -149,12 +173,11 @@ class CustomVideoBufferPatch : BytecodePatch( val result = this.result!! val method = result.mutableMethod val scanResult = result.scanResult.patternScanResult!! - val index = ( - if (unwrapInfo?.forEndIndex == true) - scanResult.endIndex - else - scanResult.startIndex - ) + (unwrapInfo?.offset ?: 0) + val index = + if (unwrapInfo?.useEndIndex == true) scanResult.endIndex + else { + scanResult.startIndex + } + (unwrapInfo?.offset ?: 0) val register = (method.instruction(index) as OneRegisterInstruction).registerA