From e051136de84f0096f9b718fb91933a6f31d7c14d Mon Sep 17 00:00:00 2001 From: inotia00 <108592928+inotia00@users.noreply.github.com> Date: Thu, 9 May 2024 00:54:51 +0900 Subject: [PATCH] feat(YouTube): add `Spoof test client` patch --- .../youtube/misc/test/SpoofTestClientPatch.kt | 111 ++++++++++++++++++ .../ClientNamelEnumConstructorFingerprint.kt | 11 ++ .../OverrideBuildVersionFingerprint.kt | 18 +++ .../fingerprints/SetClientNameFingerprint.kt | 18 +++ .../youtube/settings/host/values/strings.xml | 5 + .../youtube/settings/xml/revanced_prefs.xml | 6 +- 6 files changed, 168 insertions(+), 1 deletion(-) create mode 100644 src/main/kotlin/app/revanced/patches/youtube/misc/test/SpoofTestClientPatch.kt create mode 100644 src/main/kotlin/app/revanced/patches/youtube/misc/test/fingerprints/ClientNamelEnumConstructorFingerprint.kt create mode 100644 src/main/kotlin/app/revanced/patches/youtube/misc/test/fingerprints/OverrideBuildVersionFingerprint.kt create mode 100644 src/main/kotlin/app/revanced/patches/youtube/misc/test/fingerprints/SetClientNameFingerprint.kt diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/test/SpoofTestClientPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/test/SpoofTestClientPatch.kt new file mode 100644 index 000000000..d6fed81a3 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/test/SpoofTestClientPatch.kt @@ -0,0 +1,111 @@ +package app.revanced.patches.youtube.misc.test + +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.patch.PatchException +import app.revanced.patcher.util.smali.ExternalLabel +import app.revanced.patches.youtube.misc.test.fingerprints.ClientNamelEnumConstructorFingerprint +import app.revanced.patches.youtube.misc.test.fingerprints.OverrideBuildVersionFingerprint +import app.revanced.patches.youtube.misc.test.fingerprints.SetClientNameFingerprint +import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE +import app.revanced.patches.youtube.utils.integrations.Constants.MISC_PATH +import app.revanced.patches.youtube.utils.settings.SettingsPatch +import app.revanced.util.getStringInstructionIndex +import app.revanced.util.getTargetIndex +import app.revanced.util.getWalkerMethod +import app.revanced.util.patch.BaseBytecodePatch +import app.revanced.util.resultOrThrow +import com.android.tools.smali.dexlib2.Opcode +import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction +import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction +import com.android.tools.smali.dexlib2.iface.reference.MethodReference + +@Suppress("unused") +object SpoofTestClientPatch : BaseBytecodePatch( + name = "Spoof test client", + description = "Adds an option to spoof as test client.", + dependencies = setOf(SettingsPatch::class), + compatiblePackages = COMPATIBLE_PACKAGE, + fingerprints = setOf( + ClientNamelEnumConstructorFingerprint, + OverrideBuildVersionFingerprint, + SetClientNameFingerprint + ) +) { + private const val INTEGRATIONS_CLASS_DESCRIPTOR = + "$MISC_PATH/SpoofTestClientPatch;" + + override fun execute(context: BytecodeContext) { + var clientNameEnumClass: String + var testClientEnumReference: String + + // region get test client enum and reference + + ClientNamelEnumConstructorFingerprint.resultOrThrow().mutableMethod.apply { + clientNameEnumClass = definingClass + + val testClientStringIndex = getStringInstructionIndex("ANDROID_TESTSUITE") + val testClientEnumIndex = getTargetIndex(testClientStringIndex, Opcode.SPUT_OBJECT) + testClientEnumReference = getInstruction(testClientEnumIndex).reference.toString() + } + + // endregion + + // region override client name + + SetClientNameFingerprint.resultOrThrow().let { + it.mutableMethod.apply { + val walkerIndex = it.scanResult.patternScanResult!!.startIndex + 2 + val walkerReference = getInstruction(walkerIndex).reference as MethodReference + if (walkerReference.parameterTypes[2].toString() != clientNameEnumClass) + throw PatchException("parameterType does not match") + + val walkerMethod = getWalkerMethod(context, walkerIndex) + walkerMethod.apply { + addInstructionsWithLabels( + 0, """ + invoke-static {}, $INTEGRATIONS_CLASS_DESCRIPTOR->spoofTestClient()Z + move-result v0 + if-eqz v0, :ignore + sget-object p2, $testClientEnumReference + """, ExternalLabel("ignore", getInstruction(0)) + ) + } + } + } + + // endregion + + // region override client version + + OverrideBuildVersionFingerprint.resultOrThrow().let { + it.mutableMethod.apply { + val insertIndex = it.scanResult.patternScanResult!!.startIndex + 1 + val insertRegister = getInstruction(insertIndex + 1).registerA + + addInstructions( + insertIndex, """ + invoke-static {v$insertRegister}, $INTEGRATIONS_CLASS_DESCRIPTOR->spoofTestClient(Ljava/lang/String;)Ljava/lang/String; + move-result-object v$insertRegister + """ + ) + } + } + + // endregion + + /** + * Add settings + */ + SettingsPatch.addPreference( + arrayOf( + "PREFERENCE_CATEGORY: MISC_EXPERIMENTAL_FLAGS", + "SETTINGS: SPOOF_TEST_CLIENT" + ) + ) + + SettingsPatch.updatePatchStatus(this) + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/test/fingerprints/ClientNamelEnumConstructorFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/test/fingerprints/ClientNamelEnumConstructorFingerprint.kt new file mode 100644 index 000000000..00f50acd1 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/test/fingerprints/ClientNamelEnumConstructorFingerprint.kt @@ -0,0 +1,11 @@ +package app.revanced.patches.youtube.misc.test.fingerprints + +import app.revanced.patcher.fingerprint.MethodFingerprint + +internal object ClientNamelEnumConstructorFingerprint : MethodFingerprint( + returnType = "V", + strings = listOf( + "UNKNOWN_INTERFACE", + "ANDROID_TESTSUITE" + ) +) diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/test/fingerprints/OverrideBuildVersionFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/test/fingerprints/OverrideBuildVersionFingerprint.kt new file mode 100644 index 000000000..d44599a00 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/test/fingerprints/OverrideBuildVersionFingerprint.kt @@ -0,0 +1,18 @@ +package app.revanced.patches.youtube.misc.test.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 + +internal object OverrideBuildVersionFingerprint : MethodFingerprint( + returnType = "L", + accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC, + parameters = listOf("L"), + opcodes = listOf( + Opcode.IGET_OBJECT, + Opcode.GOTO, + Opcode.CONST_STRING, + ), + strings = listOf("pref_override_build_version_name") +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/test/fingerprints/SetClientNameFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/test/fingerprints/SetClientNameFingerprint.kt new file mode 100644 index 000000000..928872a05 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/test/fingerprints/SetClientNameFingerprint.kt @@ -0,0 +1,18 @@ +package app.revanced.patches.youtube.misc.test.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 + +internal object SetClientNameFingerprint : MethodFingerprint( + returnType = "V", + accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, + parameters = listOf("L"), + opcodes = listOf( + Opcode.CONST_HIGH16, + Opcode.CONST_HIGH16, + Opcode.INVOKE_STATIC, + ), + strings = listOf("_partition") +) \ 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 4d5d81355..c606f1152 100644 --- a/src/main/resources/youtube/settings/host/values/strings.xml +++ b/src/main/resources/youtube/settings/host/values/strings.xml @@ -1388,6 +1388,11 @@ Limitation: Automatically played feed videos will show up in your watch history. "Player parameter not spoofed for feed videos. Limitation: Feed videos will play for less than 1 minute before encountering playback issues." + Spoof test client + "Spoof the client as a test client. + +• This client is used for testing purposes, so most YouTube features are not available. +• There are no playback buffer issues in the test client." Import / Export settings diff --git a/src/main/resources/youtube/settings/xml/revanced_prefs.xml b/src/main/resources/youtube/settings/xml/revanced_prefs.xml index a89b37bfc..4698c982e 100644 --- a/src/main/resources/youtube/settings/xml/revanced_prefs.xml +++ b/src/main/resources/youtube/settings/xml/revanced_prefs.xml @@ -557,7 +557,10 @@ - + + + @@ -630,6 +633,7 @@ +