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,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
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.Version
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.addInstructions
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.PatchResult
import app.revanced.patcher.patch.PatchResultError
import app.revanced.patcher.patch.PatchResultSuccess
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.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.integrations.Constants.ADS_PATH
import org.jf.dexlib2.Opcode
import org.jf.dexlib2.builder.instruction.BuilderInstruction21s
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
import org.jf.dexlib2.iface.instruction.formats.*
@DependsOn([ResourceMappingPatch::class])
@Name("hide-general-ads-bytecode-patch")
@DependsOn([ResourceMappingPatch::class])
@YouTubeCompatibility
@Version("0.0.1")
class GeneralAdsBytecodePatch : BytecodePatch(
listOf(ComponentContextParserFingerprint)
) {
class GeneralAdsBytecodePatch : 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 {
ComponentContextParserFingerprint.result?.let { result ->
val builderMethodIndex = EmptyComponentBuilderFingerprint
.also { it.resolve(context, result.mutableMethod, result.mutableClass) }
.let { it.result?.scanResult?.patternScanResult?.startIndex?: return EmptyComponentBuilderFingerprint.toErrorResult() }
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 emptyComponentFieldIndex = builderMethodIndex + 2
val mutableMethod = context.proxy(classDef).mutableClass.findMutableMethodOf(method)
with(result.mutableMethod) {
val insertHookIndex = implementation!!.instructions.indexOfFirst {
it.opcode == Opcode.CONST_16 &&
(it as BuilderInstruction21s).narrowLiteral == 124
} + 3
val viewRegister = (invokeInstruction as Instruction35c).registerC
mutableMethod.implementation!!.injectHideCall(insertIndex, viewRegister, "ads/GeneralAdsPatch", "hideAdAttributionView")
patchSuccessArray[0] = true;
}
val stringBuilderRegister = (instruction(insertHookIndex) as OneRegisterInstruction).registerA
val clobberedRegister = (instruction(insertHookIndex - 3) as OneRegisterInstruction).registerA
resourceIds[1] -> { // breaking news
val insertIndex = index + 4
val invokeInstruction = instructions.elementAt(insertIndex)
if (invokeInstruction.opcode != Opcode.CHECK_CAST) return@forEachIndexed
val bufferIndex = implementation!!.instructions.indexOfFirst {
it.opcode == Opcode.CONST &&
(it as Instruction31i).narrowLiteral == 183314536
} - 1
val mutableMethod = context.proxy(classDef).mutableClass.findMutableMethodOf(method)
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()
val emptyComponentFieldDescriptor = instruction(emptyComponentFieldIndex).toDescriptor()
resourceIds[2] -> { // album cards
val insertIndex = index + 4
val invokeInstruction = instructions.elementAt(insertIndex)
if (invokeInstruction.opcode != Opcode.CHECK_CAST) return@forEachIndexed
addInstructions(
insertHookIndex, // right after setting the component.pathBuilder field,
"""
invoke-static {v$stringBuilderRegister, v$bufferRegister}, $ADS_PATH/LithoFilterPatch;->filter(Ljava/lang/StringBuilder;Ljava/lang/String;)Z
move-result v$clobberedRegister
if-eqz v$clobberedRegister, :not_an_ad
move-object/from16 v$bufferRegister, p1
invoke-static {v$bufferRegister}, $builderMethodDescriptor
move-result-object v0
iget-object v0, v0, $emptyComponentFieldDescriptor
return-object v0
""",
listOf(ExternalLabel("not_an_ad", instruction(insertHookIndex)))
)
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 ComponentContextParserFingerprint.toErrorResult()
}
context.updatePatchStatus("GeneralAds")
return PatchResultSuccess()
return toResult(patchSuccessArray.indexOf(false))
}
private companion object {
fun Instruction.toDescriptor() = when (val reference = (this as? ReferenceInstruction)?.reference) {
is MethodReference -> "${reference.definingClass}->${reference.name}(${
reference.parameterTypes.joinToString(
""
) { it }
})${reference.returnType}"
is FieldReference -> "${reference.definingClass}->${reference.name}:${reference.type}"
else -> throw PatchResultError("Unsupported reference type")
}
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

@ -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.patches.shared.annotation.YouTubeCompatibility
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.settings.resource.patch.SettingsPatch
import org.w3c.dom.Element
@ -24,7 +23,6 @@ import org.w3c.dom.Element
@DependsOn(
[
GeneralAdsBytecodePatch::class,
GeneralAdsSecondaryBytecodePatch::class,
LithoFilterPatch::class,
SettingsPatch::class
]