From 175c18cc34dc156de74c1b2f1bf61314481b89a8 Mon Sep 17 00:00:00 2001 From: inotia00 <108592928+inotia00@users.noreply.github.com> Date: Sat, 27 Jul 2024 17:37:36 +0900 Subject: [PATCH] fix(YouTube/Client spoof): some side effects of iOS client https://github.com/inotia00/ReVanced_Extended/issues/2261 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit • No HDR video → HDR video is supported only on AV1 codec • Higher video qualities may not be available → fixed • Live streams not available on Android 8.0 → fixed --- .../utils/fix/client/SpoofClientPatch.kt | 45 +++++++++++++++++++ ...equestBodyWithVersionReleaseFingerprint.kt | 30 +++++++++++++ .../UserAgentHeaderBuilderFingerprint.kt | 19 ++++++++ .../youtube/settings/host/values/strings.xml | 6 +-- 4 files changed, 96 insertions(+), 4 deletions(-) create mode 100644 src/main/kotlin/app/revanced/patches/youtube/utils/fix/client/fingerprints/CreatePlayerRequestBodyWithVersionReleaseFingerprint.kt create mode 100644 src/main/kotlin/app/revanced/patches/youtube/utils/fix/client/fingerprints/UserAgentHeaderBuilderFingerprint.kt diff --git a/src/main/kotlin/app/revanced/patches/youtube/utils/fix/client/SpoofClientPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/utils/fix/client/SpoofClientPatch.kt index 6abcf087f..4d1819553 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/utils/fix/client/SpoofClientPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/utils/fix/client/SpoofClientPatch.kt @@ -16,9 +16,12 @@ import app.revanced.patches.youtube.utils.fix.client.fingerprints.BuildInitPlayb import app.revanced.patches.youtube.utils.fix.client.fingerprints.BuildPlayerRequestURIFingerprint import app.revanced.patches.youtube.utils.fix.client.fingerprints.CreatePlaybackSpeedMenuItemFingerprint import app.revanced.patches.youtube.utils.fix.client.fingerprints.CreatePlayerRequestBodyFingerprint +import app.revanced.patches.youtube.utils.fix.client.fingerprints.CreatePlayerRequestBodyWithVersionReleaseFingerprint +import app.revanced.patches.youtube.utils.fix.client.fingerprints.CreatePlayerRequestBodyWithVersionReleaseFingerprint.indexOfBuildInstruction import app.revanced.patches.youtube.utils.fix.client.fingerprints.NerdsStatsVideoFormatBuilderFingerprint import app.revanced.patches.youtube.utils.fix.client.fingerprints.PlayerGestureConfigSyntheticFingerprint import app.revanced.patches.youtube.utils.fix.client.fingerprints.SetPlayerRequestClientTypeFingerprint +import app.revanced.patches.youtube.utils.fix.client.fingerprints.UserAgentHeaderBuilderFingerprint import app.revanced.patches.youtube.utils.integrations.Constants.MISC_PATH import app.revanced.patches.youtube.utils.integrations.Constants.PATCH_STATUS_CLASS_DESCRIPTOR import app.revanced.patches.youtube.utils.settings.SettingsPatch @@ -61,6 +64,8 @@ object SpoofClientPatch : BaseBytecodePatch( SetPlayerRequestClientTypeFingerprint, CreatePlayerRequestBodyFingerprint, CreatePlayerRequestBodyWithModelFingerprint, + CreatePlayerRequestBodyWithVersionReleaseFingerprint, + UserAgentHeaderBuilderFingerprint, // Player gesture config. PlayerGestureConfigSyntheticFingerprint, @@ -178,6 +183,24 @@ object SpoofClientPatch : BaseBytecodePatch( ?: throw PatchException("Could not find clientInfoClientModelField") } + val clientInfoOsVersionField = + CreatePlayerRequestBodyWithVersionReleaseFingerprint.resultOrThrow().mutableMethod.let { + val buildIndex = indexOfBuildInstruction(it) + val instructions = it.getInstructions() + + // The next IPUT_OBJECT instruction after getting the client model is setting the client model field. + instructions.subList( + buildIndex - 5, + buildIndex, + ).find { instruction -> + val reference = instruction.getReference() + instruction.opcode == Opcode.IPUT_OBJECT + && reference?.definingClass == CLIENT_INFO_CLASS_DESCRIPTOR + && reference.type == "Ljava/lang/String;" + }?.getReference() + ?: throw PatchException("Could not find clientInfoOsVersionField") + } + // endregion // region Spoof client type for /player requests. @@ -243,6 +266,12 @@ object SpoofClientPatch : BaseBytecodePatch( move-result-object v1 iput-object v1, v0, $clientInfoClientVersionField + # Set client os version to the spoofed value. + iget-object v1, v0, $clientInfoOsVersionField + invoke-static { v1 }, $INTEGRATIONS_CLASS_DESCRIPTOR->getOsVersion(Ljava/lang/String;)Ljava/lang/String; + move-result-object v1 + iput-object v1, v0, $clientInfoOsVersionField + :disabled return-void """, @@ -254,6 +283,22 @@ object SpoofClientPatch : BaseBytecodePatch( // endregion + // region Spoof user-agent + + UserAgentHeaderBuilderFingerprint.resultOrThrow().mutableMethod.apply { + val insertIndex = implementation!!.instructions.lastIndex + val insertRegister = getInstruction(insertIndex).registerA + + addInstructions( + insertIndex, """ + invoke-static { v$insertRegister }, $INTEGRATIONS_CLASS_DESCRIPTOR->getUserAgent(Ljava/lang/String;)Ljava/lang/String; + move-result-object v$insertRegister + """ + ) + } + + // endregion + // region check whether video is Shorts or Clips. PlayerResponseMethodHookPatch += PlayerResponseMethodHookPatch.Hook.PlayerParameter( diff --git a/src/main/kotlin/app/revanced/patches/youtube/utils/fix/client/fingerprints/CreatePlayerRequestBodyWithVersionReleaseFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/utils/fix/client/fingerprints/CreatePlayerRequestBodyWithVersionReleaseFingerprint.kt new file mode 100644 index 000000000..a4157fdc4 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/utils/fix/client/fingerprints/CreatePlayerRequestBodyWithVersionReleaseFingerprint.kt @@ -0,0 +1,30 @@ +package app.revanced.patches.youtube.utils.fix.client.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.MethodFingerprint +import app.revanced.patches.youtube.utils.fix.client.fingerprints.CreatePlayerRequestBodyWithVersionReleaseFingerprint.indexOfBuildInstruction +import app.revanced.util.getReference +import app.revanced.util.indexOfFirstInstruction +import com.android.tools.smali.dexlib2.AccessFlags +import com.android.tools.smali.dexlib2.Opcode +import com.android.tools.smali.dexlib2.iface.Method +import com.android.tools.smali.dexlib2.iface.reference.MethodReference + +internal object CreatePlayerRequestBodyWithVersionReleaseFingerprint : MethodFingerprint( + returnType = "V", + accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, + parameters = listOf("L"), + strings = listOf("Google Inc."), + customFingerprint = { methodDef, _ -> + indexOfBuildInstruction(methodDef) >= 0 + }, +) { + fun indexOfBuildInstruction(methodDef: Method) = + methodDef.indexOfFirstInstruction { + val reference = getReference() + opcode == Opcode.INVOKE_VIRTUAL && + reference?.name == "build" && + reference.parameterTypes.isEmpty() && + reference.returnType.startsWith("L") + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/utils/fix/client/fingerprints/UserAgentHeaderBuilderFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/utils/fix/client/fingerprints/UserAgentHeaderBuilderFingerprint.kt new file mode 100644 index 000000000..c724a6718 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/utils/fix/client/fingerprints/UserAgentHeaderBuilderFingerprint.kt @@ -0,0 +1,19 @@ +package app.revanced.patches.youtube.utils.fix.client.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.MethodFingerprint +import com.android.tools.smali.dexlib2.AccessFlags +import com.android.tools.smali.dexlib2.Opcode + +/** + * This is the fingerprint used in the 'client-spoof' patch around 2022. + * (Integrated into 'UserAgentClientSpoofPatch' now.) + * + * This method is modified by 'UserAgentClientSpoofPatch', so the fingerprint does not check the [Opcode]. + */ +internal object UserAgentHeaderBuilderFingerprint : MethodFingerprint( + accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC, + returnType = "Ljava/lang/String;", + parameters = listOf("Landroid/content/Context;", "Ljava/lang/String;", "Ljava/lang/String;"), + strings = listOf("(Linux; U; Android "), +) \ No newline at end of file diff --git a/src/main/resources/youtube/settings/host/values/strings.xml b/src/main/resources/youtube/settings/host/values/strings.xml index e5f864756..f31507442 100644 --- a/src/main/resources/youtube/settings/host/values/strings.xml +++ b/src/main/resources/youtube/settings/host/values/strings.xml @@ -1608,11 +1608,9 @@ Limitation: Feed videos will play for less than 1 minute before encountering pla "Spoof client to iOS. Side effects include: -• No HDR video. -• Higher video qualities may not be available. +• HDR video is supported only on AV1 codec. • Watch history does not work with a brand account. -• Live streams cannot play as audio-only. -• Live streams not available on Android 8.0." +• Live streams cannot play as audio-only." Android Testsuite "Spoof client to Android Testsuite.