diff --git a/.gitignore b/.gitignore index 55e6dfc03..414507c33 100644 --- a/.gitignore +++ b/.gitignore @@ -111,4 +111,7 @@ gradle-app.setting .gradletasknamecache # # Work around https://youtrack.jetbrains.com/issue/IDEA-116898 -# gradle/wrapper/gradle-wrapper.properties \ No newline at end of file +# gradle/wrapper/gradle-wrapper.properties + +# Potentially copyrighted test APK +*.apk \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index 6ecf2d4f6..95529895b 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,5 +1,5 @@ plugins { - kotlin("jvm") version "1.6.10" + kotlin("jvm") version "1.6.20" java `maven-publish` } @@ -8,8 +8,9 @@ group = "app.revanced" repositories { mavenCentral() + mavenLocal() maven { - url = uri("https://maven.pkg.github.com/ReVancedTeam/revanced-patcher") // note the "r"! + url = uri("https://maven.pkg.github.com/revanced/revanced-patcher") // note the "r"! credentials { // DO NOT set these variables in the project's gradle.properties. // Instead, you should set them in: @@ -22,14 +23,10 @@ repositories { } dependencies { - implementation("org.jetbrains.kotlin:kotlin-stdlib:1.6.10") + implementation(kotlin("stdlib")) + testImplementation(kotlin("test")) - 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("app.revanced:revanced-patcher:1.0.0-dev.9") } java { @@ -37,15 +34,21 @@ java { withJavadocJar() } +val isGitHubCI = System.getenv("GITHUB_ACTOR") != null + publishing { repositories { - maven { - name = "GitHubPackages" - url = uri("https://maven.pkg.github.com/ReVancedTeam/revanced-patches") // note the "s"! - credentials { - username = System.getenv("GITHUB_ACTOR") - password = System.getenv("GITHUB_TOKEN") + if (isGitHubCI) { + maven { + name = "GitHubPackages" + url = uri("https://maven.pkg.github.com/revanced/revanced-patches") // note the "s"! + credentials { + username = System.getenv("GITHUB_ACTOR") + password = System.getenv("GITHUB_TOKEN") + } } + } else { + mavenLocal() } } publications { @@ -53,4 +56,4 @@ publishing { from(components["java"]) } } -} \ No newline at end of file +} diff --git a/src/main/kotlin/app/revanced/extensions/Extensions.kt b/src/main/kotlin/app/revanced/extensions/Extensions.kt new file mode 100644 index 000000000..16242c940 --- /dev/null +++ b/src/main/kotlin/app/revanced/extensions/Extensions.kt @@ -0,0 +1,14 @@ +package app.revanced.extensions + +import app.revanced.patcher.smali.toInstruction +import org.jf.dexlib2.builder.MutableMethodImplementation + +internal fun MutableMethodImplementation.injectHideCall( + index: Int, + register: Int +) { + this.addInstruction( + index, + "invoke-static { v$register }, Lfi/razerman/youtube/XAdRemover;->HideView(Landroid/view/View;)V".toInstruction() + ) +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/Index.kt b/src/main/kotlin/app/revanced/patches/Index.kt index 91787b99c..4c4e843d8 100644 --- a/src/main/kotlin/app/revanced/patches/Index.kt +++ b/src/main/kotlin/app/revanced/patches/Index.kt @@ -1,12 +1,22 @@ package app.revanced.patches -import app.revanced.patcher.patch.Patch -import app.revanced.patches.ad.VideoAds -import app.revanced.patches.interaction.EnableSeekbarTapping -import app.revanced.patches.layout.* +import app.revanced.patcher.data.base.Data +import app.revanced.patcher.patch.base.Patch +import app.revanced.patches.music.audio.CodecsUnlockPatch +import app.revanced.patches.music.audio.EnableAudioOnlyPatch +import app.revanced.patches.music.layout.RemoveTasteBuilderPatch +import app.revanced.patches.music.layout.RemoveUpgradeTabPatch +import app.revanced.patches.music.premium.BackgroundPlayPatch +import app.revanced.patches.youtube.ad.HomeAdsPatch +import app.revanced.patches.youtube.ad.HomePromoPatch +import app.revanced.patches.youtube.ad.VideoAdsPatch +import app.revanced.patches.youtube.interaction.EnableSeekbarTappingPatch +import app.revanced.patches.youtube.layout.* +import app.revanced.patches.youtube.misc.FixLocaleConfigErrorPatch +import app.revanced.patches.youtube.misc.IntegrationsPatch /** - * Index contains all the patches and should be imported when using this library. + * Index contains all the patches. */ @Suppress("Unused") object Index { @@ -14,13 +24,22 @@ object Index { * Array of patches. * New patches should be added to the array. */ - val patches: Array<() -> Patch> = arrayOf( - ::VideoAds, - ::MinimizedPlayback, - ::CreateButtonRemover, - ::HideReels, - ::HideSuggestions, - ::OldQualityLayout, - ::EnableSeekbarTapping + val patches: List<() -> Patch> = listOf( + ::IntegrationsPatch, + ::FixLocaleConfigErrorPatch, + ::HomeAdsPatch, + ::VideoAdsPatch, + ::HomePromoPatch, + ::MinimizedPlaybackPatch, + ::CreateButtonRemoverPatch, + ::ShortsButtonRemoverPatch, + ::HideReelsPatch, + ::OldQualityLayoutPatch, + ::EnableSeekbarTappingPatch, + ::EnableAudioOnlyPatch, + ::RemoveUpgradeTabPatch, + ::RemoveTasteBuilderPatch, + ::BackgroundPlayPatch, + ::CodecsUnlockPatch ) -} \ No newline at end of file +} diff --git a/src/main/kotlin/app/revanced/patches/ad/VideoAds.kt b/src/main/kotlin/app/revanced/patches/ad/VideoAds.kt deleted file mode 100644 index 42ac26f40..000000000 --- a/src/main/kotlin/app/revanced/patches/ad/VideoAds.kt +++ /dev/null @@ -1,39 +0,0 @@ -package app.revanced.patches.ad - -import app.revanced.patcher.cache.Cache -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 - -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), - null - ) - ) ?: return PatchResultError("Could not find required method to patch") - - showVideoAdsMethodData.method.instructions.insertAt( - 0, - MethodInsnNode( - Opcodes.INVOKESTATIC, - "fi/vanced/libraries/youtube/whitelisting/Whitelist", - "shouldShowAds", - Type.getMethodDescriptor(Type.BOOLEAN_TYPE) - ) - ) - - return PatchResultSuccess() - } -} - diff --git a/src/main/kotlin/app/revanced/patches/interaction/EnableSeekbarTapping.kt b/src/main/kotlin/app/revanced/patches/interaction/EnableSeekbarTapping.kt deleted file mode 100644 index 7262dbb34..000000000 --- a/src/main/kotlin/app/revanced/patches/interaction/EnableSeekbarTapping.kt +++ /dev/null @@ -1,49 +0,0 @@ -package app.revanced.patches.interaction - -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.* - -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 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 - ) - - 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 deleted file mode 100644 index 92c500006..000000000 --- a/src/main/kotlin/app/revanced/patches/layout/CreateButtonRemover.kt +++ /dev/null @@ -1,32 +0,0 @@ -package app.revanced.patches.layout - -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 - -class CreateButtonRemover : Patch("create-button-remover") { - override fun execute(cache: Cache): PatchResult { - val patchData = cache.methods["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" - ) - ) - - return PatchResultSuccess() - } -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/layout/HideReels.kt b/src/main/kotlin/app/revanced/patches/layout/HideReels.kt deleted file mode 100644 index 79c9cd3c0..000000000 --- a/src/main/kotlin/app/revanced/patches/layout/HideReels.kt +++ /dev/null @@ -1,29 +0,0 @@ -package app.revanced.patches.layout - -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 - -class HideReels : Patch("hide-reels") { - override fun execute(cache: Cache): PatchResult { - val patchData = cache.methods["hide-reel-patch"] - - patchData.method.instructions.insertAt( - patchData.scanData.endIndex + 1, - VarInsnNode(Opcodes.ALOAD, 18), - MethodInsnNode( - Opcodes.INVOKESTATIC, - "fi/razerman/youtube/XAdRemover", - "HideReels", - "(Landroid/view/View;)V" - ) - ) - - return PatchResultSuccess() - } -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/layout/HideSuggestions.kt b/src/main/kotlin/app/revanced/patches/layout/HideSuggestions.kt deleted file mode 100644 index 955dd685f..000000000 --- a/src/main/kotlin/app/revanced/patches/layout/HideSuggestions.kt +++ /dev/null @@ -1,52 +0,0 @@ -package app.revanced.patches.layout - -import app.revanced.patcher.cache.Cache -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 - -class HideSuggestions : Patch("hide-suggestions") { - override fun execute(cache: Cache): PatchResult { - val method = cache.methods["hide-suggestions-patch"].findParentMethod( - Signature( - "hide-suggestions-method", - Type.VOID_TYPE, - Opcodes.ACC_PUBLIC or Opcodes.ACC_FINAL, - arrayOf(Type.BOOLEAN_TYPE), - arrayOf( - Opcodes.ALOAD, - Opcodes.ILOAD, - Opcodes.PUTFIELD, - Opcodes.ALOAD, - Opcodes.GETFIELD - ) - ) - ) ?: return PatchResultError("Parent method hide-suggestions-method has not been found") - - method.method.instructions.insertAt( - 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" - ) - ) - - 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 deleted file mode 100644 index b5380d9c3..000000000 --- a/src/main/kotlin/app/revanced/patches/layout/MinimizedPlayback.kt +++ /dev/null @@ -1,13 +0,0 @@ -package app.revanced.patches.layout - -import app.revanced.patcher.cache.Cache -import app.revanced.patcher.patch.Patch -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess - -class MinimizedPlayback : Patch("minimized-playback") { - override fun execute(cache: Cache): PatchResult { - cache.methods["minimized-playback-manager"].method.instructions.clear() - 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 deleted file mode 100644 index 54a9f871f..000000000 --- a/src/main/kotlin/app/revanced/patches/layout/OldQualityLayout.kt +++ /dev/null @@ -1,52 +0,0 @@ -package app.revanced.patches.layout - -import app.revanced.patcher.cache.Cache -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 - -class OldQualityLayout : Patch("old-quality-restore") { - override fun execute(cache: Cache): PatchResult { - val method = cache.methods["old-quality-patch"].findParentMethod( - Signature( - "old-quality-patch-method", - ExtraTypes.Any, - Opcodes.ACC_PUBLIC or Opcodes.ACC_FINAL, - arrayOf(), - arrayOf( - Opcodes.ALOAD, - Opcodes.GETFIELD, - Opcodes.ISTORE, - Opcodes.ICONST_3, - Opcodes.ISTORE - ) - ) - ) ?: return PatchResultError("Parent method old-quality-patch-method has not been found") - - method.method.instructions.insertAt( - 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 - ), - ) - - return PatchResultSuccess() - } -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/music/audio/CodecsUnlockPatch.kt b/src/main/kotlin/app/revanced/patches/music/audio/CodecsUnlockPatch.kt new file mode 100644 index 000000000..03c2264ff --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/music/audio/CodecsUnlockPatch.kt @@ -0,0 +1,157 @@ +package app.revanced.patches.music.audio + +import app.revanced.patcher.data.implementation.BytecodeData +import app.revanced.patcher.data.implementation.toMethodWalker +import app.revanced.patcher.extensions.or +import app.revanced.patcher.patch.implementation.BytecodePatch +import app.revanced.patcher.patch.implementation.metadata.PackageMetadata +import app.revanced.patcher.patch.implementation.metadata.PatchMetadata +import app.revanced.patcher.patch.implementation.misc.PatchResult +import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess +import app.revanced.patcher.signature.MethodMetadata +import app.revanced.patcher.signature.MethodSignature +import app.revanced.patcher.signature.MethodSignatureMetadata +import app.revanced.patcher.signature.PatternScanMethod +import app.revanced.patcher.smali.toInstruction +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.Opcode + +private val packageMetadata = listOf( + PackageMetadata( + "com.google.android.apps.youtube.music", + listOf("5.03.50") + ) +) + +private val patchMetadata = PatchMetadata( + "codecs-unlock", + "Audio codecs unlock patch", + "Enables more audio codecs. Usually results in better audio quality but may depend on song and device.", + packageMetadata, + "0.0.1" +) + +class CodecsUnlockPatch : BytecodePatch( + patchMetadata, + listOf( + MethodSignature( + MethodSignatureMetadata( + "codec-lock-method", + MethodMetadata( + "Labwj;", + "a", + ), + PatternScanMethod.Fuzzy(2),// FIXME: Test this threshold and find the best value. + packageMetadata, + "Required signature for ${patchMetadata.name}. Discovered in version 5.03.50.", + "0.0.1" + ), + "L", + AccessFlags.PUBLIC or AccessFlags.STATIC, + listOf("L", "L", "L", "L"), + listOf( + Opcode.INVOKE_STATIC, + Opcode.MOVE_RESULT_OBJECT, + Opcode.INVOKE_DIRECT, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT, + Opcode.IF_NEZ, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT, + Opcode.IF_NEZ, + Opcode.SGET, + Opcode.INVOKE_STATIC, + Opcode.MOVE_RESULT_OBJECT, + Opcode.INVOKE_INTERFACE, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT, + Opcode.IF_NEZ, + Opcode.SGET_OBJECT, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CHECK_CAST, + Opcode.INVOKE_INTERFACE, + Opcode.INVOKE_DIRECT, + Opcode.RETURN_OBJECT + ) + ), + MethodSignature( + MethodSignatureMetadata( + "all-codecs-reference-method", + MethodMetadata( + "Laari;", + "b", + ), + PatternScanMethod.Fuzzy(2),// FIXME: Test this threshold and find the best value. + packageMetadata, + "Required signature for ${patchMetadata.name}. Discovered in version 5.03.50.", + "0.0.1" + ), + "J", + AccessFlags.PUBLIC or AccessFlags.FINAL, + listOf("L"), + listOf( + Opcode.INVOKE_STATIC, + Opcode.MOVE_RESULT_OBJECT, + Opcode.INVOKE_STATIC, + Opcode.MOVE_RESULT_OBJECT, + Opcode.INVOKE_INTERFACE, + Opcode.MOVE_RESULT, + Opcode.CONST_4, + Opcode.IF_EQZ, + Opcode.IGET_BOOLEAN, + Opcode.IF_NEZ, + Opcode.IGET_OBJECT, + Opcode.INVOKE_INTERFACE, + Opcode.IPUT_BOOLEAN, + Opcode.IGET_OBJECT, + Opcode.INVOKE_INTERFACE, + Opcode.GOTO, + Opcode.INVOKE_STATIC, + Opcode.MOVE_RESULT_OBJECT, + Opcode.INVOKE_INTERFACE, + Opcode.MOVE_RESULT, + Opcode.IF_NEZ, + Opcode.INVOKE_STATIC, + Opcode.MOVE_RESULT_OBJECT, + Opcode.INVOKE_INTERFACE, + Opcode.MOVE_RESULT, + Opcode.IF_EQZ, + Opcode.IGET_BOOLEAN, + Opcode.IF_NEZ, + Opcode.IGET_OBJECT, + Opcode.INVOKE_INTERFACE, + Opcode.IPUT_BOOLEAN, + Opcode.IGET_OBJECT, + Opcode.INVOKE_INTERFACE, + Opcode.GOTO, + Opcode.MOVE_EXCEPTION, + Opcode.INVOKE_SUPER, + Opcode.MOVE_RESULT_WIDE, + Opcode.RETURN_WIDE + ), + listOf("itag") + ) + ) +) { + override fun execute(data: BytecodeData): PatchResult { + var result = signatures.first().result!! + + val implementation = result.method.implementation!! + + val instructionIndex = result.scanData.startIndex + + result = signatures.last().result!! + val codecMethod = data + .toMethodWalker(result.immutableMethod) + .walk(result.scanData.startIndex) + .getMethod() + + implementation.replaceInstruction( + instructionIndex, + "invoke-static {}, ${codecMethod.definingClass}->${codecMethod.name}()Ljava/util/Set;".toInstruction() + ) + + return PatchResultSuccess() + } +} diff --git a/src/main/kotlin/app/revanced/patches/music/audio/EnableAudioOnlyPatch.kt b/src/main/kotlin/app/revanced/patches/music/audio/EnableAudioOnlyPatch.kt new file mode 100644 index 000000000..e1186acb0 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/music/audio/EnableAudioOnlyPatch.kt @@ -0,0 +1,133 @@ +package app.revanced.patches.music.audio + +import app.revanced.patcher.data.implementation.BytecodeData +import app.revanced.patcher.extensions.or +import app.revanced.patcher.patch.implementation.BytecodePatch +import app.revanced.patcher.patch.implementation.metadata.PackageMetadata +import app.revanced.patcher.patch.implementation.metadata.PatchMetadata +import app.revanced.patcher.patch.implementation.misc.PatchResult +import app.revanced.patcher.patch.implementation.misc.PatchResultError +import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess +import app.revanced.patcher.signature.MethodMetadata +import app.revanced.patcher.signature.MethodSignature +import app.revanced.patcher.signature.MethodSignatureMetadata +import app.revanced.patcher.signature.PatternScanMethod +import app.revanced.patcher.smali.toInstruction +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.Opcode + +private val compatiblePackages = listOf( + PackageMetadata( + "com.google.android.apps.youtube.music", + listOf("5.03.50") + ) +) + +class EnableAudioOnlyPatch : BytecodePatch( + PatchMetadata( + "audio-only-playback-patch", + "Audio Only Mode Patch", + "Add the option to play music without video.", + compatiblePackages, + "0.0.1" + ), + listOf( + MethodSignature( + MethodSignatureMetadata( + "audio-only-method-signature", + MethodMetadata("Lgmd;", "c"), + PatternScanMethod.Fuzzy(2), // FIXME: Test this threshold and find the best value. + compatiblePackages, + "Signature for the method required to be patched.", + "0.0.1" + ), + "V", + AccessFlags.PUBLIC or AccessFlags.FINAL, + listOf("L", "Z"), + listOf( + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CHECK_CAST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT, + Opcode.IF_EQ, + Opcode.CONST_4, + Opcode.GOTO, + Opcode.NOP, + Opcode.IGET_OBJECT, + Opcode.INVOKE_INTERFACE, + Opcode.MOVE_RESULT_OBJECT, + Opcode.INVOKE_STATIC, + Opcode.MOVE_RESULT_OBJECT, + Opcode.INVOKE_VIRTUAL, + Opcode.IGET_OBJECT, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.INVOKE_INTERFACE, + Opcode.MOVE_RESULT, + Opcode.IF_EQZ, + Opcode.INVOKE_INTERFACE, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CHECK_CAST, + Opcode.IF_EQZ, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CHECK_CAST, + Opcode.IF_EQZ, + Opcode.IF_EQZ, + Opcode.INVOKE_INTERFACE, + Opcode.INVOKE_INTERFACE, + Opcode.GOTO, + Opcode.RETURN_VOID + ) + ) + ) +) { + override fun execute(data: BytecodeData): PatchResult { + val result = signatures.first().result!!.findParentMethod( + MethodSignature( + MethodSignatureMetadata( + "audio-only-enabler-method", + MethodMetadata("Lgmd;", "d"), + PatternScanMethod.Fuzzy(2), // FIXME: Test this threshold and find the best value. + compatiblePackages, + "Signature for the method required to be patched.", + "0.0.1" + ), + "Z", + AccessFlags.PUBLIC or AccessFlags.FINAL, + listOf(), + listOf( + Opcode.IGET_OBJECT, + Opcode.INVOKE_INTERFACE, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IGET_OBJECT, + Opcode.INVOKE_INTERFACE, + Opcode.MOVE_RESULT_OBJECT, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CHECK_CAST, + Opcode.IF_NEZ, + Opcode.IGET_OBJECT, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT, + Opcode.GOTO, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT, + Opcode.RETURN + ) + ) + ) ?: return PatchResultError("Required method for ${metadata.shortName} not found.") + + val implementation = result.method.implementation!! + implementation.replaceInstruction( + implementation.instructions.count() - 1, + "const/4 v0, 0x1".toInstruction() + ) + implementation.addInstruction( + "return v0".toInstruction() + ) + + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/music/layout/RemoveTasteBuilderPatch.kt b/src/main/kotlin/app/revanced/patches/music/layout/RemoveTasteBuilderPatch.kt new file mode 100644 index 000000000..904c16e5d --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/music/layout/RemoveTasteBuilderPatch.kt @@ -0,0 +1,94 @@ +package app.revanced.patches.music.layout + +import app.revanced.patcher.data.implementation.BytecodeData +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.extensions.or +import app.revanced.patcher.patch.implementation.BytecodePatch +import app.revanced.patcher.patch.implementation.metadata.PackageMetadata +import app.revanced.patcher.patch.implementation.metadata.PatchMetadata +import app.revanced.patcher.patch.implementation.misc.PatchResult +import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess +import app.revanced.patcher.signature.MethodMetadata +import app.revanced.patcher.signature.MethodSignature +import app.revanced.patcher.signature.MethodSignatureMetadata +import app.revanced.patcher.signature.PatternScanMethod +import app.revanced.patcher.smali.toInstructions +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.Opcode +import org.jf.dexlib2.iface.instruction.formats.Instruction22c + +private val compatiblePackages = listOf( + PackageMetadata( + "com.google.android.apps.youtube.music", + listOf("5.03.50") + ) +) + +class RemoveTasteBuilderPatch : BytecodePatch( + PatchMetadata( + "tasteBuilder-remover", + "Remove TasteBuilder Patch", + "Removes the \"Tell us which artists you like\" card from the Home screen. The same functionality can be triggered from the settings anyway.", + compatiblePackages, + "0.0.1" + ), + listOf( + MethodSignature( + MethodSignatureMetadata( + "taste-builder-constructor", + MethodMetadata("Lkyu;", ""), + PatternScanMethod.Fuzzy(2), // FIXME: Test this threshold and find the best value. + compatiblePackages, + "Required signature for this patch.", + "0.0.1" + ), + "V", + AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, + listOf("L", "L", "L", "L"), + listOf( + Opcode.INVOKE_DIRECT, + Opcode.INVOKE_VIRTUAL, + Opcode.NEW_INSTANCE, + Opcode.INVOKE_DIRECT, + Opcode.IPUT_OBJECT, + Opcode.INVOKE_STATIC, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CONST, + Opcode.CONST_4, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CHECK_CAST, + Opcode.IPUT_OBJECT, + Opcode.NEW_INSTANCE, + Opcode.INVOKE_DIRECT, + Opcode.IPUT_OBJECT + ) + ) + ) +) { + override fun execute(data: BytecodeData): PatchResult { + val result = signatures.first().result!! + val implementation = result.method.implementation!! + + val insertIndex = result.scanData.endIndex - 8 + + val register = (implementation.instructions[insertIndex] as Instruction22c).registerA + + val instructionList = + """ + const/16 v1, 0x8 + invoke-virtual {v${register}, v1}, Landroid/view/View;->setVisibility(I)V + """.trimIndent().toInstructions().toMutableList() + + implementation.addInstructions( + insertIndex, + instructionList + ) + + return PatchResultSuccess() + } +} diff --git a/src/main/kotlin/app/revanced/patches/music/layout/RemoveUpgradeTabPatch.kt b/src/main/kotlin/app/revanced/patches/music/layout/RemoveUpgradeTabPatch.kt new file mode 100644 index 000000000..b55c28008 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/music/layout/RemoveUpgradeTabPatch.kt @@ -0,0 +1,151 @@ +package app.revanced.patches.music.layout + +import app.revanced.patcher.data.implementation.BytecodeData +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.extensions.or +import app.revanced.patcher.patch.implementation.BytecodePatch +import app.revanced.patcher.patch.implementation.metadata.PackageMetadata +import app.revanced.patcher.patch.implementation.metadata.PatchMetadata +import app.revanced.patcher.patch.implementation.misc.PatchResult +import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess +import app.revanced.patcher.signature.MethodMetadata +import app.revanced.patcher.signature.MethodSignature +import app.revanced.patcher.signature.MethodSignatureMetadata +import app.revanced.patcher.signature.PatternScanMethod +import app.revanced.patcher.smali.toInstructions +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.Opcode +import org.jf.dexlib2.builder.instruction.BuilderInstruction22t +import org.jf.dexlib2.iface.instruction.formats.Instruction22c +import org.jf.dexlib2.iface.instruction.formats.Instruction35c + +private val compatiblePackages = listOf( + PackageMetadata( + "com.google.android.apps.youtube.music", + listOf("5.03.50") + ) +) + +class RemoveUpgradeTabPatch : BytecodePatch( + PatchMetadata( + "upgrade-tab-remover", + "Remove Upgrade Tab Patch", + "Remove the upgrade tab from t he pivot bar in YouTube music.", + compatiblePackages, + "0.0.1" + ), + listOf( + MethodSignature( + MethodSignatureMetadata( + "pivot-bar-constructor", + MethodMetadata("Lhfu;", ""), // unknown + PatternScanMethod.Fuzzy(2), // FIXME: Test this threshold and find the best value. + compatiblePackages, + "Required signature for this patch.", + "0.0.1" + ), + "V", + AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, + listOf("L", "Z"), + listOf( + Opcode.INVOKE_DIRECT, + Opcode.CONST_4, + Opcode.IPUT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.IPUT_BOOLEAN, + Opcode.IGET_OBJECT, + Opcode.IF_NEZ, + Opcode.GOTO, + Opcode.NEW_INSTANCE, + Opcode.INVOKE_DIRECT, + Opcode.IGET_OBJECT, + Opcode.INVOKE_INTERFACE, + Opcode.MOVE_RESULT_OBJECT, + Opcode.INVOKE_INTERFACE, + Opcode.MOVE_RESULT, + Opcode.IF_EQZ, + Opcode.INVOKE_INTERFACE, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CHECK_CAST, + Opcode.IGET, + Opcode.CONST, + Opcode.IF_NE, + Opcode.IGET_OBJECT, + Opcode.CHECK_CAST, + Opcode.GOTO, + Opcode.SGET_OBJECT, + Opcode.IGET_OBJECT, + Opcode.INVOKE_INTERFACE, + Opcode.MOVE_RESULT_OBJECT, + Opcode.INVOKE_INTERFACE, + Opcode.MOVE_RESULT, + Opcode.IF_EQZ, + Opcode.INVOKE_INTERFACE, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CHECK_CAST, + Opcode.IGET, + Opcode.CONST, + Opcode.IF_NE, + Opcode.IGET_OBJECT, + Opcode.CHECK_CAST, + Opcode.INVOKE_INTERFACE, + Opcode.GOTO, + Opcode.NOP, + Opcode.IPUT_OBJECT, + Opcode.RETURN_VOID + ) + ) + ) +) { + override fun execute(data: BytecodeData): PatchResult { + val result = signatures.first().result!! + val implementation = result.method.implementation!! + + val pivotBarElementFieldRef = + (implementation.instructions[result.scanData.endIndex - 1] as Instruction22c).reference + + val register = (implementation.instructions.first() as Instruction35c).registerC + // first compile all the needed instructions + val instructionList = + """ + invoke-interface { v0 }, Ljava/util/List;->size()I + move-result v1 + const/4 v2, 0x3 + invoke-interface {v0, v2}, Ljava/util/List;->remove(I)Ljava/lang/Object; + iput-object v0, v$register, $pivotBarElementFieldRef + """.trimIndent().toInstructions().toMutableList() + + + // replace the instruction to retain the label at given index + implementation.replaceInstruction( + result.scanData.endIndex - 1, + instructionList[0] // invoke-interface + ) + // do not forget to remove this instruction since we added it already + instructionList.removeFirst() + + val exitInstruction = instructionList.last() // iput-object + implementation.addInstruction( + result.scanData.endIndex, + exitInstruction + ) + // do not forget to remove this instruction since we added it already + instructionList.removeLast() + + // add the necessary if statement to remove the upgrade tab button in case it exists + instructionList.add( + 2, // if-le + BuilderInstruction22t( + Opcode.IF_LE, + 1, 2, + implementation.newLabelForIndex(result.scanData.endIndex) + ) + ) + + implementation.addInstructions( + result.scanData.endIndex, + instructionList + ) + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/music/premium/BackgroundPlayPatch.kt b/src/main/kotlin/app/revanced/patches/music/premium/BackgroundPlayPatch.kt new file mode 100644 index 000000000..f84aec6fb --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/music/premium/BackgroundPlayPatch.kt @@ -0,0 +1,92 @@ +package app.revanced.patches.music.premium + +import app.revanced.patcher.data.implementation.BytecodeData +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.extensions.or +import app.revanced.patcher.patch.implementation.BytecodePatch +import app.revanced.patcher.patch.implementation.metadata.PackageMetadata +import app.revanced.patcher.patch.implementation.metadata.PatchMetadata +import app.revanced.patcher.patch.implementation.misc.PatchResult +import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess +import app.revanced.patcher.signature.MethodMetadata +import app.revanced.patcher.signature.MethodSignature +import app.revanced.patcher.signature.MethodSignatureMetadata +import app.revanced.patcher.signature.PatternScanMethod +import app.revanced.patcher.smali.toInstructions +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.Opcode + +private val compatiblePackages = listOf( + PackageMetadata( + "com.google.android.apps.youtube.music", + listOf("5.03.50") + ) +) + +class BackgroundPlayPatch : BytecodePatch( + PatchMetadata( + "background-play", + "Enable Background Playback Patch", + "Enable playing music in the background.", + compatiblePackages, + "0.0.1" + ), + listOf( + MethodSignature( + MethodSignatureMetadata( + "background-playback-disabler-method", + MethodMetadata("Lafgf;", "e"), + PatternScanMethod.Fuzzy(2), // FIXME: Test this threshold and find the best value. + compatiblePackages, + "Signature for the method required to be patched.", + "0.0.1" + ), + "Z", + AccessFlags.PUBLIC or AccessFlags.STATIC, + listOf("L"), + listOf( + Opcode.CONST_4, + Opcode.IF_EQZ, + Opcode.IGET, + Opcode.AND_INT_LIT16, + Opcode.IF_EQZ, + Opcode.IGET_OBJECT, + Opcode.IF_NEZ, + Opcode.SGET_OBJECT, + Opcode.IGET, + Opcode.CONST, + Opcode.IF_NE, + Opcode.IGET_OBJECT, + Opcode.IF_NEZ, + Opcode.SGET_OBJECT, + Opcode.IGET, + Opcode.IF_NE, + Opcode.IGET_OBJECT, + Opcode.CHECK_CAST, + Opcode.GOTO, + Opcode.SGET_OBJECT, + Opcode.GOTO, + Opcode.CONST_4, + Opcode.IF_EQZ, + Opcode.IGET_BOOLEAN, + Opcode.IF_EQZ, + Opcode.CONST_4, + Opcode.RETURN, + Opcode.RETURN, + Opcode.RETURN + ) + ) + ) +) { + override fun execute(data: BytecodeData): PatchResult { + signatures.first().result!!.method.implementation!!.addInstructions( + 0, + """ + const/4 v0, 0x1 + return v0 + """.trimIndent().toInstructions() + ) + + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/ad/HomeAdsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/ad/HomeAdsPatch.kt new file mode 100644 index 000000000..fda073ee8 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/ad/HomeAdsPatch.kt @@ -0,0 +1,1706 @@ +package app.revanced.patches.youtube.ad + +import app.revanced.extensions.injectHideCall +import app.revanced.patcher.data.implementation.BytecodeData +import app.revanced.patcher.extensions.or +import app.revanced.patcher.patch.implementation.BytecodePatch +import app.revanced.patcher.patch.implementation.metadata.PackageMetadata +import app.revanced.patcher.patch.implementation.metadata.PatchMetadata +import app.revanced.patcher.patch.implementation.misc.PatchResult +import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess +import app.revanced.patcher.signature.MethodMetadata +import app.revanced.patcher.signature.MethodSignature +import app.revanced.patcher.signature.MethodSignatureMetadata +import app.revanced.patcher.signature.PatternScanMethod +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.Opcode +import org.jf.dexlib2.iface.instruction.formats.Instruction11x + + +private val packageMetadata = listOf( + PackageMetadata( + "com.google.android.youtube", + listOf("17.03.38") + ), +) + +private val patchMetadata = PatchMetadata( + "home-ads", + "Home Ads Patch", + "Patch to remove ads in YouTube", + packageMetadata, + "0.0.1" +) + +private val signatureDescription = "Required signature for ${patchMetadata.name}. Discovered in version 17.03.38." + +class HomeAdsPatch : BytecodePatch( + patchMetadata, + listOf( + MethodSignature( + MethodSignatureMetadata( + "home-ads-method-1", + MethodMetadata( + "Ljke;", + "k", + ), + PatternScanMethod.Fuzzy(2), // FIXME: Test this threshold and find the best value. + packageMetadata, + signatureDescription, + "0.0.1" + ), + "Z", + AccessFlags.PRIVATE or AccessFlags.FINAL, + listOf("L"), + listOf( + Opcode.INVOKE_DIRECT, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.GOTO, + Opcode.IGET_OBJECT, + Opcode.IF_EQ, + Opcode.CONST, + Opcode.GOTO, + Opcode.CONST, + Opcode.INVOKE_DIRECT, + Opcode.MOVE_RESULT_OBJECT, + Opcode.INVOKE_DIRECT, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.INVOKE_STATIC, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.INVOKE_STATIC, + Opcode.IGET_OBJECT, + Opcode.GOTO, + Opcode.IGET_OBJECT, + Opcode.INVOKE_STATIC, + Opcode.MOVE_RESULT, + Opcode.IF_EQZ, + Opcode.IGET_OBJECT, + Opcode.IF_EQ, + ) + ), + MethodSignature( + MethodSignatureMetadata( + "home-ads-method-2", + MethodMetadata( + "Ljsi;", + "", + ), + PatternScanMethod.Fuzzy(2), // FIXME: Test this threshold and find the best value. + packageMetadata, + signatureDescription, + "0.0.1" + ), + "V", + AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, + listOf( + "L", + "I" + ), + listOf( + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CHECK_CAST, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CHECK_CAST, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CHECK_CAST, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CHECK_CAST, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CHECK_CAST, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CHECK_CAST, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CHECK_CAST, + Opcode.IPUT_OBJECT, + Opcode.NEW_INSTANCE, + Opcode.INVOKE_DIRECT, + Opcode.IPUT_OBJECT, + Opcode.IGET_OBJECT, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CONST, + Opcode.CONST_4, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT, + Opcode.IPUT_BOOLEAN, + ) + ), + MethodSignature( + MethodSignatureMetadata( + "home-ads-method-3", + MethodMetadata( + "Ljrh;", + "", + ), + PatternScanMethod.Fuzzy(2), // FIXME: Test this threshold and find the best value. + packageMetadata, + signatureDescription, + "0.0.1" + ), + "V", + AccessFlags.PROTECTED or AccessFlags.CONSTRUCTOR, + listOf( + "L", + "L", + "L", + "L", + "L", + "L", + "L", + "L", + "L", + "L", + "L", + "L", + "L", + "[B", + "[B", + "[B", + "[B" + ), + listOf( + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.MOVE_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CHECK_CAST, + Opcode.IPUT_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CHECK_CAST, + Opcode.IPUT_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CHECK_CAST, + Opcode.IPUT_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CHECK_CAST, + Opcode.IPUT_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CHECK_CAST, + Opcode.IPUT_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.NEW_INSTANCE, + Opcode.MOVE_OBJECT_FROM16, + Opcode.INVOKE_DIRECT, + Opcode.IPUT_OBJECT, + Opcode.NEW_INSTANCE, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.NEW_INSTANCE, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.CONST_16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.CONST_4, + Opcode.INVOKE_DIRECT, + Opcode.NEW_INSTANCE, + Opcode.MOVE_OBJECT_FROM16, + Opcode.CONST_16, + Opcode.INVOKE_DIRECT, + Opcode.NEW_INSTANCE, + Opcode.MOVE_OBJECT_FROM16, + Opcode.INVOKE_DIRECT, + Opcode.CONST_4, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.CONST_16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.INVOKE_DIRECT_RANGE, + Opcode.MOVE_OBJECT_FROM16 + ) + ), + MethodSignature( + MethodSignatureMetadata( + "home-ads-method-4", + MethodMetadata( + "Ljrk;", + "", + ), + PatternScanMethod.Fuzzy(2), // FIXME: Test this threshold and find the best value. + packageMetadata, + signatureDescription, + "0.0.1" + ), + "V", + AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, + listOf("L", "I"), + listOf( + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.MOVE_OBJECT, + Opcode.CHECK_CAST, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.IPUT_OBJECT, + ) + ), + MethodSignature( + MethodSignatureMetadata( + "home-ads-method-5", + MethodMetadata( + "Ljrn;", + "", + ), + PatternScanMethod.Fuzzy(2), // FIXME: Test this threshold and find the best value. + packageMetadata, + signatureDescription, + "0.0.1" + ), + "V", + AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, + listOf("L", "I"), + listOf( + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.MOVE_OBJECT, + Opcode.CHECK_CAST, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.MOVE_OBJECT, + Opcode.CHECK_CAST, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.MOVE_OBJECT, + Opcode.CHECK_CAST, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.IPUT_OBJECT, + ) + ), + MethodSignature( + MethodSignatureMetadata( + "home-ads-method-6", + MethodMetadata( + "Ljrq;", + "", + ), + PatternScanMethod.Fuzzy(2), // FIXME: Test this threshold and find the best value. + packageMetadata, + signatureDescription, + "0.0.1" + ), + "V", + AccessFlags.PROTECTED or AccessFlags.CONSTRUCTOR, + listOf( + "L", + "L", + "L", + "L", + "L", + "L", + "L", + "L", + "L", + "L", + "L", + "L", + "L", + "[B", + "[B", + "[B", + "[B" + ), + listOf( + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CHECK_CAST, + Opcode.IPUT_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CHECK_CAST, + Opcode.IPUT_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + ) + ), + MethodSignature( + MethodSignatureMetadata( + "home-ads-method-7", + MethodMetadata( + "Ljrr;", + "", + ), + PatternScanMethod.Fuzzy(2), // FIXME: Test this threshold and find the best value. + packageMetadata, + signatureDescription, + "0.0.1" + ), + "V", + AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, + listOf( + "L", + "I", + "[B" + ), + listOf( + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.MOVE_OBJECT, + Opcode.CHECK_CAST, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.MOVE_OBJECT, + Opcode.CHECK_CAST, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + ) + ), + MethodSignature( + MethodSignatureMetadata( + "home-ads-method-8", + MethodMetadata( + "Ljrt;", + "", + ), + PatternScanMethod.Fuzzy(2), // FIXME: Test this threshold and find the best value. + packageMetadata, + signatureDescription, + "0.0.1" + ), + "V", + AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, + listOf( + "L", + "L", + "L", + "L", + "L", + "L", + "L", + "L", + "L", + "L", + "L", + "L", + "L", + "[B", + "[B", + "[B", + "[B" + ), + listOf( + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CHECK_CAST, + Opcode.MOVE_OBJECT_FROM16, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CHECK_CAST, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT, + Opcode.MOVE_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + ) + ), + MethodSignature( + MethodSignatureMetadata( + "home-ads-method-9", + MethodMetadata( + "Ljru;", + "", + ), + PatternScanMethod.Fuzzy(2), // FIXME: Test this threshold and find the best value. + packageMetadata, + signatureDescription, + "0.0.1" + ), + "V", + AccessFlags.PROTECTED or AccessFlags.CONSTRUCTOR, + listOf( + "L", + "L", + "L", + "L", + "L", + "L", + "L", + "L", + "L", + "L", + "L", + "L", + "L", + "L", + "[B", + "[B", + "[B", + "[B" + ), + listOf( + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.MOVE_OBJECT, + Opcode.CHECK_CAST, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.NEW_INSTANCE, + Opcode.INVOKE_DIRECT, + Opcode.IPUT_OBJECT, + ) + ), + MethodSignature( + MethodSignatureMetadata( + "home-ads-method-10", + MethodMetadata( + "Ljrv;", + "", + ), + PatternScanMethod.Fuzzy(2), // FIXME: Test this threshold and find the best value. + packageMetadata, + signatureDescription, + "0.0.1" + ), + "V", + AccessFlags.PROTECTED or AccessFlags.CONSTRUCTOR, + listOf( + "L", + "L", + "L", + "L", + "L", + "L", + "L", + "L", + "L", + "L", + "L", + "L", + "L", + "[B", + "[B", + "[B", + "[B" + ), + listOf( + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CHECK_CAST, + Opcode.IPUT_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.IPUT_OBJECT, + Opcode.NEW_INSTANCE, + Opcode.MOVE_OBJECT_FROM16, + Opcode.INVOKE_DIRECT, + Opcode.IPUT_OBJECT, + Opcode.NEW_INSTANCE, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.NEW_INSTANCE, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.CONST_16, + Opcode.INVOKE_DIRECT, + Opcode.NEW_INSTANCE, + Opcode.MOVE_OBJECT_FROM16, + ) + ), + MethodSignature( + MethodSignatureMetadata( + "home-ads-method-11", + MethodMetadata( + "Ljpm;", + "lX", + ), + PatternScanMethod.Fuzzy(2), // FIXME: Test this threshold and find the best value. + packageMetadata, + signatureDescription, + "0.0.1" + ), + "V", + AccessFlags.PUBLIC or AccessFlags.FINAL or AccessFlags.BRIDGE or AccessFlags.SYNTHETIC, + listOf("L", "L"), + listOf( + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CHECK_CAST, + Opcode.IPUT_OBJECT, + Opcode.IGET_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CHECK_CAST, + Opcode.IPUT_OBJECT, + Opcode.IGET_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CHECK_CAST, + Opcode.IPUT_OBJECT, + Opcode.IGET_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CHECK_CAST, + Opcode.IPUT_OBJECT, + Opcode.IGET_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CHECK_CAST, + Opcode.IPUT_OBJECT, + Opcode.IGET_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CHECK_CAST, + Opcode.IPUT_OBJECT, + Opcode.IGET_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CHECK_CAST, + Opcode.IPUT_OBJECT, + Opcode.IGET_OBJECT, + Opcode.INVOKE_STATIC, + ) + ), + MethodSignature( + MethodSignatureMetadata( + "home-ads-method-12", + MethodMetadata( + "Ljpr;", + "b", + ), + PatternScanMethod.Fuzzy(2), // FIXME: Test this threshold and find the best value. + packageMetadata, + signatureDescription, + "0.0.1" + ), + "V", + AccessFlags.PRIVATE or AccessFlags.FINAL, + listOf(), + listOf( + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.IGET_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CHECK_CAST, + Opcode.IPUT_OBJECT, + Opcode.IGET_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.IGET_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.IGET_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.IGET_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.IGET_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IGET_OBJECT, + Opcode.IGET_OBJECT, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.NEW_INSTANCE, + Opcode.INVOKE_DIRECT, + Opcode.IPUT_OBJECT, + Opcode.CONST_4, + Opcode.INVOKE_VIRTUAL, + Opcode.CONST_4, + Opcode.INVOKE_VIRTUAL, + Opcode.RETURN_VOID + ) + ), + MethodSignature( + MethodSignatureMetadata( + "home-ads-method-13", + MethodMetadata( + "Ljqk;", + "", + ), + PatternScanMethod.Fuzzy(2), // FIXME: Test this threshold and find the best value. + packageMetadata, + signatureDescription, + "0.0.1" + ), + "V", + AccessFlags.PROTECTED or AccessFlags.CONSTRUCTOR, + listOf( + "L", + "L", + "L", + "L", + "L", + "[B", + "[B" + ), + listOf( + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.CONST_4, + Opcode.INVOKE_STATIC, + ) + ), + MethodSignature( + MethodSignatureMetadata( + "home-ads-method-14", + MethodMetadata( + "Ljqa;", + "b", + ), + PatternScanMethod.Fuzzy(2), // FIXME: Test this threshold and find the best value. + packageMetadata, + signatureDescription, + "0.0.1" + ), + "V", + AccessFlags.PRIVATE or AccessFlags.FINAL, + listOf(), + listOf( + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.IGET_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CHECK_CAST, + Opcode.IPUT_OBJECT, + Opcode.IGET_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CHECK_CAST, + Opcode.IPUT_OBJECT, + Opcode.IGET_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CHECK_CAST, + Opcode.IPUT_OBJECT, + Opcode.IGET_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.IGET_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.IGET_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.IGET_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.RETURN_VOID + ) + ), + MethodSignature( + MethodSignatureMetadata( + "home-ads-method-15", + MethodMetadata( + "Ljra;", + "", + ), + PatternScanMethod.Fuzzy(2), // FIXME: Test this threshold and find the best value. + packageMetadata, + signatureDescription, + "0.0.1" + ), + "V", + AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, + listOf("L", "I"), + listOf( + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.MOVE_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.MOVE_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.MOVE_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.MOVE_OBJECT, + Opcode.CHECK_CAST, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.MOVE_OBJECT, + Opcode.CHECK_CAST, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.MOVE_OBJECT, + Opcode.CHECK_CAST, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.MOVE_OBJECT, + Opcode.CHECK_CAST, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CHECK_CAST, + Opcode.IPUT_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.NEW_INSTANCE, + Opcode.MOVE_OBJECT_FROM16, + Opcode.INVOKE_DIRECT, + Opcode.IPUT_OBJECT, + Opcode.NEW_INSTANCE, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.IGET_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.IGET_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.IGET_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.IGET_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.IGET_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.IGET_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.IGET_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.IGET_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.NEW_INSTANCE, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.CONST_4, + Opcode.MOVE_OBJECT_FROM16, + Opcode.CONST_4, + Opcode.INVOKE_DIRECT, + Opcode.NEW_INSTANCE, + Opcode.MOVE_OBJECT_FROM16, + Opcode.CONST_4, + Opcode.INVOKE_DIRECT, + Opcode.NEW_INSTANCE, + Opcode.MOVE_OBJECT_FROM16, + Opcode.INVOKE_DIRECT, + Opcode.CONST_16, + Opcode.INVOKE_DIRECT_RANGE, + Opcode.MOVE_OBJECT_FROM16, + Opcode.IPUT_OBJECT, + Opcode.NEW_INSTANCE, + Opcode.IGET_OBJECT, + Opcode.IGET_OBJECT, + Opcode.IGET_OBJECT, + Opcode.IGET_OBJECT, + Opcode.IGET_OBJECT, + Opcode.IGET_OBJECT, + Opcode.CONST_4, + Opcode.CONST_4, + Opcode.CONST_16, + Opcode.CONST_16, + Opcode.CONST_16, + Opcode.MOVE_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT, + Opcode.MOVE_OBJECT, + Opcode.INVOKE_DIRECT_RANGE, + Opcode.IPUT_OBJECT, + Opcode.NEW_INSTANCE, + Opcode.CONST, + Opcode.MOVE_OBJECT_FROM16, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CHECK_CAST, + Opcode.NEW_INSTANCE, + Opcode.CONST_4, + Opcode.INVOKE_DIRECT, + Opcode.INVOKE_DIRECT, + Opcode.IPUT_OBJECT, + Opcode.NEW_INSTANCE, + Opcode.MOVE_OBJECT_FROM16, + Opcode.INVOKE_DIRECT, + Opcode.IPUT_OBJECT, + Opcode.SGET_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.INVOKE_VIRTUAL, + Opcode.SGET_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.INVOKE_VIRTUAL, + Opcode.SGET_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.INVOKE_VIRTUAL, + Opcode.SGET_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.INVOKE_VIRTUAL, + Opcode.SGET_OBJECT, + Opcode.CONST_4, + Opcode.MOVE_OBJECT_FROM16, + Opcode.INVOKE_VIRTUAL, + Opcode.SGET_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.INVOKE_VIRTUAL, + Opcode.SGET_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.INVOKE_VIRTUAL, + Opcode.SGET_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.INVOKE_VIRTUAL, + Opcode.SGET_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.INVOKE_VIRTUAL, + Opcode.SGET_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.INVOKE_VIRTUAL, + Opcode.RETURN_VOID + ) + ), + MethodSignature( + MethodSignatureMetadata( + "home-ads-method-16", + MethodMetadata( + "Ljrd;", + "", + ), + PatternScanMethod.Fuzzy(2), // FIXME: Test this threshold and find the best value. + packageMetadata, + signatureDescription, + "0.0.1" + ), + "V", + AccessFlags.PROTECTED or AccessFlags.CONSTRUCTOR, + listOf( + "L", + "L", + "L", + "L", + "L", + "L", + "L", + "L", + "L", + "L", + "L", + "L", + "L", + "[B", + "[B", + "[B", + "[B" + ), + listOf( + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.MOVE_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.MOVE_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CHECK_CAST, + Opcode.IPUT_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CHECK_CAST, + Opcode.IPUT_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CHECK_CAST, + Opcode.IPUT_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CHECK_CAST, + Opcode.IPUT_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CHECK_CAST, + Opcode.IPUT_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CHECK_CAST, + Opcode.IPUT_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT, + Opcode.MOVE_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.NEW_INSTANCE, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.NEW_INSTANCE, + Opcode.MOVE_OBJECT_FROM16, + Opcode.CONST_4, + Opcode.INVOKE_DIRECT, + Opcode.CONST_4, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.INVOKE_DIRECT, + Opcode.IPUT_OBJECT, + Opcode.NEW_INSTANCE, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.NEW_INSTANCE, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.CONST_4, + Opcode.INVOKE_DIRECT, + Opcode.NEW_INSTANCE, + Opcode.MOVE_OBJECT_FROM16, + Opcode.CONST_4, + Opcode.INVOKE_DIRECT, + Opcode.NEW_INSTANCE, + Opcode.MOVE_OBJECT_FROM16, + Opcode.INVOKE_DIRECT, + Opcode.CONST_16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.INVOKE_DIRECT_RANGE, + Opcode.MOVE_OBJECT_FROM16, + Opcode.IPUT_OBJECT, + Opcode.NEW_INSTANCE, + Opcode.CONST_16, + Opcode.CONST_16, + Opcode.CONST_16, + Opcode.CONST_16, + Opcode.CONST_16, + Opcode.MOVE_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.INVOKE_DIRECT_RANGE, + Opcode.IPUT_OBJECT, + Opcode.NEW_INSTANCE, + Opcode.CONST_4, + Opcode.CONST_4, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.INVOKE_DIRECT_RANGE, + Opcode.IPUT_OBJECT, + Opcode.NEW_INSTANCE, + Opcode.CONST, + Opcode.MOVE_OBJECT_FROM16, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CHECK_CAST, + Opcode.NEW_INSTANCE, + Opcode.CONST_4, + Opcode.INVOKE_DIRECT, + Opcode.INVOKE_DIRECT, + Opcode.IPUT_OBJECT, + Opcode.NEW_INSTANCE, + Opcode.MOVE_OBJECT_FROM16, + Opcode.INVOKE_DIRECT, + Opcode.IPUT_OBJECT, + Opcode.SGET_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.INVOKE_VIRTUAL, + Opcode.SGET_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.INVOKE_VIRTUAL, + Opcode.SGET_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.INVOKE_VIRTUAL, + Opcode.SGET_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.INVOKE_VIRTUAL, + Opcode.SGET_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.INVOKE_VIRTUAL, + Opcode.SGET_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.INVOKE_VIRTUAL, + Opcode.SGET_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.INVOKE_VIRTUAL, + Opcode.SGET_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.INVOKE_VIRTUAL, + Opcode.SGET_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.INVOKE_VIRTUAL, + Opcode.SGET_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.INVOKE_VIRTUAL, + Opcode.RETURN_VOID + ) + ), + MethodSignature( + MethodSignatureMetadata( + "home-ads-method-17", + MethodMetadata( + "Ljre;", + "", + ), + PatternScanMethod.Fuzzy(2), // FIXME: Test this threshold and find the best value. + packageMetadata, + signatureDescription, + "0.0.1" + ), + "V", + AccessFlags.PROTECTED or AccessFlags.CONSTRUCTOR, + listOf( + "L", + "L", + "L", + "L", + "L", + "L", + "L", + "L", + "L", + "L", + "L", + "L", + "L", + "L", + "[B", + "[B", + "[B", + "[B" + ), + listOf( + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.MOVE_OBJECT, + Opcode.CHECK_CAST, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CHECK_CAST, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.MOVE_OBJECT, + Opcode.CHECK_CAST, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.MOVE_OBJECT, + Opcode.CHECK_CAST, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.MOVE_OBJECT, + Opcode.CHECK_CAST, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.MOVE_OBJECT, + Opcode.CHECK_CAST, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.MOVE_OBJECT, + Opcode.CHECK_CAST, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.NEW_INSTANCE, + Opcode.INVOKE_DIRECT, + Opcode.IPUT_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.NEW_INSTANCE, + Opcode.IF_NEZ, + Opcode.MOVE_OBJECT_FROM16, + Opcode.GOTO, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.NEW_INSTANCE, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.CONST_4, + Opcode.INVOKE_DIRECT, + Opcode.NEW_INSTANCE, + Opcode.MOVE_OBJECT_FROM16, + Opcode.CONST_16, + Opcode.INVOKE_DIRECT, + Opcode.NEW_INSTANCE, + Opcode.MOVE_OBJECT_FROM16, + Opcode.INVOKE_DIRECT, + Opcode.CONST_16, + Opcode.CONST_16, + Opcode.CONST_16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.INVOKE_DIRECT_RANGE, + Opcode.IPUT_OBJECT, + Opcode.NEW_INSTANCE, + Opcode.CONST_4, + Opcode.CONST_4, + Opcode.CONST_4, + Opcode.CONST_16, + Opcode.MOVE_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT, + Opcode.MOVE_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.INVOKE_DIRECT_RANGE, + Opcode.IPUT_OBJECT, + Opcode.NEW_INSTANCE, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CHECK_CAST, + Opcode.NEW_INSTANCE, + Opcode.CONST_16, + Opcode.INVOKE_DIRECT, + Opcode.INVOKE_DIRECT, + Opcode.IPUT_OBJECT, + Opcode.NEW_INSTANCE, + Opcode.MOVE_OBJECT_FROM16, + Opcode.INVOKE_DIRECT, + Opcode.IPUT_OBJECT, + Opcode.SGET_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.INVOKE_VIRTUAL, + Opcode.SGET_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.INVOKE_VIRTUAL, + Opcode.SGET_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.INVOKE_VIRTUAL, + Opcode.SGET_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.INVOKE_VIRTUAL, + Opcode.SGET_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.INVOKE_VIRTUAL, + Opcode.SGET_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.INVOKE_VIRTUAL, + Opcode.SGET_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.INVOKE_VIRTUAL, + Opcode.SGET_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_OBJECT_FROM16, + Opcode.IF_EQZ, + Opcode.SGET_OBJECT, + Opcode.INVOKE_VIRTUAL, + Opcode.RETURN_VOID + ) + ) + ) +) { + override fun execute(data: BytecodeData): PatchResult { + for (i in 0 until signatures.count()) { + val signature = signatures.elementAt(i) + val result = signature.result!! + val implementation = result.method.implementation!! + val index = result.scanData.startIndex + val instructions = implementation.instructions + + val register = (instructions[index + (if (i < 2) -1 else 1)] as Instruction11x).registerA + implementation.injectHideCall(index + 2, register) + } + + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/ad/HomePromoPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/ad/HomePromoPatch.kt new file mode 100644 index 000000000..60cf6105e --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/ad/HomePromoPatch.kt @@ -0,0 +1,188 @@ +package app.revanced.patches.youtube.ad + +import app.revanced.extensions.injectHideCall +import app.revanced.patcher.data.implementation.BytecodeData +import app.revanced.patcher.data.implementation.toMethodWalker +import app.revanced.patcher.extensions.or +import app.revanced.patcher.patch.implementation.BytecodePatch +import app.revanced.patcher.patch.implementation.metadata.PackageMetadata +import app.revanced.patcher.patch.implementation.metadata.PatchMetadata +import app.revanced.patcher.patch.implementation.misc.PatchResult +import app.revanced.patcher.patch.implementation.misc.PatchResultError +import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess +import app.revanced.patcher.proxy.mutableTypes.MutableMethod +import app.revanced.patcher.signature.MethodMetadata +import app.revanced.patcher.signature.MethodSignature +import app.revanced.patcher.signature.MethodSignatureMetadata +import app.revanced.patcher.signature.PatternScanMethod +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.Opcode +import org.jf.dexlib2.iface.instruction.formats.Instruction11x + +private val compatiblePackages = listOf( + PackageMetadata( + "com.google.android.youtube", + listOf("17.03.38", "17.14.35") + ) +) + +private val patchMetadata = PatchMetadata( + "home-promo-ads", + "Home Promo Ads Patch", + "Patch to remove promoted ads in YouTube", + compatiblePackages, + "0.0.1" +) + +private val signatureDescription = "Required signature for ${patchMetadata.name}. Discovered in version 17.03.38." + +class HomePromoPatch : BytecodePatch( + patchMetadata, + listOf( + MethodSignature( + MethodSignatureMetadata( + "promoted-discovery-app-parent-method", + MethodMetadata( + "Ljjl;", + "lG", + ), + PatternScanMethod.Fuzzy(2), // FIXME: Test this threshold and find the best value. + compatiblePackages, + signatureDescription, + "0.0.1" + ), + "V", + AccessFlags.PUBLIC or AccessFlags.FINAL or AccessFlags.BRIDGE or AccessFlags.SYNTHETIC, + listOf("L", "L"), + listOf( + Opcode.INVOKE_DIRECT, + Opcode.IGET_BOOLEAN, + Opcode.INVOKE_VIRTUAL, + Opcode.IGET_OBJECT, + Opcode.IGET_OBJECT, + Opcode.IF_NEZ, + Opcode.IGET_OBJECT, + Opcode.IGET_OBJECT, + Opcode.IF_NEZ, + Opcode.SGET_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.IGET_OBJECT, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IGET_OBJECT, + Opcode.IF_NEZ, + Opcode.IGET_OBJECT, + Opcode.IGET_OBJECT, + Opcode.INVOKE_INTERFACE, + Opcode.MOVE_RESULT, + Opcode.NEW_ARRAY, + Opcode.IPUT_OBJECT, + Opcode.CONST_4, + Opcode.INVOKE_INTERFACE, + Opcode.MOVE_RESULT, + Opcode.IF_GE, + Opcode.IGET_OBJECT, + Opcode.INVOKE_INTERFACE, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CHECK_CAST, + Opcode.APUT_OBJECT, + Opcode.ADD_INT_LIT8, + Opcode.GOTO + ) + ), + MethodSignature( + MethodSignatureMetadata( + "promoted-discovery-action-parent-method", + MethodMetadata( + "Ljjc;", + "lG", + ), + PatternScanMethod.Fuzzy(2), // FIXME: Test this threshold and find the best value. + compatiblePackages, + signatureDescription, + "0.0.1" + ), + "V", + AccessFlags.PUBLIC or AccessFlags.FINAL or AccessFlags.BRIDGE or AccessFlags.SYNTHETIC, + listOf("L", "L"), + listOf( + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, + Opcode.CHECK_CAST, + Opcode.INVOKE_VIRTUAL_RANGE, + Opcode.INVOKE_VIRTUAL, + Opcode.IGET_OBJECT, + Opcode.INVOKE_VIRTUAL, + Opcode.IGET_OBJECT, + Opcode.IGET_BOOLEAN, + Opcode.CONST_4, + Opcode.XOR_INT_2ADDR, + Opcode.IGET_BOOLEAN, + Opcode.INVOKE_DIRECT, + Opcode.IGET_BOOLEAN, + Opcode.INVOKE_VIRTUAL, + Opcode.IGET_OBJECT, + Opcode.IGET_OBJECT, + Opcode.IF_NEZ, + Opcode.IGET_OBJECT, + Opcode.IGET_OBJECT, + Opcode.IF_NEZ, + Opcode.SGET_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.IGET_OBJECT, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IGET_OBJECT, + Opcode.CONST_4, + Opcode.IF_NEZ, + Opcode.IGET_OBJECT, + Opcode.IGET_OBJECT + ) + ) + ) +) { + override fun execute(data: BytecodeData): PatchResult { + for (signature in signatures) { + val result = signature.result!! + + val methodMetadata = MethodMetadata(signature.metadata.methodMetadata!!.definingClass, "d") + val requiredMethod = result.findParentMethod( + MethodSignature( + MethodSignatureMetadata( + "promoted-discovery-action-parent-method", + methodMetadata, + PatternScanMethod.Fuzzy(2), // FIXME: Test this threshold and find the best value. + compatiblePackages, + signatureDescription, + "0.0.1" + ), + "V", + AccessFlags.PRIVATE or AccessFlags.FINAL, + listOf("Z", "Z"), + null + ) + ) + ?: return PatchResultError("Required parent method ${methodMetadata.name} could not be found in ${methodMetadata.definingClass}") + + val toBePatchedInvokeOffset = + requiredMethod.immutableMethod.implementation!!.instructions.indexOfFirst { it.opcode == Opcode.INVOKE_DIRECT } + val toBePatchedMethod = data + .toMethodWalker(requiredMethod.immutableMethod) + .walk(toBePatchedInvokeOffset, true) + .getMethod() as MutableMethod + + val implementation = toBePatchedMethod.implementation!! + val invokeVirtualOffset = implementation.instructions.indexOfFirst { it.opcode == Opcode.INVOKE_VIRTUAL } + + val moveResultInstruction = implementation.instructions[invokeVirtualOffset + 1] + if (moveResultInstruction.opcode != Opcode.MOVE_RESULT_OBJECT) + return PatchResultError("The toBePatchedInvokeOffset offset was wrong in ${metadata.name}") + + val register = (moveResultInstruction as Instruction11x).registerA + implementation.injectHideCall(invokeVirtualOffset + 2, register) + } + + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/ad/VideoAdsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/ad/VideoAdsPatch.kt new file mode 100644 index 000000000..4498d3354 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/ad/VideoAdsPatch.kt @@ -0,0 +1,112 @@ +package app.revanced.patches.youtube.ad + +import app.revanced.patcher.data.implementation.BytecodeData +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.extensions.or +import app.revanced.patcher.patch.implementation.BytecodePatch +import app.revanced.patcher.patch.implementation.metadata.PackageMetadata +import app.revanced.patcher.patch.implementation.metadata.PatchMetadata +import app.revanced.patcher.patch.implementation.misc.PatchResult +import app.revanced.patcher.patch.implementation.misc.PatchResultError +import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess +import app.revanced.patcher.signature.MethodMetadata +import app.revanced.patcher.signature.MethodSignature +import app.revanced.patcher.signature.MethodSignatureMetadata +import app.revanced.patcher.signature.PatternScanMethod +import app.revanced.patcher.smali.toInstructions +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.Opcode + +private val packageMetadata = listOf( + PackageMetadata( + "com.google.android.youtube", + listOf("17.14.35") + ) +) + +private val patchMetadata = PatchMetadata( + "video-ads", + "YouTube Video Ads Patch", + "Patch to remove ads in the YouTube video player.", + packageMetadata, + "0.0.1" +) + +class VideoAdsPatch : BytecodePatch( + patchMetadata, + listOf( + MethodSignature( + MethodSignatureMetadata( + "show-video-ads-constructor", + MethodMetadata( + "zai", + "", + ), + PatternScanMethod.Fuzzy(2),// FIXME: Test this threshold and find the best value. + packageMetadata, + "Required signature for ${patchMetadata.name}. Discovered in version 17.14.35.", + "0.0.1" + ), + "V", + AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, + listOf("L", "L", "L"), + listOf( + Opcode.INVOKE_DIRECT, + Opcode.NEW_INSTANCE, + Opcode.INVOKE_DIRECT, + Opcode.IPUT_OBJECT, + Opcode.NEW_INSTANCE, + null, // either CONST_4 or CONST_16 + Opcode.INVOKE_DIRECT, + Opcode.IPUT_OBJECT, + Opcode.NEW_INSTANCE, + Opcode.INVOKE_DIRECT, + Opcode.IPUT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.CONST_4, + Opcode.IPUT_BOOLEAN, + Opcode.RETURN_VOID + ) + ) + ) +) { + override fun execute(data: BytecodeData): PatchResult { + var result = signatures.first().result!! + + val responsibleMethodSignature = MethodSignature( + MethodSignatureMetadata( + "show-video-ads-method", + MethodMetadata( + "zai", + null // unknown + ), + PatternScanMethod.Direct(), + packageMetadata, + "Signature to find the method, which is responsible for showing the video ads. Discovered in version 17.14.35", + "0.0.1" + ), + "V", + AccessFlags.PUBLIC or AccessFlags.FINAL, + listOf("Z"), + null + ) + + result = result.findParentMethod( + responsibleMethodSignature + ) ?: return PatchResultError( + "Could not find parent method with signature ${responsibleMethodSignature.metadata.name}" + ) + + // Override the parameter by calling shouldShowAds and setting the parameter to the result + result.method.implementation!!.addInstructions( + 0, + """ + invoke-static { }, Lfi/vanced/libraries/youtube/whitelisting/Whitelist;->shouldShowAds()Z + move-result v1 + """.trimIndent().toInstructions() + ) + + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/interaction/EnableSeekbarTappingPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/interaction/EnableSeekbarTappingPatch.kt new file mode 100644 index 000000000..3f49f8309 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/interaction/EnableSeekbarTappingPatch.kt @@ -0,0 +1,196 @@ +package app.revanced.patches.youtube.interaction + +import app.revanced.patcher.data.implementation.BytecodeData +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.extensions.or +import app.revanced.patcher.patch.implementation.BytecodePatch +import app.revanced.patcher.patch.implementation.metadata.PackageMetadata +import app.revanced.patcher.patch.implementation.metadata.PatchMetadata +import app.revanced.patcher.patch.implementation.misc.PatchResult +import app.revanced.patcher.patch.implementation.misc.PatchResultError +import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess +import app.revanced.patcher.signature.MethodMetadata +import app.revanced.patcher.signature.MethodSignature +import app.revanced.patcher.signature.MethodSignatureMetadata +import app.revanced.patcher.signature.PatternScanMethod +import app.revanced.patcher.smali.toInstructions +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.Opcode +import org.jf.dexlib2.builder.instruction.BuilderInstruction21t +import org.jf.dexlib2.iface.Method +import org.jf.dexlib2.iface.instruction.formats.Instruction11n +import org.jf.dexlib2.iface.instruction.formats.Instruction35c + +private val compatiblePackages = listOf( + PackageMetadata( + "com.google.android.youtube", + listOf("17.14.35") + ) +) + +class EnableSeekbarTappingPatch : BytecodePatch( + PatchMetadata( + "seekbar-tapping", + "Enable seekbar tapping patch", + "Enable tapping on the seekbar of the YouTube player.", + compatiblePackages, + "0.0.1" + ), + listOf( + MethodSignature( + MethodSignatureMetadata( + "enable-seekbar-tapping-parent-signature", + MethodMetadata("Lesa;", ""), // unknown + PatternScanMethod.Fuzzy(2), // FIXME: Test this threshold and find the best value. + compatiblePackages, + "Signature for a parent method, which is needed to find the actual method required to be patched.", + "0.0.1" + ), + "L", + AccessFlags.PUBLIC or AccessFlags.FINAL, + listOf(), + listOf( + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CONST_4, + Opcode.NEW_ARRAY, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_WIDE, + Opcode.INVOKE_STATIC, + Opcode.MOVE_RESULT_OBJECT, + Opcode.INVOKE_STATIC, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CONST_4, + Opcode.APUT_OBJECT, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_WIDE, + Opcode.INVOKE_STATIC, + Opcode.MOVE_RESULT_OBJECT, + Opcode.INVOKE_STATIC, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CONST_4, + Opcode.APUT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.RETURN_OBJECT + ) + ), + MethodSignature( + MethodSignatureMetadata( + "enable-seekbar-tapping-signature", + MethodMetadata("Lesa;", "onTouchEvent"), // unknown + PatternScanMethod.Fuzzy(2), // FIXME: Test this threshold and find the best value. + compatiblePackages, + "Signature for the method required to be patched.", + "0.0.1" + ), + "Z", + AccessFlags.PUBLIC or AccessFlags.FINAL, + listOf("L"), + listOf( + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_WIDE, + Opcode.INT_TO_FLOAT, + Opcode.IGET, + Opcode.IGET_OBJECT, + Opcode.IGET, + Opcode.DIV_INT_2ADDR, + Opcode.ADD_INT, + Opcode.SUB_INT_2ADDR, + Opcode.INT_TO_FLOAT, + Opcode.CMPG_FLOAT, + Opcode.IF_GTZ, + Opcode.INT_TO_FLOAT, + Opcode.CMPG_FLOAT, + Opcode.IF_GTZ, + Opcode.CONST_4, + Opcode.INVOKE_INTERFACE, + Opcode.NEW_INSTANCE, + Opcode.INVOKE_DIRECT, + Opcode.IPUT_OBJECT, + Opcode.NEW_INSTANCE, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT, + Opcode.FLOAT_TO_INT, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT, + Opcode.FLOAT_TO_INT, + Opcode.INVOKE_DIRECT, + Opcode.IPUT_OBJECT, + Opcode.INVOKE_VIRTUAL + ) + ) + ) +) { + override fun execute(data: BytecodeData): PatchResult { + var result = signatures.first().result!! + + val tapSeekMethods = mutableMapOf() + + // find the methods which tap the seekbar + for (it in result.definingClassProxy.immutableClass.methods) { + if (it.implementation == null) continue + + 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) continue + + // we know that the 7th instruction has the opcode CONST_4 + val instruction = instructions.elementAt(6) + if (instruction.opcode != Opcode.CONST_4) continue + + // the literal for this instruction has to be either 1 or 2 + val literal = (instruction as Instruction11n).narrowLiteral + + // method founds + if (literal == 1) tapSeekMethods["P"] = it + if (literal == 2) tapSeekMethods["O"] = it + } + + // replace map because we dont need the upper one anymore + result = signatures.last().result!! + + val implementation = result.method.implementation!! + + // if tap-seeking is enabled, do not invoke the two methods below + val pMethod = tapSeekMethods["P"]!! + val oMethod = tapSeekMethods["O"]!! + + // get the required register + val instruction = implementation.instructions[result.scanData.endIndex] + if (instruction.opcode != Opcode.INVOKE_VIRTUAL) + return PatchResultError("Could not find the correct register") + val register = (instruction as Instruction35c).registerC + + // the instructions are written in reverse order. + implementation.addInstructions( + result.scanData.endIndex + 1, + """ + invoke-virtual { v$register, v2 }, ${oMethod.definingClass}->${oMethod.name}(I)V + invoke-virtual { v$register, v2 }, ${pMethod.definingClass}->${pMethod.name}(I)V + """.trimIndent().toInstructions() + ) + + // if tap-seeking is disabled, do not invoke the two methods above by jumping to the else label + val elseLabel = implementation.newLabelForIndex(result.scanData.endIndex + 1) + implementation.addInstruction( + result.scanData.endIndex + 1, + BuilderInstruction21t(Opcode.IF_EQZ, 0, elseLabel) + ) + implementation.addInstructions( + result.scanData.endIndex + 1, + """ + invoke-static { }, Lfi/razerman/youtube/preferences/BooleanPreferences;->isTapSeekingEnabled()Z + move-result v0 + """.trimIndent().toInstructions() + ) + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/CreateButtonRemoverPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/CreateButtonRemoverPatch.kt new file mode 100644 index 000000000..4bcde789a --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/CreateButtonRemoverPatch.kt @@ -0,0 +1,102 @@ +package app.revanced.patches.youtube.layout + +import app.revanced.patcher.data.implementation.BytecodeData +import app.revanced.patcher.extensions.or +import app.revanced.patcher.patch.implementation.BytecodePatch +import app.revanced.patcher.patch.implementation.metadata.PackageMetadata +import app.revanced.patcher.patch.implementation.metadata.PatchMetadata +import app.revanced.patcher.patch.implementation.misc.PatchResult +import app.revanced.patcher.patch.implementation.misc.PatchResultError +import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess +import app.revanced.patcher.signature.MethodMetadata +import app.revanced.patcher.signature.MethodSignature +import app.revanced.patcher.signature.MethodSignatureMetadata +import app.revanced.patcher.signature.PatternScanMethod +import app.revanced.patcher.smali.toInstruction +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.Opcode +import org.jf.dexlib2.iface.instruction.formats.Instruction35c + +private val compatiblePackages = listOf( + PackageMetadata( + "com.google.android.youtube", + listOf("17.14.35") + ) +) + +class CreateButtonRemoverPatch : BytecodePatch( + PatchMetadata( + "create-button", + "Create button patch", + "Disable the create button.", + compatiblePackages, + "0.0.1" + ), + listOf( + MethodSignature( + MethodSignatureMetadata( + "create-button-method", + MethodMetadata(null, null), // unknown + PatternScanMethod.Fuzzy(2), // FIXME: Test this threshold and find the best value. + compatiblePackages, + "Signature for the method required to be patched.", + "0.0.1" + ), + "V", + AccessFlags.PUBLIC or AccessFlags.FINAL, + listOf("Z"), + listOf( + Opcode.IGET, + Opcode.INVOKE_STATIC, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IF_NEZ, + Opcode.SGET_OBJECT, + Opcode.INVOKE_INTERFACE, + Opcode.MOVE_RESULT, + Opcode.IGET_OBJECT, + Opcode.IF_NEZ, + Opcode.SGET_OBJECT, + Opcode.IGET_OBJECT, + Opcode.IF_NEZ, + Opcode.SGET_OBJECT, + Opcode.IGET_OBJECT, + Opcode.IGET_OBJECT, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.INVOKE_STATIC, + Opcode.MOVE_RESULT_OBJECT, + Opcode.NEW_INSTANCE, + Opcode.NEW_INSTANCE, + Opcode.INVOKE_DIRECT, + Opcode.CONST, + Opcode.INVOKE_STATIC, + Opcode.MOVE_RESULT_OBJECT, + Opcode.MOVE_OBJECT, + Opcode.MOVE_OBJECT, + Opcode.INVOKE_DIRECT_RANGE, + Opcode.CONST_4, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + ) + ) + ) +) { + override fun execute(data: BytecodeData): PatchResult { + val result = signatures.first().result!! + + // Get the required register which holds the view object we need to pass to the method hideCreateButton + val implementation = result.method.implementation!! + val instruction = implementation.instructions[result.scanData.endIndex + 1] + if (instruction.opcode != Opcode.INVOKE_STATIC) + return PatchResultError("Could not find the correct register") + val register = (instruction as Instruction35c).registerC + + // Hide the button view via proxy by passing it to the hideCreateButton method + implementation.addInstruction( + result.scanData.endIndex + 1, + "invoke-static { v$register }, Lfi/razerman/youtube/XAdRemover;->hideCreateButton(Landroid/view/View;)V".toInstruction() + ) + + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/HideReelsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/HideReelsPatch.kt new file mode 100644 index 000000000..59fc80e6c --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/HideReelsPatch.kt @@ -0,0 +1,116 @@ +package app.revanced.patches.youtube.layout + +import app.revanced.patcher.data.implementation.BytecodeData +import app.revanced.patcher.extensions.or +import app.revanced.patcher.patch.implementation.BytecodePatch +import app.revanced.patcher.patch.implementation.metadata.PackageMetadata +import app.revanced.patcher.patch.implementation.metadata.PatchMetadata +import app.revanced.patcher.patch.implementation.misc.PatchResult +import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess +import app.revanced.patcher.signature.MethodMetadata +import app.revanced.patcher.signature.MethodSignature +import app.revanced.patcher.signature.MethodSignatureMetadata +import app.revanced.patcher.signature.PatternScanMethod +import app.revanced.patcher.smali.toInstruction +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.Opcode + +private val compatiblePackages = listOf( + PackageMetadata( + "com.google.android.youtube", + listOf("17.14.35") + ) +) + +class HideReelsPatch : BytecodePatch( + PatchMetadata( + "hide-reels", + "Hide reels patch", + "Hide reels on the page.", + compatiblePackages, + "0.0.1" + ), + listOf( + MethodSignature( + MethodSignatureMetadata( + "hide-reels-signature", + MethodMetadata(null, null), // unknown + PatternScanMethod.Fuzzy(3), // FIXME: Test this threshold and find the best value. + compatiblePackages, + "Signature for the method required to be patched.", + "0.0.1" + ), + "V", + AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, + listOf( + "L", + "L", + "L", + "L", + "L", + "L", + "L", + "L", + "L", + "L", + "L", + "[B", + "[B", + "[B", + "[B", + "[B", + "[B", + "[B" + ), + listOf( + Opcode.MOVE_OBJECT, + Opcode.MOVE_OBJECT, + Opcode.INVOKE_DIRECT, + Opcode.MOVE_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.MOVE_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.MOVE_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.MOVE_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.MOVE_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.IPUT_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.IPUT_OBJECT, + Opcode.NEW_INSTANCE, + Opcode.INVOKE_DIRECT, + Opcode.IPUT_OBJECT, + Opcode.NEW_INSTANCE, + Opcode.INVOKE_DIRECT, + Opcode.IPUT_OBJECT, + Opcode.MOVE_OBJECT_FROM16, + Opcode.IPUT_OBJECT, + Opcode.INVOKE_STATIC, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CONST, + Opcode.CONST_4, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IPUT_OBJECT + ) + ) + ) +) { + override fun execute(data: BytecodeData): PatchResult { + val result = signatures.first().result!! + val implementation = result.method.implementation!! + + // HideReel will hide the reel view before it is being used, + // so we pass the view to the HideReel method + implementation.addInstruction( + result.scanData.endIndex, + "invoke-static { v2 }, Lfi/razerman/youtube/XAdRemover;->HideReel(Landroid/view/View;)V".toInstruction() + ) + + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/MinimizedPlaybackPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/MinimizedPlaybackPatch.kt new file mode 100644 index 000000000..2383fcfd1 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/MinimizedPlaybackPatch.kt @@ -0,0 +1,89 @@ +package app.revanced.patches.youtube.layout + +import app.revanced.patcher.data.implementation.BytecodeData +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.extensions.or +import app.revanced.patcher.patch.implementation.BytecodePatch +import app.revanced.patcher.patch.implementation.metadata.PackageMetadata +import app.revanced.patcher.patch.implementation.metadata.PatchMetadata +import app.revanced.patcher.patch.implementation.misc.PatchResult +import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess +import app.revanced.patcher.signature.MethodMetadata +import app.revanced.patcher.signature.MethodSignature +import app.revanced.patcher.signature.MethodSignatureMetadata +import app.revanced.patcher.signature.PatternScanMethod +import app.revanced.patcher.smali.toInstructions +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.Opcode + +private val compatiblePackages = listOf( + PackageMetadata( + "com.google.android.youtube", + listOf("17.14.35") + ) +) + +class MinimizedPlaybackPatch : BytecodePatch( + PatchMetadata( + "minimized-playback", + "Minimized Playback Patch", + "Enable minimized and background playback.", + compatiblePackages, + "0.0.1" + ), + listOf( + MethodSignature( + MethodSignatureMetadata( + "minimized-playback-manager", + MethodMetadata(null, null), // unknown + PatternScanMethod.Fuzzy(2), // FIXME: Test this threshold and find the best value. + compatiblePackages, + "Signature for the method required to be patched.", + "0.0.1" + ), + "Z", + AccessFlags.PUBLIC or AccessFlags.STATIC, + listOf("L"), + listOf( + Opcode.CONST_4, + Opcode.IF_EQZ, + Opcode.IGET, + Opcode.AND_INT_LIT16, + Opcode.IF_EQZ, + Opcode.IGET_OBJECT, + Opcode.IF_NEZ, + Opcode.SGET_OBJECT, + Opcode.IGET, + Opcode.CONST, + Opcode.IF_NE, + Opcode.IGET_OBJECT, + Opcode.IF_NEZ, + Opcode.SGET_OBJECT, + Opcode.IGET, + Opcode.IF_NE, + Opcode.IGET_OBJECT, + Opcode.CHECK_CAST, + Opcode.GOTO, + Opcode.SGET_OBJECT, + Opcode.GOTO, + Opcode.CONST_4, + Opcode.IF_EQZ, + Opcode.IGET_BOOLEAN, + Opcode.IF_EQZ + ) + ) + ) +) { + override fun execute(data: BytecodeData): PatchResult { + // Instead of removing all instructions like Vanced, + // we return the method at the beginning instead + signatures.first().result!!.method.implementation!!.addInstructions( + 0, + """ + const/4 v0, 0x1 + return v0 + """.trimIndent().toInstructions() + ) + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/OldQualityLayoutPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/OldQualityLayoutPatch.kt new file mode 100644 index 000000000..65eb3744b --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/OldQualityLayoutPatch.kt @@ -0,0 +1,127 @@ +package app.revanced.patches.youtube.layout + +import app.revanced.patcher.data.implementation.BytecodeData +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.extensions.or +import app.revanced.patcher.patch.implementation.BytecodePatch +import app.revanced.patcher.patch.implementation.metadata.PackageMetadata +import app.revanced.patcher.patch.implementation.metadata.PatchMetadata +import app.revanced.patcher.patch.implementation.misc.PatchResult +import app.revanced.patcher.patch.implementation.misc.PatchResultError +import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess +import app.revanced.patcher.signature.MethodMetadata +import app.revanced.patcher.signature.MethodSignature +import app.revanced.patcher.signature.MethodSignatureMetadata +import app.revanced.patcher.signature.PatternScanMethod +import app.revanced.patcher.smali.toInstructions +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.Opcode +import org.jf.dexlib2.builder.instruction.BuilderInstruction21t + +private val compatiblePackages = listOf( + PackageMetadata( + "com.google.android.youtube", + listOf("17.14.35") + ) +) + +class OldQualityLayoutPatch : BytecodePatch( + PatchMetadata( + "old-quality-layout", + "Old Quality Layout Patch", + "Enable the original quality flyout menu", + compatiblePackages, + "0.0.1" + ), + listOf( + MethodSignature( + MethodSignatureMetadata( + "old-quality-parent-method-signature", + MethodMetadata(null, null), // unknown + PatternScanMethod.Fuzzy(2), // FIXME: Test this threshold and find the best value. + compatiblePackages, + "Signature to find a parent method required by the Old Quality Layout patch.", + "0.0.1" + ), + "V", + AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, + listOf("L", "L", "L", "L", "L", "L", "L", "[B"), + listOf( + Opcode.INVOKE_DIRECT, + Opcode.IPUT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.SGET_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.SGET_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IGET_OBJECT, + Opcode.IF_NEZ, + Opcode.SGET_OBJECT, + Opcode.IGET_OBJECT, + Opcode.IF_NEZ, + Opcode.SGET_OBJECT, + Opcode.IGET_BOOLEAN, + Opcode.CONST_4, + Opcode.CONST_4, + Opcode.CONST_4, + ) + ) + ) +) { + override fun execute(data: BytecodeData): PatchResult { + var result = signatures.first().result!! + + result = result.findParentMethod( + MethodSignature( + MethodSignatureMetadata( + "old-quality-method-signature", + MethodMetadata(null, null), // unknown + PatternScanMethod.Fuzzy(2), // FIXME: Test this threshold and find the best value. + compatiblePackages, + "Signature to find the method required by the Old Quality Layout patch", + "0.0.1" + ), + "L", + AccessFlags.FINAL or AccessFlags.PRIVATE, + listOf("Z"), + listOf( + Opcode.CONST_4, + Opcode.INVOKE_VIRTUAL, + Opcode.IGET_OBJECT, + Opcode.IGET_OBJECT, + Opcode.INVOKE_VIRTUAL, + Opcode.IGET_OBJECT, + Opcode.GOTO, + Opcode.IGET_OBJECT, + ) + ) + ) ?: return PatchResultError("Method old-quality-patch-method has not been found") + + val implementation = result.method.implementation!! + + // if useOldStyleQualitySettings == true, jump over all instructions + val jmpInstruction = + BuilderInstruction21t( + Opcode.IF_NEZ, + 0, + implementation.instructions[result.scanData.endIndex].location.labels.first() + ) + implementation.addInstruction(5, jmpInstruction) + implementation.addInstructions( + 0, + """ + invoke-static { }, Lfi/razerman/youtube/XGlobals;->useOldStyleQualitySettings()Z + move-result v0 + """.trimIndent().toInstructions() + ) + + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/ShortsButtonRemoverPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/ShortsButtonRemoverPatch.kt new file mode 100644 index 000000000..0b0102c66 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/ShortsButtonRemoverPatch.kt @@ -0,0 +1,135 @@ +package app.revanced.patches.youtube.layout + +import app.revanced.patcher.data.implementation.BytecodeData +import app.revanced.patcher.extensions.or +import app.revanced.patcher.patch.implementation.BytecodePatch +import app.revanced.patcher.patch.implementation.metadata.PackageMetadata +import app.revanced.patcher.patch.implementation.metadata.PatchMetadata +import app.revanced.patcher.patch.implementation.misc.PatchResult +import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess +import app.revanced.patcher.signature.MethodMetadata +import app.revanced.patcher.signature.MethodSignature +import app.revanced.patcher.signature.MethodSignatureMetadata +import app.revanced.patcher.signature.PatternScanMethod +import app.revanced.patcher.smali.toInstruction +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.Opcode +import org.jf.dexlib2.iface.instruction.formats.Instruction11x + +private val compatiblePackages = listOf( + PackageMetadata( + "com.google.android.youtube", + listOf("17.14.35") + ) +) + +class ShortsButtonRemoverPatch : BytecodePatch( + PatchMetadata( + "shorts-button", + "Shorts button patch", + "Hide the shorts button.", + compatiblePackages, + "0.0.1" + ), + listOf( + MethodSignature( + MethodSignatureMetadata( + "pivotbar-buttons-method-tabenum", + MethodMetadata(null, null), // unknown + PatternScanMethod.Fuzzy(2), // FIXME: Test this threshold and find the best value. + compatiblePackages, + "Signature for the pivotbar method that creates all button views.", + "0.0.1" + ), + "V", + AccessFlags.PUBLIC or AccessFlags.FINAL, + listOf("Z"), + listOf( + Opcode.CHECK_CAST, + Opcode.IGET_OBJECT, + Opcode.IF_NEZ, + Opcode.SGET_OBJECT, + Opcode.IGET, + Opcode.INVOKE_STATIC, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IF_NEZ, + Opcode.SGET_OBJECT, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT, + Opcode.IGET_OBJECT, + Opcode.CHECK_CAST, + Opcode.IGET_OBJECT, + Opcode.IF_NEZ, + Opcode.SGET_OBJECT, + Opcode.IGET, + Opcode.INVOKE_STATIC, // SomeEnum.fromValue(tabOrdinal) + Opcode.MOVE_RESULT_OBJECT + ) + ), + MethodSignature( + MethodSignatureMetadata( + "pivotbar-buttons-method-view", + MethodMetadata(null, null), // unknown + PatternScanMethod.Fuzzy(2), // FIXME: Test this threshold and find the best value. + compatiblePackages, + "Signature for the pivotbar method that creates all button views.", + "0.0.1" + ), + "V", + AccessFlags.PUBLIC or AccessFlags.FINAL, + listOf("Z"), + listOf( + Opcode.NEW_INSTANCE, // new StateListDrawable() + Opcode.INVOKE_DIRECT, + Opcode.NEW_ARRAY, + Opcode.CONST, + Opcode.CONST_16, + Opcode.APUT, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.INVOKE_STATIC, + Opcode.MOVE_RESULT_OBJECT, + Opcode.INVOKE_VIRTUAL, + Opcode.SGET_OBJECT, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.INVOKE_STATIC, + Opcode.MOVE_RESULT_OBJECT, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_OBJECT, + Opcode.MOVE_OBJECT, + Opcode.MOVE, + Opcode.MOVE_OBJECT, + Opcode.INVOKE_VIRTUAL_RANGE, // pivotBar.getView(drawable, tabName, z, i, map, akebVar, optional) + Opcode.MOVE_RESULT_OBJECT, + ) + ), + ) +) { + override fun execute(data: BytecodeData): PatchResult { + val result1 = signatures.first().result!! + val implementation1 = result1.method.implementation!! + val moveEnumInstruction = implementation1.instructions[result1.scanData.endIndex] + val enumRegister = (moveEnumInstruction as Instruction11x).registerA + + val result2 = signatures.last().result!! + val implementation2 = result2.method.implementation!! + val moveViewInstruction = implementation2.instructions[result2.scanData.endIndex] + val viewRegister = (moveViewInstruction as Instruction11x).registerA + + // Save the tab enum in XGlobals to avoid smali/register workarounds + implementation1.addInstruction( + result1.scanData.endIndex + 1, + "sput-object v$enumRegister, Lfi/razerman/youtube/XGlobals;->lastPivotTab:Ljava/lang/Enum;".toInstruction() + ) + + // Hide the button view via proxy by passing it to the hideShortsButton method + // It only hides it if the last tab name is "TAB_SHORTS" + implementation2.addInstruction( + result2.scanData.endIndex + 2, + "invoke-static { v$viewRegister }, Lfi/razerman/youtube/XAdRemover;->hideShortsButton(Landroid/view/View;)V".toInstruction() + ) + + return PatchResultSuccess() + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/FixLocaleConfigErrorPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/FixLocaleConfigErrorPatch.kt new file mode 100644 index 000000000..873ea1ad0 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/FixLocaleConfigErrorPatch.kt @@ -0,0 +1,46 @@ +package app.revanced.patches.youtube.misc + +import app.revanced.patcher.data.implementation.ResourceData +import app.revanced.patcher.patch.implementation.ResourcePatch +import app.revanced.patcher.patch.implementation.metadata.PackageMetadata +import app.revanced.patcher.patch.implementation.metadata.PatchMetadata +import app.revanced.patcher.patch.implementation.misc.PatchResult +import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess +import org.w3c.dom.Element + +private val compatiblePackages = listOf( + PackageMetadata( + "com.google.android.youtube", + listOf("17.14.35") + ) +) +class FixLocaleConfigErrorPatch : ResourcePatch( + PatchMetadata( + "locale-config-fix", + "Manifest attribute fix patch", + "Fix an error when building the resources by patching the manifest file.", + compatiblePackages, + "0.0.1" + ), +) { + override fun execute(data: ResourceData): PatchResult { + // create an xml editor instance + val editor = data.getXmlEditor("AndroidManifest.xml") + + // edit the application nodes attribute... + val applicationNode = editor + .file + .getElementsByTagName("application") + .item(0) as Element + + // by replacing the attributes name + val attribute = "android:localeConfig" + applicationNode.setAttribute("localeConfig", applicationNode.getAttribute(attribute)) + applicationNode.removeAttribute("android:localeConfig") + + // close & save the modified file + editor.close() + + return PatchResultSuccess() + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/IntegrationsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/IntegrationsPatch.kt new file mode 100644 index 000000000..7683f18fb --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/IntegrationsPatch.kt @@ -0,0 +1,125 @@ +package app.revanced.patches.youtube.misc + +import app.revanced.patcher.data.implementation.BytecodeData +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.extensions.or +import app.revanced.patcher.patch.implementation.BytecodePatch +import app.revanced.patcher.patch.implementation.metadata.PackageMetadata +import app.revanced.patcher.patch.implementation.metadata.PatchMetadata +import app.revanced.patcher.patch.implementation.misc.PatchResult +import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess +import app.revanced.patcher.proxy.mutableTypes.MutableMethod.Companion.toMutable +import app.revanced.patcher.signature.MethodMetadata +import app.revanced.patcher.signature.MethodSignature +import app.revanced.patcher.signature.MethodSignatureMetadata +import app.revanced.patcher.signature.PatternScanMethod +import app.revanced.patcher.smali.toInstructions +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.Opcode +import org.jf.dexlib2.immutable.ImmutableMethod +import org.jf.dexlib2.immutable.ImmutableMethodImplementation + +private val compatiblePackages = listOf( + PackageMetadata( + "com.google.android.youtube", + listOf("17.03.38", "17.14.35") + ) +) + +class IntegrationsPatch : BytecodePatch( + PatchMetadata( + "integrations", + "Inject Integrations Patch", + "Applies mandatory patches to implement the ReVanced integrations into the application.", + compatiblePackages, + "0.0.1" + ), + listOf( + MethodSignature( + MethodSignatureMetadata( + "integrations-patch", + MethodMetadata(null, null), // unknown + PatternScanMethod.Fuzzy(2), // FIXME: Test this threshold and find the best value. + compatiblePackages, + "Inject the integrations into the application with the method of this signature", + "0.0.1" + ), + "V", + AccessFlags.PUBLIC.value, + listOf(), + listOf( + Opcode.SGET_OBJECT, + Opcode.NEW_INSTANCE, + Opcode.INVOKE_DIRECT, + Opcode.IGET_OBJECT, + Opcode.CONST_STRING, + Opcode.IF_NEZ, + Opcode.IGET_OBJECT, + Opcode.IGET_OBJECT, + Opcode.IGET_OBJECT, + Opcode.IGET_OBJECT, + Opcode.MOVE_OBJECT, + Opcode.CHECK_CAST, + Opcode.MOVE_OBJECT, + Opcode.CHECK_CAST, + Opcode.CONST_4, + Opcode.CONST_STRING, + Opcode.INVOKE_INTERFACE_RANGE, + Opcode.MOVE_RESULT_OBJECT, + Opcode.INVOKE_STATIC, + Opcode.MOVE_RESULT_OBJECT, + Opcode.SPUT_OBJECT, + Opcode.SGET_OBJECT, + Opcode.INVOKE_STATIC, + Opcode.INVOKE_STATIC, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IGET_OBJECT, + Opcode.INVOKE_INTERFACE, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CHECK_CAST, + Opcode.INVOKE_VIRTUAL, + Opcode.INVOKE_SUPER, + Opcode.INVOKE_VIRTUAL + ) + ) + ) +) { + override fun execute(data: BytecodeData): PatchResult { + val result = signatures.first().result!! + + val implementation = result.method.implementation!! + val count = implementation.registerCount - 1 + + implementation.addInstructions( + result.scanData.endIndex + 1, + """ + invoke-static {v$count}, Lpl/jakubweg/StringRef;->setContext(Landroid/content/Context;)V + sput-object v$count, Lapp/revanced/integrations/Globals;->context:Landroid/content/Context; + """.trimIndent().toInstructions() + ) + + val classDef = result.definingClassProxy.resolve() + classDef.methods.add( + ImmutableMethod( + classDef.type, + "getAppContext", + null, + "Landroid/content/Context;", + AccessFlags.PUBLIC or AccessFlags.STATIC, + null, + null, + ImmutableMethodImplementation( + 1, + """ + invoke-static { }, Lapp/revanced/integrations/Globals;->getAppContext()Landroid/content/Context; + move-result-object v0 + return-object v0 + """.trimIndent().toInstructions(), + null, + null + ) + ).toMutable() + ) + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/test/kotlin/app/revanced/patches/SignatureChecker.kt b/src/test/kotlin/app/revanced/patches/SignatureChecker.kt new file mode 100644 index 000000000..43bf21de7 --- /dev/null +++ b/src/test/kotlin/app/revanced/patches/SignatureChecker.kt @@ -0,0 +1,59 @@ +package app.revanced.patches + +import app.revanced.patcher.Patcher +import app.revanced.patcher.signature.MethodMetadata +import app.revanced.patcher.signature.MethodSignature +import app.revanced.patcher.signature.PatternScanMethod +import org.jf.dexlib2.iface.Method +import org.junit.Test +import java.io.File + +internal class SignatureChecker { + @Test + fun checkSignatures() { + return + // FIXME: instead of having this as a test, it should be turned into a task which can be ran manually + val file = File("stock.apk") + if (!file.exists()) { + throw IllegalStateException("Missing $file! To run this test, please place stock.apk here: ${file.absolutePath}") + } + val patcher = Patcher(file, "signatureCheckerCache", false) + patcher.addPatches(Index.patches.map { it() }) + val unresolved = mutableListOf() + for (signature in patcher.resolveSignatures()) { + if (!signature.resolved) { + unresolved.add(signature) + continue + } + + val patternScanMethod = signature.metadata.patternScanMethod + if (patternScanMethod is PatternScanMethod.Fuzzy) { + val warnings = patternScanMethod.warnings!! + val method = signature.result!!.method + val methodFromMetadata = + if (signature.metadata.methodMetadata != null) signature.metadata.methodMetadata!! else MethodMetadata( + null, + null + ) + + println("Signature: ${signature.metadata.name}.\nMethod: ${methodFromMetadata.definingClass}->${methodFromMetadata.name} (Signature matches: ${method.definingClass}->${method.toStr()})\nWarnings: ${warnings.count()}") + for (warning in warnings) { + println("${warning.instructionIndex} / ${warning.patternIndex}: ${warning.wrongOpcode} (expected: ${warning.correctOpcode})") + } + + println("=".repeat(20)) + } + } + if (unresolved.isNotEmpty()) { + val base = Exception("${unresolved.size} signatures were not resolved.") + for (signature in unresolved) { + base.addSuppressed(Exception("Signature ${signature.metadata.name} was not resolved!")) + } + throw base + } + } + + private fun Method.toStr(): String { + return "${this.name}(${this.parameterTypes.joinToString("")})${this.returnType}" + } +} \ No newline at end of file