diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/ConnectionResultFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/ConnectionResultFingerprint.kt new file mode 100644 index 00000000..e69de29b diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/OpenCronetDataSourceFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/OpenCronetDataSourceFingerprint.kt new file mode 100644 index 00000000..559ab0ea --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/OpenCronetDataSourceFingerprint.kt @@ -0,0 +1,17 @@ +package app.revanced.patches.youtube.misc.fix.playback.fingerprints + +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import org.jf.dexlib2.Opcode + +// Resolves to the method CronetDataSource.open +// https://androidx.tech/artifacts/media3/media3-datasource-cronet/1.0.0-alpha03-source/androidx/media3/datasource/cronet/CronetDataSource.java.html +object OpenCronetDataSourceFingerprint : MethodFingerprint( + opcodes = listOf( + Opcode.MOVE_RESULT, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + ), + strings = listOf( + "err_cleartext_not_permitted", + ), +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/patch/SpoofSignatureVerificationPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/patch/SpoofSignatureVerificationPatch.kt index 4de9200c..ef637078 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/patch/SpoofSignatureVerificationPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/patch/SpoofSignatureVerificationPatch.kt @@ -7,27 +7,50 @@ import app.revanced.patcher.annotation.Version import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.data.toMethodWalker import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.extensions.instruction 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.patcher.util.proxy.mutableTypes.MutableMethod +import app.revanced.patches.shared.settings.preference.impl.StringResource +import app.revanced.patches.shared.settings.preference.impl.SwitchPreference import app.revanced.patches.youtube.misc.fix.playback.annotation.ProtobufSpoofCompatibility +import app.revanced.patches.youtube.misc.fix.playback.fingerprints.OpenCronetDataSourceFingerprint import app.revanced.patches.youtube.misc.fix.playback.fingerprints.ProtobufParameterBuilderFingerprint +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 @Name("spoof-signature-verification") @Description("Spoofs the client to prevent playback issues.") @ProtobufSpoofCompatibility +@DependsOn([IntegrationsPatch::class, SettingsPatch::class]) @Version("0.0.1") class SpoofSignatureVerificationPatch : BytecodePatch( - listOf(ProtobufParameterBuilderFingerprint) + listOf( + ProtobufParameterBuilderFingerprint, + OpenCronetDataSourceFingerprint, + ) ) { override fun execute(context: BytecodeContext): PatchResult { + SettingsPatch.PreferenceScreen.MISC.addPreferences( + SwitchPreference( + "revanced_spoof_signature_verification", + StringResource("revanced_spoof_signature_verification_title", "Spoof app signature"), + false, + StringResource("revanced_spoof_signature_verification_summary_on", "App signature spoofed"), + StringResource("revanced_spoof_signature_verification_summary_off", "App signature not spoofed") + ) + ) + + // hook parameter ProtobufParameterBuilderFingerprint.result?.let { val setParamMethod = context .toMethodWalker(it.method) - .nextMethod(it.scanResult.patternScanResult!!.startIndex, true).getMethod() as MutableMethod + .nextMethod(it.scanResult.patternScanResult!!.startIndex, true).getMethod() as MutableMethod setParamMethod.apply { val protobufParameterRegister = 3 @@ -35,13 +58,30 @@ class SpoofSignatureVerificationPatch : BytecodePatch( addInstructions( 0, """ - invoke-static {p$protobufParameterRegister}, $INTEGRATIONS_CLASS_DESCRIPTOR->getVerificationSpoofOverride(Ljava/lang/String;)Ljava/lang/String; + invoke-static {p$protobufParameterRegister}, $INTEGRATIONS_CLASS_DESCRIPTOR->overrideProtobufParameter(Ljava/lang/String;)Ljava/lang/String; move-result-object p$protobufParameterRegister """ ) } } ?: return ProtobufParameterBuilderFingerprint.toErrorResult() + // hook video playback result + OpenCronetDataSourceFingerprint.result?.let { + it.mutableMethod.apply { + val getHeadersInstructionIndex = it.scanResult.patternScanResult!!.endIndex + val responseCodeRegister = + (instruction(getHeadersInstructionIndex - 2) as OneRegisterInstruction).registerA + + addInstructions( + getHeadersInstructionIndex + 1, + """ + invoke-static {v$responseCodeRegister}, $INTEGRATIONS_CLASS_DESCRIPTOR->onResponse(I)V + """ + ) + } + + } ?: return OpenCronetDataSourceFingerprint.toErrorResult() + return PatchResultSuccess() }