From bd4d3b5706f26e398292df952ca8aec6c7dd1d6a Mon Sep 17 00:00:00 2001 From: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com> Date: Tue, 10 Jan 2023 22:27:53 +0400 Subject: [PATCH] feat(youtube): `spoof-app-version` patch (#1449) Co-authored-by: oSumAtrIX --- .../SpoofAppVersionCompatibility.kt | 14 ++++ .../SpoofAppVersionFingerprint.kt | 19 ++++++ .../bytecode/patch/SpoofAppVersionPatch.kt | 64 +++++++++++++++++++ 3 files changed, 97 insertions(+) create mode 100644 src/main/kotlin/app/revanced/patches/youtube/layout/spoofappversion/annotations/SpoofAppVersionCompatibility.kt create mode 100644 src/main/kotlin/app/revanced/patches/youtube/layout/spoofappversion/bytecode/fingerprints/SpoofAppVersionFingerprint.kt create mode 100644 src/main/kotlin/app/revanced/patches/youtube/layout/spoofappversion/bytecode/patch/SpoofAppVersionPatch.kt diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/spoofappversion/annotations/SpoofAppVersionCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/spoofappversion/annotations/SpoofAppVersionCompatibility.kt new file mode 100644 index 000000000..0a4637ce3 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/spoofappversion/annotations/SpoofAppVersionCompatibility.kt @@ -0,0 +1,14 @@ +package app.revanced.patches.youtube.layout.spoofappversion.annotations + +import app.revanced.patcher.annotation.Compatibility +import app.revanced.patcher.annotation.Package + +@Compatibility( + [Package( + "com.google.android.youtube", arrayOf("17.49.37") + )] +) +@Target(AnnotationTarget.CLASS) +@Retention(AnnotationRetention.RUNTIME) +internal annotation class SpoofAppVersionCompatibility + diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/spoofappversion/bytecode/fingerprints/SpoofAppVersionFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/spoofappversion/bytecode/fingerprints/SpoofAppVersionFingerprint.kt new file mode 100644 index 000000000..8a5736f12 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/spoofappversion/bytecode/fingerprints/SpoofAppVersionFingerprint.kt @@ -0,0 +1,19 @@ +package app.revanced.patches.youtube.layout.spoofappversion.bytecode.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.Opcode + +object SpoofAppVersionFingerprint : MethodFingerprint( + "L", AccessFlags.PUBLIC or AccessFlags.STATIC, listOf("L"), listOf( + Opcode.IGET_OBJECT, + Opcode.GOTO, + Opcode.CONST_STRING, + ), + + // Instead of applying a bytecode patch, it might be possible to only rely on code from the integrations and + // manually set the desired version string as this keyed value in the SharedPreferences. + // But, this bytecode patch is simple and it works. + strings = listOf("pref_override_build_version_name") +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/spoofappversion/bytecode/patch/SpoofAppVersionPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/spoofappversion/bytecode/patch/SpoofAppVersionPatch.kt new file mode 100644 index 000000000..3a3b5c81b --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/spoofappversion/bytecode/patch/SpoofAppVersionPatch.kt @@ -0,0 +1,64 @@ +package app.revanced.patches.youtube.layout.spoofappversion.bytecode.patch + +import app.revanced.extensions.toErrorResult +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patches.shared.settings.preference.impl.StringResource +import app.revanced.patches.shared.settings.preference.impl.SwitchPreference +import app.revanced.patches.youtube.layout.spoofappversion.annotations.SpoofAppVersionCompatibility +import app.revanced.patches.youtube.layout.spoofappversion.bytecode.fingerprints.SpoofAppVersionFingerprint +import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch +import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch +import org.jf.dexlib2.iface.instruction.OneRegisterInstruction + +@Patch +@DependsOn([IntegrationsPatch::class, SettingsPatch::class]) +@Name("spoof-app-version") +@Description("Tricks YouTube into thinking, you are running an older version of the app. One of the side effects also includes restoring the old UI.") +@SpoofAppVersionCompatibility +@Version("0.0.1") +class SpoofAppVersionPatch : BytecodePatch( + listOf( + SpoofAppVersionFingerprint + ) +) { + companion object { + const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/patches/SpoofAppVersionPatch" + } + + override fun execute(context: BytecodeContext): PatchResult { + SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( + SwitchPreference( + "revanced_spoof_app_version", + StringResource("revanced_spoof_app_version_title", "Spoof app version"), + false, + StringResource("revanced_spoof_app_version_summary_on", "Version spoofed to 17.30.34. If switched off, the old UI layout may remain until logging out or clearing app data"), + StringResource("revanced_spoof_app_version_summary_off", "Version not spoofed") + ) + ) + + SpoofAppVersionFingerprint.result?.apply { + val insertIndex = scanResult.patternScanResult!!.startIndex + 1 + val buildOverrideNameRegister = + (mutableMethod.implementation!!.instructions[insertIndex - 1] as OneRegisterInstruction).registerA + + mutableMethod.addInstructions( + insertIndex, + """ + invoke-static {v$buildOverrideNameRegister}, $INTEGRATIONS_CLASS_DESCRIPTOR;->getYouTubeVersionOverride(Ljava/lang/String;)Ljava/lang/String; + move-result-object v$buildOverrideNameRegister + """ + ) + } ?: return SpoofAppVersionFingerprint.toErrorResult() + + return PatchResultSuccess() + } +} \ No newline at end of file