From 44a8a1399897caaff3ff45db8549ddedb2f01b68 Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Fri, 15 Mar 2024 00:27:02 +0100 Subject: [PATCH] fix(YouTube - Client spoof): Spoof all user agents --- api/revanced-patches.api | 8 +- .../misc/fix/playback/ClientSpoofPatch.kt | 102 ++++++++++++------ .../UserAgentHeaderBuilderFingerprint.kt | 10 -- 3 files changed, 74 insertions(+), 46 deletions(-) delete mode 100644 src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/UserAgentHeaderBuilderFingerprint.kt diff --git a/api/revanced-patches.api b/api/revanced-patches.api index 4e1ad810a5..842b91499d 100644 --- a/api/revanced-patches.api +++ b/api/revanced-patches.api @@ -1514,10 +1514,12 @@ public final class app/revanced/patches/youtube/misc/dimensions/spoof/SpoofDevic public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V } -public final class app/revanced/patches/youtube/misc/fix/playback/ClientSpoofPatch : app/revanced/patcher/patch/BytecodePatch { +public final class app/revanced/patches/youtube/misc/fix/playback/ClientSpoofPatch : app/revanced/patches/all/misc/transformation/BaseTransformInstructionsPatch { public static final field INSTANCE Lapp/revanced/patches/youtube/misc/fix/playback/ClientSpoofPatch; - public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V - public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V + public synthetic fun filterMap (Lcom/android/tools/smali/dexlib2/iface/ClassDef;Lcom/android/tools/smali/dexlib2/iface/Method;Lcom/android/tools/smali/dexlib2/iface/instruction/Instruction;I)Ljava/lang/Object; + public fun filterMap (Lcom/android/tools/smali/dexlib2/iface/ClassDef;Lcom/android/tools/smali/dexlib2/iface/Method;Lcom/android/tools/smali/dexlib2/iface/instruction/Instruction;I)Lkotlin/Triple; + public synthetic fun transform (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;Ljava/lang/Object;)V + public fun transform (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;Lkotlin/Triple;)V } public final class app/revanced/patches/youtube/misc/fix/playback/SpoofSignaturePatch : app/revanced/patcher/patch/BytecodePatch { diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/ClientSpoofPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/ClientSpoofPatch.kt index 509778ef56..57572996a6 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/ClientSpoofPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/ClientSpoofPatch.kt @@ -1,51 +1,87 @@ package app.revanced.patches.youtube.misc.fix.playback -import app.revanced.util.exception -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.InstructionExtensions.addInstruction import app.revanced.patcher.extensions.InstructionExtensions.getInstruction -import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.Patch -import app.revanced.patches.youtube.misc.fix.playback.fingerprints.UserAgentHeaderBuilderFingerprint -import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction +import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod +import app.revanced.patches.all.misc.transformation.BaseTransformInstructionsPatch +import app.revanced.patches.all.misc.transformation.IMethodCall +import app.revanced.patches.all.misc.transformation.Instruction35cInfo +import app.revanced.patches.all.misc.transformation.filterMapInstruction35c +import app.revanced.util.getReference +import com.android.tools.smali.dexlib2.iface.ClassDef +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.OneRegisterInstruction +import com.android.tools.smali.dexlib2.iface.reference.MethodReference @Patch( name = "Client spoof", description = "Adds options to spoof the client to allow video playback.", dependencies = [SpoofSignaturePatch::class], compatiblePackages = [ - CompatiblePackage( - "com.google.android.youtube", [ - "18.48.39", - "18.49.37", - "19.01.34", - "19.02.39", - "19.03.36", - "19.04.38", - "19.05.36", - "19.06.39", - "19.07.40", - "19.08.36", - "19.09.37" - ] - ) - ] + CompatiblePackage("com.google.android.youtube"), + ], ) -object ClientSpoofPatch : BytecodePatch( - setOf(UserAgentHeaderBuilderFingerprint) -) { +object ClientSpoofPatch : BaseTransformInstructionsPatch() { private const val ORIGINAL_PACKAGE_NAME = "com.google.android.youtube" + private const val USER_AGENT_STRING_BUILDER_APPEND_METHOD_REFERENCE = + "Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;" - override fun execute(context: BytecodeContext) { - UserAgentHeaderBuilderFingerprint.result?.let { result -> - val insertIndex = result.scanResult.patternScanResult!!.endIndex - result.mutableMethod.apply { - val packageNameRegister = getInstruction(insertIndex).registerD + override fun filterMap( + classDef: ClassDef, + method: Method, + instruction: Instruction, + instructionIndex: Int, + ) = filterMapInstruction35c( + "Lapp/revanced/integrations", + classDef, + instruction, + instructionIndex, + ) - addInstruction(insertIndex, "const-string v$packageNameRegister, \"$ORIGINAL_PACKAGE_NAME\"") - } + override fun transform(mutableMethod: MutableMethod, entry: Instruction35cInfo) { + val (_, _, instructionIndex) = entry - } ?: throw UserAgentHeaderBuilderFingerprint.exception + // Replace the result of context.getPackageName(), if it is used in a user agent string. + mutableMethod.apply { + // After context.getPackageName() the result is moved to a register. + val targetRegister = ( + getInstruction(instructionIndex + 1) + as? OneRegisterInstruction ?: return + ).registerA + + // IndexOutOfBoundsException is not possible here, + // but no such occurrences are present in the app. + val referee = getInstruction(instructionIndex + 2).getReference()?.toString() + + // This can technically also match non-user agent string builder append methods, + // but no such occurrences are present in the app. + if (referee != USER_AGENT_STRING_BUILDER_APPEND_METHOD_REFERENCE) { + return + } + + // Overwrite the result of context.getPackageName() with the original package name. + replaceInstruction( + instructionIndex + 1, + "const-string v$targetRegister, \"${ORIGINAL_PACKAGE_NAME}\"", + ) + } + } + + @Suppress("unused") + private enum class MethodCall( + override val definedClassName: String, + override val methodName: String, + override val methodParams: Array, + override val returnType: String, + ) : IMethodCall { + GetPackageName( + "Landroid/content/Context;", + "getPackageName", + emptyArray(), + "Ljava/lang/String;", + ), } } diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/UserAgentHeaderBuilderFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/UserAgentHeaderBuilderFingerprint.kt deleted file mode 100644 index 0d593ab852..0000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/UserAgentHeaderBuilderFingerprint.kt +++ /dev/null @@ -1,10 +0,0 @@ -package app.revanced.patches.youtube.misc.fix.playback.fingerprints - -import app.revanced.patcher.fingerprint.MethodFingerprint -import com.android.tools.smali.dexlib2.Opcode - -internal object UserAgentHeaderBuilderFingerprint : MethodFingerprint( - parameters = listOf("L", "L", "L"), - opcodes = listOf(Opcode.MOVE_RESULT_OBJECT, Opcode.INVOKE_VIRTUAL), - strings = listOf("(Linux; U; Android "), -) \ No newline at end of file