make litho patch to abstract patch

This commit is contained in:
inotia00
2023-02-27 22:49:47 +09:00
parent 5e289b7e1e
commit 60bcf6658a
9 changed files with 229 additions and 285 deletions

View File

@ -1,11 +1,16 @@
package app.revanced.patches.youtube.misc.litho.fingerprints package app.revanced.patches.shared.fingerprints
import app.revanced.patcher.extensions.or import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
object LithoFingerprint : MethodFingerprint( object LithoFingerprint : MethodFingerprint(
returnType = "L", returnType = "L",
access = AccessFlags.PUBLIC or AccessFlags.FINAL, access = AccessFlags.PUBLIC or AccessFlags.FINAL,
opcodes = listOf(
Opcode.INVOKE_VIRTUAL,
Opcode.IF_EQZ
),
strings = listOf("Element missing type extension") strings = listOf("Element missing type extension")
) )

View File

@ -0,0 +1,16 @@
package app.revanced.patches.shared.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 LithoObjectFingerprint : MethodFingerprint(
returnType = "L",
access = AccessFlags.PUBLIC or AccessFlags.FINAL,
opcodes = listOf(
Opcode.CONST_STRING,
Opcode.INVOKE_VIRTUAL
),
strings = listOf("Element missing type extension")
)

View File

@ -0,0 +1,93 @@
package app.revanced.patches.shared.patch.litho
import app.revanced.extensions.toErrorResult
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.instruction
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.util.smali.ExternalLabel
import app.revanced.patches.shared.fingerprints.LithoFingerprint
import app.revanced.patches.shared.fingerprints.LithoObjectFingerprint
import org.jf.dexlib2.Opcode
import org.jf.dexlib2.builder.instruction.BuilderInstruction21c
import org.jf.dexlib2.builder.instruction.BuilderInstruction35c
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
import org.jf.dexlib2.iface.instruction.TwoRegisterInstruction
import org.jf.dexlib2.iface.reference.FieldReference
import org.jf.dexlib2.iface.reference.MethodReference
@Version("0.0.1")
abstract class AbstractLithoFilterPatch(
private val descriptor: String
) : BytecodePatch(
listOf(
LithoFingerprint,
LithoObjectFingerprint
)
) {
override fun execute(context: BytecodeContext): PatchResult {
/*
* Compatible with both YouTube and YouTube Music
* But not yet implemented in Music integrations
*/
LithoObjectFingerprint.result?.let {
val endIndex = it.scanResult.patternScanResult!!.endIndex
objectRegister = (it.mutableMethod.instruction(endIndex) as BuilderInstruction35c).registerC
} ?: return LithoObjectFingerprint.toErrorResult()
LithoFingerprint.result?.let { result ->
val endIndex = result.scanResult.patternScanResult!!.endIndex
val method = result.mutableMethod
with (method.implementation!!.instructions) {
val targetIndex = indexOfFirst {
it.opcode == Opcode.CONST_STRING &&
(it as BuilderInstruction21c).reference.toString() == "Element missing type extension"
} + 2
val builderMethodDescriptor = (elementAt(targetIndex) as ReferenceInstruction).reference as MethodReference
val emptyComponentFieldDescriptor = (elementAt(targetIndex + 2) as ReferenceInstruction).reference as FieldReference
val identifierRegister = (method.instruction(endIndex) as OneRegisterInstruction).registerA
val bytebufferRegister = method.implementation!!.registerCount - method.parameters.size + 2
val secondParameter = method.parameters[2]
filter { instruction ->
val fieldReference = (instruction as? ReferenceInstruction)?.reference as? FieldReference
fieldReference?.let { it.type == "Ljava/lang/StringBuilder;" } == true
}.forEach { instruction ->
val insertIndex = indexOf(instruction) + 1
val stringBuilderRegister = (method.instruction(insertIndex) as OneRegisterInstruction).registerA
val clobberedRegister = (method.instruction(insertIndex + 1) as TwoRegisterInstruction).registerA
method.addInstructions(
insertIndex, // right after setting the component.pathBuilder field,
"""
move-object/from16 v$clobberedRegister, v$bytebufferRegister
iget-object v$clobberedRegister, v$clobberedRegister, $secondParameter->b:Ljava/nio/ByteBuffer;
invoke-static {v$stringBuilderRegister, v$identifierRegister, v$objectRegister, v$clobberedRegister}, $descriptor->filter(Ljava/lang/StringBuilder;Ljava/lang/String;Ljava/lang/Object;Ljava/nio/ByteBuffer;)Z
move-result v$clobberedRegister
if-eqz v$clobberedRegister, :not_an_ad
move-object/from16 v$identifierRegister, p1
invoke-static {v$identifierRegister}, $builderMethodDescriptor
move-result-object v0
iget-object v0, v0, $emptyComponentFieldDescriptor
return-object v0
""",listOf(ExternalLabel("not_an_ad", method.instruction(insertIndex)))
)
}
}
} ?: return LithoFingerprint.toErrorResult()
return PatchResultSuccess()
}
private companion object {
private var objectRegister: Int = 3
}
}

View File

@ -1,20 +0,0 @@
package app.revanced.patches.youtube.ads.general.bytecode.fingerprints
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import org.jf.dexlib2.Opcode
object ComponentContextParserFingerprint : MethodFingerprint(
opcodes = listOf(
Opcode.INVOKE_INTERFACE,
Opcode.MOVE_RESULT_OBJECT,
Opcode.CHECK_CAST,
Opcode.INVOKE_VIRTUAL,
Opcode.GOTO,
Opcode.INVOKE_VIRTUAL,
Opcode.CONST_16,
Opcode.INVOKE_VIRTUAL,
Opcode.IPUT_OBJECT,
Opcode.NEW_INSTANCE
),
strings = listOf("LoggingProperties are not in proto format")
)

View File

@ -1,10 +0,0 @@
package app.revanced.patches.youtube.ads.general.bytecode.fingerprints
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import org.jf.dexlib2.Opcode
object EmptyComponentBuilderFingerprint : MethodFingerprint(
opcodes = listOf(
Opcode.INVOKE_STATIC_RANGE
),
)

View File

@ -1,98 +1,142 @@
package app.revanced.patches.youtube.ads.general.bytecode.patch package app.revanced.patches.youtube.ads.general.bytecode.patch
import app.revanced.extensions.toErrorResult import app.revanced.extensions.findMutableMethodOf
import app.revanced.extensions.injectHideCall
import app.revanced.extensions.toResult
import app.revanced.patcher.annotation.Name import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.addInstructions import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.instruction import app.revanced.patcher.extensions.instruction
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve
import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultError
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.DependsOn import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
import app.revanced.patcher.util.smali.ExternalLabel import app.revanced.patcher.util.smali.ExternalLabel
import app.revanced.patches.shared.annotation.YouTubeCompatibility import app.revanced.patches.shared.annotation.YouTubeCompatibility
import app.revanced.patches.shared.patch.mapping.ResourceMappingPatch import app.revanced.patches.shared.patch.mapping.ResourceMappingPatch
import app.revanced.patches.youtube.ads.general.bytecode.fingerprints.ComponentContextParserFingerprint
import app.revanced.patches.youtube.ads.general.bytecode.fingerprints.EmptyComponentBuilderFingerprint
import app.revanced.util.bytecode.BytecodeHelper.updatePatchStatus import app.revanced.util.bytecode.BytecodeHelper.updatePatchStatus
import app.revanced.util.integrations.Constants.ADS_PATH import app.revanced.util.integrations.Constants.ADS_PATH
import org.jf.dexlib2.Opcode import org.jf.dexlib2.Opcode
import org.jf.dexlib2.builder.instruction.BuilderInstruction21s import org.jf.dexlib2.iface.instruction.formats.*
import org.jf.dexlib2.iface.instruction.Instruction
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
import org.jf.dexlib2.iface.instruction.formats.Instruction31i
import org.jf.dexlib2.iface.reference.FieldReference
import org.jf.dexlib2.iface.reference.MethodReference
@DependsOn([ResourceMappingPatch::class])
@Name("hide-general-ads-bytecode-patch") @Name("hide-general-ads-bytecode-patch")
@DependsOn([ResourceMappingPatch::class])
@YouTubeCompatibility @YouTubeCompatibility
@Version("0.0.1") @Version("0.0.1")
class GeneralAdsBytecodePatch : BytecodePatch( class GeneralAdsBytecodePatch : BytecodePatch() {
listOf(ComponentContextParserFingerprint) private val resourceIds = arrayOf(
) { "id" to "ad_attribution",
"layout" to "horizontal_card_list",
"layout" to "album_card",
"id" to "reel_player_badge",
"id" to "reel_player_badge2",
"id" to "reel_player_info_panel"
).map { (type, name) ->
ResourceMappingPatch
.resourceMappings
.single { it.type == type && it.name == name }.id
}
private var patchSuccessArray = Array(resourceIds.size) {false}
override fun execute(context: BytecodeContext): PatchResult { override fun execute(context: BytecodeContext): PatchResult {
ComponentContextParserFingerprint.result?.let { result -> context.classes.forEach { classDef ->
val builderMethodIndex = EmptyComponentBuilderFingerprint classDef.methods.forEach { method ->
.also { it.resolve(context, result.mutableMethod, result.mutableClass) } with(method.implementation) {
.let { it.result?.scanResult?.patternScanResult?.startIndex?: return EmptyComponentBuilderFingerprint.toErrorResult() } this?.instructions?.forEachIndexed { index, instruction ->
when (instruction.opcode) {
Opcode.CONST -> {
when ((instruction as Instruction31i).wideLiteral) {
resourceIds[0] -> { // general ads
val insertIndex = index + 1
val invokeInstruction = instructions.elementAt(insertIndex)
if (invokeInstruction.opcode != Opcode.INVOKE_VIRTUAL) return@forEachIndexed
val emptyComponentFieldIndex = builderMethodIndex + 2 val mutableMethod = context.proxy(classDef).mutableClass.findMutableMethodOf(method)
with(result.mutableMethod) { val viewRegister = (invokeInstruction as Instruction35c).registerC
val insertHookIndex = implementation!!.instructions.indexOfFirst { mutableMethod.implementation!!.injectHideCall(insertIndex, viewRegister, "ads/GeneralAdsPatch", "hideAdAttributionView")
it.opcode == Opcode.CONST_16 && patchSuccessArray[0] = true;
(it as BuilderInstruction21s).narrowLiteral == 124 }
} + 3
val stringBuilderRegister = (instruction(insertHookIndex) as OneRegisterInstruction).registerA resourceIds[1] -> { // breaking news
val clobberedRegister = (instruction(insertHookIndex - 3) as OneRegisterInstruction).registerA val insertIndex = index + 4
val invokeInstruction = instructions.elementAt(insertIndex)
if (invokeInstruction.opcode != Opcode.CHECK_CAST) return@forEachIndexed
val bufferIndex = implementation!!.instructions.indexOfFirst { val mutableMethod = context.proxy(classDef).mutableClass.findMutableMethodOf(method)
it.opcode == Opcode.CONST &&
(it as Instruction31i).narrowLiteral == 183314536
} - 1
val bufferRegister = (instruction(bufferIndex) as OneRegisterInstruction).registerA val viewRegister = (invokeInstruction as Instruction21c).registerA
mutableMethod.implementation!!.injectHideCall(insertIndex, viewRegister, "ads/GeneralAdsPatch", "hideBreakingNewsShelf")
patchSuccessArray[1] = true;
}
val builderMethodDescriptor = instruction(builderMethodIndex).toDescriptor() resourceIds[2] -> { // album cards
val emptyComponentFieldDescriptor = instruction(emptyComponentFieldIndex).toDescriptor() val insertIndex = index + 4
val invokeInstruction = instructions.elementAt(insertIndex)
if (invokeInstruction.opcode != Opcode.CHECK_CAST) return@forEachIndexed
addInstructions( val mutableMethod = context.proxy(classDef).mutableClass.findMutableMethodOf(method)
insertHookIndex, // right after setting the component.pathBuilder field,
""" val viewRegister = (invokeInstruction as Instruction21c).registerA
invoke-static {v$stringBuilderRegister, v$bufferRegister}, $ADS_PATH/LithoFilterPatch;->filter(Ljava/lang/StringBuilder;Ljava/lang/String;)Z mutableMethod.implementation!!.injectHideCall(insertIndex, viewRegister, "ads/GeneralAdsPatch", "hideAlbumCards")
move-result v$clobberedRegister patchSuccessArray[2] = true;
if-eqz v$clobberedRegister, :not_an_ad }
move-object/from16 v$bufferRegister, p1
invoke-static {v$bufferRegister}, $builderMethodDescriptor resourceIds[3], resourceIds[4] -> { // paid content banner
move-result-object v0 val insertIndex = index + 3
iget-object v0, v0, $emptyComponentFieldDescriptor val invokeInstruction = instructions.elementAt(insertIndex)
return-object v0 if (invokeInstruction.opcode != Opcode.CHECK_CAST) return@forEachIndexed
""",
listOf(ExternalLabel("not_an_ad", instruction(insertHookIndex))) val mutableMethod = context.proxy(classDef).mutableClass.findMutableMethodOf(method)
) val dummyRegister = (instructions.elementAt(index) as Instruction31i).registerA
val viewRegister = (invokeInstruction as Instruction21c).registerA
mutableMethod.addInjectCall(insertIndex, dummyRegister, viewRegister, "hidePaidContentBanner")
patchSuccessArray[3] = true;
patchSuccessArray[4] = true;
}
resourceIds[5] -> { // info panel
val insertIndex = index + 3
val invokeInstruction = instructions.elementAt(insertIndex)
if (invokeInstruction.opcode != Opcode.CHECK_CAST) return@forEachIndexed
val mutableMethod = context.proxy(classDef).mutableClass.findMutableMethodOf(method)
val dummyRegister = (instructions.elementAt(index) as Instruction31i).registerA
val viewRegister = (invokeInstruction as Instruction21c).registerA
mutableMethod.addInjectCall(insertIndex + 7, dummyRegister, viewRegister, "hideInfoPanel")
patchSuccessArray[5] = true;
}
}
}
else -> return@forEachIndexed
}
}
}
} }
} ?: return ComponentContextParserFingerprint.toErrorResult() }
context.updatePatchStatus("GeneralAds") context.updatePatchStatus("GeneralAds")
return PatchResultSuccess() return toResult(patchSuccessArray.indexOf(false))
} }
private companion object { private fun MutableMethod.addInjectCall(
fun Instruction.toDescriptor() = when (val reference = (this as? ReferenceInstruction)?.reference) { index: Int,
is MethodReference -> "${reference.definingClass}->${reference.name}(${ dummyRegister: Int,
reference.parameterTypes.joinToString( viewRegister: Int,
"" method: String
) { it } ) {
})${reference.returnType}" addInstructions(
is FieldReference -> "${reference.definingClass}->${reference.name}:${reference.type}" index + 1, """
else -> throw PatchResultError("Unsupported reference type") invoke-static {}, $ADS_PATH/GeneralAdsPatch;->$method()Z
} move-result v$dummyRegister
if-eqz v$dummyRegister, :shown
const v$viewRegister, 0x0
""", listOf(ExternalLabel("shown", this.instruction(index + 1)))
)
} }
} }

View File

@ -1,139 +0,0 @@
package app.revanced.patches.youtube.ads.general.bytecode.patch
import app.revanced.extensions.findMutableMethodOf
import app.revanced.extensions.injectHideCall
import app.revanced.extensions.toResult
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.instruction
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
import app.revanced.patcher.util.smali.ExternalLabel
import app.revanced.patches.shared.annotation.YouTubeCompatibility
import app.revanced.patches.shared.patch.mapping.ResourceMappingPatch
import app.revanced.util.integrations.Constants.ADS_PATH
import org.jf.dexlib2.Opcode
import org.jf.dexlib2.iface.instruction.formats.*
@Name("hide-general-ads-secondary-bytecode-patch")
@DependsOn([ResourceMappingPatch::class])
@YouTubeCompatibility
@Version("0.0.1")
class GeneralAdsSecondaryBytecodePatch : BytecodePatch() {
private val resourceIds = arrayOf(
"id" to "ad_attribution",
"layout" to "horizontal_card_list",
"layout" to "album_card",
"id" to "reel_player_badge",
"id" to "reel_player_badge2",
"id" to "reel_player_info_panel"
).map { (type, name) ->
ResourceMappingPatch
.resourceMappings
.single { it.type == type && it.name == name }.id
}
private var patchSuccessArray = Array(resourceIds.size) {false}
override fun execute(context: BytecodeContext): PatchResult {
context.classes.forEach { classDef ->
classDef.methods.forEach { method ->
with(method.implementation) {
this?.instructions?.forEachIndexed { index, instruction ->
when (instruction.opcode) {
Opcode.CONST -> {
when ((instruction as Instruction31i).wideLiteral) {
resourceIds[0] -> { // general ads
val insertIndex = index + 1
val invokeInstruction = instructions.elementAt(insertIndex)
if (invokeInstruction.opcode != Opcode.INVOKE_VIRTUAL) return@forEachIndexed
val mutableMethod = context.proxy(classDef).mutableClass.findMutableMethodOf(method)
val viewRegister = (invokeInstruction as Instruction35c).registerC
mutableMethod.implementation!!.injectHideCall(insertIndex, viewRegister, "ads/GeneralAdsPatch", "hideAdAttributionView")
patchSuccessArray[0] = true;
}
resourceIds[1] -> { // breaking news
val insertIndex = index + 4
val invokeInstruction = instructions.elementAt(insertIndex)
if (invokeInstruction.opcode != Opcode.CHECK_CAST) return@forEachIndexed
val mutableMethod = context.proxy(classDef).mutableClass.findMutableMethodOf(method)
val viewRegister = (invokeInstruction as Instruction21c).registerA
mutableMethod.implementation!!.injectHideCall(insertIndex, viewRegister, "ads/GeneralAdsPatch", "hideBreakingNewsShelf")
patchSuccessArray[1] = true;
}
resourceIds[2] -> { // album cards
val insertIndex = index + 4
val invokeInstruction = instructions.elementAt(insertIndex)
if (invokeInstruction.opcode != Opcode.CHECK_CAST) return@forEachIndexed
val mutableMethod = context.proxy(classDef).mutableClass.findMutableMethodOf(method)
val viewRegister = (invokeInstruction as Instruction21c).registerA
mutableMethod.implementation!!.injectHideCall(insertIndex, viewRegister, "ads/GeneralAdsPatch", "hideAlbumCards")
patchSuccessArray[2] = true;
}
resourceIds[3], resourceIds[4] -> { // paid content banner
val insertIndex = index + 3
val invokeInstruction = instructions.elementAt(insertIndex)
if (invokeInstruction.opcode != Opcode.CHECK_CAST) return@forEachIndexed
val mutableMethod = context.proxy(classDef).mutableClass.findMutableMethodOf(method)
val dummyRegister = (instructions.elementAt(index) as Instruction31i).registerA
val viewRegister = (invokeInstruction as Instruction21c).registerA
mutableMethod.addInjectCall(insertIndex, dummyRegister, viewRegister, "hidePaidContentBanner")
patchSuccessArray[3] = true;
patchSuccessArray[4] = true;
}
resourceIds[5] -> { // info panel
val insertIndex = index + 3
val invokeInstruction = instructions.elementAt(insertIndex)
if (invokeInstruction.opcode != Opcode.CHECK_CAST) return@forEachIndexed
val mutableMethod = context.proxy(classDef).mutableClass.findMutableMethodOf(method)
val dummyRegister = (instructions.elementAt(index) as Instruction31i).registerA
val viewRegister = (invokeInstruction as Instruction21c).registerA
mutableMethod.addInjectCall(insertIndex + 7, dummyRegister, viewRegister, "hideInfoPanel")
patchSuccessArray[5] = true;
}
}
}
else -> return@forEachIndexed
}
}
}
}
}
return toResult(patchSuccessArray.indexOf(false))
}
private fun MutableMethod.addInjectCall(
index: Int,
dummyRegister: Int,
viewRegister: Int,
method: String
) {
addInstructions(
index + 1, """
invoke-static {}, $ADS_PATH/GeneralAdsPatch;->$method()Z
move-result v$dummyRegister
if-eqz v$dummyRegister, :shown
const v$viewRegister, 0x0
""", listOf(ExternalLabel("shown", this.instruction(index + 1)))
)
}
}

View File

@ -13,7 +13,6 @@ import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.patch.annotations.Patch import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patches.shared.annotation.YouTubeCompatibility import app.revanced.patches.shared.annotation.YouTubeCompatibility
import app.revanced.patches.youtube.ads.general.bytecode.patch.GeneralAdsBytecodePatch import app.revanced.patches.youtube.ads.general.bytecode.patch.GeneralAdsBytecodePatch
import app.revanced.patches.youtube.ads.general.bytecode.patch.GeneralAdsSecondaryBytecodePatch
import app.revanced.patches.youtube.misc.litho.patch.LithoFilterPatch import app.revanced.patches.youtube.misc.litho.patch.LithoFilterPatch
import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch
import org.w3c.dom.Element import org.w3c.dom.Element
@ -24,7 +23,6 @@ import org.w3c.dom.Element
@DependsOn( @DependsOn(
[ [
GeneralAdsBytecodePatch::class, GeneralAdsBytecodePatch::class,
GeneralAdsSecondaryBytecodePatch::class,
LithoFilterPatch::class, LithoFilterPatch::class,
SettingsPatch::class SettingsPatch::class
] ]

View File

@ -1,25 +1,16 @@
package app.revanced.patches.youtube.misc.litho.patch package app.revanced.patches.youtube.misc.litho.patch
import app.revanced.extensions.toErrorResult
import app.revanced.patcher.annotation.Version import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.instruction
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.DependsOn import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.util.smali.ExternalLabel
import app.revanced.patches.shared.annotation.YouTubeCompatibility import app.revanced.patches.shared.annotation.YouTubeCompatibility
import app.revanced.patches.shared.patch.litho.AbstractLithoFilterPatch
import app.revanced.patches.youtube.ads.doublebacktoclose.patch.DoubleBackToClosePatch import app.revanced.patches.youtube.ads.doublebacktoclose.patch.DoubleBackToClosePatch
import app.revanced.patches.youtube.misc.litho.fingerprints.LithoFingerprint
import app.revanced.patches.youtube.ads.swiperefresh.patch.SwipeRefreshPatch import app.revanced.patches.youtube.ads.swiperefresh.patch.SwipeRefreshPatch
import app.revanced.util.bytecode.BytecodeHelper.updatePatchStatus
import app.revanced.util.integrations.Constants.ADS_PATH import app.revanced.util.integrations.Constants.ADS_PATH
import org.jf.dexlib2.Opcode
import org.jf.dexlib2.builder.instruction.BuilderInstruction21c
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
import org.jf.dexlib2.iface.reference.FieldReference
import org.jf.dexlib2.iface.reference.MethodReference
@DependsOn( @DependsOn(
[ [
@ -29,47 +20,13 @@ import org.jf.dexlib2.iface.reference.MethodReference
) )
@YouTubeCompatibility @YouTubeCompatibility
@Version("0.0.1") @Version("0.0.1")
class LithoFilterPatch : BytecodePatch( class LithoFilterPatch : AbstractLithoFilterPatch(
listOf( "$ADS_PATH/LithoFilterPatch;"
LithoFingerprint ) {
)
)
{
override fun execute(context: BytecodeContext): PatchResult { override fun execute(context: BytecodeContext): PatchResult {
super.execute(context)
LithoFingerprint.result?.mutableMethod?.let { context.updatePatchStatus("ByteBuffer")
val implementations = it.implementation!!
val instructions = implementations.instructions
val parameter = it.parameters[2]
val stringRegister = implementations.registerCount - it.parameters.size + 1
val dummyRegister = stringRegister + 1
val lithoIndex = instructions.indexOfFirst { instruction->
instruction.opcode == Opcode.CONST_STRING &&
(instruction as BuilderInstruction21c).reference.toString() == "Element missing type extension"
} + 2
val firstReference = (instructions.elementAt(lithoIndex) as ReferenceInstruction).reference as MethodReference
val secondReference = (instructions.elementAt(lithoIndex + 2) as ReferenceInstruction).reference as FieldReference
it.addInstructions(
0, """
move-object/from16 v1, v$stringRegister
invoke-virtual {v1}, Ljava/lang/Object;->toString()Ljava/lang/String;
move-result-object v1
move-object/from16 v2, v$dummyRegister
iget-object v2, v2, $parameter->b:Ljava/nio/ByteBuffer;
invoke-static {v1, v2}, $ADS_PATH/ExtendedLithoFilterPatch;->InflatedLithoView(Ljava/lang/String;Ljava/nio/ByteBuffer;)Z
move-result v3
if-eqz v3, :do_not_block
move-object/from16 v0, p1
invoke-static {v0}, $firstReference
move-result-object v0
iget-object v0, v0, ${secondReference.definingClass}->${secondReference.name}:${secondReference.type}
return-object v0
""", listOf(ExternalLabel("do_not_block", it.instruction(0)))
)
} ?: return LithoFingerprint.toErrorResult()
return PatchResultSuccess() return PatchResultSuccess()
} }