From 8250e9e3cb5abf957c8de35efb431fc53beb4714 Mon Sep 17 00:00:00 2001 From: inotia00 Date: Wed, 22 Mar 2023 11:46:02 +0900 Subject: [PATCH] fix: app crashes on YT Music v5.49.54+ --- .../misc/litho/patch/MusicLithoFilterPatch.kt | 66 +++++++++++++- .../patch/litho/AbstractLithoFilterPatch.kt | 89 ------------------- .../misc/litho/patch/LithoFilterPatch.kt | 76 +++++++++++++++- 3 files changed, 134 insertions(+), 97 deletions(-) delete mode 100644 src/main/kotlin/app/revanced/patches/shared/patch/litho/AbstractLithoFilterPatch.kt diff --git a/src/main/kotlin/app/revanced/patches/music/misc/litho/patch/MusicLithoFilterPatch.kt b/src/main/kotlin/app/revanced/patches/music/misc/litho/patch/MusicLithoFilterPatch.kt index 2b694cc58..ec2a1ae9a 100644 --- a/src/main/kotlin/app/revanced/patches/music/misc/litho/patch/MusicLithoFilterPatch.kt +++ b/src/main/kotlin/app/revanced/patches/music/misc/litho/patch/MusicLithoFilterPatch.kt @@ -1,20 +1,78 @@ package app.revanced.patches.music.misc.litho.patch +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.annotation.YouTubeMusicCompatibility -import app.revanced.patches.shared.patch.litho.AbstractLithoFilterPatch +import app.revanced.patches.shared.fingerprints.LithoFingerprint 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.OneRegisterInstruction +import org.jf.dexlib2.iface.instruction.ReferenceInstruction +import org.jf.dexlib2.iface.instruction.TwoRegisterInstruction +import org.jf.dexlib2.iface.instruction.formats.Instruction31i +import org.jf.dexlib2.iface.reference.FieldReference +import org.jf.dexlib2.iface.reference.MethodReference @YouTubeMusicCompatibility @Version("0.0.1") -class MusicLithoFilterPatch : AbstractLithoFilterPatch( - "$ADS_PATH/MusicLithoFilterPatch;" +class MusicLithoFilterPatch : BytecodePatch( + listOf( + LithoFingerprint + ) ) { override fun execute(context: BytecodeContext): PatchResult { - super.execute(context) + LithoFingerprint.result?.let { result -> + val endIndex = result.scanResult.patternScanResult!!.endIndex + val method = result.mutableMethod + + with (method.implementation!!.instructions) { + val bufferIndex = indexOfFirst { + it.opcode == Opcode.CONST && + (it as Instruction31i).narrowLiteral == 168777401 + } + val bufferRegister = (method.instruction(bufferIndex) as Instruction31i).registerA + + 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 + + filter { instruction -> + val fieldReference = (instruction as? ReferenceInstruction)?.reference as? FieldReference + fieldReference?.let { it.type == "Ljava/lang/StringBuilder;" } == true + }.forEach { instruction -> + val insertIndex = indexOf(instruction) + val stringBuilderRegister = (method.instruction(insertIndex) as TwoRegisterInstruction).registerA + + method.addInstructions( + insertIndex, // right after setting the component.pathBuilder field, + """ + invoke-static {v$stringBuilderRegister, v$identifierRegister}, $ADS_PATH/MusicLithoFilterPatch;->filter(Ljava/lang/StringBuilder;Ljava/lang/String;)Z + move-result v$bufferRegister + if-eqz v$bufferRegister, :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() } diff --git a/src/main/kotlin/app/revanced/patches/shared/patch/litho/AbstractLithoFilterPatch.kt b/src/main/kotlin/app/revanced/patches/shared/patch/litho/AbstractLithoFilterPatch.kt deleted file mode 100644 index f9f30d90a..000000000 --- a/src/main/kotlin/app/revanced/patches/shared/patch/litho/AbstractLithoFilterPatch.kt +++ /dev/null @@ -1,89 +0,0 @@ -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 { - - 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 - } -} diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/litho/patch/LithoFilterPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/litho/patch/LithoFilterPatch.kt index be2c295ee..67cef7dee 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/litho/patch/LithoFilterPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/litho/patch/LithoFilterPatch.kt @@ -1,16 +1,30 @@ package app.revanced.patches.youtube.misc.litho.patch +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.patch.annotations.DependsOn +import app.revanced.patcher.util.smali.ExternalLabel import app.revanced.patches.shared.annotation.YouTubeCompatibility -import app.revanced.patches.shared.patch.litho.AbstractLithoFilterPatch +import app.revanced.patches.shared.fingerprints.LithoFingerprint +import app.revanced.patches.shared.fingerprints.LithoObjectFingerprint import app.revanced.patches.youtube.ads.doublebacktoclose.patch.DoubleBackToClosePatch 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 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 @DependsOn( [ @@ -20,14 +34,68 @@ import app.revanced.util.integrations.Constants.ADS_PATH ) @YouTubeCompatibility @Version("0.0.1") -class LithoFilterPatch : AbstractLithoFilterPatch( - "$ADS_PATH/LithoFilterPatch;" +class LithoFilterPatch : BytecodePatch( + listOf( + LithoFingerprint, + LithoObjectFingerprint + ) ) { override fun execute(context: BytecodeContext): PatchResult { - super.execute(context) + 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}, $ADS_PATH/LithoFilterPatch;->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() context.updatePatchStatus("ByteBuffer") return PatchResultSuccess() } + private companion object { + private var objectRegister: Int = 3 + } }