mirror of
https://github.com/revanced/revanced-patches.git
synced 2025-05-03 16:14:28 +02:00
refactor(YouTube - Return YouTube Dislike): Make patch more robust by removing opcode patterns from fingerprints (#2602)
This commit is contained in:
parent
43a5677397
commit
d93a356ec2
@ -1,8 +1,5 @@
|
|||||||
package app.revanced.patches.youtube.layout.returnyoutubedislike
|
package app.revanced.patches.youtube.layout.returnyoutubedislike
|
||||||
|
|
||||||
import app.revanced.util.exception
|
|
||||||
import app.revanced.util.getReference
|
|
||||||
import app.revanced.util.indexOfFirstInstruction
|
|
||||||
import app.revanced.patcher.data.BytecodeContext
|
import app.revanced.patcher.data.BytecodeContext
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||||
@ -11,19 +8,39 @@ import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
|||||||
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
|
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
|
||||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||||
import app.revanced.patcher.patch.BytecodePatch
|
import app.revanced.patcher.patch.BytecodePatch
|
||||||
|
import app.revanced.patcher.patch.PatchException
|
||||||
import app.revanced.patcher.patch.annotation.CompatiblePackage
|
import app.revanced.patcher.patch.annotation.CompatiblePackage
|
||||||
import app.revanced.patcher.patch.annotation.Patch
|
import app.revanced.patcher.patch.annotation.Patch
|
||||||
import app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints.*
|
import app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints.ConversionContextFingerprint
|
||||||
|
import app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints.DislikeFingerprint
|
||||||
|
import app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints.DislikesOldLayoutTextViewFingerprint
|
||||||
|
import app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints.LikeFingerprint
|
||||||
|
import app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints.RemoveLikeFingerprint
|
||||||
|
import app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints.RollingNumberMeasureAnimatedTextFingerprint
|
||||||
|
import app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints.RollingNumberMeasureStaticLabelFingerprint
|
||||||
|
import app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints.RollingNumberMeasureTextParentFingerprint
|
||||||
|
import app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints.RollingNumberSetterFingerprint
|
||||||
|
import app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints.RollingNumberTextViewFingerprint
|
||||||
|
import app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints.ShortsTextViewFingerprint
|
||||||
|
import app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints.TextComponentConstructorFingerprint
|
||||||
|
import app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints.TextComponentDataFingerprint
|
||||||
|
import app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints.TextComponentLookupFingerprint
|
||||||
import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch
|
import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch
|
||||||
import app.revanced.patches.youtube.misc.litho.filter.LithoFilterPatch
|
import app.revanced.patches.youtube.misc.litho.filter.LithoFilterPatch
|
||||||
import app.revanced.patches.youtube.misc.playertype.PlayerTypeHookPatch
|
import app.revanced.patches.youtube.misc.playertype.PlayerTypeHookPatch
|
||||||
import app.revanced.patches.youtube.shared.fingerprints.RollingNumberTextViewAnimationUpdateFingerprint
|
import app.revanced.patches.youtube.shared.fingerprints.RollingNumberTextViewAnimationUpdateFingerprint
|
||||||
import app.revanced.patches.youtube.video.videoid.VideoIdPatch
|
import app.revanced.patches.youtube.video.videoid.VideoIdPatch
|
||||||
|
import app.revanced.util.exception
|
||||||
|
import app.revanced.util.getReference
|
||||||
|
import app.revanced.util.indexOfFirstInstruction
|
||||||
|
import com.android.tools.smali.dexlib2.Opcode
|
||||||
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
|
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.OneRegisterInstruction
|
||||||
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
|
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.instruction.TwoRegisterInstruction
|
||||||
|
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
|
||||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||||
|
import com.android.tools.smali.dexlib2.iface.reference.TypeReference
|
||||||
|
|
||||||
@Patch(
|
@Patch(
|
||||||
name = "Return YouTube Dislike",
|
name = "Return YouTube Dislike",
|
||||||
@ -38,6 +55,7 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
|||||||
compatiblePackages = [
|
compatiblePackages = [
|
||||||
CompatiblePackage(
|
CompatiblePackage(
|
||||||
"com.google.android.youtube", [
|
"com.google.android.youtube", [
|
||||||
|
"18.38.44",
|
||||||
"18.43.45",
|
"18.43.45",
|
||||||
"18.44.41",
|
"18.44.41",
|
||||||
"18.45.41",
|
"18.45.41",
|
||||||
@ -49,7 +67,9 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
|||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
object ReturnYouTubeDislikePatch : BytecodePatch(
|
object ReturnYouTubeDislikePatch : BytecodePatch(
|
||||||
setOf(
|
setOf(
|
||||||
|
ConversionContextFingerprint,
|
||||||
TextComponentConstructorFingerprint,
|
TextComponentConstructorFingerprint,
|
||||||
|
TextComponentDataFingerprint,
|
||||||
ShortsTextViewFingerprint,
|
ShortsTextViewFingerprint,
|
||||||
DislikesOldLayoutTextViewFingerprint,
|
DislikesOldLayoutTextViewFingerprint,
|
||||||
LikeFingerprint,
|
LikeFingerprint,
|
||||||
@ -67,6 +87,8 @@ object ReturnYouTubeDislikePatch : BytecodePatch(
|
|||||||
private const val FILTER_CLASS_DESCRIPTOR =
|
private const val FILTER_CLASS_DESCRIPTOR =
|
||||||
"Lapp/revanced/integrations/youtube/patches/components/ReturnYouTubeDislikeFilterPatch;"
|
"Lapp/revanced/integrations/youtube/patches/components/ReturnYouTubeDislikeFilterPatch;"
|
||||||
|
|
||||||
|
private fun MethodFingerprint.resultOrThrow() = result ?: throw exception
|
||||||
|
|
||||||
override fun execute(context: BytecodeContext) {
|
override fun execute(context: BytecodeContext) {
|
||||||
// region Inject newVideoLoaded event handler to update dislikes when a new video is loaded.
|
// region Inject newVideoLoaded event handler to update dislikes when a new video is loaded.
|
||||||
|
|
||||||
@ -97,64 +119,132 @@ object ReturnYouTubeDislikePatch : BytecodePatch(
|
|||||||
|
|
||||||
// endregion
|
// endregion
|
||||||
|
|
||||||
// region Hook creation of Spans and the cached lookup of them.
|
// region Hook code for creation and cached lookup of text Spans.
|
||||||
|
|
||||||
// Alternatively the hook can be made at the creation of Spans in TextComponentSpec,
|
// Alternatively the hook can be made at the creation of Spans in TextComponentSpec,
|
||||||
// And it works in all situations except it fails to update the Span when the user dislikes,
|
// And it works in all situations except it fails to update the Span when the user dislikes,
|
||||||
// since the underlying (likes only) text did not change.
|
// 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.
|
// This hook handles all situations, as it's where the created Spans are stored and later reused.
|
||||||
TextComponentContextFingerprint.also {
|
TextComponentConstructorFingerprint.result?.let { textConstructorResult ->
|
||||||
if (!it.resolve(context, TextComponentConstructorFingerprint.result!!.classDef))
|
// Find the field name of the conversion context.
|
||||||
throw it.exception
|
val conversionContextClassType = ConversionContextFingerprint.resultOrThrow().classDef.type
|
||||||
}.result?.also { result ->
|
val conversionContextField = textConstructorResult.classDef.fields.find {
|
||||||
if (!TextComponentAtomicReferenceFingerprint.resolve(context, result.method, result.classDef))
|
it.type == conversionContextClassType
|
||||||
throw TextComponentAtomicReferenceFingerprint.exception
|
} ?: throw PatchException("Could not find conversion context field")
|
||||||
}?.let { textComponentContextFingerprintResult ->
|
|
||||||
val conversionContextIndex = textComponentContextFingerprintResult
|
|
||||||
.scanResult.patternScanResult!!.endIndex
|
|
||||||
val atomicReferenceStartIndex = TextComponentAtomicReferenceFingerprint.result!!
|
|
||||||
.scanResult.patternScanResult!!.startIndex
|
|
||||||
|
|
||||||
val insertIndex = atomicReferenceStartIndex + 9
|
TextComponentLookupFingerprint.resolve(context, textConstructorResult.classDef)
|
||||||
|
TextComponentLookupFingerprint.resultOrThrow().mutableMethod.apply {
|
||||||
|
// Find the instruction for creating the text data object.
|
||||||
|
val textDataClassType = TextComponentDataFingerprint.resultOrThrow().classDef.type
|
||||||
|
val insertIndex = indexOfFirstInstruction {
|
||||||
|
opcode == Opcode.NEW_INSTANCE &&
|
||||||
|
getReference<TypeReference>()?.type == textDataClassType
|
||||||
|
}
|
||||||
|
if (insertIndex < 0) throw PatchException("Could not find data creation instruction")
|
||||||
|
val tempRegister = getInstruction<OneRegisterInstruction>(insertIndex).registerA
|
||||||
|
|
||||||
textComponentContextFingerprintResult.mutableMethod.apply {
|
// Find the instruction that sets the span to an instance field.
|
||||||
// Get the conversion context obfuscated field name
|
// The instruction is only a few lines after the creation of the instance.
|
||||||
val conversionContextFieldReference =
|
// The method has multiple iput-object instructions using a CharSequence,
|
||||||
getInstruction<ReferenceInstruction>(conversionContextIndex).reference
|
// so verify the found instruction is in the expected location.
|
||||||
|
val putFieldInstruction = implementation!!.instructions
|
||||||
|
.subList(insertIndex, insertIndex + 20)
|
||||||
|
.find {
|
||||||
|
it.opcode == Opcode.IPUT_OBJECT &&
|
||||||
|
it.getReference<FieldReference>()?.type == "Ljava/lang/CharSequence;"
|
||||||
|
} ?: throw PatchException("Could not find put object instruction")
|
||||||
|
val charSequenceRegister = (putFieldInstruction as TwoRegisterInstruction).registerA
|
||||||
|
|
||||||
// Free register to hold the conversion context
|
|
||||||
val freeRegister =
|
|
||||||
getInstruction<TwoRegisterInstruction>(atomicReferenceStartIndex).registerB
|
|
||||||
|
|
||||||
val atomicReferenceRegister =
|
|
||||||
getInstruction<FiveRegisterInstruction>(atomicReferenceStartIndex + 6).registerC
|
|
||||||
|
|
||||||
// Instruction that is replaced, and also has the CharacterSequence register.
|
|
||||||
val moveCharSequenceInstruction = getInstruction<TwoRegisterInstruction>(insertIndex)
|
|
||||||
val charSequenceSourceRegister = moveCharSequenceInstruction.registerB
|
|
||||||
val charSequenceTargetRegister = moveCharSequenceInstruction.registerA
|
|
||||||
|
|
||||||
// Move the current instance to the free register, and get the conversion context from it.
|
|
||||||
// Must replace the instruction to preserve the control flow label.
|
|
||||||
replaceInstruction(insertIndex, "move-object/from16 v$freeRegister, p0")
|
|
||||||
addInstructions(
|
addInstructions(
|
||||||
insertIndex + 1,
|
insertIndex,
|
||||||
"""
|
|
||||||
# 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 instruction
|
|
||||||
move-object v${charSequenceTargetRegister}, v${freeRegister}
|
|
||||||
"""
|
"""
|
||||||
|
# Copy conversion context
|
||||||
|
move-object/from16 v$tempRegister, p0
|
||||||
|
iget-object v$tempRegister, v$tempRegister, $conversionContextField
|
||||||
|
invoke-static {v$tempRegister, v$charSequenceRegister}, $INTEGRATIONS_CLASS_DESCRIPTOR->onLithoTextLoaded(Ljava/lang/Object;Ljava/lang/CharSequence;)Ljava/lang/CharSequence;
|
||||||
|
move-result-object v$charSequenceRegister
|
||||||
|
"""
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
} ?: throw TextComponentContextFingerprint.exception
|
} ?: throw TextComponentConstructorFingerprint.exception
|
||||||
|
|
||||||
// endregion
|
// endregion
|
||||||
|
|
||||||
|
// region Hook for non-litho Short videos.
|
||||||
|
|
||||||
|
ShortsTextViewFingerprint.result?.let {
|
||||||
|
it.mutableMethod.apply {
|
||||||
|
val patternResult = it.scanResult.patternScanResult!!
|
||||||
|
|
||||||
|
// If the field is true, the TextView is for a dislike button.
|
||||||
|
val isDisLikesBooleanReference = getInstruction<ReferenceInstruction>(patternResult.endIndex).reference
|
||||||
|
|
||||||
|
val textViewFieldReference = // Like/Dislike button TextView field
|
||||||
|
getInstruction<ReferenceInstruction>(patternResult.endIndex - 1).reference
|
||||||
|
|
||||||
|
// Check if the hooked TextView object is that of the dislike button.
|
||||||
|
// If RYD is disabled, or the TextView object is not that of the dislike button, the execution flow is not interrupted.
|
||||||
|
// Otherwise, the TextView object is modified, and the execution flow is interrupted to prevent it from being changed afterward.
|
||||||
|
val insertIndex = patternResult.startIndex + 6
|
||||||
|
addInstructionsWithLabels(
|
||||||
|
insertIndex,
|
||||||
|
"""
|
||||||
|
# Check, if the TextView is for a dislike button
|
||||||
|
iget-boolean v0, p0, $isDisLikesBooleanReference
|
||||||
|
if-eqz v0, :is_like
|
||||||
|
|
||||||
|
# Hook the TextView, if it is for the dislike button
|
||||||
|
iget-object v0, p0, $textViewFieldReference
|
||||||
|
invoke-static {v0}, $INTEGRATIONS_CLASS_DESCRIPTOR->setShortsDislikes(Landroid/view/View;)Z
|
||||||
|
move-result v0
|
||||||
|
if-eqz v0, :ryd_disabled
|
||||||
|
return-void
|
||||||
|
|
||||||
|
:is_like
|
||||||
|
:ryd_disabled
|
||||||
|
nop
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} ?: throw ShortsTextViewFingerprint.exception
|
||||||
|
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
// region Hook for litho Shorts
|
||||||
|
|
||||||
|
// Filter that parses the video id from the UI
|
||||||
|
LithoFilterPatch.addFilter(FILTER_CLASS_DESCRIPTOR)
|
||||||
|
|
||||||
|
// Player response video id is needed to search for the video ids in Shorts litho components.
|
||||||
|
VideoIdPatch.hookPlayerResponseVideoId("$FILTER_CLASS_DESCRIPTOR->newPlayerResponseVideoId(Ljava/lang/String;Z)V")
|
||||||
|
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
// region Hook old UI layout dislikes, for the older app spoofs used with spoof-app-version.
|
||||||
|
|
||||||
|
DislikesOldLayoutTextViewFingerprint.result?.let {
|
||||||
|
it.mutableMethod.apply {
|
||||||
|
val startIndex = it.scanResult.patternScanResult!!.startIndex
|
||||||
|
|
||||||
|
val resourceIdentifierRegister = getInstruction<OneRegisterInstruction>(startIndex).registerA
|
||||||
|
val textViewRegister = getInstruction<OneRegisterInstruction>(startIndex + 4).registerA
|
||||||
|
|
||||||
|
addInstruction(
|
||||||
|
startIndex + 4,
|
||||||
|
"invoke-static {v$resourceIdentifierRegister, v$textViewRegister}, $INTEGRATIONS_CLASS_DESCRIPTOR->setOldUILayoutDislikes(ILandroid/widget/TextView;)V"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} ?: throw DislikesOldLayoutTextViewFingerprint.exception
|
||||||
|
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
|
||||||
// region Hook rolling numbers.
|
// region Hook rolling numbers.
|
||||||
|
|
||||||
|
// Do this last to allow patching old unsupported versions (if the user really wants),
|
||||||
|
// On older unsupported version this will fail to resolve and throw an exception,
|
||||||
|
// but everything will still work correctly anyways.
|
||||||
|
|
||||||
RollingNumberSetterFingerprint.result?.let {
|
RollingNumberSetterFingerprint.result?.let {
|
||||||
val dislikesIndex = it.scanResult.patternScanResult!!.endIndex
|
val dislikesIndex = it.scanResult.patternScanResult!!.endIndex
|
||||||
|
|
||||||
@ -164,7 +254,7 @@ object ReturnYouTubeDislikePatch : BytecodePatch(
|
|||||||
val charSequenceInstanceRegister =
|
val charSequenceInstanceRegister =
|
||||||
getInstruction<OneRegisterInstruction>(0).registerA
|
getInstruction<OneRegisterInstruction>(0).registerA
|
||||||
val charSequenceFieldReference =
|
val charSequenceFieldReference =
|
||||||
getInstruction<ReferenceInstruction>(dislikesIndex).reference.toString()
|
getInstruction<ReferenceInstruction>(dislikesIndex).reference
|
||||||
|
|
||||||
val registerCount = implementation!!.registerCount
|
val registerCount = implementation!!.registerCount
|
||||||
|
|
||||||
@ -268,73 +358,6 @@ object ReturnYouTubeDislikePatch : BytecodePatch(
|
|||||||
|
|
||||||
// endregion
|
// endregion
|
||||||
|
|
||||||
// region Hook for non-litho Short videos.
|
|
||||||
|
|
||||||
ShortsTextViewFingerprint.result?.let {
|
|
||||||
it.mutableMethod.apply {
|
|
||||||
val patternResult = it.scanResult.patternScanResult!!
|
|
||||||
|
|
||||||
// If the field is true, the TextView is for a dislike button.
|
|
||||||
val isDisLikesBooleanReference = getInstruction<ReferenceInstruction>(patternResult.endIndex).reference
|
|
||||||
|
|
||||||
val textViewFieldReference = // Like/Dislike button TextView field
|
|
||||||
getInstruction<ReferenceInstruction>(patternResult.endIndex - 1).reference
|
|
||||||
|
|
||||||
// Check if the hooked TextView object is that of the dislike button.
|
|
||||||
// If RYD is disabled, or the TextView object is not that of the dislike button, the execution flow is not interrupted.
|
|
||||||
// Otherwise, the TextView object is modified, and the execution flow is interrupted to prevent it from being changed afterward.
|
|
||||||
val insertIndex = patternResult.startIndex + 6
|
|
||||||
addInstructionsWithLabels(
|
|
||||||
insertIndex,
|
|
||||||
"""
|
|
||||||
# Check, if the TextView is for a dislike button
|
|
||||||
iget-boolean v0, p0, $isDisLikesBooleanReference
|
|
||||||
if-eqz v0, :is_like
|
|
||||||
|
|
||||||
# Hook the TextView, if it is for the dislike button
|
|
||||||
iget-object v0, p0, $textViewFieldReference
|
|
||||||
invoke-static {v0}, $INTEGRATIONS_CLASS_DESCRIPTOR->setShortsDislikes(Landroid/view/View;)Z
|
|
||||||
move-result v0
|
|
||||||
if-eqz v0, :ryd_disabled
|
|
||||||
return-void
|
|
||||||
|
|
||||||
:is_like
|
|
||||||
:ryd_disabled
|
|
||||||
nop
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} ?: throw ShortsTextViewFingerprint.exception
|
|
||||||
|
|
||||||
// endregion
|
|
||||||
|
|
||||||
// region Hook for litho Shorts
|
|
||||||
|
|
||||||
// Filter that parses the video id from the UI
|
|
||||||
LithoFilterPatch.addFilter(FILTER_CLASS_DESCRIPTOR)
|
|
||||||
|
|
||||||
// Player response video id is needed to search for the video ids in Shorts litho components.
|
|
||||||
VideoIdPatch.hookPlayerResponseVideoId("$FILTER_CLASS_DESCRIPTOR->newPlayerResponseVideoId(Ljava/lang/String;Z)V")
|
|
||||||
|
|
||||||
// endregion
|
|
||||||
|
|
||||||
// region Hook old UI layout dislikes, for the older app spoofs used with spoof-app-version.
|
|
||||||
|
|
||||||
DislikesOldLayoutTextViewFingerprint.result?.let {
|
|
||||||
it.mutableMethod.apply {
|
|
||||||
val startIndex = it.scanResult.patternScanResult!!.startIndex
|
|
||||||
|
|
||||||
val resourceIdentifierRegister = getInstruction<OneRegisterInstruction>(startIndex).registerA
|
|
||||||
val textViewRegister = getInstruction<OneRegisterInstruction>(startIndex + 4).registerA
|
|
||||||
|
|
||||||
addInstruction(
|
|
||||||
startIndex + 4,
|
|
||||||
"invoke-static {v$resourceIdentifierRegister, v$textViewRegister}, $INTEGRATIONS_CLASS_DESCRIPTOR->setOldUILayoutDislikes(ILandroid/widget/TextView;)V"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} ?: throw DislikesOldLayoutTextViewFingerprint.exception
|
|
||||||
|
|
||||||
// endregion
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun MethodFingerprint.toPatch(voteKind: Vote) = VotePatch(this, voteKind)
|
private fun MethodFingerprint.toPatch(voteKind: Vote) = VotePatch(this, voteKind)
|
||||||
|
@ -0,0 +1,18 @@
|
|||||||
|
package app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints
|
||||||
|
|
||||||
|
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||||
|
|
||||||
|
internal object ConversionContextFingerprint : MethodFingerprint(
|
||||||
|
returnType = "Ljava/lang/String;",
|
||||||
|
parameters = listOf(),
|
||||||
|
strings = listOf(
|
||||||
|
", widthConstraint=",
|
||||||
|
", heightConstraint=",
|
||||||
|
", templateLoggerFactory=",
|
||||||
|
", rootDisposableContainer=",
|
||||||
|
// 18.37.36 and after this String is: ConversionContext{containerInternal=
|
||||||
|
// and before it is: ConversionContext{container=
|
||||||
|
// Use a partial string to match both.
|
||||||
|
"ConversionContext{container"
|
||||||
|
)
|
||||||
|
)
|
@ -1,33 +0,0 @@
|
|||||||
package app.revanced.patches.youtube.layout.returnyoutubedislike.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
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Resolves against the same method that [TextComponentContextFingerprint] resolves to.
|
|
||||||
*/
|
|
||||||
internal object TextComponentAtomicReferenceFingerprint : MethodFingerprint(
|
|
||||||
returnType = "L",
|
|
||||||
accessFlags = AccessFlags.PROTECTED or AccessFlags.FINAL,
|
|
||||||
parameters = listOf("L"),
|
|
||||||
opcodes = listOf(
|
|
||||||
Opcode.MOVE_OBJECT, // Register B is free register
|
|
||||||
Opcode.MOVE_OBJECT_FROM16,
|
|
||||||
Opcode.MOVE_OBJECT_FROM16,
|
|
||||||
Opcode.MOVE_OBJECT_FROM16,
|
|
||||||
Opcode.MOVE_OBJECT_FROM16,
|
|
||||||
null,
|
|
||||||
Opcode.INVOKE_VIRTUAL, // Register C is atomic reference
|
|
||||||
Opcode.MOVE_RESULT_OBJECT, // Register A is char sequence
|
|
||||||
Opcode.CHECK_CAST,
|
|
||||||
Opcode.MOVE_OBJECT, // Replace this instruction with patch code
|
|
||||||
Opcode.INVOKE_INTERFACE,
|
|
||||||
Opcode.MOVE_RESULT,
|
|
||||||
Opcode.IF_EQZ,
|
|
||||||
Opcode.INVOKE_INTERFACE,
|
|
||||||
Opcode.MOVE_RESULT_OBJECT,
|
|
||||||
Opcode.GOTO
|
|
||||||
)
|
|
||||||
)
|
|
@ -1,6 +1,5 @@
|
|||||||
package app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints
|
package app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints
|
||||||
|
|
||||||
|
|
||||||
import app.revanced.patcher.extensions.or
|
import app.revanced.patcher.extensions.or
|
||||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||||
import com.android.tools.smali.dexlib2.AccessFlags
|
import com.android.tools.smali.dexlib2.AccessFlags
|
||||||
|
@ -1,27 +0,0 @@
|
|||||||
package app.revanced.patches.youtube.layout.returnyoutubedislike.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
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Resolves against the same class that [TextComponentConstructorFingerprint] resolves to.
|
|
||||||
*/
|
|
||||||
internal object TextComponentContextFingerprint : MethodFingerprint(
|
|
||||||
returnType = "L",
|
|
||||||
accessFlags = AccessFlags.PROTECTED or AccessFlags.FINAL,
|
|
||||||
parameters = listOf("L"),
|
|
||||||
opcodes = listOf(
|
|
||||||
Opcode.MOVE_OBJECT_FROM16,
|
|
||||||
Opcode.MOVE_OBJECT_FROM16,
|
|
||||||
Opcode.INVOKE_STATIC_RANGE,
|
|
||||||
Opcode.MOVE_RESULT_OBJECT,
|
|
||||||
Opcode.IGET_OBJECT,
|
|
||||||
Opcode.IGET_OBJECT,
|
|
||||||
Opcode.IGET_OBJECT,
|
|
||||||
Opcode.IGET_OBJECT,
|
|
||||||
Opcode.IGET_OBJECT,
|
|
||||||
Opcode.IGET_OBJECT, // conversion context field name
|
|
||||||
)
|
|
||||||
)
|
|
@ -0,0 +1,16 @@
|
|||||||
|
package app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints
|
||||||
|
|
||||||
|
import app.revanced.patcher.extensions.or
|
||||||
|
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||||
|
import com.android.tools.smali.dexlib2.AccessFlags
|
||||||
|
|
||||||
|
internal object TextComponentDataFingerprint : MethodFingerprint(
|
||||||
|
accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
|
||||||
|
parameters = listOf("L", "L"),
|
||||||
|
strings = listOf("text"),
|
||||||
|
customFingerprint = { _, classDef ->
|
||||||
|
val fields = classDef.fields
|
||||||
|
fields.find { it.type == "Ljava/util/BitSet;" } != null &&
|
||||||
|
fields.find { it.type == "[Ljava/lang/String;" } != null
|
||||||
|
}
|
||||||
|
)
|
@ -0,0 +1,15 @@
|
|||||||
|
package app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints
|
||||||
|
|
||||||
|
import app.revanced.patcher.extensions.or
|
||||||
|
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||||
|
import com.android.tools.smali.dexlib2.AccessFlags
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolves against the same class that [TextComponentConstructorFingerprint] resolves to.
|
||||||
|
*/
|
||||||
|
internal object TextComponentLookupFingerprint : MethodFingerprint(
|
||||||
|
returnType = "L",
|
||||||
|
accessFlags = AccessFlags.PROTECTED or AccessFlags.FINAL,
|
||||||
|
parameters = listOf("L"),
|
||||||
|
strings = listOf("…")
|
||||||
|
)
|
Loading…
x
Reference in New Issue
Block a user