mirror of
https://github.com/inotia00/revanced-patches.git
synced 2025-05-04 08:34:27 +02:00
refactor(YouTube/Return YouTube Dislike): make patch more robust by removing opcode patterns from fingerprints
This commit is contained in:
parent
34e5606c22
commit
dd2f636a4a
@ -3,8 +3,6 @@ package app.revanced.patches.youtube.utils.returnyoutubedislike.general
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.removeInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.annotation.CompatiblePackage
|
||||
@ -16,11 +14,8 @@ import app.revanced.patches.youtube.utils.playerresponse.PlayerResponsePatch
|
||||
import app.revanced.patches.youtube.utils.returnyoutubedislike.general.fingerprints.DislikeFingerprint
|
||||
import app.revanced.patches.youtube.utils.returnyoutubedislike.general.fingerprints.LikeFingerprint
|
||||
import app.revanced.patches.youtube.utils.returnyoutubedislike.general.fingerprints.RemoveLikeFingerprint
|
||||
import app.revanced.patches.youtube.utils.returnyoutubedislike.general.fingerprints.TextComponentAtomicReferenceFingerprint
|
||||
import app.revanced.patches.youtube.utils.returnyoutubedislike.general.fingerprints.TextComponentAtomicReferenceLegacyFingerprint
|
||||
import app.revanced.patches.youtube.utils.returnyoutubedislike.general.fingerprints.TextComponentConstructorFingerprint
|
||||
import app.revanced.patches.youtube.utils.returnyoutubedislike.general.fingerprints.TextComponentContextFingerprint
|
||||
import app.revanced.patches.youtube.utils.returnyoutubedislike.general.fingerprints.TextComponentTmpFingerprint
|
||||
import app.revanced.patches.youtube.utils.returnyoutubedislike.oldlayout.ReturnYouTubeDislikeOldLayoutPatch
|
||||
import app.revanced.patches.youtube.utils.returnyoutubedislike.rollingnumber.ReturnYouTubeDislikeRollingNumberPatch
|
||||
import app.revanced.patches.youtube.utils.returnyoutubedislike.shorts.ReturnYouTubeDislikeShortsPatch
|
||||
@ -28,10 +23,8 @@ import app.revanced.patches.youtube.utils.settings.SettingsPatch
|
||||
import app.revanced.patches.youtube.utils.videoid.general.VideoIdPatch
|
||||
import app.revanced.util.exception
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.reference.Reference
|
||||
|
||||
@Patch(
|
||||
name = "Return YouTube Dislike",
|
||||
@ -101,88 +94,34 @@ object ReturnYouTubeDislikePatch : BytecodePatch(
|
||||
|
||||
TextComponentConstructorFingerprint.result?.let { parentResult ->
|
||||
// Resolves fingerprints
|
||||
val parentClassDef = parentResult.classDef
|
||||
TextComponentContextFingerprint.resolve(context, parentClassDef)
|
||||
TextComponentTmpFingerprint.resolve(context, parentClassDef)
|
||||
TextComponentAtomicReferenceFingerprint.resolve(context, parentClassDef)
|
||||
TextComponentAtomicReferenceLegacyFingerprint.resolve(context, parentClassDef)
|
||||
TextComponentContextFingerprint.resolve(context, parentResult.classDef)
|
||||
|
||||
TextComponentContextFingerprint.result?.let {
|
||||
it.mutableMethod.apply {
|
||||
val booleanIndex = it.scanResult.patternScanResult!!.endIndex
|
||||
val conversionContextFieldIndex = implementation!!.instructions.indexOfFirst { instruction ->
|
||||
instruction.opcode == Opcode.IGET_OBJECT
|
||||
&& (instruction as ReferenceInstruction).reference.toString().endsWith("Ljava/util/Map;")
|
||||
} - 1
|
||||
val conversionContextFieldReference =
|
||||
getInstruction<ReferenceInstruction>(conversionContextFieldIndex).reference
|
||||
|
||||
for (index in booleanIndex downTo 0) {
|
||||
if (getInstruction(index).opcode != Opcode.IGET_OBJECT) continue
|
||||
|
||||
val targetReference =
|
||||
getInstruction<ReferenceInstruction>(index).reference.toString()
|
||||
|
||||
if (targetReference.endsWith("Ljava/util/Map;")) {
|
||||
conversionContextFieldReference =
|
||||
getInstruction<ReferenceInstruction>(index - 1).reference
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
} ?: throw TextComponentContextFingerprint.exception
|
||||
|
||||
TextComponentTmpFingerprint.result?.let {
|
||||
it.mutableMethod.apply {
|
||||
val startIndex = it.scanResult.patternScanResult!!.startIndex
|
||||
tmpRegister =
|
||||
getInstruction<FiveRegisterInstruction>(startIndex).registerE
|
||||
}
|
||||
} ?: throw TextComponentTmpFingerprint.exception
|
||||
|
||||
|
||||
val textComponentAtomicReferenceResult =
|
||||
TextComponentAtomicReferenceFingerprint.result
|
||||
?: TextComponentAtomicReferenceLegacyFingerprint.result
|
||||
?: throw TextComponentAtomicReferenceLegacyFingerprint.exception
|
||||
|
||||
TextComponentAtomicReferenceFingerprint.result?.let {
|
||||
it.mutableMethod.apply {
|
||||
val startIndex = it.scanResult.patternScanResult!!.startIndex
|
||||
val originalRegisterA =
|
||||
getInstruction<TwoRegisterInstruction>(startIndex + 2).registerA
|
||||
|
||||
replaceInstruction(
|
||||
startIndex + 2,
|
||||
"move-object v$originalRegisterA, v$tmpRegister"
|
||||
)
|
||||
replaceInstruction(
|
||||
startIndex + 1,
|
||||
"move-result-object v$tmpRegister"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
textComponentAtomicReferenceResult.let {
|
||||
it.mutableMethod.apply {
|
||||
val atomicReferenceStartIndex = it.scanResult.patternScanResult!!.startIndex
|
||||
val insertIndex = it.scanResult.patternScanResult!!.endIndex
|
||||
val moveCharSequenceInstruction =
|
||||
getInstruction<TwoRegisterInstruction>(insertIndex)
|
||||
|
||||
val atomicReferenceRegister =
|
||||
getInstruction<FiveRegisterInstruction>(atomicReferenceStartIndex).registerC
|
||||
|
||||
val charSequenceRegister =
|
||||
moveCharSequenceInstruction.registerB
|
||||
val charSequenceIndex = implementation!!.instructions.indexOfFirst { instruction ->
|
||||
instruction.opcode == Opcode.IGET_OBJECT
|
||||
&& (instruction as ReferenceInstruction).reference.toString().endsWith("Ljava/util/BitSet;")
|
||||
} - 1
|
||||
val charSequenceRegister = getInstruction<TwoRegisterInstruction>(charSequenceIndex).registerA
|
||||
val freeRegister = getInstruction<TwoRegisterInstruction>(charSequenceIndex).registerB
|
||||
|
||||
addInstructions(
|
||||
insertIndex + 1, """
|
||||
move-object/from16 v$tmpRegister, p0
|
||||
iget-object v$tmpRegister, v$tmpRegister, $conversionContextFieldReference
|
||||
invoke-static {v$tmpRegister, v$atomicReferenceRegister, v$charSequenceRegister}, $INTEGRATIONS_RYD_CLASS_DESCRIPTOR->onLithoTextLoaded(Ljava/lang/Object;Ljava/util/concurrent/atomic/AtomicReference;Ljava/lang/CharSequence;)Ljava/lang/CharSequence;
|
||||
charSequenceIndex - 1, """
|
||||
move-object/from16 v$freeRegister, p0
|
||||
iget-object v$freeRegister, v$freeRegister, $conversionContextFieldReference
|
||||
invoke-static {v$freeRegister, v$charSequenceRegister}, $INTEGRATIONS_RYD_CLASS_DESCRIPTOR->onLithoTextLoaded(Ljava/lang/Object;Ljava/lang/CharSequence;)Ljava/lang/CharSequence;
|
||||
move-result-object v$charSequenceRegister
|
||||
move-object v${moveCharSequenceInstruction.registerA}, v${charSequenceRegister}
|
||||
"""
|
||||
)
|
||||
removeInstruction(insertIndex)
|
||||
}
|
||||
}
|
||||
} ?: throw TextComponentContextFingerprint.exception
|
||||
} ?: throw TextComponentConstructorFingerprint.exception
|
||||
|
||||
VideoIdPatch.injectCall("$INTEGRATIONS_RYD_CLASS_DESCRIPTOR->newVideoLoaded(Ljava/lang/String;)V")
|
||||
@ -208,9 +147,6 @@ object ReturnYouTubeDislikePatch : BytecodePatch(
|
||||
private const val FILTER_CLASS_DESCRIPTOR =
|
||||
"$COMPONENTS_PATH/ReturnYouTubeDislikeFilterPatch;"
|
||||
|
||||
private lateinit var conversionContextFieldReference: Reference
|
||||
private var tmpRegister: Int = 12
|
||||
|
||||
private fun MethodFingerprint.toPatch(voteKind: Vote) = VotePatch(this, voteKind)
|
||||
|
||||
private data class VotePatch(val fingerprint: MethodFingerprint, val voteKind: Vote)
|
||||
|
@ -1,19 +0,0 @@
|
||||
package app.revanced.patches.youtube.utils.returnyoutubedislike.general.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 TextComponentAtomicReferenceFingerprint : MethodFingerprint(
|
||||
returnType = "L",
|
||||
accessFlags = AccessFlags.PROTECTED or AccessFlags.FINAL,
|
||||
parameters = listOf("L"),
|
||||
opcodes = listOf(
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.MOVE_OBJECT,
|
||||
Opcode.CHECK_CAST,
|
||||
Opcode.MOVE_OBJECT
|
||||
)
|
||||
)
|
@ -1,18 +0,0 @@
|
||||
package app.revanced.patches.youtube.utils.returnyoutubedislike.general.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 TextComponentAtomicReferenceLegacyFingerprint : MethodFingerprint(
|
||||
returnType = "L",
|
||||
accessFlags = AccessFlags.PROTECTED or AccessFlags.FINAL,
|
||||
parameters = listOf("L"),
|
||||
opcodes = listOf(
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.CHECK_CAST,
|
||||
Opcode.MOVE_OBJECT
|
||||
)
|
||||
)
|
@ -1,16 +0,0 @@
|
||||
package app.revanced.patches.youtube.utils.returnyoutubedislike.general.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 TextComponentTmpFingerprint : MethodFingerprint(
|
||||
returnType = "L",
|
||||
accessFlags = AccessFlags.PROTECTED or AccessFlags.FINAL,
|
||||
parameters = listOf("L"),
|
||||
opcodes = listOf(
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.MOVE_RESULT_OBJECT, // last instruction of the method
|
||||
)
|
||||
)
|
@ -2,11 +2,13 @@ package app.revanced.patches.youtube.utils.returnyoutubedislike.rollingnumber
|
||||
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.removeInstruction
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.PatchException
|
||||
import app.revanced.patcher.patch.annotation.Patch
|
||||
import app.revanced.patcher.util.smali.ExternalLabel
|
||||
import app.revanced.patches.youtube.utils.fingerprints.RollingNumberTextViewAnimationUpdateFingerprint
|
||||
import app.revanced.patches.youtube.utils.integrations.Constants.UTILS_PATH
|
||||
import app.revanced.patches.youtube.utils.returnyoutubedislike.rollingnumber.fingerprints.RollingNumberMeasureAnimatedTextFingerprint
|
||||
@ -31,6 +33,7 @@ object ReturnYouTubeDislikeRollingNumberPatch : BytecodePatch(
|
||||
RollingNumberSetterFingerprint,
|
||||
RollingNumberMeasureTextParentFingerprint,
|
||||
RollingNumberTextViewFingerprint,
|
||||
RollingNumberMeasureAnimatedTextFingerprint,
|
||||
RollingNumberTextViewAnimationUpdateFingerprint
|
||||
)
|
||||
) {
|
||||
@ -88,41 +91,42 @@ object ReturnYouTubeDislikeRollingNumberPatch : BytecodePatch(
|
||||
}
|
||||
} ?: throw RollingNumberSetterFingerprint.exception
|
||||
|
||||
RollingNumberMeasureTextParentFingerprint.result?.let { parentResult ->
|
||||
// Rolling Number text views use the measured width of the raw string for layout.
|
||||
// Modify the measure text calculation to include the left drawable separator if needed.
|
||||
RollingNumberMeasureAnimatedTextFingerprint.also {
|
||||
it.resolve(
|
||||
context,
|
||||
parentResult.classDef
|
||||
)
|
||||
}.result?.let {
|
||||
it.mutableMethod.apply {
|
||||
val returnInstructionIndex = it.scanResult.patternScanResult!!.endIndex
|
||||
val measuredTextWidthRegister =
|
||||
getInstruction<OneRegisterInstruction>(returnInstructionIndex).registerA
|
||||
// Rolling Number text views use the measured width of the raw string for layout.
|
||||
// Modify the measure text calculation to include the left drawable separator if needed.
|
||||
RollingNumberMeasureAnimatedTextFingerprint.result?.let {
|
||||
it.mutableMethod.apply {
|
||||
val endIndex = it.scanResult.patternScanResult!!.endIndex
|
||||
val measuredTextWidthIndex = endIndex - 2
|
||||
val measuredTextWidthRegister =
|
||||
getInstruction<TwoRegisterInstruction>(measuredTextWidthIndex).registerA
|
||||
|
||||
replaceInstruction( // Replace instruction to preserve control flow label.
|
||||
returnInstructionIndex,
|
||||
"invoke-static {p1, v$measuredTextWidthRegister}, $INTEGRATIONS_RYD_CLASS_DESCRIPTOR->onRollingNumberMeasured(Ljava/lang/String;F)F"
|
||||
)
|
||||
addInstructions(
|
||||
returnInstructionIndex + 1, """
|
||||
move-result v$measuredTextWidthRegister
|
||||
return v$measuredTextWidthRegister
|
||||
"""
|
||||
)
|
||||
addInstructions(
|
||||
endIndex + 1, """
|
||||
invoke-static {p1, v$measuredTextWidthRegister}, $INTEGRATIONS_RYD_CLASS_DESCRIPTOR->onRollingNumberMeasured(Ljava/lang/String;F)F
|
||||
move-result v$measuredTextWidthRegister
|
||||
"""
|
||||
)
|
||||
|
||||
val ifGeIndex = implementation!!.instructions.indexOfFirst { instruction ->
|
||||
instruction.opcode == Opcode.IF_GE
|
||||
}
|
||||
} ?: throw RollingNumberMeasureAnimatedTextFingerprint.exception
|
||||
val ifGeInstruction = getInstruction<TwoRegisterInstruction>(ifGeIndex)
|
||||
|
||||
removeInstruction(ifGeIndex)
|
||||
addInstructionsWithLabels(
|
||||
ifGeIndex, """
|
||||
if-ge v${ifGeInstruction.registerA}, v${ifGeInstruction.registerB}, :jump
|
||||
""", ExternalLabel("jump", getInstruction(endIndex))
|
||||
)
|
||||
}
|
||||
} ?: throw RollingNumberMeasureAnimatedTextFingerprint.exception
|
||||
|
||||
RollingNumberMeasureTextParentFingerprint.result?.classDef?.let { parentClassDef ->
|
||||
RollingNumberMeasureStaticLabelFingerprint.resolve(context, parentClassDef)
|
||||
|
||||
// Additional text measurement method. Used if YouTube decides not to animate the likes count
|
||||
// and sometimes used for initial video load.
|
||||
RollingNumberMeasureStaticLabelFingerprint.also {
|
||||
it.resolve(
|
||||
context,
|
||||
parentResult.classDef
|
||||
)
|
||||
}.result?.let {
|
||||
RollingNumberMeasureStaticLabelFingerprint.result?.let {
|
||||
it.mutableMethod.apply {
|
||||
val measureTextIndex = it.scanResult.patternScanResult!!.startIndex + 1
|
||||
val freeRegister = getInstruction<TwoRegisterInstruction>(0).registerA
|
||||
|
@ -1,23 +1,34 @@
|
||||
package app.revanced.patches.youtube.utils.returnyoutubedislike.rollingnumber.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
|
||||
|
||||
/**
|
||||
* Resolves to class found in [RollingNumberMeasureTextParentFingerprint].
|
||||
* Compatible with YouTube v18.30.xx to v18.49.xx
|
||||
*/
|
||||
object RollingNumberMeasureAnimatedTextFingerprint : MethodFingerprint(
|
||||
returnType = "F",
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
parameters = listOf("Ljava/lang/String;"),
|
||||
opcodes = listOf(
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT,
|
||||
Opcode.ADD_FLOAT_2ADDR,
|
||||
Opcode.ADD_FLOAT_2ADDR, // measuredTextWidth
|
||||
Opcode.ADD_INT_LIT8,
|
||||
Opcode.GOTO,
|
||||
Opcode.RETURN
|
||||
)
|
||||
Opcode.GOTO
|
||||
),
|
||||
customFingerprint = custom@{ methodDef, _ ->
|
||||
if (methodDef.implementation == null)
|
||||
return@custom false
|
||||
|
||||
for (instruction in methodDef.implementation!!.instructions) {
|
||||
if (instruction.opcode != Opcode.INVOKE_VIRTUAL)
|
||||
continue
|
||||
|
||||
val invokeInstruction = instruction as ReferenceInstruction
|
||||
if (!invokeInstruction.reference.toString().endsWith("Landroid/text/TextPaint;->measureText([CII)F"))
|
||||
continue
|
||||
|
||||
return@custom true
|
||||
}
|
||||
return@custom false
|
||||
}
|
||||
)
|
Loading…
x
Reference in New Issue
Block a user