migrate batch

This commit is contained in:
oSumAtrIX
2026-01-09 20:00:49 +01:00
parent 69a71fbd3a
commit a103eb5b7a
26 changed files with 334 additions and 438 deletions

View File

@@ -11,7 +11,7 @@ import app.revanced.patches.shared.misc.gms.gmsCoreSupportResourcePatch
val gmsCoreSupportPatch = gmsCoreSupportPatch(
fromPackageName = MAGAZINES_PACKAGE_NAME,
toPackageName = REVANCED_MAGAZINES_PACKAGE_NAME,
mainActivityOnCreateFingerprint = magazinesActivityOnCreateFingerprint,
getMainActivityOnCreate = magazinesActivityOnCreateFingerprint,
extensionPatch = extensionPatch,
gmsCoreSupportResourcePatchFactory = ::gmsCoreSupportResourcePatch,
) {

View File

@@ -10,7 +10,7 @@ import app.revanced.patches.shared.misc.gms.gmsCoreSupportPatch
val gmsCoreSupportPatch = gmsCoreSupportPatch(
fromPackageName = PHOTOS_PACKAGE_NAME,
toPackageName = REVANCED_PHOTOS_PACKAGE_NAME,
mainActivityOnCreateFingerprint = homeActivityOnCreateFingerprint,
getMainActivityOnCreate = homeActivityOnCreateFingerprint,
extensionPatch = extensionPatch,
gmsCoreSupportResourcePatchFactory = ::gmsCoreSupportResourcePatch,
) {

View File

@@ -6,7 +6,7 @@ import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patches.music.misc.extension.sharedExtensionPatch
import app.revanced.patches.music.misc.gms.Constants.MUSIC_MAIN_ACTIVITY_NAME
import app.revanced.patches.music.misc.gms.Constants.MUSIC_PACKAGE_NAME
import app.revanced.patches.music.misc.gms.musicActivityOnCreateFingerprint
import app.revanced.patches.music.misc.gms.musicActivityOnCreateMethod
import app.revanced.patches.music.misc.settings.PreferenceScreen
import app.revanced.patches.shared.layout.branding.EXTENSION_CLASS_DESCRIPTOR
import app.revanced.patches.shared.layout.branding.baseCustomBrandingPatch
@@ -62,7 +62,7 @@ val customBrandingPatch = baseCustomBrandingPatch(
originalAppPackageName = MUSIC_PACKAGE_NAME,
isYouTubeMusic = true,
numberOfPresetAppNames = 5,
mainActivityOnCreateFingerprint = musicActivityOnCreateFingerprint,
getMainActivityOnCreate = { musicActivityOnCreateMethod },
mainActivityName = MUSIC_MAIN_ACTIVITY_NAME,
activityAliasNameWithIntents = MUSIC_MAIN_ACTIVITY_NAME,
preferenceScreen = PreferenceScreen.GENERAL,

View File

@@ -1,7 +1,7 @@
package app.revanced.patches.music.misc.dns
import app.revanced.patches.music.misc.extension.sharedExtensionPatch
import app.revanced.patches.music.shared.mainActivityOnCreateFingerprint
import app.revanced.patches.music.shared.mainActivityOnCreateMethod
import app.revanced.patches.shared.misc.dns.checkWatchHistoryDomainNameResolutionPatch
val checkWatchHistoryDomainNameResolutionPatch = checkWatchHistoryDomainNameResolutionPatch(
@@ -18,5 +18,5 @@ val checkWatchHistoryDomainNameResolutionPatch = checkWatchHistoryDomainNameReso
)
},
mainActivityFingerprint = mainActivityOnCreateFingerprint
mainActivityFingerprint = mainActivityOnCreateMethod
)

View File

@@ -1,11 +1,13 @@
package app.revanced.patches.music.misc.gms
import app.revanced.patcher.fingerprint
import app.revanced.patcher.*
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.patch.BytecodePatchContext
internal val musicActivityOnCreateFingerprint = fingerprint {
returns("V")
parameters("Landroid/os/Bundle;")
custom { method, classDef ->
method.name == "onCreate" && classDef.endsWith("/MusicActivity;")
}
}
internal val BytecodePatchContext.musicActivityOnCreateMethod by gettingFirstMutableMethodDeclaratively {
name("onCreate")
definingClass("/MusicActivity;"::endsWith)
returnType("V")
parameterTypes("Landroid/os/Bundle;")
}

View File

@@ -4,30 +4,26 @@ import app.revanced.patcher.patch.Option
import app.revanced.patches.all.misc.resources.addResources
import app.revanced.patches.all.misc.resources.addResourcesPatch
import app.revanced.patches.music.misc.extension.sharedExtensionPatch
import app.revanced.patches.music.misc.fileprovider.fileProviderPatch
import app.revanced.patches.music.misc.gms.Constants.MUSIC_PACKAGE_NAME
import app.revanced.patches.music.misc.gms.Constants.REVANCED_MUSIC_PACKAGE_NAME
import app.revanced.patches.music.misc.settings.PreferenceScreen
import app.revanced.patches.music.misc.settings.settingsPatch
import app.revanced.patches.music.misc.spoof.spoofVideoStreamsPatch
import app.revanced.patches.music.misc.fileprovider.fileProviderPatch
import app.revanced.patches.shared.castContextFetchFingerprint
import app.revanced.patches.shared.castContextFetchMethod
import app.revanced.patches.shared.misc.gms.gmsCoreSupportPatch
import app.revanced.patches.shared.misc.settings.preference.IntentPreference
import app.revanced.patches.shared.primeMethodFingerprint
import app.revanced.patches.shared.primeMethod
@Suppress("unused")
val gmsCoreSupportPatch = gmsCoreSupportPatch(
fromPackageName = MUSIC_PACKAGE_NAME,
toPackageName = REVANCED_MUSIC_PACKAGE_NAME,
primeMethodFingerprint = primeMethodFingerprint,
earlyReturnFingerprints = setOf(
castContextFetchFingerprint,
),
mainActivityOnCreateFingerprint = musicActivityOnCreateFingerprint,
getPrimeMethod = { primeMethod },
getEarlyReturnMethods = { setOf(castContextFetchMethod) },
getMainActivityOnCreateMethod = { musicActivityOnCreateMethod },
extensionPatch = sharedExtensionPatch,
gmsCoreSupportResourcePatchFactory = ::gmsCoreSupportResourcePatch,
) {
dependsOn(spoofVideoStreamsPatch)
compatibleWith(
MUSIC_PACKAGE_NAME(

View File

@@ -3,14 +3,10 @@ package app.revanced.patches.music.misc.spoof
import app.revanced.patches.all.misc.resources.addResources
import app.revanced.patches.all.misc.resources.addResourcesPatch
import app.revanced.patches.music.misc.extension.sharedExtensionPatch
import app.revanced.patches.music.misc.gms.musicActivityOnCreateFingerprint
import app.revanced.patches.music.misc.gms.musicActivityOnCreateMethod
import app.revanced.patches.music.misc.settings.PreferenceScreen
import app.revanced.patches.music.misc.settings.settingsPatch
import app.revanced.patches.music.playservice.is_7_16_or_greater
import app.revanced.patches.music.playservice.is_7_33_or_greater
import app.revanced.patches.music.playservice.is_8_11_or_greater
import app.revanced.patches.music.playservice.is_8_15_or_greater
import app.revanced.patches.music.playservice.versionCheckPatch
import app.revanced.patches.music.playservice.*
import app.revanced.patches.shared.misc.settings.preference.ListPreference
import app.revanced.patches.shared.misc.settings.preference.PreferenceScreenPreference
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
@@ -18,7 +14,7 @@ import app.revanced.patches.shared.misc.spoof.spoofVideoStreamsPatch
val spoofVideoStreamsPatch = spoofVideoStreamsPatch(
extensionClassDescriptor = "Lapp/revanced/extension/music/patches/spoof/SpoofVideoStreamsPatch;",
mainActivityOnCreateFingerprint = musicActivityOnCreateFingerprint,
getMainActivityOnCreateMethod = { musicActivityOnCreateMethod },
fixMediaFetchHotConfig = { is_7_16_or_greater },
fixMediaFetchHotConfigAlternative = { is_8_11_or_greater && !is_8_15_or_greater },
fixParsePlaybackResponseFeatureFlag = { is_7_33_or_greater },

View File

@@ -5,7 +5,7 @@ import app.revanced.patches.music.misc.settings.PreferenceScreen
import app.revanced.patches.music.misc.settings.settingsPatch
import app.revanced.patches.music.playservice.is_8_05_or_greater
import app.revanced.patches.music.playservice.versionCheckPatch
import app.revanced.patches.music.shared.mainActivityOnCreateFingerprint
import app.revanced.patches.music.shared.mainActivityOnCreateMethod
import app.revanced.patches.shared.misc.audio.forceOriginalAudioPatch
@Suppress("unused")
@@ -25,7 +25,7 @@ val forceOriginalAudioPatch = forceOriginalAudioPatch(
)
},
fixUseLocalizedAudioTrackFlag = { is_8_05_or_greater },
mainActivityOnCreateFingerprint = mainActivityOnCreateFingerprint,
getMainActivityOnCreateMethod = { mainActivityOnCreateMethod },
subclassExtensionClassDescriptor = "Lapp/revanced/extension/music/patches/ForceOriginalAudioPatch;",
preferenceScreen = PreferenceScreen.MISC,
)

View File

@@ -1,13 +1,18 @@
package app.revanced.patches.music.shared
import app.revanced.patcher.fingerprint
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.definingClass
import app.revanced.patcher.name
import app.revanced.patcher.parameterTypes
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.returnType
internal const val YOUTUBE_MUSIC_MAIN_ACTIVITY_CLASS_TYPE = "Lcom/google/android/apps/youtube/music/activities/MusicActivity;"
internal const val YOUTUBE_MUSIC_MAIN_ACTIVITY_CLASS_TYPE =
"Lcom/google/android/apps/youtube/music/activities/MusicActivity;"
internal val mainActivityOnCreateFingerprint = fingerprint {
returns("V")
parameters("Landroid/os/Bundle;")
custom { method, classDef ->
method.name == "onCreate" && classDef.type == YOUTUBE_MUSIC_MAIN_ACTIVITY_CLASS_TYPE
}
internal val BytecodePatchContext.mainActivityOnCreateMethod by gettingFirstMutableMethodDeclaratively {
name("onCreate")
definingClass(YOUTUBE_MUSIC_MAIN_ACTIVITY_CLASS_TYPE)
returnType("V")
parameterTypes("Landroid/os/Bundle;")
}

View File

@@ -2,6 +2,4 @@ package app.revanced.patches.reddit.customclients.baconreader.misc.extension.hoo
import app.revanced.patches.shared.misc.extension.activityOnCreateExtensionHook
internal val initHook = activityOnCreateExtensionHook(
"Lcom/onelouder/baconreader/BaconReader;"
)
internal val initHook = activityOnCreateExtensionHook("Lcom/onelouder/baconreader/BaconReader;")

View File

@@ -1,17 +1,13 @@
package app.revanced.patches.shared
import app.revanced.patcher.fingerprint
import app.revanced.patcher.addString
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.patch.BytecodePatchContext
internal val castContextFetchFingerprint = fingerprint {
instructions(
addString("Error fetching CastContext.")
)
}
internal val BytecodePatchContext.castContextFetchMethod by gettingFirstMutableMethodDeclaratively(
"Error fetching CastContext."
)
internal val primeMethodFingerprint = fingerprint {
instructions(
addString("com.android.vending"),
addString("com.google.android.GoogleCamera")
)
}
internal val BytecodePatchContext.primeMethod by gettingFirstMutableMethodDeclaratively(
"com.android.vending",
"com.google.android.GoogleCamera"
)

View File

@@ -1,36 +1,21 @@
package app.revanced.patches.shared.layout.branding
import app.revanced.patcher.Fingerprint
import app.revanced.patcher.extensions.addInstruction
import app.revanced.patcher.extensions.getInstruction
import app.revanced.patcher.patch.PatchException
import app.revanced.patcher.patch.ResourcePatch
import app.revanced.patcher.patch.ResourcePatchBuilder
import app.revanced.patcher.patch.ResourcePatchContext
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.patch.resourcePatch
import app.revanced.patcher.patch.stringOption
import app.revanced.patcher.patch.*
import app.revanced.patches.all.misc.packagename.setOrGetFallbackPackageName
import app.revanced.patches.all.misc.resources.addResources
import app.revanced.patches.all.misc.resources.addResourcesPatch
import app.revanced.patches.shared.misc.mapping.resourceMappingPatch
import app.revanced.patches.shared.misc.settings.preference.BasePreferenceScreen
import app.revanced.patches.shared.misc.settings.preference.ListPreference
import app.revanced.util.ResourceGroup
import app.revanced.util.*
import app.revanced.util.Utils.trimIndentMultiline
import app.revanced.util.addInstructionsAtControlFlowLabel
import app.revanced.util.copyResources
import app.revanced.util.findElementByAttributeValueOrThrow
import app.revanced.util.findInstructionIndicesReversedOrThrow
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.indexOfFirstInstructionReversedOrThrow
import app.revanced.util.removeFromParent
import app.revanced.util.returnEarly
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
import com.android.tools.smali.dexlib2.iface.reference.TypeReference
import com.android.tools.smali.dexlib2.mutable.MutableMethod
import org.w3c.dom.Element
import org.w3c.dom.NodeList
import java.io.File
@@ -81,13 +66,13 @@ internal fun baseCustomBrandingPatch(
originalAppPackageName: String,
isYouTubeMusic: Boolean,
numberOfPresetAppNames: Int,
mainActivityOnCreateFingerprint: Fingerprint,
getMainActivityOnCreate: BytecodePatchContext.() -> MutableMethod,
mainActivityName: String,
activityAliasNameWithIntents: String,
preferenceScreen: BasePreferenceScreen.Screen,
block: ResourcePatchBuilder.() -> Unit,
executeBlock: ResourcePatchContext.() -> Unit = {}
): ResourcePatch = resourcePatch(
) = resourcePatch(
name = "Custom branding",
description = "Adds options to change the app icon and app name. " +
"Branding cannot be changed for mounted (root) installations."
@@ -125,7 +110,7 @@ internal fun baseCustomBrandingPatch(
addBrandLicensePatch,
bytecodePatch {
apply {
mainActivityOnCreateFingerprint.method.addInstruction(
getMainActivityOnCreate().addInstruction(
0,
"invoke-static { }, $EXTENSION_CLASS_DESCRIPTOR->setBranding()V"
)

View File

@@ -1,24 +1,18 @@
package app.revanced.patches.shared.misc.audio
import app.revanced.patcher.fingerprint
import app.revanced.patcher.literal
import app.revanced.patcher.*
import com.android.tools.smali.dexlib2.AccessFlags
internal val formatStreamModelToStringFingerprint = fingerprint {
internal val formatStreamModelToStringMethodMatch = firstMethodComposite {
name("toString")
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("Ljava/lang/String;")
custom { method, _ ->
method.name == "toString"
}
strings(
// Strings are partial matches.
"isDefaultAudioTrack=",
"audioTrackId="
returnType("Ljava/lang/String;")
instructions(
"isDefaultAudioTrack="(String::contains),
"audioTrackId="(String::contains)
)
}
internal val selectAudioStreamFingerprint = fingerprint {
instructions(
literal(45666189L)
)
internal val selectAudioStreamMethodMatch = firstMethodComposite {
instructions(45666189L())
}

View File

@@ -1,6 +1,5 @@
package app.revanced.patches.shared.misc.audio
import app.revanced.patcher.Fingerprint
import app.revanced.patcher.extensions.addInstruction
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.addInstructionsWithLabels
@@ -8,8 +7,6 @@ import app.revanced.patcher.extensions.getInstruction
import app.revanced.patcher.patch.BytecodePatchBuilder
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.patch.bytecodePatch
import com.android.tools.smali.dexlib2.mutable.MutableField.Companion.toMutable
import com.android.tools.smali.dexlib2.mutable.MutableMethod.Companion.toMutable
import app.revanced.patches.all.misc.resources.addResources
import app.revanced.patches.all.misc.resources.addResourcesPatch
import app.revanced.patches.shared.misc.settings.preference.BasePreferenceScreen
@@ -24,6 +21,9 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.immutable.ImmutableField
import com.android.tools.smali.dexlib2.immutable.ImmutableMethod
import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter
import com.android.tools.smali.dexlib2.mutable.MutableField.Companion.toMutable
import com.android.tools.smali.dexlib2.mutable.MutableMethod
import com.android.tools.smali.dexlib2.mutable.MutableMethod.Companion.toMutable
private const val EXTENSION_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/shared/patches/ForceOriginalAudioPatch;"
@@ -35,7 +35,7 @@ internal fun forceOriginalAudioPatch(
block: BytecodePatchBuilder.() -> Unit = {},
executeBlock: BytecodePatchContext.() -> Unit = {},
fixUseLocalizedAudioTrackFlag: BytecodePatchContext.() -> Boolean,
mainActivityOnCreateFingerprint: Fingerprint,
getMainActivityOnCreateMethod: BytecodePatchContext.() -> MutableMethod,
subclassExtensionClassDescriptor: String,
preferenceScreen: BasePreferenceScreen.Screen
) = bytecodePatch(
@@ -57,7 +57,7 @@ internal fun forceOriginalAudioPatch(
)
)
mainActivityOnCreateFingerprint.method.addInstruction(
getMainActivityOnCreateMethod().addInstruction(
0,
"invoke-static { }, $subclassExtensionClassDescriptor->setEnabled()V"
)
@@ -65,90 +65,91 @@ internal fun forceOriginalAudioPatch(
// Disable feature flag that ignores the default track flag
// and instead overrides to the user region language.
if (fixUseLocalizedAudioTrackFlag()) {
selectAudioStreamFingerprint.method.insertLiteralOverride(
selectAudioStreamFingerprint.instructionMatches.first().index,
selectAudioStreamMethodMatch.method.insertLiteralOverride(
selectAudioStreamMethodMatch.indices.first(),
"$EXTENSION_CLASS_DESCRIPTOR->ignoreDefaultAudioStream(Z)Z"
)
}
formatStreamModelToStringFingerprint.let {
val isDefaultAudioTrackMethod = it.originalMethod.findMethodFromToString("isDefaultAudioTrack=")
val audioTrackDisplayNameMethod = it.originalMethod.findMethodFromToString("audioTrackDisplayName=")
val audioTrackIdMethod = it.originalMethod.findMethodFromToString("audioTrackId=")
val isDefaultAudioTrackMethod =
formatStreamModelToStringMethodMatch.immutableMethod.findMethodFromToString("isDefaultAudioTrack=")
val audioTrackDisplayNameMethod =
formatStreamModelToStringMethodMatch.immutableMethod.findMethodFromToString("audioTrackDisplayName=")
val audioTrackIdMethod =
formatStreamModelToStringMethodMatch.immutableMethod.findMethodFromToString("audioTrackId=")
it.classDef.apply {
// Add a new field to store the override.
val helperFieldName = "patch_isDefaultAudioTrackOverride"
fields.add(
ImmutableField(
type,
helperFieldName,
"Ljava/lang/Boolean;",
// Boolean is a 100% immutable class (all fields are final)
// and safe to write to a shared field without volatile/synchronization,
// but without volatile the field can show stale data
// and the same field is calculated more than once by different threads.
AccessFlags.PRIVATE.value or AccessFlags.VOLATILE.value,
null,
null,
null
).toMutable()
formatStreamModelToStringMethodMatch.classDef.apply {
// Add a new field to store the override.
val helperFieldName = "patch_isDefaultAudioTrackOverride"
fields.add(
ImmutableField(
type,
helperFieldName,
"Ljava/lang/Boolean;",
// Boolean is a 100% immutable class (all fields are final)
// and safe to write to a shared field without volatile/synchronization,
// but without volatile the field can show stale data
// and the same field is calculated more than once by different threads.
AccessFlags.PRIVATE.value or AccessFlags.VOLATILE.value,
null,
null,
null
).toMutable()
)
// Add a helper method because the isDefaultAudioTrack() has only 2 registers and 3 are needed.
val helperMethodClass = type
val helperMethodName = "patch_isDefaultAudioTrack"
val helperMethod = ImmutableMethod(
helperMethodClass,
helperMethodName,
listOf(ImmutableMethodParameter("Z", null, null)),
"Z",
AccessFlags.PRIVATE.value,
null,
null,
MutableMethodImplementation(6),
).toMutable().apply {
addInstructionsWithLabels(
0,
"""
iget-object v0, p0, $helperMethodClass->$helperFieldName:Ljava/lang/Boolean;
if-eqz v0, :call_extension
invoke-virtual { v0 }, Ljava/lang/Boolean;->booleanValue()Z
move-result v3
return v3
:call_extension
invoke-virtual { p0 }, $audioTrackIdMethod
move-result-object v1
invoke-virtual { p0 }, $audioTrackDisplayNameMethod
move-result-object v2
invoke-static { p1, v1, v2 }, $EXTENSION_CLASS_DESCRIPTOR->isDefaultAudioStream(ZLjava/lang/String;Ljava/lang/String;)Z
move-result v3
invoke-static { v3 }, Ljava/lang/Boolean;->valueOf(Z)Ljava/lang/Boolean;
move-result-object v0
iput-object v0, p0, $helperMethodClass->$helperFieldName:Ljava/lang/Boolean;
return v3
"""
)
}
methods.add(helperMethod)
// Add a helper method because the isDefaultAudioTrack() has only 2 registers and 3 are needed.
val helperMethodClass = type
val helperMethodName = "patch_isDefaultAudioTrack"
val helperMethod = ImmutableMethod(
helperMethodClass,
helperMethodName,
listOf(ImmutableMethodParameter("Z", null, null)),
"Z",
AccessFlags.PRIVATE.value,
null,
null,
MutableMethodImplementation(6),
).toMutable().apply {
addInstructionsWithLabels(
0,
"""
iget-object v0, p0, $helperMethodClass->$helperFieldName:Ljava/lang/Boolean;
if-eqz v0, :call_extension
invoke-virtual { v0 }, Ljava/lang/Boolean;->booleanValue()Z
move-result v3
return v3
:call_extension
invoke-virtual { p0 }, $audioTrackIdMethod
move-result-object v1
invoke-virtual { p0 }, $audioTrackDisplayNameMethod
move-result-object v2
invoke-static { p1, v1, v2 }, $EXTENSION_CLASS_DESCRIPTOR->isDefaultAudioStream(ZLjava/lang/String;Ljava/lang/String;)Z
move-result v3
invoke-static { v3 }, Ljava/lang/Boolean;->valueOf(Z)Ljava/lang/Boolean;
move-result-object v0
iput-object v0, p0, $helperMethodClass->$helperFieldName:Ljava/lang/Boolean;
return v3
"""
)
}
methods.add(helperMethod)
// Modify isDefaultAudioTrack() to call extension helper method.
isDefaultAudioTrackMethod.apply {
val index = indexOfFirstInstructionOrThrow(Opcode.RETURN)
val register = getInstruction<OneRegisterInstruction>(index).registerA
// Modify isDefaultAudioTrack() to call extension helper method.
isDefaultAudioTrackMethod.apply {
val index = indexOfFirstInstructionOrThrow(Opcode.RETURN)
val register = getInstruction<OneRegisterInstruction>(index).registerA
addInstructions(
index,
"""
addInstructions(
index,
"""
invoke-direct { p0, v$register }, $helperMethodClass->$helperMethodName(Z)Z
move-result v$register
"""
)
}
)
}
}

View File

@@ -20,9 +20,9 @@ internal const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/shared/
*/
fun sharedExtensionPatch(
extensionName: String,
vararg hooks: () -> ExtensionHook,
vararg hooks: ExtensionHook,
) = bytecodePatch {
dependsOn(sharedExtensionPatch(*hooks))
dependsOn(sharedExtensionPatch(hooks = hooks))
extendWith("extensions/$extensionName.rve")
}
@@ -34,7 +34,7 @@ fun sharedExtensionPatch(
* commonly for the onCreate method of exported activities.
*/
fun sharedExtensionPatch(
vararg hooks: () -> ExtensionHook,
vararg hooks: ExtensionHook,
) = bytecodePatch {
extendWith("extensions/shared.rve")
@@ -45,7 +45,7 @@ fun sharedExtensionPatch(
afterDependents {
// The hooks are made in afterDependents to ensure that the context is hooked before any other patches.
hooks.forEach { hook -> hook()(EXTENSION_CLASS_DESCRIPTOR) }
hooks.forEach { hook -> hook(EXTENSION_CLASS_DESCRIPTOR) }
// Modify Utils method to include the patches release version.
/**
@@ -87,9 +87,9 @@ class ExtensionHook internal constructor(
private val getContextRegister: Method.() -> String,
private val predicate: DeclarativePredicate<Method>,
) {
context(context: BytecodePatchContext)
context(_: BytecodePatchContext)
operator fun invoke(extensionClassDescriptor: String) {
val method = context.firstMutableMethodDeclaratively(predicate = predicate)
val method = firstMutableMethodDeclaratively(predicate = predicate)
val insertIndex = method.getInsertIndex()
val contextRegister = method.getContextRegister()

View File

@@ -1,6 +1,5 @@
package app.revanced.patches.shared.misc.gms
import app.revanced.patcher.Fingerprint
import app.revanced.patcher.extensions.addInstruction
import app.revanced.patcher.extensions.instructions
import app.revanced.patcher.extensions.replaceInstruction
@@ -20,6 +19,7 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction21c
import com.android.tools.smali.dexlib2.iface.reference.StringReference
import com.android.tools.smali.dexlib2.immutable.reference.ImmutableStringReference
import com.android.tools.smali.dexlib2.mutable.MutableMethod
import com.android.tools.smali.dexlib2.util.MethodUtil
import org.w3c.dom.Element
import org.w3c.dom.Node
@@ -34,9 +34,9 @@ private const val PACKAGE_NAME_REGEX_PATTERN = "^[a-z]\\w*(\\.[a-z]\\w*)+\$"
*
* @param fromPackageName The package name of the original app.
* @param toPackageName The package name to fall back to if no custom package name is specified in patch options.
* @param primeMethodFingerprint The fingerprint of the "prime" method that needs to be patched.
* @param earlyReturnFingerprints The fingerprints of methods that need to be returned early.
* @param mainActivityOnCreateFingerprint The fingerprint of the main activity onCreate method.
* @param getPrimeMethod The "prime" method that needs to be patched.
* @param getEarlyReturnMethods The methods that need to be returned early.
* @param getMainActivityOnCreateMethod The main activity onCreate method.
* @param extensionPatch The patch responsible for the extension.
* @param gmsCoreSupportResourcePatchFactory The factory for the corresponding resource patch
* that is used to patch the resources.
@@ -46,9 +46,9 @@ private const val PACKAGE_NAME_REGEX_PATTERN = "^[a-z]\\w*(\\.[a-z]\\w*)+\$"
fun gmsCoreSupportPatch(
fromPackageName: String,
toPackageName: String,
primeMethodFingerprint: Fingerprint? = null,
earlyReturnFingerprints: Set<Fingerprint> = setOf(),
mainActivityOnCreateFingerprint: Fingerprint,
getPrimeMethod: (BytecodePatchContext.() -> MutableMethod)? = null,
getEarlyReturnMethods: BytecodePatchContext.() -> Set<MutableMethod> = { setOf() },
getMainActivityOnCreateMethod: BytecodePatchContext.() -> MutableMethod,
extensionPatch: Patch,
gmsCoreSupportResourcePatchFactory: (gmsCoreVendorGroupIdOption: Option<String>) -> Patch,
executeBlock: BytecodePatchContext.() -> Unit = {},
@@ -165,18 +165,18 @@ fun gmsCoreSupportPatch(
}
fun transformPrimeMethod(packageName: String) {
primeMethodFingerprint!!.method.apply {
var register = 2
val primeMethod = getPrimeMethod!!()
val index = instructions.indexOfFirst {
if (it.getReference<StringReference>()?.string != fromPackageName) return@indexOfFirst false
var register = 2
register = (it as OneRegisterInstruction).registerA
return@indexOfFirst true
}
val index = primeMethod.instructions.indexOfFirst {
if (it.getReference<StringReference>()?.string != fromPackageName) return@indexOfFirst false
replaceInstruction(index, "const-string v$register, \"$packageName\"")
register = (it as OneRegisterInstruction).registerA
return@indexOfFirst true
}
primeMethod.replaceInstruction(index, "const-string v$register, \"$packageName\"")
}
// endregion
@@ -198,18 +198,10 @@ fun gmsCoreSupportPatch(
}
// Specific method that needs to be patched.
primeMethodFingerprint?.let { transformPrimeMethod(packageName) }
getPrimeMethod?.let { transformPrimeMethod(packageName) }
// Return these methods early to prevent the app from crashing.
earlyReturnFingerprints.forEach {
it.method.apply {
if (returnType == "Z") {
returnEarly(false)
} else {
returnEarly()
}
}
}
getEarlyReturnMethods().forEach { it.returnEarly() }
serviceCheckFingerprint.method.returnEarly()
// Google Play Utility is not present in all apps, so we need to check if it's present.
@@ -221,7 +213,7 @@ fun gmsCoreSupportPatch(
originalPackageNameExtensionFingerprint.method.returnEarly(fromPackageName)
// Verify GmsCore is installed and whitelisted for power optimizations and background usage.
mainActivityOnCreateFingerprint.method.addInstruction(
getMainActivityOnCreateMethod().addInstruction(
0,
"invoke-static/range { p0 .. p0 }, $EXTENSION_CLASS_DESCRIPTOR->" +
"checkGmsCore(Landroid/app/Activity;)V"

View File

@@ -1,69 +1,39 @@
package app.revanced.patches.shared.misc.privacy
import app.revanced.patcher.InstructionLocation.MatchAfterImmediately
import app.revanced.patcher.InstructionLocation.MatchAfterWithin
import app.revanced.patcher.checkCast
import app.revanced.patcher.fieldAccess
import app.revanced.patcher.fingerprint
import app.revanced.patcher.methodCall
import app.revanced.patcher.opcode
import app.revanced.patcher.addString
import app.revanced.patcher.*
import com.android.tools.smali.dexlib2.Opcode
internal val youTubeCopyTextFingerprint = fingerprint {
returns("V")
parameters("L", "Ljava/util/Map;")
internal val youTubeCopyTextFingerprintMethodMatch = firstMethodComposite {
returnType("V")
parameterTypes("L", "Ljava/util/Map;")
instructions(
opcode(Opcode.IGET_OBJECT),
addString("text/plain", location = MatchAfterWithin(2)),
methodCall(
smali = "Landroid/content/ClipData;->newPlainText(Ljava/lang/CharSequence;Ljava/lang/CharSequence;)Landroid/content/ClipData;",
location = MatchAfterWithin(2)
),
opcode(Opcode.MOVE_RESULT_OBJECT, location = MatchAfterWithin(2)),
methodCall(
smali = "Landroid/content/ClipboardManager;->setPrimaryClip(Landroid/content/ClipData;)V",
location = MatchAfterWithin(2)
)
Opcode.IGET_OBJECT(),
after(0..2, "text/plain"()),
after(0..2, method("newPlainText")),
after(0..2, Opcode.MOVE_RESULT_OBJECT()),
after(0..2, method("setPrimaryClip"))
)
}
internal val youTubeSystemShareSheetFingerprint = fingerprint {
returns("V")
parameters("L", "Ljava/util/Map;")
internal val youTubeSystemShareSheetMethodMatch = firstMethodComposite {
returnType("V")
parameterTypes("L", "Ljava/util/Map;")
instructions(
methodCall(
smali = "Landroid/content/Intent;->setClassName(Ljava/lang/String;Ljava/lang/String;)Landroid/content/Intent;"
),
methodCall(
smali = "Ljava/util/List;->iterator()Ljava/util/Iterator;",
location = MatchAfterWithin(4)
),
fieldAccess(
opcode = Opcode.IGET_OBJECT,
type = "Ljava/lang/String;",
location = MatchAfterWithin(15)
),
methodCall(
smali = "Landroid/content/Intent;->putExtra(Ljava/lang/String;Ljava/lang/String;)Landroid/content/Intent;",
location = MatchAfterWithin(15)
)
method("setClassName"),
after(0..4, method("iterator")),
after(0..15, allOf(Opcode.IGET_OBJECT(), type("Ljava/lang/String;"))),
after(0..15, method("putExtra"))
)
}
internal val youTubeShareSheetFingerprint = fingerprint {
returns("V")
parameters("L", "Ljava/util/Map;")
internal val youTubeShareSheetMethodMatch = firstMethodComposite {
returnType("V")
parameterTypes("L", "Ljava/util/Map;")
instructions(
opcode(Opcode.IGET_OBJECT),
checkCast("Ljava/lang/String;", location = MatchAfterImmediately()),
opcode(Opcode.GOTO, location = MatchAfterImmediately()),
methodCall(smali = "Landroid/content/Intent;->putExtra(Ljava/lang/String;Ljava/lang/String;)Landroid/content/Intent;"),
addString("YTShare_Logging_Share_Intent_Endpoint_Byte_Array")
Opcode.IGET_OBJECT(),
after(allOf(Opcode.CHECK_CAST(), type("Ljava/lang/String;"))),
after(Opcode.GOTO()),
method("putExtra"),
"YTShare_Logging_Share_Intent_Endpoint_Byte_Array"()
)
}

View File

@@ -1,6 +1,6 @@
package app.revanced.patches.shared.misc.privacy
import app.revanced.patcher.Fingerprint
import app.revanced.patcher.MatchBuilder
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.getInstruction
import app.revanced.patcher.patch.BytecodePatchBuilder
@@ -60,8 +60,8 @@ internal fun sanitizeSharingLinksPatch(
}
)
fun Fingerprint.hookUrlString(matchIndex: Int) {
val index = instructionMatches[matchIndex].index
fun MatchBuilder.hookUrlString(matchIndex: Int) {
val index = indices[matchIndex]
val urlRegister = method.getInstruction<OneRegisterInstruction>(index).registerA
method.addInstructions(
@@ -73,8 +73,8 @@ internal fun sanitizeSharingLinksPatch(
)
}
fun Fingerprint.hookIntentPutExtra(matchIndex: Int) {
val index = instructionMatches[matchIndex].index
fun MatchBuilder.hookIntentPutExtra(matchIndex: Int) {
val index = indices[matchIndex]
val urlRegister = method.getInstruction<FiveRegisterInstruction>(index).registerE
method.addInstructionsAtControlFlowLabel(
@@ -87,12 +87,12 @@ internal fun sanitizeSharingLinksPatch(
}
// YouTube share sheet copy link.
youTubeCopyTextFingerprint.hookUrlString(0)
youTubeCopyTextFingerprintMethodMatch.hookUrlString(0)
// YouTube share sheet other apps.
youTubeShareSheetFingerprint.hookIntentPutExtra(3)
youTubeShareSheetMethodMatch.hookIntentPutExtra(3)
// Native system share sheet.
youTubeSystemShareSheetFingerprint.hookIntentPutExtra(3)
youTubeSystemShareSheetMethodMatch.hookIntentPutExtra(3)
}
}

View File

@@ -1,51 +1,48 @@
package app.revanced.patches.shared.misc.spoof
import app.revanced.patcher.accessFlags
import app.revanced.patcher.fingerprint
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstruction
import app.revanced.patcher.literal
import app.revanced.patcher.methodCall
import app.revanced.patcher.addString
import app.revanced.patcher.custom
import app.revanced.patcher.extensions.methodReference
import app.revanced.patcher.firstMethodComposite
import app.revanced.patcher.immutableClassDef
import app.revanced.patcher.instructions
import app.revanced.patcher.invoke
import app.revanced.patcher.method
import app.revanced.patcher.parameterTypes
import app.revanced.patcher.returnType
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 val buildInitPlaybackRequestFingerprint = fingerprint {
returns("Lorg/chromium/net/UrlRequest\$Builder;")
opcodes(
Opcode.MOVE_RESULT_OBJECT,
Opcode.IGET_OBJECT, // Moves the request URI string to a register to build the request with.
)
strings(
"Content-Type",
"Range",
)
}
internal val buildPlayerRequestURIFingerprint = fingerprint {
returns("Ljava/lang/String;")
opcodes(
Opcode.INVOKE_VIRTUAL, // Register holds player request URI.
Opcode.MOVE_RESULT_OBJECT,
Opcode.IPUT_OBJECT,
Opcode.IGET_OBJECT,
Opcode.MONITOR_EXIT,
Opcode.RETURN_OBJECT,
)
strings(
"key",
"asig",
)
}
internal val buildRequestFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC)
returns("Lorg/chromium/net/UrlRequest") // UrlRequest; or UrlRequest$Builder;
internal val buildInitPlaybackRequestMatch = firstMethodComposite("Content-Type", "Range") {
returnType("Lorg/chromium/net/UrlRequest\$Builder;")
instructions(
methodCall(name = "newUrlRequestBuilder")
Opcode.MOVE_RESULT_OBJECT(),
Opcode.IGET_OBJECT(), // Moves the request URI string to a register to build the request with.
)
}
internal val buildPlayerRequestURIMethodMatch = firstMethodComposite("key", "asig") {
returnType("Ljava/lang/String;")
instructions(
Opcode.INVOKE_VIRTUAL(), // Register holds player request URI.
Opcode.MOVE_RESULT_OBJECT(),
Opcode.IPUT_OBJECT(),
Opcode.IGET_OBJECT(),
Opcode.MONITOR_EXIT(),
Opcode.RETURN_OBJECT(),
)
}
internal val buildRequestMethodMatch = firstMethodComposite() {
accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC)
returnType("Lorg/chromium/net/UrlRequest") // UrlRequest; or UrlRequest$Builder;
instructions(
method("newUrlRequestBuilder"),
) // UrlRequest; or UrlRequest$Builder;
custom { methodDef, _ ->
custom {
// Different targets have slightly different parameters
// Earlier targets have parameters:
@@ -75,11 +72,11 @@ internal val buildRequestFingerprint = fingerprint {
// Lorg/chromium/net/UrlRequest$Callback;
// L
val parameterTypes = methodDef.parameterTypes
val parameterTypes = parameterTypes
val parameterTypesSize = parameterTypes.size
(parameterTypesSize == 6 || parameterTypesSize == 7 || parameterTypesSize == 8) &&
parameterTypes[1] == "Ljava/util/Map;" // URL headers.
&& indexOfNewUrlRequestBuilderInstruction(methodDef) >= 0
&& indexOfNewUrlRequestBuilderInstruction(this) >= 0
}
}
@@ -96,19 +93,19 @@ internal val protobufClassParseByteBufferFingerprint = fingerprint {
custom { method, _ -> method.name == "parseFrom" }
}
internal val createStreamingDataFingerprint = fingerprint {
internal val createStreamingDataMethodMatch = firstMethodComposite {
accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR)
parameters("L")
opcodes(
Opcode.IPUT_OBJECT,
Opcode.IGET_OBJECT,
Opcode.IF_NEZ,
Opcode.SGET_OBJECT,
Opcode.IPUT_OBJECT,
parameterTypes("L")
instructions(
Opcode.IPUT_OBJECT(),
Opcode.IGET_OBJECT(),
Opcode.IF_NEZ(),
Opcode.SGET_OBJECT(),
Opcode.IPUT_OBJECT(),
)
custom { method, classDef ->
classDef.fields.any { field ->
field.name == "a" && field.type.endsWith("/StreamingDataOuterClass\$StreamingData;")
custom {
immutableClassDef.fields.any { field ->
field.name == "a" && field.type.endsWith($$"/StreamingDataOuterClass$StreamingData;")
}
}
}
@@ -129,22 +126,22 @@ internal val buildMediaDataSourceFingerprint = fingerprint {
)
}
internal val hlsCurrentTimeFingerprint = fingerprint {
internal val hlsCurrentTimeMethodMatch = firstMethodComposite {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
parameters("Z", "L")
parameterTypes("Z", "L")
instructions(
literal(45355374L) // HLS current time feature flag.
45355374L() // HLS current time feature flag.
)
}
internal const val DISABLED_BY_SABR_STREAMING_URI_STRING = "DISABLED_BY_SABR_STREAMING_URI"
internal val mediaFetchEnumConstructorFingerprint = fingerprint {
returns("V")
strings(
"ENABLED",
"DISABLED_FOR_PLAYBACK",
DISABLED_BY_SABR_STREAMING_URI_STRING
internal val mediaFetchEnumConstructorMethodMatch = firstMethodComposite {
returnType("V")
instructions(
"ENABLED"(),
"DISABLED_FOR_PLAYBACK"(),
DISABLED_BY_SABR_STREAMING_URI_STRING()
)
}
@@ -169,35 +166,30 @@ internal val patchIncludedExtensionMethodFingerprint = fingerprint {
// This code appears to replace the player config after the streams are loaded.
// Flag is present in YouTube 19.34, but is missing Platypus stream replacement code until 19.43.
// Flag and Platypus code is also present in newer versions of YouTube Music.
internal val mediaFetchHotConfigFingerprint = fingerprint {
instructions(
literal(45645570L)
)
internal val mediaFetchHotConfigMethodMatch = firstMethodComposite {
instructions(45645570L())
}
// YT 20.10+, YT Music 8.11 - 8.14.
// Flag is missing in YT Music 8.15+, and it is not known if a replacement flag/feature exists.
internal val mediaFetchHotConfigAlternativeFingerprint = fingerprint {
instructions(
literal(45683169L)
)
internal val mediaFetchHotConfigAlternativeMethodMatch = firstMethodComposite {
instructions(45683169L())
}
// Feature flag that enables different code for parsing and starting video playback,
// but it's exact purpose is not known. If this flag is enabled while stream spoofing
// but its exact purpose is not known. If this flag is enabled while stream spoofing
// then videos will never start playback and load forever.
// Flag does not seem to affect playback if spoofing is off.
internal val playbackStartDescriptorFeatureFlagFingerprint = fingerprint {
parameters()
returns("Z")
instructions(
literal(45665455L)
)
internal val playbackStartDescriptorFeatureFlagMethodMatch = firstMethodComposite() {
parameterTypes()
returnType("Z")
instructions(45665455L())
}
internal fun indexOfNewUrlRequestBuilderInstruction(method: Method) = method.indexOfFirstInstruction {
val reference = getReference<MethodReference>()
opcode == Opcode.INVOKE_VIRTUAL && reference?.definingClass == "Lorg/chromium/net/CronetEngine;"
val reference = methodReference ?: return@indexOfFirstInstruction false
opcode == Opcode.INVOKE_VIRTUAL && reference.definingClass == "Lorg/chromium/net/CronetEngine;"
&& reference.name == "newUrlRequestBuilder"
&& reference.parameterTypes.size == 3
&& reference.parameterTypes[0] == "Ljava/lang/String;"

View File

@@ -1,25 +1,13 @@
package app.revanced.patches.shared.misc.spoof
import app.revanced.patcher.Fingerprint
import app.revanced.patcher.extensions.addInstruction
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.addInstructionsWithLabels
import app.revanced.patcher.extensions.getInstruction
import app.revanced.patcher.extensions.instructions
import app.revanced.patcher.extensions.*
import app.revanced.patcher.fingerprint
import app.revanced.patcher.patch.BytecodePatchBuilder
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.patch.bytecodePatch
import com.android.tools.smali.dexlib2.mutable.MutableMethod
import com.android.tools.smali.dexlib2.mutable.MutableMethod.Companion.toMutable
import app.revanced.patches.all.misc.resources.addResources
import app.revanced.patches.all.misc.resources.addResourcesPatch
import app.revanced.util.findFreeRegister
import app.revanced.util.findInstructionIndicesReversedOrThrow
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.insertLiteralOverride
import app.revanced.util.returnEarly
import app.revanced.util.*
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.builder.MutableMethodImplementation
@@ -30,6 +18,8 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
import com.android.tools.smali.dexlib2.immutable.ImmutableMethod
import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter
import com.android.tools.smali.dexlib2.mutable.MutableMethod
import com.android.tools.smali.dexlib2.mutable.MutableMethod.Companion.toMutable
internal const val EXTENSION_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/shared/spoof/SpoofVideoStreamsPatch;"
@@ -39,7 +29,7 @@ private var buildRequestMethodUrlRegister = -1
internal fun spoofVideoStreamsPatch(
extensionClassDescriptor: String,
mainActivityOnCreateFingerprint: Fingerprint,
getMainActivityOnCreateMethod: BytecodePatchContext.() -> MutableMethod,
fixMediaFetchHotConfig: BytecodePatchBuilder.() -> Boolean = { false },
fixMediaFetchHotConfigAlternative: BytecodePatchBuilder.() -> Boolean = { false },
fixParsePlaybackResponseFeatureFlag: BytecodePatchBuilder.() -> Boolean = { false },
@@ -56,7 +46,7 @@ internal fun spoofVideoStreamsPatch(
apply {
addResources("shared", "misc.fix.playback.spoofVideoStreamsPatch")
mainActivityOnCreateFingerprint.method.addInstruction(
getMainActivityOnCreateMethod().addInstruction(
0,
"invoke-static { }, $extensionClassDescriptor->setClientOrderToUse()V"
)
@@ -72,48 +62,44 @@ internal fun spoofVideoStreamsPatch(
// region Block /initplayback requests to fall back to /get_watch requests.
buildInitPlaybackRequestFingerprint.let {
it.method.apply {
val moveUriStringIndex = it.instructionMatches.first().index
val targetRegister = getInstruction<OneRegisterInstruction>(moveUriStringIndex).registerA
buildInitPlaybackRequestMatch.method.apply {
val moveUriStringIndex = buildInitPlaybackRequestMatch.indices.first()
val targetRegister = getInstruction<OneRegisterInstruction>(moveUriStringIndex).registerA
addInstructions(
moveUriStringIndex + 1,
"""
invoke-static { v$targetRegister }, $EXTENSION_CLASS_DESCRIPTOR->blockInitPlaybackRequest(Ljava/lang/String;)Ljava/lang/String;
move-result-object v$targetRegister
"""
)
}
addInstructions(
moveUriStringIndex + 1,
"""
invoke-static { v$targetRegister }, $EXTENSION_CLASS_DESCRIPTOR->blockInitPlaybackRequest(Ljava/lang/String;)Ljava/lang/String;
move-result-object v$targetRegister
"""
)
}
// endregion
// region Block /get_watch requests to fall back to /player requests.
buildPlayerRequestURIFingerprint.let {
it.method.apply {
val invokeToStringIndex = it.instructionMatches.first().index
val uriRegister = getInstruction<FiveRegisterInstruction>(invokeToStringIndex).registerC
buildPlayerRequestURIMethodMatch.method.apply {
val invokeToStringIndex = buildPlayerRequestURIMethodMatch.indices.first()
val uriRegister = getInstruction<FiveRegisterInstruction>(invokeToStringIndex).registerC
addInstructions(
invokeToStringIndex,
"""
invoke-static { v$uriRegister }, $EXTENSION_CLASS_DESCRIPTOR->blockGetWatchRequest(Landroid/net/Uri;)Landroid/net/Uri;
move-result-object v$uriRegister
"""
)
}
addInstructions(
invokeToStringIndex,
"""
invoke-static { v$uriRegister }, $EXTENSION_CLASS_DESCRIPTOR->blockGetWatchRequest(Landroid/net/Uri;)Landroid/net/Uri;
move-result-object v$uriRegister
"""
)
}
// endregion
// region Get replacement streams at player requests.
buildRequestFingerprint.method.apply {
buildRequestMethodMatch.method.apply {
buildRequestMethod = this
val newRequestBuilderIndex = buildRequestFingerprint.instructionMatches.first().index
val newRequestBuilderIndex = buildRequestMethodMatch.indices.first()
buildRequestMethodUrlRegister = getInstruction<FiveRegisterInstruction>(newRequestBuilderIndex).registerD
val freeRegister = findFreeRegister(newRequestBuilderIndex, buildRequestMethodUrlRegister)
@@ -130,21 +116,21 @@ internal fun spoofVideoStreamsPatch(
// region Replace the streaming data with the replacement streams.
createStreamingDataFingerprint.method.apply {
createStreamingDataMethodMatch.method.apply {
val setStreamDataMethodName = "patch_setStreamingData"
val resultMethodType = createStreamingDataFingerprint.classDef.type
val videoDetailsIndex = createStreamingDataFingerprint.instructionMatches.last().index
val resultMethodType = createStreamingDataMethodMatch.classDef.type
val videoDetailsIndex = createStreamingDataMethodMatch.indices.last()
val videoDetailsRegister = getInstruction<TwoRegisterInstruction>(videoDetailsIndex).registerA
val videoDetailsClass = getInstruction(videoDetailsIndex).getReference<FieldReference>()!!.type
addInstruction(
videoDetailsIndex + 1,
"invoke-direct { p0, v$videoDetailsRegister }, " +
"$resultMethodType->$setStreamDataMethodName($videoDetailsClass)V",
"$resultMethodType->$setStreamDataMethodName($videoDetailsClass)V",
)
val protobufClass = protobufClassParseByteBufferFingerprint.method.definingClass
val setStreamingDataIndex = createStreamingDataFingerprint.instructionMatches.first().index
val setStreamingDataIndex = createStreamingDataMethodMatch.indices.first()
val playerProtoClass = getInstruction(setStreamingDataIndex + 1)
.getReference<FieldReference>()!!.definingClass
@@ -158,7 +144,7 @@ internal fun spoofVideoStreamsPatch(
).getReference<FieldReference>()
// Use a helper method to avoid the need of picking out multiple free registers from the hooked code.
createStreamingDataFingerprint.classDef.methods.add(
createStreamingDataMethodMatch.classDef.methods.add(
ImmutableMethod(
resultMethodType,
setStreamDataMethodName,
@@ -270,25 +256,21 @@ internal fun spoofVideoStreamsPatch(
// region Fix iOS livestream current time.
hlsCurrentTimeFingerprint.let {
it.method.insertLiteralOverride(
it.instructionMatches.first().index,
"$EXTENSION_CLASS_DESCRIPTOR->fixHLSCurrentTime(Z)Z"
)
}
hlsCurrentTimeMethodMatch.method.insertLiteralOverride(
hlsCurrentTimeMethodMatch.indices.first(),
"$EXTENSION_CLASS_DESCRIPTOR->fixHLSCurrentTime(Z)Z"
)
// endregion
// region Disable SABR playback.
// If SABR is disabled, it seems 'MediaFetchHotConfig' may no longer need an override (not confirmed).
val (mediaFetchEnumClass, sabrFieldReference) = with(mediaFetchEnumConstructorFingerprint.method) {
val stringIndex = mediaFetchEnumConstructorFingerprint.stringMatches.first {
it.string == DISABLED_BY_SABR_STREAMING_URI_STRING
}.index
val (mediaFetchEnumClass, sabrFieldReference) = with(mediaFetchEnumConstructorMethodMatch.method) {
val disabledBySABRStreamingUrlString = mediaFetchEnumConstructorMethodMatch.indices.last()
val mediaFetchEnumClass = definingClass
val sabrFieldIndex = indexOfFirstInstructionOrThrow(stringIndex) {
val sabrFieldIndex = indexOfFirstInstructionOrThrow(disabledBySABRStreamingUrlString) {
opcode == Opcode.SPUT_OBJECT &&
getReference<FieldReference>()?.type == mediaFetchEnumClass
}
@@ -327,30 +309,24 @@ internal fun spoofVideoStreamsPatch(
// region turn off stream config replacement feature flag.
if (fixMediaFetchHotConfig()) {
mediaFetchHotConfigFingerprint.let {
it.method.insertLiteralOverride(
it.instructionMatches.first().index,
"$EXTENSION_CLASS_DESCRIPTOR->useMediaFetchHotConfigReplacement(Z)Z"
)
}
mediaFetchHotConfigMethodMatch.method.insertLiteralOverride(
mediaFetchHotConfigMethodMatch.indices.first(),
"$EXTENSION_CLASS_DESCRIPTOR->useMediaFetchHotConfigReplacement(Z)Z"
)
}
if (fixMediaFetchHotConfigAlternative()) {
mediaFetchHotConfigAlternativeFingerprint.let {
it.method.insertLiteralOverride(
it.instructionMatches.first().index,
"$EXTENSION_CLASS_DESCRIPTOR->useMediaFetchHotConfigReplacement(Z)Z"
)
}
mediaFetchHotConfigAlternativeMethodMatch.method.insertLiteralOverride(
mediaFetchHotConfigAlternativeMethodMatch.indices.first(),
"$EXTENSION_CLASS_DESCRIPTOR->useMediaFetchHotConfigReplacement(Z)Z"
)
}
if (fixParsePlaybackResponseFeatureFlag()) {
playbackStartDescriptorFeatureFlagFingerprint.let {
it.method.insertLiteralOverride(
it.instructionMatches.first().index,
"$EXTENSION_CLASS_DESCRIPTOR->usePlaybackStartFeatureFlag(Z)Z"
)
}
playbackStartDescriptorFeatureFlagMethodMatch.method.insertLiteralOverride(
playbackStartDescriptorFeatureFlagMethodMatch.indices.first(),
"$EXTENSION_CLASS_DESCRIPTOR->usePlaybackStartFeatureFlag(Z)Z"
)
}
// endregion

View File

@@ -1,10 +1,10 @@
package app.revanced.patches.twitter.misc.extension.hooks
import app.revanced.patcher.definingClass
import app.revanced.patcher.name
import app.revanced.patches.shared.misc.extension.extensionHook
internal val applicationInitHook =
extensionHook {
custom { method, classDef ->
classDef.type == "Lcom/twitter/app/TwitterApplication;" && method.name == "onCreate"
}
}
internal val applicationInitHook = extensionHook {
name("onCreate")
definingClass("Lcom/twitter/app/TwitterApplication;")
}

View File

@@ -15,7 +15,7 @@ val customBrandingPatch = baseCustomBrandingPatch(
originalAppPackageName = YOUTUBE_PACKAGE_NAME,
isYouTubeMusic = false,
numberOfPresetAppNames = 5,
mainActivityOnCreateFingerprint = mainActivityOnCreateFingerprint,
getMainActivityOnCreate = mainActivityOnCreateFingerprint,
mainActivityName = YOUTUBE_MAIN_ACTIVITY_NAME,
activityAliasNameWithIntents = "com.google.android.youtube.app.honeycomb.Shell\$HomeActivity",
preferenceScreen = PreferenceScreen.GENERAL_LAYOUT,

View File

@@ -12,12 +12,6 @@ import app.revanced.util.literal
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
internal val infocardsIncognitoMatch = firstMethodBuilder {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returnType("V")
parameterTypes("L", "J")
instructions(string("vibrator"))
}
internal val infocardsIncognitoFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("Ljava/lang/Boolean;")

View File

@@ -3,7 +3,6 @@ package app.revanced.patches.youtube.misc.gms
import app.revanced.patcher.patch.Option
import app.revanced.patches.all.misc.resources.addResources
import app.revanced.patches.all.misc.resources.addResourcesPatch
import app.revanced.patches.shared.castContextFetchFingerprint
import app.revanced.patches.shared.misc.gms.gmsCoreSupportPatch
import app.revanced.patches.shared.misc.settings.preference.IntentPreference
import app.revanced.patches.shared.primeMethodFingerprint
@@ -20,11 +19,11 @@ import app.revanced.patches.youtube.shared.mainActivityOnCreateFingerprint
val gmsCoreSupportPatch = gmsCoreSupportPatch(
fromPackageName = YOUTUBE_PACKAGE_NAME,
toPackageName = REVANCED_YOUTUBE_PACKAGE_NAME,
primeMethodFingerprint = primeMethodFingerprint,
earlyReturnFingerprints = setOf(
getPrimeMethod = primeMethodFingerprint,
getEarlyReturnMethods = setOf(
castContextFetchFingerprint,
),
mainActivityOnCreateFingerprint = mainActivityOnCreateFingerprint,
getMainActivityOnCreateMethod = mainActivityOnCreateFingerprint,
extensionPatch = sharedExtensionPatch,
gmsCoreSupportResourcePatchFactory = ::gmsCoreSupportResourcePatch,
) {

View File

@@ -17,7 +17,7 @@ import app.revanced.patches.youtube.shared.mainActivityOnCreateFingerprint
val spoofVideoStreamsPatch = spoofVideoStreamsPatch(
extensionClassDescriptor = "Lapp/revanced/extension/youtube/patches/spoof/SpoofVideoStreamsPatch;",
mainActivityOnCreateFingerprint = mainActivityOnCreateFingerprint,
getMainActivityOnCreateMethod = mainActivityOnCreateFingerprint,
fixMediaFetchHotConfig = {
is_19_34_or_greater
},

View File

@@ -27,7 +27,7 @@ val forceOriginalAudioPatch = forceOriginalAudioPatch(
)
},
fixUseLocalizedAudioTrackFlag = { is_20_07_or_greater },
mainActivityOnCreateFingerprint = mainActivityOnCreateFingerprint,
getMainActivityOnCreateMethod = mainActivityOnCreateFingerprint,
subclassExtensionClassDescriptor = "Lapp/revanced/extension/youtube/patches/ForceOriginalAudioPatch;",
preferenceScreen = PreferenceScreen.VIDEO,
)