From a60975717d29711f3e08e6550013294823b1697e Mon Sep 17 00:00:00 2001 From: crimera Date: Sun, 12 May 2024 20:42:31 +0800 Subject: [PATCH 01/12] update and add dependencies --- build.gradle.kts | 13 ++++++++++--- gradle.properties | 2 +- gradle/libs.versions.toml | 8 +++++++- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 0604cde9..0d16655a 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,7 +1,8 @@ import org.gradle.kotlin.dsl.support.listFilesOrdered plugins { - kotlin("jvm") version "1.9.23" + alias(libs.plugins.kotlin) + alias(libs.plugins.binary.compatibility.validator) `maven-publish` } @@ -11,7 +12,13 @@ repositories { mavenCentral() mavenLocal() google() - maven { url = uri("https://jitpack.io") } + maven { + url = uri("https://maven.pkg.github.com/revanced/registry") + credentials { + username = project.findProperty("gpr.user") as String? ?: System.getenv("GITHUB_ACTOR") + password = project.findProperty("gpr.key") as String? ?: System.getenv("GITHUB_TOKEN") + } + } } dependencies { @@ -59,7 +66,7 @@ tasks { exec { workingDir = workingDirectory - commandLine = listOf(d8, artifacts) + commandLine = listOf(d8, "--release", artifacts) } exec { diff --git a/gradle.properties b/gradle.properties index 2aa36b11..97a7898b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.parallel = true org.gradle.caching = true kotlin.code.style = official -version = 1.27.0-dev.8 +version = 1.27.0-dev.8 \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index dc46a812..75763c75 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,11 +1,17 @@ [versions] -revanced-patcher = "19.2.0" +revanced-patcher = "19.3.1" smali = "3.0.5" guava = "33.1.0-jre" gson = "2.10.1" +binary-compatibility-validator = "0.14.0" +kotlin = "1.9.22" [libraries] revanced-patcher = { module = "app.revanced:revanced-patcher", version.ref = "revanced-patcher" } smali = { module = "com.android.tools.smali:smali", version.ref = "smali" } guava = { module = "com.google.guava:guava", version.ref = "guava" } gson = { module = "com.google.code.gson:gson", version.ref = "gson" } + +[plugins] +binary-compatibility-validator = { id = "org.jetbrains.kotlinx.binary-compatibility-validator", version.ref = "binary-compatibility-validator" } +kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } \ No newline at end of file From 60263648353942b3872283200c6f50ea023f8b58 Mon Sep 17 00:00:00 2001 From: crimera Date: Wed, 15 May 2024 22:07:53 +0800 Subject: [PATCH 02/12] add `Download patch` --- build.gradle.kts | 1 - .../kotlin/app/revanced/util/BytecodeUtils.kt | 142 ++++++++++++++++++ .../app/{ => revanced}/util/ResourceUtils.kt | 0 .../util/resource/ArrayResource.kt | 0 .../util/resource/BaseResource.kt | 0 .../util/resource/StringResource.kt | 0 .../interaction/download/DownloadPatch.kt | 130 ++++++++++++++++ .../DialogItemClickedFingerprint.kt | 7 + .../FeedBottomSheetFingerprint.kt | 7 + .../fingerprints/FeedItemClassFingerprint.kt | 11 ++ .../FeedItemClassNameHookFingerprint.kt | 9 ++ .../fingerprints/FeedItemIconsFingerprint.kt | 7 + ...dOptionItemIconClassNameHookFingerprint.kt | 9 ++ .../MediaOptionsSheetFingerprint.kt | 7 + .../twitter/featureFlag/FeatureFlagPatch.kt | 43 +++++- 15 files changed, 364 insertions(+), 9 deletions(-) create mode 100644 src/main/kotlin/app/revanced/util/BytecodeUtils.kt rename src/main/kotlin/app/{ => revanced}/util/ResourceUtils.kt (100%) rename src/main/kotlin/app/{ => revanced}/util/resource/ArrayResource.kt (100%) rename src/main/kotlin/app/{ => revanced}/util/resource/BaseResource.kt (100%) rename src/main/kotlin/app/{ => revanced}/util/resource/StringResource.kt (100%) create mode 100644 src/main/kotlin/crimera/patches/instagram/interaction/download/DownloadPatch.kt create mode 100644 src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/DialogItemClickedFingerprint.kt create mode 100644 src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/FeedBottomSheetFingerprint.kt create mode 100644 src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/FeedItemClassFingerprint.kt create mode 100644 src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/FeedItemClassNameHookFingerprint.kt create mode 100644 src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/FeedItemIconsFingerprint.kt create mode 100644 src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/FeedOptionItemIconClassNameHookFingerprint.kt create mode 100644 src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/MediaOptionsSheetFingerprint.kt diff --git a/build.gradle.kts b/build.gradle.kts index 0d16655a..aff2bd28 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -2,7 +2,6 @@ import org.gradle.kotlin.dsl.support.listFilesOrdered plugins { alias(libs.plugins.kotlin) - alias(libs.plugins.binary.compatibility.validator) `maven-publish` } diff --git a/src/main/kotlin/app/revanced/util/BytecodeUtils.kt b/src/main/kotlin/app/revanced/util/BytecodeUtils.kt new file mode 100644 index 00000000..f4356650 --- /dev/null +++ b/src/main/kotlin/app/revanced/util/BytecodeUtils.kt @@ -0,0 +1,142 @@ +package app.revanced.util + +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.InstructionExtensions.addInstruction +import app.revanced.patcher.extensions.InstructionExtensions.addInstructions +import app.revanced.patcher.fingerprint.MethodFingerprint +import app.revanced.patcher.patch.PatchException +import app.revanced.patcher.util.proxy.mutableTypes.MutableClass +import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod +import com.android.tools.smali.dexlib2.iface.Method +import com.android.tools.smali.dexlib2.iface.instruction.Instruction +import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction +import com.android.tools.smali.dexlib2.iface.instruction.WideLiteralInstruction +import com.android.tools.smali.dexlib2.iface.reference.Reference +import com.android.tools.smali.dexlib2.util.MethodUtil + +fun MethodFingerprint.resultOrThrow() = result ?: throw exception + +/** + * The [PatchException] of failing to resolve a [MethodFingerprint]. + * + * @return The [PatchException]. + */ +val MethodFingerprint.exception + get() = PatchException("Failed to resolve ${this.javaClass.simpleName}") + +/** + * Find the [MutableMethod] from a given [Method] in a [MutableClass]. + * + * @param method The [Method] to find. + * @return The [MutableMethod]. + */ +fun MutableClass.findMutableMethodOf(method: Method) = this.methods.first { + MethodUtil.methodSignaturesMatch(it, method) +} + +/** + * Apply a transform to all methods of the class. + * + * @param transform The transformation function. Accepts a [MutableMethod] and returns a transformed [MutableMethod]. + */ +fun MutableClass.transformMethods(transform: MutableMethod.() -> MutableMethod) { + val transformedMethods = methods.map { it.transform() } + methods.clear() + methods.addAll(transformedMethods) +} + +/** + * Inject a call to a method that hides a view. + * + * @param insertIndex The index to insert the call at. + * @param viewRegister The register of the view to hide. + * @param classDescriptor The descriptor of the class that contains the method. + * @param targetMethod The name of the method to call. + */ +fun MutableMethod.injectHideViewCall( + insertIndex: Int, + viewRegister: Int, + classDescriptor: String, + targetMethod: String, +) = addInstruction( + insertIndex, + "invoke-static { v$viewRegister }, $classDescriptor->$targetMethod(Landroid/view/View;)V", +) + +/** + * Find the index of the first wide literal instruction with the given value. + * + * @return the first literal instruction with the value, or -1 if not found. + */ +fun Method.indexOfFirstWideLiteralInstructionValue(literal: Long) = implementation?.let { + it.instructions.indexOfFirst { instruction -> + (instruction as? WideLiteralInstruction)?.wideLiteral == literal + } +} ?: -1 + +/** + * Check if the method contains a literal with the given value. + * + * @return if the method contains a literal with the given value. + */ +fun Method.containsWideLiteralInstructionValue(literal: Long) = + indexOfFirstWideLiteralInstructionValue(literal) >= 0 + +/** + * Traverse the class hierarchy starting from the given root class. + * + * @param targetClass the class to start traversing the class hierarchy from. + * @param callback function that is called for every class in the hierarchy. + */ +fun BytecodeContext.traverseClassHierarchy(targetClass: MutableClass, callback: MutableClass.() -> Unit) { + callback(targetClass) + this.findClass(targetClass.superclass ?: return)?.mutableClass?.let { + traverseClassHierarchy(it, callback) + } +} + +/** + * Get the [Reference] of an [Instruction] as [T]. + * + * @param T The type of [Reference] to cast to. + * @return The [Reference] as [T] or null + * if the [Instruction] is not a [ReferenceInstruction] or the [Reference] is not of type [T]. + * @see ReferenceInstruction + */ +inline fun Instruction.getReference() = (this as? ReferenceInstruction)?.reference as? T + +/** + * Get the index of the first [Instruction] that matches the predicate. + * + * @param predicate The predicate to match. + * @return The index of the first [Instruction] that matches the predicate. + */ +fun Method.indexOfFirstInstruction(predicate: Instruction.() -> Boolean) = + this.implementation!!.instructions.indexOfFirst(predicate) + +/** + * Return the resolved methods of [MethodFingerprint]s early. + */ +fun List.returnEarly(bool: Boolean = false) { + val const = if (bool) "0x1" else "0x0" + this.forEach { fingerprint -> + fingerprint.result?.let { result -> + val stringInstructions = when (result.method.returnType.first()) { + 'L' -> + """ + const/4 v0, $const + return-object v0 + """ + 'V' -> "return-void" + 'I', 'Z' -> + """ + const/4 v0, $const + return v0 + """ + else -> throw Exception("This case should never happen.") + } + + result.mutableMethod.addInstructions(0, stringInstructions) + } ?: throw fingerprint.exception + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/util/ResourceUtils.kt b/src/main/kotlin/app/revanced/util/ResourceUtils.kt similarity index 100% rename from src/main/kotlin/app/util/ResourceUtils.kt rename to src/main/kotlin/app/revanced/util/ResourceUtils.kt diff --git a/src/main/kotlin/app/util/resource/ArrayResource.kt b/src/main/kotlin/app/revanced/util/resource/ArrayResource.kt similarity index 100% rename from src/main/kotlin/app/util/resource/ArrayResource.kt rename to src/main/kotlin/app/revanced/util/resource/ArrayResource.kt diff --git a/src/main/kotlin/app/util/resource/BaseResource.kt b/src/main/kotlin/app/revanced/util/resource/BaseResource.kt similarity index 100% rename from src/main/kotlin/app/util/resource/BaseResource.kt rename to src/main/kotlin/app/revanced/util/resource/BaseResource.kt diff --git a/src/main/kotlin/app/util/resource/StringResource.kt b/src/main/kotlin/app/revanced/util/resource/StringResource.kt similarity index 100% rename from src/main/kotlin/app/util/resource/StringResource.kt rename to src/main/kotlin/app/revanced/util/resource/StringResource.kt diff --git a/src/main/kotlin/crimera/patches/instagram/interaction/download/DownloadPatch.kt b/src/main/kotlin/crimera/patches/instagram/interaction/download/DownloadPatch.kt new file mode 100644 index 00000000..162ea76e --- /dev/null +++ b/src/main/kotlin/crimera/patches/instagram/interaction/download/DownloadPatch.kt @@ -0,0 +1,130 @@ +package crimera.patches.instagram.interaction.download + +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.InstructionExtensions.addInstructions +import app.revanced.patcher.extensions.InstructionExtensions.getInstructions +import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.annotation.CompatiblePackage +import app.revanced.patcher.patch.annotation.Patch +import app.revanced.util.exception +import com.android.tools.smali.dexlib2.Opcode +import crimera.patches.instagram.interaction.download.fingerprints.* +import crimera.patches.instagram.interaction.download.fingerprints.DialogItemClickedFingerprint + + +@Patch( + name = "Download patch", + compatiblePackages = [CompatiblePackage("com.instagram.android")], + requiresIntegrations = true +) +object DownloadPatch : BytecodePatch( + setOf( + DialogItemClickedFingerprint, + MediaOptionsSheetFingerprint, + FeedBottomSheetFingerprint, + FeedItemIconsFingerprint, + FeedItemClassFingerprint, + FeedOptionItemIconClassNameHookFingerprint, + FeedItemClassNameHookFingerprint + ) +) { + val log = """ + const-string v0, "BRUH" + const-string v1, "Sheet opened" + + invoke-static {v0, v1}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I + """ + + private fun String.toJavaClass() = this.replace("/".toRegex(), ".").removePrefix("L").removeSuffix(";") + + private fun setFeedItemClassName() { + val downloadPatchHooksClass = FeedItemClassNameHookFingerprint.result?.mutableMethod + ?: throw FeedItemClassNameHookFingerprint.exception + + val feedItemClassName = FeedItemClassFingerprint.result?.classDef?.toString()?.toJavaClass() + ?: throw FeedItemClassFingerprint.exception + + downloadPatchHooksClass.replaceInstruction(0, "const-string v0, \"$feedItemClassName\"") + } + + private fun setFeedIconClassName() { + val feedIconHookMethod = FeedOptionItemIconClassNameHookFingerprint.result?.mutableMethod + ?: throw FeedOptionItemIconClassNameHookFingerprint.exception + + val feedItemIconsClassName = FeedItemIconsFingerprint.result?.classDef?.toString()?.toJavaClass() + ?: throw FeedItemIconsFingerprint.exception + + feedIconHookMethod.replaceInstruction(0, "const-string v0, \"$feedItemIconsClassName\"") + } + + override fun execute(context: BytecodeContext) { + setFeedItemClassName() + setFeedIconClassName() + +// For real media options sheet + FeedBottomSheetFingerprint.result?.mutableMethod?.let { method -> + val loc = method.getInstructions().filter { it.opcode == Opcode.GOTO }[2].location.index + 3 + method.addInstructions( + loc, +// TODO make the register dynamic + """ + invoke-static {v5}, Lapp/revanced/integrations/instagram/patches/DownloadPatch;->addDownloadButton(Ljava/util/List;)V + """ + ) + } ?: throw FeedBottomSheetFingerprint.exception + + DialogItemClickedFingerprint.result?.mutableMethod?.let { method -> + val loc = method.getInstructions().first { it.opcode == Opcode.PACKED_SWITCH }.location.index + 1 + + method.replaceInstruction( +// TODO should make registers dynamic + method.getInstructions().filter { it.opcode == Opcode.CONST_4 }[1].location.index, + "const/4 v0, 0x0" + ) + +/* Fingerprints + 2Tf: strings - "Music Overlay Not Found" + + only one fingerprint { + 3Pw: strings - "shouldShowFeedDelaySkipPill" + is a function of 3Pw + 3Pw->Aj5:get the first function that returns an int and that has only one register + } + + 0wU: class have more than 2 fields, and has the method getDeviceSession + */ + method.addInstructions( + loc, + """ + const/16 v4, 0x8f + + if-ne v2, v4, :cond_0 + + iget-object v5, v0, LX/Ikk;->A04:Landroidx/fragment/app/FragmentActivity; + + iget-object v2, v0, LX/Ikk;->A0D:LX/2Tf; + + iget-object v4, v0, LX/Ikk;->A0G:LX/3Pw; + + invoke-virtual {v4}, LX/3Pw;->Aj5()I + + move-result v4 + + iget-object v6, v0, LX/Ikk;->A09:LX/0wU; + + invoke-static {v2, v4, v6, v5}, Lme/bluepapilte/DownloadPosts;->downloadSpecificPosts(Ljava/lang/Object;ILjava/lang/Object;Landroid/app/Activity;)V + + return-void + """ + ) + +// Log when a button is clicked + method.addInstructions( + 0, + log + ) + + } ?: throw DialogItemClickedFingerprint.exception + } +} \ No newline at end of file diff --git a/src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/DialogItemClickedFingerprint.kt b/src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/DialogItemClickedFingerprint.kt new file mode 100644 index 00000000..efe446c9 --- /dev/null +++ b/src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/DialogItemClickedFingerprint.kt @@ -0,0 +1,7 @@ +package crimera.patches.instagram.interaction.download.fingerprints + +import app.revanced.patcher.fingerprint.MethodFingerprint + +internal object DialogItemClickedFingerprint: MethodFingerprint( + strings = listOf("Required value was null.", "media_options"), +) \ No newline at end of file diff --git a/src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/FeedBottomSheetFingerprint.kt b/src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/FeedBottomSheetFingerprint.kt new file mode 100644 index 00000000..6bdacc19 --- /dev/null +++ b/src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/FeedBottomSheetFingerprint.kt @@ -0,0 +1,7 @@ +package crimera.patches.instagram.interaction.download.fingerprints + +import app.revanced.patcher.fingerprint.MethodFingerprint + +object FeedBottomSheetFingerprint: MethodFingerprint( + strings = listOf("feed", "instagram_shopping_home") +) \ No newline at end of file diff --git a/src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/FeedItemClassFingerprint.kt b/src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/FeedItemClassFingerprint.kt new file mode 100644 index 00000000..e8879e22 --- /dev/null +++ b/src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/FeedItemClassFingerprint.kt @@ -0,0 +1,11 @@ +package crimera.patches.instagram.interaction.download.fingerprints + +import app.revanced.patcher.fingerprint.MethodFingerprint + +object FeedItemClassFingerprint : MethodFingerprint( + customFingerprint = { methodDef, _ -> + methodDef.parameters.size == 3 && + methodDef.parameters[0].toString() == "Lcom/instagram/api/schemas/MediaOptionStyle;" && + methodDef.parameters[2].toString() == "Ljava/lang/CharSequence;" + } +) \ No newline at end of file diff --git a/src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/FeedItemClassNameHookFingerprint.kt b/src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/FeedItemClassNameHookFingerprint.kt new file mode 100644 index 00000000..23a569d7 --- /dev/null +++ b/src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/FeedItemClassNameHookFingerprint.kt @@ -0,0 +1,9 @@ +package crimera.patches.instagram.interaction.download.fingerprints + +import app.revanced.patcher.fingerprint.MethodFingerprint + +object FeedItemClassNameHookFingerprint: MethodFingerprint( + customFingerprint = { methodDef, classDef -> + methodDef.name == "feedItemClassName" + } +) \ No newline at end of file diff --git a/src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/FeedItemIconsFingerprint.kt b/src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/FeedItemIconsFingerprint.kt new file mode 100644 index 00000000..9c6e3923 --- /dev/null +++ b/src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/FeedItemIconsFingerprint.kt @@ -0,0 +1,7 @@ +package crimera.patches.instagram.interaction.download.fingerprints + +import app.revanced.patcher.fingerprint.MethodFingerprint + +object FeedItemIconsFingerprint: MethodFingerprint( + strings = listOf("HIDE_AD", "DOWNLOAD") +) \ No newline at end of file diff --git a/src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/FeedOptionItemIconClassNameHookFingerprint.kt b/src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/FeedOptionItemIconClassNameHookFingerprint.kt new file mode 100644 index 00000000..d0ec758d --- /dev/null +++ b/src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/FeedOptionItemIconClassNameHookFingerprint.kt @@ -0,0 +1,9 @@ +package crimera.patches.instagram.interaction.download.fingerprints + +import app.revanced.patcher.fingerprint.MethodFingerprint + +object FeedOptionItemIconClassNameHookFingerprint: MethodFingerprint( + customFingerprint = { methodDef, classDef -> + methodDef.name == "feedOptionItemIconClassName" + }, +) \ No newline at end of file diff --git a/src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/MediaOptionsSheetFingerprint.kt b/src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/MediaOptionsSheetFingerprint.kt new file mode 100644 index 00000000..d854f30d --- /dev/null +++ b/src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/MediaOptionsSheetFingerprint.kt @@ -0,0 +1,7 @@ +package crimera.patches.instagram.interaction.download.fingerprints + +import app.revanced.patcher.fingerprint.MethodFingerprint + +object MediaOptionsSheetFingerprint : MethodFingerprint( + strings = listOf("sfplt_in_viewer") +) \ No newline at end of file diff --git a/src/main/kotlin/crimera/patches/twitter/featureFlag/FeatureFlagPatch.kt b/src/main/kotlin/crimera/patches/twitter/featureFlag/FeatureFlagPatch.kt index 3eda785a..050af5a7 100644 --- a/src/main/kotlin/crimera/patches/twitter/featureFlag/FeatureFlagPatch.kt +++ b/src/main/kotlin/crimera/patches/twitter/featureFlag/FeatureFlagPatch.kt @@ -6,11 +6,12 @@ import app.revanced.patcher.extensions.InstructionExtensions.addInstructions import app.revanced.patcher.extensions.InstructionExtensions.getInstructions import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.PatchException -import crimera.patches.twitter.featureFlag.fingerprints.FeatureFlagFingerprint import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.Patch +import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod import app.revanced.patches.shared.misc.integrations.fingerprint.IntegrationsUtilsFingerprint import com.android.tools.smali.dexlib2.Opcode +import crimera.patches.twitter.featureFlag.fingerprints.FeatureFlagFingerprint import crimera.patches.twitter.misc.settings.SettingsPatch import crimera.patches.twitter.misc.settings.fingerprints.SettingsStatusLoadFingerprint @@ -21,25 +22,51 @@ import crimera.patches.twitter.misc.settings.fingerprints.SettingsStatusLoadFing use = true ) @Suppress("unused") -object FeatureFlagPatch:BytecodePatch( - setOf(FeatureFlagFingerprint,IntegrationsUtilsFingerprint, SettingsStatusLoadFingerprint) +object FeatureFlagPatch : BytecodePatch( + setOf(FeatureFlagFingerprint, IntegrationsUtilsFingerprint, SettingsStatusLoadFingerprint) ) { override fun execute(context: BytecodeContext) { val result = FeatureFlagFingerprint.result - ?:throw PatchException("FeatureFlagFingerprint not found") + ?: throw PatchException("FeatureFlagFingerprint not found") val methods = result.mutableClass.methods - val booleanMethod = methods.first { it.returnType == "Z" && it.parameters == listOf("Ljava/lang/String;","Z") } - val METHOD = """ + + fun patch(register: Int) = """ invoke-static {p1,v0}, ${SettingsPatch.PATCHES_DESCRIPTOR}/FeatureSwitchPatch;->flagInfo(Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object; move-result-object v0 """.trimIndent() + fun getLoc(method: MutableMethod): Int = + method.getInstructions().first { it.opcode == Opcode.MOVE_RESULT_OBJECT }.location.index + 1 + + listOf("Z", "F", "D").forEach { type -> + methods.first { it.returnType == type && it.parameters == listOf("Ljava/lang/String;", type) } + .also { method -> + method.addInstructions(getLoc(method), patch(1)) + } + } + - val loc = booleanMethod.getInstructions().first { it.opcode == Opcode.MOVE_RESULT_OBJECT }.location.index +// Integer idk + methods.first { it.returnType == "I" && it.parameters == listOf("I", "Ljava/lang/String;") } + .also { method -> + method.addInstructions(getLoc(method), + """ + invoke-static {p2,v0}, ${SettingsPatch.PATCHES_DESCRIPTOR}/FeatureSwitchPatch;->flagInfo(Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object; + move-result-object v0 + """.trimIndent()) + } - booleanMethod.addInstructions(loc+1,METHOD) +// Long idk + methods.first { it.returnType == "J" && it.parameters == listOf("J", "Ljava/lang/String;") } + .also { method -> + method.addInstructions(getLoc(method), + """ + invoke-static {p3,v0}, ${SettingsPatch.PATCHES_DESCRIPTOR}/FeatureSwitchPatch;->flagInfo(Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object; + move-result-object v0 + """.trimIndent()) + } SettingsStatusLoadFingerprint.enableSettings("enableFeatureFlags") IntegrationsUtilsFingerprint.result!!.mutableMethod.addInstruction( From a94cbc6e46e2b12bc69b532142fa9a6b34ed4738 Mon Sep 17 00:00:00 2001 From: crimera Date: Thu, 16 May 2024 20:56:53 +0800 Subject: [PATCH 03/12] call downloadPost on download clicked --- .../download/AddDownloadIconPatch.kt | 44 +++++++++ .../interaction/download/DownloadPatch.kt | 97 ++++++++++++------- .../DeviceSessionClassFingerprint.kt | 10 ++ .../MediaViewFingerprint.kt | 7 ++ .../PostMediaFingerprint.kt | 7 ++ 5 files changed, 130 insertions(+), 35 deletions(-) create mode 100644 src/main/kotlin/crimera/patches/instagram/interaction/download/AddDownloadIconPatch.kt create mode 100644 src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/itemclickedclasses/DeviceSessionClassFingerprint.kt create mode 100644 src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/itemclickedclasses/MediaViewFingerprint.kt create mode 100644 src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/itemclickedclasses/PostMediaFingerprint.kt diff --git a/src/main/kotlin/crimera/patches/instagram/interaction/download/AddDownloadIconPatch.kt b/src/main/kotlin/crimera/patches/instagram/interaction/download/AddDownloadIconPatch.kt new file mode 100644 index 00000000..4f3d14e7 --- /dev/null +++ b/src/main/kotlin/crimera/patches/instagram/interaction/download/AddDownloadIconPatch.kt @@ -0,0 +1,44 @@ +package crimera.patches.instagram.interaction.download + +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.InstructionExtensions.addInstructions +import app.revanced.patcher.extensions.InstructionExtensions.getInstruction +import app.revanced.patcher.extensions.InstructionExtensions.getInstructions +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.util.exception +import com.android.tools.smali.dexlib2.Opcode +import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction21c +import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction31i +import crimera.patches.instagram.interaction.download.fingerprints.FeedItemIconsFingerprint + +object AddDownloadIconPatch : BytecodePatch( + setOf(FeedItemIconsFingerprint) +) { + override fun execute(context: BytecodeContext) { + FeedItemIconsFingerprint.result?.mutableMethod?.let { method -> + val instructions = method.getInstructions() + + val turnOnThirdPartyDownloadsLoc = instructions.first { + it.opcode == Opcode.CONST_STRING && + (it as BuilderInstruction21c).reference.toString() == "TURN_ON_THIRD_PARTY_DOWNLOADS" + }.location.index - 1 + + val downloadIconIdRegister = + method.getInstruction(turnOnThirdPartyDownloadsLoc).registerA + + val putInstruction = instructions.let { it[it.lastIndex - 1] } + val iconsArrayRegister = (putInstruction as BuilderInstruction21c).registerA +// name index: 0x91=145 downloadIconReg + // invoke-static {v1, v0, v2}, LX/HgY;->A00(Ljava/lang/String;II)LX/HgY; + +// method.addInstructions(putInstruction.location.index, """ +// const-string v${iconsArrayRegister+1}, "MEDIA_DOWNLOAD" +// const/16 v${iconsArrayRegister+2}, 0x91 +// +// invokjjj +// """ +// ) + + } ?: throw FeedItemIconsFingerprint.exception + } +} \ No newline at end of file diff --git a/src/main/kotlin/crimera/patches/instagram/interaction/download/DownloadPatch.kt b/src/main/kotlin/crimera/patches/instagram/interaction/download/DownloadPatch.kt index 162ea76e..51af0ccc 100644 --- a/src/main/kotlin/crimera/patches/instagram/interaction/download/DownloadPatch.kt +++ b/src/main/kotlin/crimera/patches/instagram/interaction/download/DownloadPatch.kt @@ -2,21 +2,28 @@ package crimera.patches.instagram.interaction.download import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.InstructionExtensions.addInstructions +import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels +import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.extensions.InstructionExtensions.getInstructions import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.Patch +import app.revanced.patcher.util.smali.ExternalLabel import app.revanced.util.exception import com.android.tools.smali.dexlib2.Opcode import crimera.patches.instagram.interaction.download.fingerprints.* import crimera.patches.instagram.interaction.download.fingerprints.DialogItemClickedFingerprint +import crimera.patches.instagram.interaction.download.fingerprints.itemclickedclasses.DeviceSessionClassFingerprint +import crimera.patches.instagram.interaction.download.fingerprints.itemclickedclasses.MediaViewFingerprint +import crimera.patches.instagram.interaction.download.fingerprints.itemclickedclasses.PostMediaFingerprint @Patch( name = "Download patch", compatiblePackages = [CompatiblePackage("com.instagram.android")], - requiresIntegrations = true + requiresIntegrations = true, + dependencies = [AddDownloadIconPatch::class] ) object DownloadPatch : BytecodePatch( setOf( @@ -26,23 +33,21 @@ object DownloadPatch : BytecodePatch( FeedItemIconsFingerprint, FeedItemClassFingerprint, FeedOptionItemIconClassNameHookFingerprint, - FeedItemClassNameHookFingerprint + FeedItemClassNameHookFingerprint, + + PostMediaFingerprint, + MediaViewFingerprint, + DeviceSessionClassFingerprint ) ) { - val log = """ - const-string v0, "BRUH" - const-string v1, "Sheet opened" - - invoke-static {v0, v1}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I - """ - - private fun String.toJavaClass() = this.replace("/".toRegex(), ".").removePrefix("L").removeSuffix(";") + private fun String.toClassName() = + this.replace("/".toRegex(), ".").removePrefix("L").removeSuffix(";") private fun setFeedItemClassName() { val downloadPatchHooksClass = FeedItemClassNameHookFingerprint.result?.mutableMethod ?: throw FeedItemClassNameHookFingerprint.exception - val feedItemClassName = FeedItemClassFingerprint.result?.classDef?.toString()?.toJavaClass() + val feedItemClassName = FeedItemClassFingerprint.result?.classDef?.toString()?.toClassName() ?: throw FeedItemClassFingerprint.exception downloadPatchHooksClass.replaceInstruction(0, "const-string v0, \"$feedItemClassName\"") @@ -52,7 +57,7 @@ object DownloadPatch : BytecodePatch( val feedIconHookMethod = FeedOptionItemIconClassNameHookFingerprint.result?.mutableMethod ?: throw FeedOptionItemIconClassNameHookFingerprint.exception - val feedItemIconsClassName = FeedItemIconsFingerprint.result?.classDef?.toString()?.toJavaClass() + val feedItemIconsClassName = FeedItemIconsFingerprint.result?.classDef?.toString()?.toClassName() ?: throw FeedItemIconsFingerprint.exception feedIconHookMethod.replaceInstruction(0, "const-string v0, \"$feedItemIconsClassName\"") @@ -62,7 +67,6 @@ object DownloadPatch : BytecodePatch( setFeedItemClassName() setFeedIconClassName() -// For real media options sheet FeedBottomSheetFingerprint.result?.mutableMethod?.let { method -> val loc = method.getInstructions().filter { it.opcode == Opcode.GOTO }[2].location.index + 3 method.addInstructions( @@ -74,8 +78,9 @@ object DownloadPatch : BytecodePatch( ) } ?: throw FeedBottomSheetFingerprint.exception +// Need to make new icon on Hgy DialogItemClickedFingerprint.result?.mutableMethod?.let { method -> - val loc = method.getInstructions().first { it.opcode == Opcode.PACKED_SWITCH }.location.index + 1 + val loc = method.getInstructions().first { it.opcode == Opcode.PACKED_SWITCH }.location.index method.replaceInstruction( // TODO should make registers dynamic @@ -83,23 +88,16 @@ object DownloadPatch : BytecodePatch( "const/4 v0, 0x0" ) -/* Fingerprints - 2Tf: strings - "Music Overlay Not Found" + /* Fingerprints + 2Tf: strings - "Music Overlay Not Found" - only one fingerprint { - 3Pw: strings - "shouldShowFeedDelaySkipPill" - is a function of 3Pw - 3Pw->Aj5:get the first function that returns an int and that has only one register - } + only one fingerprint { + 3Pw: strings - "shouldShowFeedDelaySkipPill" + is a function of 3Pw + 3Pw->Aj5:get the first function that returns an int and that has only one register + } - 0wU: class have more than 2 fields, and has the method getDeviceSession - */ - method.addInstructions( - loc, - """ - const/16 v4, 0x8f - - if-ne v2, v4, :cond_0 + 0wU: class have more than 2 fields, and has the method getDeviceSession iget-object v5, v0, LX/Ikk;->A04:Landroidx/fragment/app/FragmentActivity; @@ -114,15 +112,44 @@ object DownloadPatch : BytecodePatch( iget-object v6, v0, LX/Ikk;->A09:LX/0wU; invoke-static {v2, v4, v6, v5}, Lme/bluepapilte/DownloadPosts;->downloadSpecificPosts(Ljava/lang/Object;ILjava/lang/Object;Landroid/app/Activity;)V + */ - return-void + val itemClickedClass = method.definingClass + val postMediaClass = + PostMediaFingerprint.result?.method?.definingClass ?: throw PostMediaFingerprint.exception + + val mediaViewResult = MediaViewFingerprint.result?.method ?: throw MediaViewFingerprint.exception + val getMediaListSizeMethod = + MediaViewFingerprint.result?.classDef?.methods?.first { it.returnType == "I" && it.implementation?.registerCount == 2 }?.name + ?: throw MediaViewFingerprint.exception + + val deviceSessionClass = DeviceSessionClassFingerprint.result?.method?.definingClass + ?: throw DeviceSessionClassFingerprint.exception + + method.addInstructionsWithLabels( + loc, """ - ) + const/16 v4, 0x60 + if-ne v2, v4, :cond_0 + + iget-object v2, v0, $itemClickedClass->A0D:$postMediaClass + + iget-object v4, v0, $itemClickedClass->A0G:${mediaViewResult.definingClass} + invoke-virtual {v4}, ${mediaViewResult.definingClass}->$getMediaListSizeMethod()I + move-result v4 + + iget-object v6, v0, $itemClickedClass->A09:$deviceSessionClass + iget-object v5, v0, $itemClickedClass->A04:Landroidx/fragment/app/FragmentActivity; + + invoke-static {v2, v4, v6, v5}, Lapp/revanced/integrations/instagram/patches/DownloadPatch;->downloadPost(Ljava/lang/Object;ILjava/lang/Object;Landroid/app/Activity;)V + + const-string v0, "BRUH" + const-string v1, "Download clicked" + invoke-static {v0, v1}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I -// Log when a button is clicked - method.addInstructions( - 0, - log + return-void + """, + ExternalLabel("cond_0", method.getInstruction(loc)) ) } ?: throw DialogItemClickedFingerprint.exception diff --git a/src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/itemclickedclasses/DeviceSessionClassFingerprint.kt b/src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/itemclickedclasses/DeviceSessionClassFingerprint.kt new file mode 100644 index 00000000..fb670d81 --- /dev/null +++ b/src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/itemclickedclasses/DeviceSessionClassFingerprint.kt @@ -0,0 +1,10 @@ +package crimera.patches.instagram.interaction.download.fingerprints.itemclickedclasses + +import app.revanced.patcher.fingerprint.MethodFingerprint + +object DeviceSessionClassFingerprint: MethodFingerprint( + customFingerprint = { methodDef, classDef -> + methodDef.name == "getDeviceSession" && + classDef.fields.count() > 2 + } +) \ No newline at end of file diff --git a/src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/itemclickedclasses/MediaViewFingerprint.kt b/src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/itemclickedclasses/MediaViewFingerprint.kt new file mode 100644 index 00000000..4ec458fd --- /dev/null +++ b/src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/itemclickedclasses/MediaViewFingerprint.kt @@ -0,0 +1,7 @@ +package crimera.patches.instagram.interaction.download.fingerprints.itemclickedclasses + +import app.revanced.patcher.fingerprint.MethodFingerprint + +object MediaViewFingerprint: MethodFingerprint( + strings = listOf("shouldShowFeedDelaySkipPill") +) \ No newline at end of file diff --git a/src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/itemclickedclasses/PostMediaFingerprint.kt b/src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/itemclickedclasses/PostMediaFingerprint.kt new file mode 100644 index 00000000..f67e131c --- /dev/null +++ b/src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/itemclickedclasses/PostMediaFingerprint.kt @@ -0,0 +1,7 @@ +package crimera.patches.instagram.interaction.download.fingerprints.itemclickedclasses + +import app.revanced.patcher.fingerprint.MethodFingerprint + +object PostMediaFingerprint : MethodFingerprint( + strings = listOf("Music Overlay Not Found") +) \ No newline at end of file From b91f7ddfb3becf750b69d348e535d74b31dfd64b Mon Sep 17 00:00:00 2001 From: crimera Date: Thu, 16 May 2024 20:58:23 +0800 Subject: [PATCH 04/12] remove stuff --- .../download/AddDownloadIconPatch.kt | 44 ------------------- .../interaction/download/DownloadPatch.kt | 1 - 2 files changed, 45 deletions(-) delete mode 100644 src/main/kotlin/crimera/patches/instagram/interaction/download/AddDownloadIconPatch.kt diff --git a/src/main/kotlin/crimera/patches/instagram/interaction/download/AddDownloadIconPatch.kt b/src/main/kotlin/crimera/patches/instagram/interaction/download/AddDownloadIconPatch.kt deleted file mode 100644 index 4f3d14e7..00000000 --- a/src/main/kotlin/crimera/patches/instagram/interaction/download/AddDownloadIconPatch.kt +++ /dev/null @@ -1,44 +0,0 @@ -package crimera.patches.instagram.interaction.download - -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.InstructionExtensions.addInstructions -import app.revanced.patcher.extensions.InstructionExtensions.getInstruction -import app.revanced.patcher.extensions.InstructionExtensions.getInstructions -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.util.exception -import com.android.tools.smali.dexlib2.Opcode -import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction21c -import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction31i -import crimera.patches.instagram.interaction.download.fingerprints.FeedItemIconsFingerprint - -object AddDownloadIconPatch : BytecodePatch( - setOf(FeedItemIconsFingerprint) -) { - override fun execute(context: BytecodeContext) { - FeedItemIconsFingerprint.result?.mutableMethod?.let { method -> - val instructions = method.getInstructions() - - val turnOnThirdPartyDownloadsLoc = instructions.first { - it.opcode == Opcode.CONST_STRING && - (it as BuilderInstruction21c).reference.toString() == "TURN_ON_THIRD_PARTY_DOWNLOADS" - }.location.index - 1 - - val downloadIconIdRegister = - method.getInstruction(turnOnThirdPartyDownloadsLoc).registerA - - val putInstruction = instructions.let { it[it.lastIndex - 1] } - val iconsArrayRegister = (putInstruction as BuilderInstruction21c).registerA -// name index: 0x91=145 downloadIconReg - // invoke-static {v1, v0, v2}, LX/HgY;->A00(Ljava/lang/String;II)LX/HgY; - -// method.addInstructions(putInstruction.location.index, """ -// const-string v${iconsArrayRegister+1}, "MEDIA_DOWNLOAD" -// const/16 v${iconsArrayRegister+2}, 0x91 -// -// invokjjj -// """ -// ) - - } ?: throw FeedItemIconsFingerprint.exception - } -} \ No newline at end of file diff --git a/src/main/kotlin/crimera/patches/instagram/interaction/download/DownloadPatch.kt b/src/main/kotlin/crimera/patches/instagram/interaction/download/DownloadPatch.kt index 51af0ccc..03ed92f5 100644 --- a/src/main/kotlin/crimera/patches/instagram/interaction/download/DownloadPatch.kt +++ b/src/main/kotlin/crimera/patches/instagram/interaction/download/DownloadPatch.kt @@ -23,7 +23,6 @@ import crimera.patches.instagram.interaction.download.fingerprints.itemclickedcl name = "Download patch", compatiblePackages = [CompatiblePackage("com.instagram.android")], requiresIntegrations = true, - dependencies = [AddDownloadIconPatch::class] ) object DownloadPatch : BytecodePatch( setOf( From 3cd6b448e1b1c6ba5ab8a59058cc9005b315b28a Mon Sep 17 00:00:00 2001 From: crimera Date: Thu, 16 May 2024 20:59:59 +0800 Subject: [PATCH 05/12] remove comments --- .../interaction/download/DownloadPatch.kt | 27 ------------------- 1 file changed, 27 deletions(-) diff --git a/src/main/kotlin/crimera/patches/instagram/interaction/download/DownloadPatch.kt b/src/main/kotlin/crimera/patches/instagram/interaction/download/DownloadPatch.kt index 03ed92f5..76ce7605 100644 --- a/src/main/kotlin/crimera/patches/instagram/interaction/download/DownloadPatch.kt +++ b/src/main/kotlin/crimera/patches/instagram/interaction/download/DownloadPatch.kt @@ -77,7 +77,6 @@ object DownloadPatch : BytecodePatch( ) } ?: throw FeedBottomSheetFingerprint.exception -// Need to make new icon on Hgy DialogItemClickedFingerprint.result?.mutableMethod?.let { method -> val loc = method.getInstructions().first { it.opcode == Opcode.PACKED_SWITCH }.location.index @@ -87,32 +86,6 @@ object DownloadPatch : BytecodePatch( "const/4 v0, 0x0" ) - /* Fingerprints - 2Tf: strings - "Music Overlay Not Found" - - only one fingerprint { - 3Pw: strings - "shouldShowFeedDelaySkipPill" - is a function of 3Pw - 3Pw->Aj5:get the first function that returns an int and that has only one register - } - - 0wU: class have more than 2 fields, and has the method getDeviceSession - - iget-object v5, v0, LX/Ikk;->A04:Landroidx/fragment/app/FragmentActivity; - - iget-object v2, v0, LX/Ikk;->A0D:LX/2Tf; - - iget-object v4, v0, LX/Ikk;->A0G:LX/3Pw; - - invoke-virtual {v4}, LX/3Pw;->Aj5()I - - move-result v4 - - iget-object v6, v0, LX/Ikk;->A09:LX/0wU; - - invoke-static {v2, v4, v6, v5}, Lme/bluepapilte/DownloadPosts;->downloadSpecificPosts(Ljava/lang/Object;ILjava/lang/Object;Landroid/app/Activity;)V - */ - val itemClickedClass = method.definingClass val postMediaClass = PostMediaFingerprint.result?.method?.definingClass ?: throw PostMediaFingerprint.exception From e74462c9b24f55f8c7e6262deb074370fca3d4cf Mon Sep 17 00:00:00 2001 From: crimera Date: Sat, 18 May 2024 00:09:46 +0800 Subject: [PATCH 06/12] refactor: separate setup --- .../interaction/download/DownloadPatch.kt | 34 ++----------- .../download/SetupHookSignaturesPatch.kt | 48 +++++++++++++++++++ .../FeedItemClassNameHookFingerprint.kt | 2 +- ...dOptionItemIconClassNameHookFingerprint.kt | 2 +- 4 files changed, 53 insertions(+), 33 deletions(-) create mode 100644 src/main/kotlin/crimera/patches/instagram/interaction/download/SetupHookSignaturesPatch.kt rename src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/{ => hook}/FeedItemClassNameHookFingerprint.kt (96%) rename src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/{ => hook}/FeedOptionItemIconClassNameHookFingerprint.kt (97%) diff --git a/src/main/kotlin/crimera/patches/instagram/interaction/download/DownloadPatch.kt b/src/main/kotlin/crimera/patches/instagram/interaction/download/DownloadPatch.kt index 76ce7605..dcbeb623 100644 --- a/src/main/kotlin/crimera/patches/instagram/interaction/download/DownloadPatch.kt +++ b/src/main/kotlin/crimera/patches/instagram/interaction/download/DownloadPatch.kt @@ -14,6 +14,8 @@ import app.revanced.util.exception import com.android.tools.smali.dexlib2.Opcode import crimera.patches.instagram.interaction.download.fingerprints.* import crimera.patches.instagram.interaction.download.fingerprints.DialogItemClickedFingerprint +import crimera.patches.instagram.interaction.download.fingerprints.hook.FeedItemClassNameHookFingerprint +import crimera.patches.instagram.interaction.download.fingerprints.hook.FeedOptionItemIconClassNameHookFingerprint import crimera.patches.instagram.interaction.download.fingerprints.itemclickedclasses.DeviceSessionClassFingerprint import crimera.patches.instagram.interaction.download.fingerprints.itemclickedclasses.MediaViewFingerprint import crimera.patches.instagram.interaction.download.fingerprints.itemclickedclasses.PostMediaFingerprint @@ -23,49 +25,19 @@ import crimera.patches.instagram.interaction.download.fingerprints.itemclickedcl name = "Download patch", compatiblePackages = [CompatiblePackage("com.instagram.android")], requiresIntegrations = true, + dependencies = [SetupHookSignaturesPatch::class] ) object DownloadPatch : BytecodePatch( setOf( DialogItemClickedFingerprint, - MediaOptionsSheetFingerprint, FeedBottomSheetFingerprint, - FeedItemIconsFingerprint, - FeedItemClassFingerprint, - FeedOptionItemIconClassNameHookFingerprint, - FeedItemClassNameHookFingerprint, PostMediaFingerprint, MediaViewFingerprint, DeviceSessionClassFingerprint ) ) { - private fun String.toClassName() = - this.replace("/".toRegex(), ".").removePrefix("L").removeSuffix(";") - - private fun setFeedItemClassName() { - val downloadPatchHooksClass = FeedItemClassNameHookFingerprint.result?.mutableMethod - ?: throw FeedItemClassNameHookFingerprint.exception - - val feedItemClassName = FeedItemClassFingerprint.result?.classDef?.toString()?.toClassName() - ?: throw FeedItemClassFingerprint.exception - - downloadPatchHooksClass.replaceInstruction(0, "const-string v0, \"$feedItemClassName\"") - } - - private fun setFeedIconClassName() { - val feedIconHookMethod = FeedOptionItemIconClassNameHookFingerprint.result?.mutableMethod - ?: throw FeedOptionItemIconClassNameHookFingerprint.exception - - val feedItemIconsClassName = FeedItemIconsFingerprint.result?.classDef?.toString()?.toClassName() - ?: throw FeedItemIconsFingerprint.exception - - feedIconHookMethod.replaceInstruction(0, "const-string v0, \"$feedItemIconsClassName\"") - } - override fun execute(context: BytecodeContext) { - setFeedItemClassName() - setFeedIconClassName() - FeedBottomSheetFingerprint.result?.mutableMethod?.let { method -> val loc = method.getInstructions().filter { it.opcode == Opcode.GOTO }[2].location.index + 3 method.addInstructions( diff --git a/src/main/kotlin/crimera/patches/instagram/interaction/download/SetupHookSignaturesPatch.kt b/src/main/kotlin/crimera/patches/instagram/interaction/download/SetupHookSignaturesPatch.kt new file mode 100644 index 00000000..835c1c93 --- /dev/null +++ b/src/main/kotlin/crimera/patches/instagram/interaction/download/SetupHookSignaturesPatch.kt @@ -0,0 +1,48 @@ +package crimera.patches.instagram.interaction.download + +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.util.exception +import crimera.patches.instagram.interaction.download.fingerprints.FeedItemClassFingerprint +import crimera.patches.instagram.interaction.download.fingerprints.FeedItemIconsFingerprint +import crimera.patches.instagram.interaction.download.fingerprints.hook.FeedItemClassNameHookFingerprint +import crimera.patches.instagram.interaction.download.fingerprints.hook.FeedOptionItemIconClassNameHookFingerprint + +object SetupHookSignaturesPatch : BytecodePatch( + setOf( + FeedItemClassNameHookFingerprint, + FeedItemClassFingerprint, + FeedOptionItemIconClassNameHookFingerprint, + FeedItemIconsFingerprint + ) +) { + private fun String.toClassName() = + this.replace("/".toRegex(), ".").removePrefix("L").removeSuffix(";") + + private fun setFeedItemClassName() { + val downloadPatchHooksClass = FeedItemClassNameHookFingerprint.result?.mutableMethod + ?: throw FeedItemClassNameHookFingerprint.exception + + val feedItemClassName = FeedItemClassFingerprint.result?.classDef?.toString()?.toClassName() + ?: throw FeedItemClassFingerprint.exception + + downloadPatchHooksClass.replaceInstruction(0, "const-string v0, \"$feedItemClassName\"") + } + + private fun setFeedIconClassName() { + val feedIconHookMethod = FeedOptionItemIconClassNameHookFingerprint.result?.mutableMethod + ?: throw FeedOptionItemIconClassNameHookFingerprint.exception + + val feedItemIconsClassName = FeedItemIconsFingerprint.result?.classDef?.toString()?.toClassName() + ?: throw FeedItemIconsFingerprint.exception + + feedIconHookMethod.replaceInstruction(0, "const-string v0, \"$feedItemIconsClassName\"") + } + + override fun execute(context: BytecodeContext) { + setFeedItemClassName() + setFeedIconClassName() + } + +} \ No newline at end of file diff --git a/src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/FeedItemClassNameHookFingerprint.kt b/src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/hook/FeedItemClassNameHookFingerprint.kt similarity index 96% rename from src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/FeedItemClassNameHookFingerprint.kt rename to src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/hook/FeedItemClassNameHookFingerprint.kt index 23a569d7..565c6085 100644 --- a/src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/FeedItemClassNameHookFingerprint.kt +++ b/src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/hook/FeedItemClassNameHookFingerprint.kt @@ -1,4 +1,4 @@ -package crimera.patches.instagram.interaction.download.fingerprints +package crimera.patches.instagram.interaction.download.fingerprints.hook import app.revanced.patcher.fingerprint.MethodFingerprint diff --git a/src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/FeedOptionItemIconClassNameHookFingerprint.kt b/src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/hook/FeedOptionItemIconClassNameHookFingerprint.kt similarity index 97% rename from src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/FeedOptionItemIconClassNameHookFingerprint.kt rename to src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/hook/FeedOptionItemIconClassNameHookFingerprint.kt index d0ec758d..24a6bc4d 100644 --- a/src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/FeedOptionItemIconClassNameHookFingerprint.kt +++ b/src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/hook/FeedOptionItemIconClassNameHookFingerprint.kt @@ -1,4 +1,4 @@ -package crimera.patches.instagram.interaction.download.fingerprints +package crimera.patches.instagram.interaction.download.fingerprints.hook import app.revanced.patcher.fingerprint.MethodFingerprint From 49f1cac52668299ec4b11c9ab2a223fa14a69d4a Mon Sep 17 00:00:00 2001 From: crimera Date: Sat, 18 May 2024 01:04:58 +0800 Subject: [PATCH 07/12] added getPhotoLink --- .../instagram/interaction/download/DownloadPatch.kt | 7 +++---- .../instagram/misc/integrations/IntegrationsPatch.kt | 12 ++++++++++++ .../integrations/fingerprints/InitFingerprint.kt | 10 ++++++++++ 3 files changed, 25 insertions(+), 4 deletions(-) create mode 100644 src/main/kotlin/crimera/patches/instagram/misc/integrations/IntegrationsPatch.kt create mode 100644 src/main/kotlin/crimera/patches/instagram/misc/integrations/fingerprints/InitFingerprint.kt diff --git a/src/main/kotlin/crimera/patches/instagram/interaction/download/DownloadPatch.kt b/src/main/kotlin/crimera/patches/instagram/interaction/download/DownloadPatch.kt index dcbeb623..83fcf6d8 100644 --- a/src/main/kotlin/crimera/patches/instagram/interaction/download/DownloadPatch.kt +++ b/src/main/kotlin/crimera/patches/instagram/interaction/download/DownloadPatch.kt @@ -12,20 +12,19 @@ import app.revanced.patcher.patch.annotation.Patch import app.revanced.patcher.util.smali.ExternalLabel import app.revanced.util.exception import com.android.tools.smali.dexlib2.Opcode -import crimera.patches.instagram.interaction.download.fingerprints.* import crimera.patches.instagram.interaction.download.fingerprints.DialogItemClickedFingerprint -import crimera.patches.instagram.interaction.download.fingerprints.hook.FeedItemClassNameHookFingerprint -import crimera.patches.instagram.interaction.download.fingerprints.hook.FeedOptionItemIconClassNameHookFingerprint +import crimera.patches.instagram.interaction.download.fingerprints.FeedBottomSheetFingerprint import crimera.patches.instagram.interaction.download.fingerprints.itemclickedclasses.DeviceSessionClassFingerprint import crimera.patches.instagram.interaction.download.fingerprints.itemclickedclasses.MediaViewFingerprint import crimera.patches.instagram.interaction.download.fingerprints.itemclickedclasses.PostMediaFingerprint +import crimera.patches.instagram.misc.integrations.IntegrationsPatch @Patch( name = "Download patch", compatiblePackages = [CompatiblePackage("com.instagram.android")], requiresIntegrations = true, - dependencies = [SetupHookSignaturesPatch::class] + dependencies = [SetupHookSignaturesPatch::class, IntegrationsPatch::class] ) object DownloadPatch : BytecodePatch( setOf( diff --git a/src/main/kotlin/crimera/patches/instagram/misc/integrations/IntegrationsPatch.kt b/src/main/kotlin/crimera/patches/instagram/misc/integrations/IntegrationsPatch.kt new file mode 100644 index 00000000..6baf2a3a --- /dev/null +++ b/src/main/kotlin/crimera/patches/instagram/misc/integrations/IntegrationsPatch.kt @@ -0,0 +1,12 @@ +package crimera.patches.instagram.misc.integrations + +import app.revanced.patcher.patch.annotation.Patch +import app.revanced.patches.shared.misc.integrations.BaseIntegrationsPatch +import crimera.patches.instagram.misc.integrations.fingerprints.InitFingerprint + +@Patch( + requiresIntegrations = true +) +object IntegrationsPatch: BaseIntegrationsPatch( + setOf(InitFingerprint) +) diff --git a/src/main/kotlin/crimera/patches/instagram/misc/integrations/fingerprints/InitFingerprint.kt b/src/main/kotlin/crimera/patches/instagram/misc/integrations/fingerprints/InitFingerprint.kt new file mode 100644 index 00000000..c74af35c --- /dev/null +++ b/src/main/kotlin/crimera/patches/instagram/misc/integrations/fingerprints/InitFingerprint.kt @@ -0,0 +1,10 @@ +package crimera.patches.instagram.misc.integrations.fingerprints + +import app.revanced.patches.shared.misc.integrations.BaseIntegrationsPatch + +object InitFingerprint : BaseIntegrationsPatch.IntegrationsFingerprint( + customFingerprint = { methodDef, _ -> + methodDef.name == "onCreate" + && methodDef.definingClass == "Lcom/instagram/app/InstagramAppShell;" + } +) \ No newline at end of file From f89f50d69170b76d1dd663583da4af766169b1b9 Mon Sep 17 00:00:00 2001 From: crimera Date: Sat, 18 May 2024 09:21:04 +0800 Subject: [PATCH 08/12] implemented basic image downloading --- .../all/appDowngrading/AppDowngradingPatch.kt | 10 +- .../interaction/download/DownloadPatch.kt | 92 +++++++++++-------- 2 files changed, 59 insertions(+), 43 deletions(-) diff --git a/src/main/kotlin/crimera/patches/all/appDowngrading/AppDowngradingPatch.kt b/src/main/kotlin/crimera/patches/all/appDowngrading/AppDowngradingPatch.kt index 41da5b81..fa805ee7 100644 --- a/src/main/kotlin/crimera/patches/all/appDowngrading/AppDowngradingPatch.kt +++ b/src/main/kotlin/crimera/patches/all/appDowngrading/AppDowngradingPatch.kt @@ -5,13 +5,13 @@ import app.revanced.patcher.patch.ResourcePatch import app.revanced.patcher.patch.annotation.Patch import org.w3c.dom.Element - @Patch( - name = "Enable app downgrading", - description = "Sets app version to a default value making installation of different versions possible", - use = false + name = "Enable app downgrading", + description = + "Sets app version to a default value making installation of different versions possible", + use = false ) -object AppDowngradingPatch: ResourcePatch() { +object AppDowngradingPatch : ResourcePatch() { override fun execute(context: ResourceContext) { context.xmlEditor["AndroidManifest.xml"].use { val manifestElement = it.file.getElementsByTagName("manifest").item(0) as Element diff --git a/src/main/kotlin/crimera/patches/instagram/interaction/download/DownloadPatch.kt b/src/main/kotlin/crimera/patches/instagram/interaction/download/DownloadPatch.kt index 83fcf6d8..31ba0cef 100644 --- a/src/main/kotlin/crimera/patches/instagram/interaction/download/DownloadPatch.kt +++ b/src/main/kotlin/crimera/patches/instagram/interaction/download/DownloadPatch.kt @@ -19,59 +19,74 @@ import crimera.patches.instagram.interaction.download.fingerprints.itemclickedcl import crimera.patches.instagram.interaction.download.fingerprints.itemclickedclasses.PostMediaFingerprint import crimera.patches.instagram.misc.integrations.IntegrationsPatch - @Patch( - name = "Download patch", - compatiblePackages = [CompatiblePackage("com.instagram.android")], - requiresIntegrations = true, - dependencies = [SetupHookSignaturesPatch::class, IntegrationsPatch::class] + name = "Download patch", + compatiblePackages = [CompatiblePackage("com.instagram.android")], + requiresIntegrations = true, + dependencies = [SetupHookSignaturesPatch::class, IntegrationsPatch::class] ) -object DownloadPatch : BytecodePatch( - setOf( - DialogItemClickedFingerprint, - FeedBottomSheetFingerprint, - - PostMediaFingerprint, - MediaViewFingerprint, - DeviceSessionClassFingerprint - ) -) { +object DownloadPatch : + BytecodePatch( + setOf( + DialogItemClickedFingerprint, + FeedBottomSheetFingerprint, + PostMediaFingerprint, + MediaViewFingerprint, + DeviceSessionClassFingerprint + ) + ) { override fun execute(context: BytecodeContext) { FeedBottomSheetFingerprint.result?.mutableMethod?.let { method -> - val loc = method.getInstructions().filter { it.opcode == Opcode.GOTO }[2].location.index + 3 + val loc = + method.getInstructions().filter { it.opcode == Opcode.GOTO }[2].location.index + + 3 method.addInstructions( - loc, -// TODO make the register dynamic - """ + loc, + // TODO make the register dynamic + """ invoke-static {v5}, Lapp/revanced/integrations/instagram/patches/DownloadPatch;->addDownloadButton(Ljava/util/List;)V """ ) - } ?: throw FeedBottomSheetFingerprint.exception + } + ?: throw FeedBottomSheetFingerprint.exception DialogItemClickedFingerprint.result?.mutableMethod?.let { method -> - val loc = method.getInstructions().first { it.opcode == Opcode.PACKED_SWITCH }.location.index + val loc = + method.getInstructions() + .first { it.opcode == Opcode.PACKED_SWITCH } + .location + .index method.replaceInstruction( -// TODO should make registers dynamic - method.getInstructions().filter { it.opcode == Opcode.CONST_4 }[1].location.index, - "const/4 v0, 0x0" + // TODO should make registers dynamic + method.getInstructions().filter { it.opcode == Opcode.CONST_4 }[1] + .location + .index, + "const/4 v0, 0x0" ) val itemClickedClass = method.definingClass val postMediaClass = - PostMediaFingerprint.result?.method?.definingClass ?: throw PostMediaFingerprint.exception + PostMediaFingerprint.result?.method?.definingClass + ?: throw PostMediaFingerprint.exception - val mediaViewResult = MediaViewFingerprint.result?.method ?: throw MediaViewFingerprint.exception + val mediaViewResult = + MediaViewFingerprint.result?.method ?: throw MediaViewFingerprint.exception val getMediaListSizeMethod = - MediaViewFingerprint.result?.classDef?.methods?.first { it.returnType == "I" && it.implementation?.registerCount == 2 }?.name - ?: throw MediaViewFingerprint.exception + MediaViewFingerprint.result?.classDef?.methods + ?.first { + it.returnType == "I" && it.implementation?.registerCount == 2 + } + ?.name + ?: throw MediaViewFingerprint.exception - val deviceSessionClass = DeviceSessionClassFingerprint.result?.method?.definingClass - ?: throw DeviceSessionClassFingerprint.exception + val deviceSessionClass = + DeviceSessionClassFingerprint.result?.method?.definingClass + ?: throw DeviceSessionClassFingerprint.exception method.addInstructionsWithLabels( - loc, - """ + loc, + """ const/16 v4, 0x60 if-ne v2, v4, :cond_0 @@ -82,19 +97,20 @@ object DownloadPatch : BytecodePatch( move-result v4 iget-object v6, v0, $itemClickedClass->A09:$deviceSessionClass - iget-object v5, v0, $itemClickedClass->A04:Landroidx/fragment/app/FragmentActivity; + iget-object v5, v0, $itemClickedClass->A04:Landroidx/fragment/app/FragmentActivity; invoke-static {v2, v4, v6, v5}, Lapp/revanced/integrations/instagram/patches/DownloadPatch;->downloadPost(Ljava/lang/Object;ILjava/lang/Object;Landroid/app/Activity;)V const-string v0, "BRUH" const-string v1, "Download clicked" - invoke-static {v0, v1}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I + invoke-static {v0, v1}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I return-void """, - ExternalLabel("cond_0", method.getInstruction(loc)) + ExternalLabel("cond_0", method.getInstruction(loc)) ) - - } ?: throw DialogItemClickedFingerprint.exception + } + ?: throw DialogItemClickedFingerprint.exception } -} \ No newline at end of file +} + From 416dd71e5747a6618eb575aab0e86ca0aee5c909 Mon Sep 17 00:00:00 2001 From: crimera Date: Sat, 18 May 2024 13:35:27 +0800 Subject: [PATCH 09/12] implemented download media list (for photos only) --- .../interaction/download/DownloadPatch.kt | 4 +- .../download/SetupHookSignaturesPatch.kt | 100 +++++++++++++----- .../{ => hook}/FeedItemClassFingerprint.kt | 2 +- .../hook/FeedItemClassNameHookFingerprint.kt | 9 -- .../{ => hook}/FeedItemIconsFingerprint.kt | 2 +- ...Fingerprint.kt => MediaListFingerprint.kt} | 7 +- 6 files changed, 82 insertions(+), 42 deletions(-) rename src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/{ => hook}/FeedItemClassFingerprint.kt (98%) delete mode 100644 src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/hook/FeedItemClassNameHookFingerprint.kt rename src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/{ => hook}/FeedItemIconsFingerprint.kt (96%) rename src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/hook/{FeedOptionItemIconClassNameHookFingerprint.kt => MediaListFingerprint.kt} (57%) diff --git a/src/main/kotlin/crimera/patches/instagram/interaction/download/DownloadPatch.kt b/src/main/kotlin/crimera/patches/instagram/interaction/download/DownloadPatch.kt index 31ba0cef..434a1bc4 100644 --- a/src/main/kotlin/crimera/patches/instagram/interaction/download/DownloadPatch.kt +++ b/src/main/kotlin/crimera/patches/instagram/interaction/download/DownloadPatch.kt @@ -44,7 +44,7 @@ object DownloadPatch : loc, // TODO make the register dynamic """ - invoke-static {v5}, Lapp/revanced/integrations/instagram/patches/DownloadPatch;->addDownloadButton(Ljava/util/List;)V + invoke-static {v5}, Lapp/revanced/integrations/instagram/patches/download/DownloadPatch;->addDownloadButton(Ljava/util/List;)V """ ) } @@ -99,7 +99,7 @@ object DownloadPatch : iget-object v6, v0, $itemClickedClass->A09:$deviceSessionClass iget-object v5, v0, $itemClickedClass->A04:Landroidx/fragment/app/FragmentActivity; - invoke-static {v2, v4, v6, v5}, Lapp/revanced/integrations/instagram/patches/DownloadPatch;->downloadPost(Ljava/lang/Object;ILjava/lang/Object;Landroid/app/Activity;)V + invoke-static {v2, v4, v6, v5}, Lapp/revanced/integrations/instagram/patches/download/DownloadPatch;->downloadPost(Ljava/lang/Object;ILjava/lang/Object;Landroid/app/Activity;)V const-string v0, "BRUH" const-string v1, "Download clicked" diff --git a/src/main/kotlin/crimera/patches/instagram/interaction/download/SetupHookSignaturesPatch.kt b/src/main/kotlin/crimera/patches/instagram/interaction/download/SetupHookSignaturesPatch.kt index 835c1c93..8c099421 100644 --- a/src/main/kotlin/crimera/patches/instagram/interaction/download/SetupHookSignaturesPatch.kt +++ b/src/main/kotlin/crimera/patches/instagram/interaction/download/SetupHookSignaturesPatch.kt @@ -1,48 +1,96 @@ package crimera.patches.instagram.interaction.download import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.InstructionExtensions.getInstruction +import app.revanced.patcher.extensions.InstructionExtensions.getInstructions import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction +import app.revanced.patcher.fingerprint.MethodFingerprint import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod import app.revanced.util.exception -import crimera.patches.instagram.interaction.download.fingerprints.FeedItemClassFingerprint -import crimera.patches.instagram.interaction.download.fingerprints.FeedItemIconsFingerprint -import crimera.patches.instagram.interaction.download.fingerprints.hook.FeedItemClassNameHookFingerprint -import crimera.patches.instagram.interaction.download.fingerprints.hook.FeedOptionItemIconClassNameHookFingerprint +import com.android.tools.smali.dexlib2.Opcode +import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction21c +import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction22c +import com.android.tools.smali.dexlib2.iface.reference.Reference +import crimera.patches.instagram.interaction.download.fingerprints.hook.* + + +object DownloadPatchHooksFingerprint : MethodFingerprint( + customFingerprint = { methodDef, classDef -> + methodDef.definingClass == "Lapp/revanced/integrations/instagram/patches/download/DownloadPatch;" + && methodDef.name == "feedItemClassName" + } +) object SetupHookSignaturesPatch : BytecodePatch( setOf( - FeedItemClassNameHookFingerprint, + DownloadPatchHooksFingerprint, FeedItemClassFingerprint, - FeedOptionItemIconClassNameHookFingerprint, - FeedItemIconsFingerprint + FeedItemIconsFingerprint, + MediaListFingerprint ) ) { - private fun String.toClassName() = - this.replace("/".toRegex(), ".").removePrefix("L").removeSuffix(";") - private fun setFeedItemClassName() { - val downloadPatchHooksClass = FeedItemClassNameHookFingerprint.result?.mutableMethod - ?: throw FeedItemClassNameHookFingerprint.exception + override fun execute(context: BytecodeContext) { + DownloadPatchHooksFingerprint.result?.mutableClass?.let { classDef -> + val methods = classDef.methods - val feedItemClassName = FeedItemClassFingerprint.result?.classDef?.toString()?.toClassName() - ?: throw FeedItemClassFingerprint.exception + methods.getMethod("feedItemClassName")?.let { + val feedItemClassName = FeedItemClassFingerprint.result?.classDef + ?: throw FeedItemClassFingerprint.exception - downloadPatchHooksClass.replaceInstruction(0, "const-string v0, \"$feedItemClassName\"") - } + it.setReturnString(feedItemClassName.toString()) + } + + methods.getMethod("feedOptionItemIconClassName")?.let { + val feedItemIconsClassName = FeedItemIconsFingerprint.result?.classDef + ?: throw FeedItemIconsFingerprint.exception + + it.setReturnString(feedItemIconsClassName.toString()) + } + + methods.getMethod("mediaListSourceClass")?.let { + val mediaListClassName = MediaListFingerprint.result?.classDef + ?: throw MediaListFingerprint.exception - private fun setFeedIconClassName() { - val feedIconHookMethod = FeedOptionItemIconClassNameHookFingerprint.result?.mutableMethod - ?: throw FeedOptionItemIconClassNameHookFingerprint.exception + it.setReturnString(mediaListClassName.toString()) + } - val feedItemIconsClassName = FeedItemIconsFingerprint.result?.classDef?.toString()?.toClassName() - ?: throw FeedItemIconsFingerprint.exception + // set media list field + methods.getMethod("listFieldName")?.let { + val method = MediaListFingerprint.result?.mutableMethod + ?: throw MediaListFingerprint.exception - feedIconHookMethod.replaceInstruction(0, "const-string v0, \"$feedItemIconsClassName\"") + val loc = method.getInstructions().filter { it.opcode == Opcode.CONST_STRING } + .firstOrNull { builderInstruction -> + (builderInstruction as BuilderInstruction21c).reference.toString() == "caption_is_edited" + }?.location?.index?.plus(2) + + if (loc != null) { + (method.getInstruction(loc) as BuilderInstruction22c).reference.getField()?.also { fieldName -> + it.setReturnString(fieldName) + } + } + + } + } } - override fun execute(context: BytecodeContext) { - setFeedItemClassName() - setFeedIconClassName() + private fun Reference.getField(): String? { + return """->(\w+):""".toRegex() + .find(this.toString())?.groupValues?.get( + 1 + ) + } + + private fun MutableMethod.setReturnString(className: String) { + this.replaceInstruction(0, "const-string v0, \"${className.toClassName()}\"") } -} \ No newline at end of file + private fun Set.getMethod(name: String): MutableMethod? { + return this.firstOrNull { it.name == name } + } + + private fun String.toClassName() = + this.replace("/".toRegex(), ".").removePrefix("L").removeSuffix(";") +} diff --git a/src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/FeedItemClassFingerprint.kt b/src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/hook/FeedItemClassFingerprint.kt similarity index 98% rename from src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/FeedItemClassFingerprint.kt rename to src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/hook/FeedItemClassFingerprint.kt index e8879e22..125d7e45 100644 --- a/src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/FeedItemClassFingerprint.kt +++ b/src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/hook/FeedItemClassFingerprint.kt @@ -1,4 +1,4 @@ -package crimera.patches.instagram.interaction.download.fingerprints +package crimera.patches.instagram.interaction.download.fingerprints.hook import app.revanced.patcher.fingerprint.MethodFingerprint diff --git a/src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/hook/FeedItemClassNameHookFingerprint.kt b/src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/hook/FeedItemClassNameHookFingerprint.kt deleted file mode 100644 index 565c6085..00000000 --- a/src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/hook/FeedItemClassNameHookFingerprint.kt +++ /dev/null @@ -1,9 +0,0 @@ -package crimera.patches.instagram.interaction.download.fingerprints.hook - -import app.revanced.patcher.fingerprint.MethodFingerprint - -object FeedItemClassNameHookFingerprint: MethodFingerprint( - customFingerprint = { methodDef, classDef -> - methodDef.name == "feedItemClassName" - } -) \ No newline at end of file diff --git a/src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/FeedItemIconsFingerprint.kt b/src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/hook/FeedItemIconsFingerprint.kt similarity index 96% rename from src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/FeedItemIconsFingerprint.kt rename to src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/hook/FeedItemIconsFingerprint.kt index 9c6e3923..9891a6e5 100644 --- a/src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/FeedItemIconsFingerprint.kt +++ b/src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/hook/FeedItemIconsFingerprint.kt @@ -1,4 +1,4 @@ -package crimera.patches.instagram.interaction.download.fingerprints +package crimera.patches.instagram.interaction.download.fingerprints.hook import app.revanced.patcher.fingerprint.MethodFingerprint diff --git a/src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/hook/FeedOptionItemIconClassNameHookFingerprint.kt b/src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/hook/MediaListFingerprint.kt similarity index 57% rename from src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/hook/FeedOptionItemIconClassNameHookFingerprint.kt rename to src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/hook/MediaListFingerprint.kt index 24a6bc4d..82741d63 100644 --- a/src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/hook/FeedOptionItemIconClassNameHookFingerprint.kt +++ b/src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/hook/MediaListFingerprint.kt @@ -2,8 +2,9 @@ package crimera.patches.instagram.interaction.download.fingerprints.hook import app.revanced.patcher.fingerprint.MethodFingerprint -object FeedOptionItemIconClassNameHookFingerprint: MethodFingerprint( +object MediaListFingerprint : MethodFingerprint( + strings = listOf("XDTMediaDict"), customFingerprint = { methodDef, classDef -> - methodDef.name == "feedOptionItemIconClassName" - }, + classDef.interfaces.size == 2 + } ) \ No newline at end of file From 09d76cae06a0c6b6800d09b6a4749450ac75dc78 Mon Sep 17 00:00:00 2001 From: crimera Date: Sat, 18 May 2024 14:19:38 +0800 Subject: [PATCH 10/12] fix incompatibility with official patches --- .../integrations/BaseIntegrationsPatch.kt | 70 ++++++++++++++----- 1 file changed, 51 insertions(+), 19 deletions(-) diff --git a/src/main/kotlin/app/revanced/patches/shared/misc/integrations/BaseIntegrationsPatch.kt b/src/main/kotlin/app/revanced/patches/shared/misc/integrations/BaseIntegrationsPatch.kt index 498b3a77..436bbab9 100644 --- a/src/main/kotlin/app/revanced/patches/shared/misc/integrations/BaseIntegrationsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/shared/misc/integrations/BaseIntegrationsPatch.kt @@ -1,11 +1,13 @@ package app.revanced.patches.shared.misc.integrations import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.InstructionExtensions.addInstruction import app.revanced.patcher.extensions.InstructionExtensions.addInstructions import app.revanced.patcher.fingerprint.MethodFingerprint import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.PatchException import app.revanced.patches.shared.misc.integrations.BaseIntegrationsPatch.IntegrationsFingerprint.IRegisterResolver +import app.revanced.util.resultOrThrow import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.iface.ClassDef import com.android.tools.smali.dexlib2.iface.Method @@ -13,37 +15,40 @@ import crimera.patches.twitter.misc.integrations.fingerprints.ReVancedUtilsPatch import java.util.jar.JarFile abstract class BaseIntegrationsPatch( - private val hooks: Set + private val hooks: Set, ) : BytecodePatch(hooks + setOf(ReVancedUtilsPatchesVersionFingerprint)) { @Deprecated( "Use the constructor without the integrationsDescriptor parameter", - ReplaceWith("AbstractIntegrationsPatch(hooks)") + ReplaceWith("BaseIntegrationsPatch(hooks)"), ) @Suppress("UNUSED_PARAMETER") constructor( integrationsDescriptor: String, - hooks: Set + hooks: Set, ) : this(hooks) override fun execute(context: BytecodeContext) { - if (context.findClass(INTEGRATIONS_CLASS_DESCRIPTOR) == null) throw PatchException( - "Integrations have not been merged yet. This patch can not succeed without merging the integrations." - ) + if (context.findClass(INTEGRATIONS_CLASS_DESCRIPTOR) == null) { + throw PatchException( + "Integrations have not been merged yet. This patch can not succeed without merging the integrations.", + ) + } hooks.forEach { hook -> hook.invoke(INTEGRATIONS_CLASS_DESCRIPTOR) } - ReVancedUtilsPatchesVersionFingerprint.result?.mutableMethod?.apply { + // Modify Utils method to include the patches release version version. + ReVancedUtilsPatchesVersionFingerprint.resultOrThrow().mutableMethod.apply { val manifestValue = getPatchesManifestEntry("Version") addInstructions( 0, """ - const-string v0, "$manifestValue" - return-object v0 - """ + const-string v0, "$manifestValue" + return-object v0 + """, ) } } @@ -88,30 +93,57 @@ abstract class BaseIntegrationsPatch( opcodes: Iterable? = null, strings: Iterable? = null, customFingerprint: ((methodDef: Method, classDef: ClassDef) -> Boolean)? = null, - private val contextRegisterResolver: (Method) -> Int = object : IRegisterResolver {} + private val insertIndexResolver: ((Method) -> Int) = object : IHookInsertIndexResolver {}, + private val contextRegisterResolver: (Method) -> Int = object : IRegisterResolver {}, ) : MethodFingerprint( returnType, accessFlags, parameters, opcodes, strings, - customFingerprint + customFingerprint, ) { + @Deprecated( + "Previous constructor that is missing the insert index." + + "Here only for binary compatibility, " + + "and this can be removed after the next major version update.", + ) + constructor( + returnType: String? = null, + accessFlags: Int? = null, + parameters: Iterable? = null, + opcodes: Iterable? = null, + strings: Iterable? = null, + customFingerprint: ((methodDef: Method, classDef: ClassDef) -> Boolean)? = null, + contextRegisterResolver: (Method) -> Int = object : IRegisterResolver {}, + ) : this( + returnType, + accessFlags, + parameters, + opcodes, + strings, + customFingerprint, + object : IHookInsertIndexResolver {}, + contextRegisterResolver, + ) + fun invoke(integrationsDescriptor: String) { result?.mutableMethod?.let { method -> + val insertIndex = insertIndexResolver(method) val contextRegister = contextRegisterResolver(method) - method.addInstructions( - 0, - """ - sput-object v$contextRegister,$integrationsDescriptor->context:Landroid/content/Context; - invoke-static {}, $integrationsDescriptor->load()V - - """.trimIndent() + method.addInstruction( + insertIndex, + "invoke-static/range { v$contextRegister .. v$contextRegister }, " + + "$integrationsDescriptor->setContext(Landroid/content/Context;)V", ) } ?: throw PatchException("Could not find hook target fingerprint.") } + interface IHookInsertIndexResolver : (Method) -> Int { + override operator fun invoke(method: Method) = 0 + } + interface IRegisterResolver : (Method) -> Int { override operator fun invoke(method: Method) = method.implementation!!.registerCount - 1 } From 81ed4ac24e6956f0913004dfb4450cead5e10cc5 Mon Sep 17 00:00:00 2001 From: crimera Date: Sat, 18 May 2024 23:24:04 +0800 Subject: [PATCH 11/12] added video downloads --- .../download/SetupHookSignaturesPatch.kt | 56 ++++++++++++++++++- .../fingerprints/VideoModelFingerprint.kt | 7 +++ 2 files changed, 61 insertions(+), 2 deletions(-) create mode 100644 src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/VideoModelFingerprint.kt diff --git a/src/main/kotlin/crimera/patches/instagram/interaction/download/SetupHookSignaturesPatch.kt b/src/main/kotlin/crimera/patches/instagram/interaction/download/SetupHookSignaturesPatch.kt index 8c099421..f9e9b361 100644 --- a/src/main/kotlin/crimera/patches/instagram/interaction/download/SetupHookSignaturesPatch.kt +++ b/src/main/kotlin/crimera/patches/instagram/interaction/download/SetupHookSignaturesPatch.kt @@ -1,8 +1,10 @@ package crimera.patches.instagram.interaction.download import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.InstructionExtensions.addInstructions import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.extensions.InstructionExtensions.getInstructions +import app.revanced.patcher.extensions.InstructionExtensions.removeInstruction import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction import app.revanced.patcher.fingerprint.MethodFingerprint import app.revanced.patcher.patch.BytecodePatch @@ -12,7 +14,11 @@ import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction21c import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction22c import com.android.tools.smali.dexlib2.iface.reference.Reference -import crimera.patches.instagram.interaction.download.fingerprints.hook.* +import crimera.patches.instagram.interaction.download.fingerprints.VideoModelFingerprint +import crimera.patches.instagram.interaction.download.fingerprints.hook.FeedItemClassFingerprint +import crimera.patches.instagram.interaction.download.fingerprints.hook.FeedItemIconsFingerprint +import crimera.patches.instagram.interaction.download.fingerprints.hook.MediaListFingerprint +import crimera.patches.instagram.interaction.download.fingerprints.itemclickedclasses.PostMediaFingerprint object DownloadPatchHooksFingerprint : MethodFingerprint( @@ -27,7 +33,9 @@ object SetupHookSignaturesPatch : BytecodePatch( DownloadPatchHooksFingerprint, FeedItemClassFingerprint, FeedItemIconsFingerprint, - MediaListFingerprint + MediaListFingerprint, + PostMediaFingerprint, + VideoModelFingerprint ) ) { @@ -71,7 +79,51 @@ object SetupHookSignaturesPatch : BytecodePatch( it.setReturnString(fieldName) } } + } + + val postMediaClass = PostMediaFingerprint.result?.classDef ?: throw PostMediaFingerprint.exception + + methods.getMethod("isVideo")?.let { mutableMethod -> + val isVideoMethod = postMediaClass.methods.firstOrNull { + it.implementation?.instructions?.elementAtOrNull(5)?.let { instruction -> + instruction.opcode == Opcode.IF_EQ + } ?: false + } ?: throw PostMediaFingerprint.exception + mutableMethod.removeInstruction(1) + mutableMethod.addInstructions( + 0, """ + invoke-virtual {p0}, $isVideoMethod + move-result v0 + + return v0 + """ + ) + } + + methods.getMethod("getVideoLink")?.let { getVideoLink -> + val videoModelResult = VideoModelFingerprint.result ?: throw VideoModelFingerprint.exception + val videoModelClass = videoModelResult.classDef + val getVideoModel = postMediaClass.methods.firstOrNull { + it.returnType == videoModelClass.toString() && it.implementation?.registerCount == 2 + } + + val videoUrlField = videoModelClass.fields.firstOrNull { + it.type == "Lcom/instagram/model/mediasize/VideoUrlImpl;" + } + getVideoLink.removeInstruction(1) + getVideoLink.addInstructions( + 0, """ + invoke-virtual {p0}, $getVideoModel + move-result-object v0 + + iget-object v0, v0, $videoUrlField + + iget-object v0, v0, Lcom/instagram/model/mediasize/VideoUrlImpl;->A06:Ljava/lang/String; + + return v0 + """ + ) } } } diff --git a/src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/VideoModelFingerprint.kt b/src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/VideoModelFingerprint.kt new file mode 100644 index 00000000..1fc94ec9 --- /dev/null +++ b/src/main/kotlin/crimera/patches/instagram/interaction/download/fingerprints/VideoModelFingerprint.kt @@ -0,0 +1,7 @@ +package crimera.patches.instagram.interaction.download.fingerprints + +import app.revanced.patcher.fingerprint.MethodFingerprint + +object VideoModelFingerprint: MethodFingerprint( + strings = listOf("Video id is not numerical: ") +) \ No newline at end of file From 14e971f0a20a69b65f568d9d556c659bfc86068e Mon Sep 17 00:00:00 2001 From: crimera Date: Sun, 19 May 2024 20:29:42 +0800 Subject: [PATCH 12/12] load settings onstart --- .../twitter/misc/settings/SettingsPatch.kt | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/crimera/patches/twitter/misc/settings/SettingsPatch.kt b/src/main/kotlin/crimera/patches/twitter/misc/settings/SettingsPatch.kt index e828d9fd..9548c4da 100644 --- a/src/main/kotlin/crimera/patches/twitter/misc/settings/SettingsPatch.kt +++ b/src/main/kotlin/crimera/patches/twitter/misc/settings/SettingsPatch.kt @@ -11,10 +11,13 @@ import app.revanced.patcher.patch.PatchException import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.Patch import app.revanced.patcher.util.smali.ExternalLabel +import app.revanced.patches.shared.misc.integrations.BaseIntegrationsPatch import app.revanced.patches.shared.misc.integrations.fingerprint.IntegrationsUtilsFingerprint +import app.revanced.util.exception import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction11x import crimera.patches.twitter.misc.integrations.IntegrationsPatch +import crimera.patches.twitter.misc.integrations.fingerprints.InitFingerprint import crimera.patches.twitter.misc.settings.fingerprints.AuthorizeAppActivity import crimera.patches.twitter.misc.settings.fingerprints.SettingsFingerprint @@ -25,7 +28,7 @@ import crimera.patches.twitter.misc.settings.fingerprints.SettingsFingerprint compatiblePackages = [CompatiblePackage("com.twitter.android")], ) object SettingsPatch : BytecodePatch( - setOf(SettingsFingerprint, AuthorizeAppActivity, IntegrationsUtilsFingerprint) + setOf(SettingsFingerprint, AuthorizeAppActivity, IntegrationsUtilsFingerprint, InitFingerprint) ) { private const val INTEGRATIONS_PACKAGE = "Lapp/revanced/integrations/twitter" private const val UTILS_DESCRIPTOR = "$INTEGRATIONS_PACKAGE/Utils" @@ -91,9 +94,16 @@ object SettingsPatch : BytecodePatch( ) } ?: throw PatchException("ProxySettingsActivityFingerprint not found") - IntegrationsUtilsFingerprint.result!!.mutableMethod.addInstruction( + InitFingerprint.result?.mutableMethod?.addInstructions( + 1, + """ + invoke-static {}, ${BaseIntegrationsPatch.INTEGRATIONS_CLASS_DESCRIPTOR}->load()V + """ + ) ?: throw InitFingerprint.exception + + IntegrationsUtilsFingerprint.result?.mutableMethod?.addInstruction( 0, "${SSTS_DESCRIPTOR}->load()V" - ) + ) ?: throw IntegrationsUtilsFingerprint.exception } } \ No newline at end of file