From 17802c1d79bd09a0efbaaff33d127571148b6af3 Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Sun, 14 Jul 2024 01:54:13 +0200 Subject: [PATCH] refactor/improve reliability --- api/revanced-patches.api | 8 ++-- .../patches/duolingo/ad/DisableAdsPatch.kt | 42 +++++++++++++++++++ .../duolingo/ad/RemoveDuolingoAdsPatch.kt | 42 ------------------- ...zeMonetizationDebugSettingsFingerprint.kt} | 4 +- .../duolingo/debug/EnableDebugMenuPatch.kt | 36 ++++++++++++++++ .../duolingo/debug/MakeDebugMenuAvailable.kt | 36 ---------------- ...itializeBuildConfigProviderFingerprint.kt} | 13 +++--- 7 files changed, 92 insertions(+), 89 deletions(-) create mode 100644 src/main/kotlin/app/revanced/patches/duolingo/ad/DisableAdsPatch.kt delete mode 100644 src/main/kotlin/app/revanced/patches/duolingo/ad/RemoveDuolingoAdsPatch.kt rename src/main/kotlin/app/revanced/patches/duolingo/ad/fingerprints/{MonetizationDebugSettingsFingerprint.kt => InitializeMonetizationDebugSettingsFingerprint.kt} (85%) create mode 100644 src/main/kotlin/app/revanced/patches/duolingo/debug/EnableDebugMenuPatch.kt delete mode 100644 src/main/kotlin/app/revanced/patches/duolingo/debug/MakeDebugMenuAvailable.kt rename src/main/kotlin/app/revanced/patches/duolingo/debug/fingerprints/{BuildConfigProviderFingerprint.kt => InitializeBuildConfigProviderFingerprint.kt} (60%) diff --git a/api/revanced-patches.api b/api/revanced-patches.api index f6cc06c07a..fcadb908d6 100644 --- a/api/revanced-patches.api +++ b/api/revanced-patches.api @@ -193,14 +193,14 @@ public final class app/revanced/patches/cieid/restrictions/root/BypassRootChecks public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V } -public final class app/revanced/patches/duolingo/ad/RemoveDuolingoAdsPatch : app/revanced/patcher/patch/BytecodePatch { - public static final field INSTANCE Lapp/revanced/patches/duolingo/ad/RemoveDuolingoAdsPatch; +public final class app/revanced/patches/duolingo/ad/DisableAdsPatch : app/revanced/patcher/patch/BytecodePatch { + public static final field INSTANCE Lapp/revanced/patches/duolingo/ad/DisableAdsPatch; public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V } -public final class app/revanced/patches/duolingo/debug/MakeDebugMenuAvailable : app/revanced/patcher/patch/BytecodePatch { - public static final field INSTANCE Lapp/revanced/patches/duolingo/debug/MakeDebugMenuAvailable; +public final class app/revanced/patches/duolingo/debug/EnableDebugMenuPatch : app/revanced/patcher/patch/BytecodePatch { + public static final field INSTANCE Lapp/revanced/patches/duolingo/debug/EnableDebugMenuPatch; public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V } diff --git a/src/main/kotlin/app/revanced/patches/duolingo/ad/DisableAdsPatch.kt b/src/main/kotlin/app/revanced/patches/duolingo/ad/DisableAdsPatch.kt new file mode 100644 index 0000000000..8c5d9081d1 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/duolingo/ad/DisableAdsPatch.kt @@ -0,0 +1,42 @@ +package app.revanced.patches.duolingo.ad + +import app.revanced.patcher.data.BytecodeContext +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.annotation.CompatiblePackage +import app.revanced.patcher.patch.annotation.Patch +import app.revanced.patches.duolingo.ad.fingerprints.InitializeMonetizationDebugSettingsFingerprint +import app.revanced.util.exception +import app.revanced.util.resultOrThrow +import com.android.tools.smali.dexlib2.Opcode +import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction22c + +@Patch( + name = "Disable ads", + compatiblePackages = [CompatiblePackage("com.duolingo")] +) +@Suppress("unused") +object DisableAdsPatch : BytecodePatch( + setOf(InitializeMonetizationDebugSettingsFingerprint) +) { + override fun execute(context: BytecodeContext) { + // Couple approaches to remove ads exist: + // + // MonetizationDebugSettings has a boolean value for "disableAds". + // OnboardingState has a getter to check if the user has any "adFreeSessions". + // SharedPreferences has a debug boolean value with key "disable_ads", which maps to "DebugCategory.DISABLE_ADS". + // + // MonetizationDebugSettings seems to be the most general setting to work fine. + InitializeMonetizationDebugSettingsFingerprint.resultOrThrow().mutableMethod.apply { + val setDisableAdsIndex = getInstructions().firstOrNull { + it.opcode == Opcode.IPUT_BOOLEAN + } as? BuilderInstruction22c ?: throw InitializeMonetizationDebugSettingsFingerprint.exception + + addInstructions( + setDisableAdsIndex.location.index, + "const/4 v${setDisableAdsIndex.registerA}, 0x1" + ) + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/duolingo/ad/RemoveDuolingoAdsPatch.kt b/src/main/kotlin/app/revanced/patches/duolingo/ad/RemoveDuolingoAdsPatch.kt deleted file mode 100644 index c9ff22213a..0000000000 --- a/src/main/kotlin/app/revanced/patches/duolingo/ad/RemoveDuolingoAdsPatch.kt +++ /dev/null @@ -1,42 +0,0 @@ -package app.revanced.patches.duolingo.ad - -import app.revanced.patcher.extensions.InstructionExtensions.addInstructions -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.InstructionExtensions.getInstructions -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.annotation.CompatiblePackage -import app.revanced.patcher.patch.annotation.Patch -import app.revanced.patches.duolingo.ad.fingerprints.MonetizationDebugSettingsFingerprint -import app.revanced.util.exception -import com.android.tools.smali.dexlib2.Opcode -import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction22c - -@Patch( - name = "Remove Duolingo Ads", compatiblePackages = [CompatiblePackage("com.duolingo")] -) -@Suppress("unused") -object RemoveDuolingoAdsPatch : BytecodePatch( - setOf( - MonetizationDebugSettingsFingerprint, - ) -) { - override fun execute(context: BytecodeContext) { - // we have a couple of options to approach this: - // - `MonetizationDebugSettings` has a boolean value for `disableAds` - // - `OnboardingState` has a getter to check if the user has any `adFreeSessions` - // - `SharedPreferences` has a debug boolean value with key `disable_ads`, which maps to `DebugCategory.DISABLE_ADS` - // - // we'll target `MonetizationDebugSettings`, as it seems to be the most general setting that seems to work a-okay - MonetizationDebugSettingsFingerprint.result?.mutableMethod?.apply { - val firstAssigner = getInstructions().filterIsInstance() - .firstOrNull { it.opcode == Opcode.IPUT_BOOLEAN } ?: throw MonetizationDebugSettingsFingerprint.exception - - // force the value of the first assignment (`disableAds`) to be `true` - addInstructions( - firstAssigner.location.index, """ - const/4 v${firstAssigner.registerA}, 0x1 - """.trimIndent() - ) - } ?: throw MonetizationDebugSettingsFingerprint.exception - } -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/duolingo/ad/fingerprints/MonetizationDebugSettingsFingerprint.kt b/src/main/kotlin/app/revanced/patches/duolingo/ad/fingerprints/InitializeMonetizationDebugSettingsFingerprint.kt similarity index 85% rename from src/main/kotlin/app/revanced/patches/duolingo/ad/fingerprints/MonetizationDebugSettingsFingerprint.kt rename to src/main/kotlin/app/revanced/patches/duolingo/ad/fingerprints/InitializeMonetizationDebugSettingsFingerprint.kt index 80d08d008d..3a2cb47e79 100644 --- a/src/main/kotlin/app/revanced/patches/duolingo/ad/fingerprints/MonetizationDebugSettingsFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/duolingo/ad/fingerprints/InitializeMonetizationDebugSettingsFingerprint.kt @@ -4,7 +4,7 @@ import app.revanced.patcher.extensions.or import app.revanced.patcher.fingerprint.MethodFingerprint import com.android.tools.smali.dexlib2.AccessFlags -internal object MonetizationDebugSettingsFingerprint : MethodFingerprint( +internal object InitializeMonetizationDebugSettingsFingerprint : MethodFingerprint( returnType = "V", accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, parameters = listOf( @@ -14,4 +14,4 @@ internal object MonetizationDebugSettingsFingerprint : MethodFingerprint( "Z", // alwaysShowSuperAds "Lcom/duolingo/debug/FamilyQuestOverride;", ) -) \ No newline at end of file +) diff --git a/src/main/kotlin/app/revanced/patches/duolingo/debug/EnableDebugMenuPatch.kt b/src/main/kotlin/app/revanced/patches/duolingo/debug/EnableDebugMenuPatch.kt new file mode 100644 index 0000000000..facaebe683 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/duolingo/debug/EnableDebugMenuPatch.kt @@ -0,0 +1,36 @@ +package app.revanced.patches.duolingo.debug + +import app.revanced.patcher.data.BytecodeContext +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.annotation.CompatiblePackage +import app.revanced.patcher.patch.annotation.Patch +import app.revanced.patches.duolingo.debug.fingerprints.InitializeBuildConfigProviderFingerprint +import app.revanced.util.exception +import app.revanced.util.resultOrThrow +import com.android.tools.smali.dexlib2.Opcode +import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction22c + +@Patch( + name = "Enable debug menu", + compatiblePackages = [CompatiblePackage("com.duolingo")], + use = false +) +@Suppress("unused") +object EnableDebugMenuPatch : BytecodePatch( + setOf(InitializeBuildConfigProviderFingerprint) +) { + override fun execute(context: BytecodeContext) { + InitializeBuildConfigProviderFingerprint.resultOrThrow().mutableMethod.apply { + val setIsDebugBuildIndex = getInstructions().firstOrNull { + it.opcode == Opcode.IPUT_BOOLEAN + } as? BuilderInstruction22c ?: throw InitializeBuildConfigProviderFingerprint.exception + + addInstructions( + setIsDebugBuildIndex.location.index, + "const/4 v${setIsDebugBuildIndex.registerA}, 0x1" + ) + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/duolingo/debug/MakeDebugMenuAvailable.kt b/src/main/kotlin/app/revanced/patches/duolingo/debug/MakeDebugMenuAvailable.kt deleted file mode 100644 index a143f9e37d..0000000000 --- a/src/main/kotlin/app/revanced/patches/duolingo/debug/MakeDebugMenuAvailable.kt +++ /dev/null @@ -1,36 +0,0 @@ -package app.revanced.patches.duolingo.debug - -import app.revanced.patcher.extensions.InstructionExtensions.addInstructions -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.InstructionExtensions.getInstructions -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.annotation.CompatiblePackage -import app.revanced.patcher.patch.annotation.Patch -import app.revanced.patches.duolingo.debug.fingerprints.BuildConfigProviderFingerprint -import app.revanced.util.exception -import com.android.tools.smali.dexlib2.Opcode -import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction22c - -@Patch( - name = "Make Duolingo debug menu available", compatiblePackages = [CompatiblePackage("com.duolingo")], use = false -) -@Suppress("unused") -object MakeDebugMenuAvailable : BytecodePatch( - setOf( - BuildConfigProviderFingerprint, - ) -) { - override fun execute(context: BytecodeContext) { - BuildConfigProviderFingerprint.result?.mutableMethod?.apply { - val firstAssigner = getInstructions().filterIsInstance() - .firstOrNull { it.opcode == Opcode.IPUT_BOOLEAN } ?: throw BuildConfigProviderFingerprint.exception - - // force the value of the first assignment (`isDebugBuild`) to be `true` - addInstructions( - firstAssigner.location.index, """ - const/4 v${firstAssigner.registerA}, 0x1 - """.trimIndent() - ) - } ?: throw BuildConfigProviderFingerprint.exception - } -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/duolingo/debug/fingerprints/BuildConfigProviderFingerprint.kt b/src/main/kotlin/app/revanced/patches/duolingo/debug/fingerprints/InitializeBuildConfigProviderFingerprint.kt similarity index 60% rename from src/main/kotlin/app/revanced/patches/duolingo/debug/fingerprints/BuildConfigProviderFingerprint.kt rename to src/main/kotlin/app/revanced/patches/duolingo/debug/fingerprints/InitializeBuildConfigProviderFingerprint.kt index 32b3818a1b..a00468175d 100644 --- a/src/main/kotlin/app/revanced/patches/duolingo/debug/fingerprints/BuildConfigProviderFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/duolingo/debug/fingerprints/InitializeBuildConfigProviderFingerprint.kt @@ -4,10 +4,13 @@ import app.revanced.patcher.extensions.or import app.revanced.patcher.fingerprint.MethodFingerprint import com.android.tools.smali.dexlib2.AccessFlags -// the `BuildConfigProvider` class has two bools: -// - `isChina`: (usually) compares "play" with "china"...except for builds in China -// - `isDebug`: compares "release" with "debug" <-- we want to force this to `true` -internal object BuildConfigProviderFingerprint : MethodFingerprint( +/** + * The `BuildConfigProvider` class has two booleans: + * + * - `isChina`: (usually) compares "play" with "china"...except for builds in China + * - `isDebug`: compares "release" with "debug" <-- we want to force this to `true` + */ +internal object InitializeBuildConfigProviderFingerprint : MethodFingerprint( returnType = "V", accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, strings = listOf( @@ -15,4 +18,4 @@ internal object BuildConfigProviderFingerprint : MethodFingerprint( "release", "china", ), -) \ No newline at end of file +)