fix(youtube): reliably resolve fingerprints

Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
This commit is contained in:
oSumAtrIX 2023-01-28 06:24:24 +01:00
parent c4c9e5bb37
commit 1598306eb5
No known key found for this signature in database
GPG Key ID: A9B3094ACDB604B4
7 changed files with 76 additions and 64 deletions

View File

@ -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
)
)

View File

@ -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()
}

View File

@ -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."
)
)

View File

@ -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, """

View File

@ -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.")
)

View File

@ -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),
)

View File

@ -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