From e088c671081bcf75586ccc1c4bdbed9366e93874 Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Thu, 7 Apr 2022 22:41:55 +0200 Subject: [PATCH] feat: migrate to dalvik patches --- build.gradle.kts | 6 +- .../app/revanced/patches/ad/VideoAds.kt | 35 +++--- .../interaction/EnableSeekbarTapping.kt | 114 ++++++++++++------ .../patches/layout/CreateButtonRemover.kt | 23 +--- .../app/revanced/patches/layout/HideReels.kt | 21 ++-- .../patches/layout/HideSuggestions.kt | 57 ++++----- .../patches/layout/MinimizedPlayback.kt | 12 +- .../patches/layout/OldQualityLayout.kt | 57 +++++---- 8 files changed, 175 insertions(+), 150 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 6ecf2d4f..0aecbd1f 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -24,12 +24,8 @@ repositories { dependencies { implementation("org.jetbrains.kotlin:kotlin-stdlib:1.6.10") - implementation("org.ow2.asm:asm:9.2") - implementation("org.ow2.asm:asm-util:9.2") - implementation("org.ow2.asm:asm-tree:9.2") - implementation("org.ow2.asm:asm-commons:9.2") - implementation("app.revanced:revanced-patcher:1.+") // use latest version. + implementation("org.smali:dexlib2:2.5.2") } java { diff --git a/src/main/kotlin/app/revanced/patches/ad/VideoAds.kt b/src/main/kotlin/app/revanced/patches/ad/VideoAds.kt index 42ac26f4..84c1997c 100644 --- a/src/main/kotlin/app/revanced/patches/ad/VideoAds.kt +++ b/src/main/kotlin/app/revanced/patches/ad/VideoAds.kt @@ -1,36 +1,35 @@ package app.revanced.patches.ad import app.revanced.patcher.cache.Cache +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.extensions.or import app.revanced.patcher.patch.Patch import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResultError import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.signature.Signature -import app.revanced.patcher.writer.ASMWriter.insertAt -import org.objectweb.asm.Opcodes -import org.objectweb.asm.Type -import org.objectweb.asm.tree.MethodInsnNode +import app.revanced.patcher.signature.MethodSignature +import app.revanced.patcher.smali.asInstructions +import org.jf.dexlib2.AccessFlags class VideoAds : Patch("VideoAds") { override fun execute(cache: Cache): PatchResult { - val showVideoAdsMethodData = cache.methods["show-video-ads"].findParentMethod( - Signature( - "method", - Type.VOID_TYPE, - Opcodes.ACC_PUBLIC or Opcodes.ACC_FINAL, - arrayOf(Type.BOOLEAN_TYPE), + val map = cache.methodMap["show-video-ads-constructor"].findParentMethod( + MethodSignature( + "show-video-ads-method", + "V", + AccessFlags.PUBLIC or AccessFlags.FINAL, + setOf("Z"), null ) ) ?: return PatchResultError("Could not find required method to patch") - showVideoAdsMethodData.method.instructions.insertAt( + // Override the parameter by calling shouldShowAds and setting the parameter to the result + map.resolveAndGetMethod().implementation!!.addInstructions( 0, - MethodInsnNode( - Opcodes.INVOKESTATIC, - "fi/vanced/libraries/youtube/whitelisting/Whitelist", - "shouldShowAds", - Type.getMethodDescriptor(Type.BOOLEAN_TYPE) - ) + """ + invoke-static { }, Lfi/vanced/libraries/youtube/whitelisting/Whitelist;->shouldShowAds()Z + move-result v0 + """.trimIndent().asInstructions() ) return PatchResultSuccess() diff --git a/src/main/kotlin/app/revanced/patches/interaction/EnableSeekbarTapping.kt b/src/main/kotlin/app/revanced/patches/interaction/EnableSeekbarTapping.kt index 7262dbb3..bdc77531 100644 --- a/src/main/kotlin/app/revanced/patches/interaction/EnableSeekbarTapping.kt +++ b/src/main/kotlin/app/revanced/patches/interaction/EnableSeekbarTapping.kt @@ -1,49 +1,95 @@ package app.revanced.patches.interaction import app.revanced.patcher.cache.Cache +import app.revanced.patcher.extensions.addInstructions import app.revanced.patcher.patch.Patch import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.writer.ASMWriter.insertAt -import org.objectweb.asm.Opcodes -import org.objectweb.asm.tree.* +import app.revanced.patcher.smali.asInstructions +import org.jf.dexlib2.Opcode +import org.jf.dexlib2.builder.instruction.BuilderInstruction11n +import org.jf.dexlib2.builder.instruction.BuilderInstruction21t +import org.jf.dexlib2.builder.instruction.BuilderInstruction35c +import org.jf.dexlib2.iface.Method +import org.jf.dexlib2.immutable.reference.ImmutableMethodReference class EnableSeekbarTapping : Patch("enable-seekbar-tapping") { override fun execute(cache: Cache): PatchResult { - val patchData = cache.methods["enable-seekbar-tapping"] - val methodOPatchData = cache.methods["enable-seekbar-tapping-method-o"] - val methodPPatchData = cache.methods["enable-seekbar-tapping-method-p"] + val map = cache.methodMap["tap-seekbar-parent-method"] - val elseLabel = LabelNode() - patchData.method.instructions.insertAt( - patchData.scanData.endIndex, - InsnNode(Opcodes.ACONST_NULL), - MethodInsnNode( - Opcodes.INVOKESTATIC, - "fi/razerman/youtube/preferences/BooleanPreferences", - "isTapSeekingEnabled", - "()Z" - ), - JumpInsnNode(Opcodes.IFEQ, elseLabel), - VarInsnNode(Opcodes.ALOAD, 0), - VarInsnNode(Opcodes.ILOAD, 6), - MethodInsnNode( - Opcodes.INVOKEVIRTUAL, - methodOPatchData.declaringClass.name, - methodOPatchData.method.name, - "(I)V" - ), - VarInsnNode(Opcodes.ALOAD, 0), - VarInsnNode(Opcodes.ILOAD, 6), - MethodInsnNode( - Opcodes.INVOKEVIRTUAL, - methodPPatchData.declaringClass.name, - methodPPatchData.method.name, - "(I)V" - ), - elseLabel + val tapSeekMethods = mutableMapOf() + + // find the methods which tap the seekbar + map.definingClassProxy.immutableClass.methods.forEach { + val instructions = it.implementation!!.instructions + // here we make sure we actually find the method because it has more then 7 instructions + if (instructions.count() < 7) return@forEach + + // we know that the 7th instruction has the opcode CONST_4 + val instruction = instructions.elementAt(6) + if (instruction.opcode != Opcode.CONST_4) return@forEach + + // the literal for this instruction has to be either 1 or 2 + val literal = (instruction as BuilderInstruction11n).narrowLiteral + + // method founds + if (literal == 1) tapSeekMethods["P"] = it + if (literal == 2) tapSeekMethods["O"] = it + } + val implementation = cache.methodMap["enable-seekbar-tapping"].resolveAndGetMethod().implementation!! + + // if tap-seeking is enabled, do not invoke the two methods below + val pMethod = tapSeekMethods["P"]!! + val oMethod = tapSeekMethods["O"]!! + implementation.addInstructions( + map.scanData.endIndex, + listOf( + BuilderInstruction35c( + Opcode.INVOKE_VIRTUAL, + 0, + 3, + 0, + 0, + 0, + 0, + ImmutableMethodReference( + oMethod.definingClass, + oMethod.name, + setOf("I"), + "V" + ) + ), + BuilderInstruction35c( + Opcode.INVOKE_VIRTUAL, + 0, + 3, + 0, + 0, + 0, + 0, + ImmutableMethodReference( + pMethod.definingClass, + pMethod.name, + setOf("I"), + "V" + ) + ) + ) ) + // if tap-seeking is disabled, do not invoke the two methods above by jumping to the else label + val elseLabel = implementation.instructions[7].location.labels.first() + implementation.addInstruction( + map.scanData.endIndex, + BuilderInstruction21t(Opcode.IF_EQZ, 0, elseLabel) + ) + implementation.addInstructions( + map.scanData.endIndex, + """ + invoke-static { }, Lfi/razerman/youtube/preferences/BooleanPreferences;->isTapSeekingEnabled()Z + move-result v0 + """.trimIndent().asInstructions() + ) return PatchResultSuccess() } } \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/layout/CreateButtonRemover.kt b/src/main/kotlin/app/revanced/patches/layout/CreateButtonRemover.kt index 92c50000..51f6f012 100644 --- a/src/main/kotlin/app/revanced/patches/layout/CreateButtonRemover.kt +++ b/src/main/kotlin/app/revanced/patches/layout/CreateButtonRemover.kt @@ -4,27 +4,16 @@ import app.revanced.patcher.cache.Cache import app.revanced.patcher.patch.Patch import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.writer.ASMWriter.insertAt -import org.objectweb.asm.Opcodes -import org.objectweb.asm.tree.MethodInsnNode -import org.objectweb.asm.tree.VarInsnNode +import app.revanced.patcher.smali.asInstruction class CreateButtonRemover : Patch("create-button-remover") { override fun execute(cache: Cache): PatchResult { - val patchData = cache.methods["create-button-patch"] + val map = cache.methodMap["create-button-patch"] - patchData.method.instructions.insertAt( - patchData.scanData.endIndex - 1, - VarInsnNode( - Opcodes.ALOAD, - 6 - ), - MethodInsnNode( - Opcodes.INVOKESTATIC, - "fi/razerman/youtube/XAdRemover", - "hideCreateButton", - "(Landroid/view/View;)V" - ) + // Hide the button view via proxy by passing it to the hideCreateButton method + map.resolveAndGetMethod().implementation!!.addInstruction( + map.scanData.endIndex, + "invoke-static { v6 }, Lfi/razerman/youtube/XAdRemover;->hideCreateButton(Landroid/view/View;)V".asInstruction() ) return PatchResultSuccess() diff --git a/src/main/kotlin/app/revanced/patches/layout/HideReels.kt b/src/main/kotlin/app/revanced/patches/layout/HideReels.kt index 79c9cd3c..d331f381 100644 --- a/src/main/kotlin/app/revanced/patches/layout/HideReels.kt +++ b/src/main/kotlin/app/revanced/patches/layout/HideReels.kt @@ -4,24 +4,17 @@ import app.revanced.patcher.cache.Cache import app.revanced.patcher.patch.Patch import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.writer.ASMWriter.insertAt -import org.objectweb.asm.Opcodes -import org.objectweb.asm.tree.MethodInsnNode -import org.objectweb.asm.tree.VarInsnNode +import app.revanced.patcher.smali.asInstruction class HideReels : Patch("hide-reels") { override fun execute(cache: Cache): PatchResult { - val patchData = cache.methods["hide-reel-patch"] + val implementation = cache.methodMap["hide-reel-patch"].resolveAndGetMethod().implementation!! - patchData.method.instructions.insertAt( - patchData.scanData.endIndex + 1, - VarInsnNode(Opcodes.ALOAD, 18), - MethodInsnNode( - Opcodes.INVOKESTATIC, - "fi/razerman/youtube/XAdRemover", - "HideReels", - "(Landroid/view/View;)V" - ) + // HideReel will hide the reel view before it is being used, + // so we pass the view to the HideReel method + implementation.addInstruction( + 22, + "invoke-static { v2 }, Lfi/razerman/youtube/XAdRemover;->HideReel(Landroid/view/View;)V".asInstruction() ) return PatchResultSuccess() diff --git a/src/main/kotlin/app/revanced/patches/layout/HideSuggestions.kt b/src/main/kotlin/app/revanced/patches/layout/HideSuggestions.kt index 955dd685..95dea7d4 100644 --- a/src/main/kotlin/app/revanced/patches/layout/HideSuggestions.kt +++ b/src/main/kotlin/app/revanced/patches/layout/HideSuggestions.kt @@ -1,52 +1,47 @@ package app.revanced.patches.layout import app.revanced.patcher.cache.Cache +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.extensions.or import app.revanced.patcher.patch.Patch import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResultError import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.signature.Signature -import app.revanced.patcher.writer.ASMWriter.insertAt -import org.objectweb.asm.Opcodes -import org.objectweb.asm.Type -import org.objectweb.asm.tree.MethodInsnNode -import org.objectweb.asm.tree.VarInsnNode +import app.revanced.patcher.signature.MethodSignature +import app.revanced.patcher.smali.asInstructions +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.Opcode class HideSuggestions : Patch("hide-suggestions") { override fun execute(cache: Cache): PatchResult { - val method = cache.methods["hide-suggestions-patch"].findParentMethod( - Signature( + val map = cache.methodMap["hide-suggestions-patch"].findParentMethod( + MethodSignature( "hide-suggestions-method", - Type.VOID_TYPE, - Opcodes.ACC_PUBLIC or Opcodes.ACC_FINAL, - arrayOf(Type.BOOLEAN_TYPE), + "V", + AccessFlags.PUBLIC or AccessFlags.PUBLIC, + setOf("Z"), arrayOf( - Opcodes.ALOAD, - Opcodes.ILOAD, - Opcodes.PUTFIELD, - Opcodes.ALOAD, - Opcodes.GETFIELD + Opcode.IPUT_BOOLEAN, + Opcode.IGET_OBJECT, + Opcode.IPUT_BOOLEAN, + Opcode.INVOKE_VIRTUAL, + Opcode.RETURN_VOID ) ) ) ?: return PatchResultError("Parent method hide-suggestions-method has not been found") - method.method.instructions.insertAt( + // Proxy the first parameter by passing it to the RemoveSuggestions method + map.resolveAndGetMethod().implementation!!.addInstructions( 0, - VarInsnNode(Opcodes.ILOAD, 1), - MethodInsnNode( - Opcodes.INVOKESTATIC, - "java/lang/Boolean", - "valueOf", - "(Z)Ljava/lang/Boolean" - ), - MethodInsnNode( - Opcodes.INVOKESTATIC, - "fi/razerman/youtube/XAdRemover", - "HideReels", - "(Landroid/view/View;)V" - ) + """ + invoke-static { p1 }, Ljava/lang/Boolean;->valueOf(Z)Ljava/lang/Boolean; + move-result-object v0 + invoke-static { v0 }, Lfi/razerman/youtube/XAdRemover;->RemoveSuggestions(Ljava/lang/Boolean;)Ljava/lang/Boolean; + move-result-object v0 + invoke-virtual { v0 }, Ljava/lang/Boolean;->booleanValue()Z + move-result v0 + """.trimIndent().asInstructions() ) - return PatchResultSuccess() } } \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/layout/MinimizedPlayback.kt b/src/main/kotlin/app/revanced/patches/layout/MinimizedPlayback.kt index b5380d9c..f898b98e 100644 --- a/src/main/kotlin/app/revanced/patches/layout/MinimizedPlayback.kt +++ b/src/main/kotlin/app/revanced/patches/layout/MinimizedPlayback.kt @@ -4,10 +4,20 @@ import app.revanced.patcher.cache.Cache import app.revanced.patcher.patch.Patch import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResultSuccess +import org.jf.dexlib2.Opcode +import org.jf.dexlib2.builder.instruction.BuilderInstruction10x class MinimizedPlayback : Patch("minimized-playback") { override fun execute(cache: Cache): PatchResult { - cache.methods["minimized-playback-manager"].method.instructions.clear() + // Instead of removing all instructions like Vanced, + // we return the method at the beginning instead + cache.methodMap["minimized-playback-manager"] + .resolveAndGetMethod() + .implementation!! + .addInstruction( + 0, + BuilderInstruction10x(Opcode.RETURN_VOID) + ) return PatchResultSuccess() } } \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/layout/OldQualityLayout.kt b/src/main/kotlin/app/revanced/patches/layout/OldQualityLayout.kt index 54a9f871..edaeb324 100644 --- a/src/main/kotlin/app/revanced/patches/layout/OldQualityLayout.kt +++ b/src/main/kotlin/app/revanced/patches/layout/OldQualityLayout.kt @@ -1,50 +1,47 @@ package app.revanced.patches.layout import app.revanced.patcher.cache.Cache +import app.revanced.patcher.extensions.or import app.revanced.patcher.patch.Patch import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResultError import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.signature.Signature -import app.revanced.patcher.util.ExtraTypes -import app.revanced.patcher.writer.ASMWriter.insertAt -import org.objectweb.asm.Opcodes -import org.objectweb.asm.tree.JumpInsnNode -import org.objectweb.asm.tree.MethodInsnNode -import org.objectweb.asm.tree.VarInsnNode +import app.revanced.patcher.signature.MethodSignature +import app.revanced.patcher.smali.asInstruction +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.Opcode +import org.jf.dexlib2.builder.instruction.BuilderInstruction21t class OldQualityLayout : Patch("old-quality-restore") { override fun execute(cache: Cache): PatchResult { - val method = cache.methods["old-quality-patch"].findParentMethod( - Signature( + val map = cache.methodMap["old-quality-patch"].findParentMethod( + MethodSignature( "old-quality-patch-method", - ExtraTypes.Any, - Opcodes.ACC_PUBLIC or Opcodes.ACC_FINAL, - arrayOf(), + "L", + AccessFlags.FINAL or AccessFlags.PUBLIC, + emptySet(), arrayOf( - Opcodes.ALOAD, - Opcodes.GETFIELD, - Opcodes.ISTORE, - Opcodes.ICONST_3, - Opcodes.ISTORE + Opcode.IF_NEZ, + Opcode.IGET, + Opcode.CONST_4, + Opcode.IF_NE ) ) ) ?: return PatchResultError("Parent method old-quality-patch-method has not been found") - method.method.instructions.insertAt( + + val implementation = map.resolveAndGetMethod().implementation!! + + // if useOldStyleQualitySettings == true, jump over all instructions and return the field at the end + val jmpInstruction = + BuilderInstruction21t(Opcode.IF_NEZ, 0, implementation.instructions[5].location.labels.first()) + implementation.addInstruction(0, jmpInstruction) + implementation.addInstruction( 0, - MethodInsnNode( - Opcodes.INVOKESTATIC, - "fi/razerman/youtube/XGlobals", - "useOldStyleQualitySettings", - "()Z" - ), - VarInsnNode(Opcodes.ISTORE, 1), - VarInsnNode(Opcodes.ILOAD, 1), - JumpInsnNode( - Opcodes.IFNE, - (method.method.instructions[method.scanData.endIndex + 3] as JumpInsnNode).label - ), + """ + invoke-static { }, Lfi/razerman/youtube/XGlobals;->useOldStyleQualitySettings()Z + move-result v0 + """.trimIndent().asInstruction() ) return PatchResultSuccess()