mirror of
https://github.com/ReVanced/revanced-patches.git
synced 2026-01-31 22:51:03 +00:00
fix(Spotify - Spoof client): Handle remaining edge cases to obtain a session (#5285)
Co-authored-by: Nuckyz <61953774+Nuckyz@users.noreply.github.com>
This commit is contained in:
@@ -87,8 +87,8 @@ fun sharedExtensionPatch(
|
||||
|
||||
class ExtensionHook internal constructor(
|
||||
internal val fingerprint: Fingerprint,
|
||||
private val insertIndexResolver: ((Method) -> Int),
|
||||
private val contextRegisterResolver: (Method) -> String,
|
||||
private val insertIndexResolver: BytecodePatchContext.(Method) -> Int,
|
||||
private val contextRegisterResolver: BytecodePatchContext.(Method) -> String,
|
||||
) {
|
||||
context(BytecodePatchContext)
|
||||
operator fun invoke(extensionClassDescriptor: String) {
|
||||
@@ -98,19 +98,19 @@ class ExtensionHook internal constructor(
|
||||
fingerprint.method.addInstruction(
|
||||
insertIndex,
|
||||
"invoke-static/range { $contextRegister .. $contextRegister }, " +
|
||||
"$extensionClassDescriptor->setContext(Landroid/content/Context;)V",
|
||||
"$extensionClassDescriptor->setContext(Landroid/content/Context;)V",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun extensionHook(
|
||||
insertIndexResolver: ((Method) -> Int) = { 0 },
|
||||
contextRegisterResolver: (Method) -> String = { "p0" },
|
||||
insertIndexResolver: BytecodePatchContext.(Method) -> Int = { 0 },
|
||||
contextRegisterResolver: BytecodePatchContext.(Method) -> String = { "p0" },
|
||||
fingerprint: Fingerprint,
|
||||
) = ExtensionHook(fingerprint, insertIndexResolver, contextRegisterResolver)
|
||||
|
||||
fun extensionHook(
|
||||
insertIndexResolver: ((Method) -> Int) = { 0 },
|
||||
contextRegisterResolver: (Method) -> String = { "p0" },
|
||||
insertIndexResolver: BytecodePatchContext.(Method) -> Int = { 0 },
|
||||
contextRegisterResolver: BytecodePatchContext.(Method) -> String = { "p0" },
|
||||
fingerprintBuilderBlock: FingerprintBuilder.() -> Unit,
|
||||
) = extensionHook(insertIndexResolver, contextRegisterResolver, fingerprint(block = fingerprintBuilderBlock))
|
||||
|
||||
@@ -2,4 +2,8 @@ package app.revanced.patches.spotify.misc.extension
|
||||
|
||||
import app.revanced.patches.shared.misc.extension.sharedExtensionPatch
|
||||
|
||||
val sharedExtensionPatch = sharedExtensionPatch("spotify", mainActivityOnCreateHook)
|
||||
val sharedExtensionPatch = sharedExtensionPatch(
|
||||
"spotify",
|
||||
mainActivityOnCreateHook,
|
||||
loadOrbitLibraryHook
|
||||
)
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
package app.revanced.patches.spotify.misc.extension
|
||||
|
||||
import app.revanced.patcher.fingerprint
|
||||
|
||||
internal val loadOrbitLibraryFingerprint = fingerprint {
|
||||
strings("OrbitLibraryLoader", "cst")
|
||||
}
|
||||
@@ -1,6 +1,26 @@
|
||||
package app.revanced.patches.spotify.misc.extension
|
||||
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patches.shared.misc.extension.extensionHook
|
||||
import app.revanced.patches.spotify.shared.mainActivityOnCreateFingerprint
|
||||
import app.revanced.util.getReference
|
||||
import app.revanced.util.indexOfFirstInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
|
||||
|
||||
internal val mainActivityOnCreateHook = extensionHook(fingerprint = mainActivityOnCreateFingerprint)
|
||||
|
||||
internal val loadOrbitLibraryHook = extensionHook(
|
||||
insertIndexResolver = {
|
||||
loadOrbitLibraryFingerprint.stringMatches!!.last().index
|
||||
},
|
||||
contextRegisterResolver = { method ->
|
||||
val contextReferenceIndex = method.indexOfFirstInstruction {
|
||||
getReference<FieldReference>()?.type == "Landroid/content/Context;"
|
||||
}
|
||||
val contextRegister = method.getInstruction<TwoRegisterInstruction>(contextReferenceIndex).registerA
|
||||
|
||||
"v$contextRegister"
|
||||
},
|
||||
fingerprint = loadOrbitLibraryFingerprint,
|
||||
)
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
package app.revanced.patches.spotify.misc.fix
|
||||
|
||||
import app.revanced.patcher.fingerprint
|
||||
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.reference.MethodReference
|
||||
|
||||
internal val getPackageInfoFingerprint = fingerprint {
|
||||
strings(
|
||||
@@ -9,7 +13,7 @@ internal val getPackageInfoFingerprint = fingerprint {
|
||||
)
|
||||
}
|
||||
|
||||
internal val startLiborbitFingerprint = fingerprint {
|
||||
internal val loadOrbitLibraryFingerprint = fingerprint {
|
||||
strings("/liborbit-jni-spotify.so")
|
||||
}
|
||||
|
||||
@@ -20,10 +24,22 @@ internal val startupPageLayoutInflateFingerprint = fingerprint {
|
||||
strings("blueprintContainer", "gradient", "valuePropositionTextView")
|
||||
}
|
||||
|
||||
internal val standardIntegrityTokenProviderBuilderFingerprint = fingerprint {
|
||||
strings(
|
||||
"standard_pi_init",
|
||||
"outcome",
|
||||
"success"
|
||||
internal val runIntegrityVerificationFingerprint = fingerprint {
|
||||
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
|
||||
returns("V")
|
||||
opcodes(
|
||||
Opcode.CHECK_CAST,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.INVOKE_STATIC, // Calendar.getInstance()
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.INVOKE_VIRTUAL, // instance.get(6)
|
||||
Opcode.MOVE_RESULT,
|
||||
Opcode.IF_EQ, // if (x == instance.get(6)) return
|
||||
)
|
||||
custom { method, _ ->
|
||||
method.indexOfFirstInstruction {
|
||||
val reference = getReference<MethodReference>()
|
||||
reference?.definingClass == "Ljava/util/Calendar;" && reference.name == "get"
|
||||
} >= 0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,8 +24,8 @@ val spoofClientPatch = bytecodePatch(
|
||||
name = "Spoof client",
|
||||
description = "Spoofs the client to fix various functions of the app.",
|
||||
) {
|
||||
val port by intOption(
|
||||
key = "port",
|
||||
val requestListenerPort by intOption(
|
||||
key = "requestListenerPort",
|
||||
default = 4345,
|
||||
title = " Login request listener port",
|
||||
description = "The port to use for the listener that intercepts and handles login requests. " +
|
||||
@@ -46,10 +46,10 @@ val spoofClientPatch = bytecodePatch(
|
||||
"x86",
|
||||
"x86_64"
|
||||
).forEach { architecture ->
|
||||
"https://login5.spotify.com/v3/login" to "http://127.0.0.1:$port/v3/login" inFile
|
||||
"https://login5.spotify.com/v3/login" to "http://127.0.0.1:$requestListenerPort/v3/login" inFile
|
||||
"lib/$architecture/liborbit-jni-spotify.so"
|
||||
|
||||
"https://login5.spotify.com/v4/login" to "http://127.0.0.1:$port/v4/login" inFile
|
||||
"https://login5.spotify.com/v4/login" to "http://127.0.0.1:$requestListenerPort/v4/login" inFile
|
||||
"lib/$architecture/liborbit-jni-spotify.so"
|
||||
}
|
||||
})
|
||||
@@ -58,6 +58,8 @@ val spoofClientPatch = bytecodePatch(
|
||||
compatibleWith("com.spotify.music")
|
||||
|
||||
execute {
|
||||
// region Spoof package info.
|
||||
|
||||
getPackageInfoFingerprint.method.apply {
|
||||
// region Spoof signature.
|
||||
|
||||
@@ -99,28 +101,33 @@ val spoofClientPatch = bytecodePatch(
|
||||
// endregion
|
||||
}
|
||||
|
||||
startLiborbitFingerprint.method.addInstructions(
|
||||
// endregion
|
||||
|
||||
// region Spoof client.
|
||||
|
||||
loadOrbitLibraryFingerprint.method.addInstructions(
|
||||
0,
|
||||
"""
|
||||
const/16 v0, $port
|
||||
invoke-static { v0 }, $EXTENSION_CLASS_DESCRIPTOR->listen(I)V
|
||||
const/16 v0, $requestListenerPort
|
||||
invoke-static { v0 }, $EXTENSION_CLASS_DESCRIPTOR->launchListener(I)V
|
||||
"""
|
||||
)
|
||||
|
||||
startupPageLayoutInflateFingerprint.method.apply {
|
||||
val openLoginWebViewDescriptor =
|
||||
"$EXTENSION_CLASS_DESCRIPTOR->login(Landroid/view/LayoutInflater;)V"
|
||||
"$EXTENSION_CLASS_DESCRIPTOR->launchLogin(Landroid/view/LayoutInflater;)V"
|
||||
|
||||
addInstructions(
|
||||
0,
|
||||
"""
|
||||
move-object/from16 v3, p1
|
||||
invoke-static { v3 }, $openLoginWebViewDescriptor
|
||||
invoke-static/range { p1 .. p1 }, $openLoginWebViewDescriptor
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
||||
// Early return to block sending bad verdicts to the API.
|
||||
standardIntegrityTokenProviderBuilderFingerprint.method.returnEarly()
|
||||
runIntegrityVerificationFingerprint.method.returnEarly()
|
||||
|
||||
// endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ package app.revanced.patches.spotify.shared
|
||||
|
||||
import app.revanced.patcher.fingerprint
|
||||
import app.revanced.patcher.patch.BytecodePatchContext
|
||||
import app.revanced.patches.spotify.misc.extension.mainActivityOnCreateHook
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
|
||||
private const val SPOTIFY_MAIN_ACTIVITY = "Lcom/spotify/music/SpotifyMainActivity;"
|
||||
|
||||
@@ -12,6 +12,9 @@ private const val SPOTIFY_MAIN_ACTIVITY = "Lcom/spotify/music/SpotifyMainActivit
|
||||
internal const val SPOTIFY_MAIN_ACTIVITY_LEGACY = "Lcom/spotify/music/MainActivity;"
|
||||
|
||||
internal val mainActivityOnCreateFingerprint = fingerprint {
|
||||
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
|
||||
returns("V")
|
||||
parameters("Landroid/os/Bundle;")
|
||||
custom { method, classDef ->
|
||||
method.name == "onCreate" && (classDef.type == SPOTIFY_MAIN_ACTIVITY
|
||||
|| classDef.type == SPOTIFY_MAIN_ACTIVITY_LEGACY)
|
||||
@@ -26,9 +29,10 @@ private var isLegacyAppTarget: Boolean? = null
|
||||
* supports Spotify integration on Kenwood/Pioneer car stereos.
|
||||
*/
|
||||
context(BytecodePatchContext)
|
||||
internal val IS_SPOTIFY_LEGACY_APP_TARGET get(): Boolean {
|
||||
if (isLegacyAppTarget == null) {
|
||||
isLegacyAppTarget = mainActivityOnCreateHook.fingerprint.originalClassDef.type == SPOTIFY_MAIN_ACTIVITY_LEGACY
|
||||
internal val IS_SPOTIFY_LEGACY_APP_TARGET
|
||||
get(): Boolean {
|
||||
if (isLegacyAppTarget == null) {
|
||||
isLegacyAppTarget = mainActivityOnCreateFingerprint.originalClassDef.type == SPOTIFY_MAIN_ACTIVITY_LEGACY
|
||||
}
|
||||
return isLegacyAppTarget!!
|
||||
}
|
||||
return isLegacyAppTarget!!
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user