some more progress

This commit is contained in:
oSumAtrIX
2026-01-21 20:09:43 +01:00
parent 44320b34f6
commit 29699557aa
83 changed files with 463 additions and 513 deletions

View File

@@ -1,6 +1,6 @@
package app.revanced.patches.googlenews.misc.gms
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.definingClass
import app.revanced.patcher.name
import app.revanced.patcher.patch.BytecodePatchContext

View File

@@ -1,5 +1,6 @@
package app.revanced.patches.googlenews.misc.gms
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.patch.Option
import app.revanced.patches.googlenews.misc.extension.extensionPatch
import app.revanced.patches.googlenews.misc.gms.Constants.MAGAZINES_PACKAGE_NAME
@@ -11,7 +12,7 @@ import app.revanced.patches.shared.misc.gms.gmsCoreSupportResourcePatch
val gmsCoreSupportPatch = gmsCoreSupportPatch(
fromPackageName = MAGAZINES_PACKAGE_NAME,
toPackageName = REVANCED_MAGAZINES_PACKAGE_NAME,
getMainActivityOnCreateMethod = { magazinesActivityOnCreateMethod },
getMainActivityOnCreateMethod = BytecodePatchContext::magazinesActivityOnCreateMethod::get,
extensionPatch = extensionPatch,
gmsCoreSupportResourcePatchFactory = ::gmsCoreSupportResourcePatch,
) {

View File

@@ -1,6 +1,6 @@
package app.revanced.patches.googlephotos.misc.gms
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.definingClass
import app.revanced.patcher.name
import app.revanced.patcher.patch.BytecodePatchContext

View File

@@ -1,5 +1,6 @@
package app.revanced.patches.googlephotos.misc.gms
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.patch.Option
import app.revanced.patches.googlephotos.misc.extension.extensionPatch
import app.revanced.patches.googlephotos.misc.gms.Constants.PHOTOS_PACKAGE_NAME
@@ -10,7 +11,7 @@ import app.revanced.patches.shared.misc.gms.gmsCoreSupportPatch
val gmsCoreSupportPatch = gmsCoreSupportPatch(
fromPackageName = PHOTOS_PACKAGE_NAME,
toPackageName = REVANCED_PHOTOS_PACKAGE_NAME,
getMainActivityOnCreateMethod = { homeActivityOnCreateMethod },
getMainActivityOnCreateMethod = BytecodePatchContext::homeActivityOnCreateMethod::get,
extensionPatch = extensionPatch,
gmsCoreSupportResourcePatchFactory = ::gmsCoreSupportResourcePatch,
) {

View File

@@ -1,7 +1,7 @@
package app.revanced.patches.music.misc.gms
import app.revanced.patcher.*
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.patch.BytecodePatchContext

View File

@@ -1,6 +1,6 @@
package app.revanced.patches.music.misc.settings
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.definingClass
import app.revanced.patcher.name
import app.revanced.patcher.parameterTypes

View File

@@ -1,6 +1,6 @@
package app.revanced.patches.music.shared
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.definingClass
import app.revanced.patcher.name
import app.revanced.patcher.parameterTypes

View File

@@ -1,6 +1,6 @@
package app.revanced.patches.myexpenses.misc.pro
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.returnType

View File

@@ -1,6 +1,6 @@
package app.revanced.patches.myfitnesspal.ads
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.accessFlags
import app.revanced.patcher.definingClass
import app.revanced.patcher.name

View File

@@ -1,7 +1,7 @@
package app.revanced.patches.nunl.ads
import app.revanced.patcher.*
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.patch.BytecodePatchContext
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode

View File

@@ -1,7 +1,7 @@
package app.revanced.patches.nunl.firebase
import app.revanced.patcher.*
import app.revanced.patcher.BytecodePatchContextMethodMatching.firstMutableMethodDeclaratively
import app.revanced.patcher.firstMutableMethodDeclaratively
import app.revanced.patcher.patch.BytecodePatchContext
import com.android.tools.smali.dexlib2.AccessFlags

View File

@@ -1,6 +1,6 @@
package app.revanced.patches.openinghours.misc.fix.crash
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.definingClass
import app.revanced.patcher.name
import app.revanced.patcher.parameterTypes

View File

@@ -1,6 +1,6 @@
package app.revanced.patches.orfon.detection.root
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.accessFlags
import app.revanced.patcher.definingClass
import app.revanced.patcher.name

View File

@@ -1,6 +1,6 @@
package app.revanced.patches.pandora.ads
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.definingClass
import app.revanced.patcher.name
import app.revanced.patcher.patch.BytecodePatchContext

View File

@@ -1,6 +1,6 @@
package app.revanced.patches.pandora.misc
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.definingClass
import app.revanced.patcher.name
import app.revanced.patcher.patch.BytecodePatchContext

View File

@@ -1,6 +1,6 @@
package app.revanced.patches.peacocktv.ads
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.accessFlags
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.returnType

View File

@@ -1,6 +1,6 @@
package app.revanced.patches.photomath.detection.deviceid
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.instructions
import app.revanced.patcher.invoke
import app.revanced.patcher.parameterTypes

View File

@@ -1,7 +1,7 @@
package app.revanced.patches.photomath.misc.annoyances
import app.revanced.patcher.*
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.patch.BytecodePatchContext
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode

View File

@@ -1,6 +1,6 @@
package app.revanced.patches.photomath.misc.unlock.bookpoint
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.accessFlags
import app.revanced.patcher.parameterTypes
import app.revanced.patcher.patch.BytecodePatchContext

View File

@@ -1,6 +1,6 @@
package app.revanced.patches.photomath.misc.unlock.plus
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.accessFlags
import app.revanced.patcher.definingClass
import app.revanced.patcher.patch.BytecodePatchContext

View File

@@ -1,6 +1,6 @@
package app.revanced.patches.piccomafr.tracking
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.accessFlags
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.returnType

View File

@@ -1,6 +1,6 @@
package app.revanced.patches.pixiv.ads
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.accessFlags
import app.revanced.patcher.definingClass
import app.revanced.patcher.name

View File

@@ -1,7 +1,7 @@
package app.revanced.patches.primevideo.ads
import app.revanced.patcher.*
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.patch.BytecodePatchContext
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode

View File

@@ -1,7 +1,7 @@
package app.revanced.patches.primevideo.video.speed
import app.revanced.patcher.*
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.patch.BytecodePatchContext
import com.android.tools.smali.dexlib2.AccessFlags

View File

@@ -1,6 +1,6 @@
package app.revanced.patches.protonvpn.delay
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.name
import app.revanced.patcher.patch.BytecodePatchContext

View File

@@ -1,6 +1,6 @@
package app.revanced.patches.rar.misc.annoyances.purchasereminder
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.accessFlags
import app.revanced.patcher.definingClass
import app.revanced.patcher.name

View File

@@ -1,6 +1,6 @@
package app.revanced.patches.reddit.ad.comments
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.definingClass
import app.revanced.patcher.name
import app.revanced.patcher.patch.BytecodePatchContext

View File

@@ -1,6 +1,6 @@
package app.revanced.patches.reddit.ad.general
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.definingClass
import app.revanced.patcher.instructions
import app.revanced.patcher.invoke

View File

@@ -1,6 +1,6 @@
package app.revanced.patches.reddit.customclients.baconreader.fix.redgifs
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.definingClass
import app.revanced.patcher.name
import app.revanced.patcher.parameterTypes

View File

@@ -3,15 +3,15 @@ package app.revanced.patches.reddit.customclients.baconreader.fix.redgifs
import app.revanced.patcher.extensions.getInstruction
import app.revanced.patcher.extensions.removeInstructions
import app.revanced.patcher.extensions.replaceInstruction
import app.revanced.patches.reddit.customclients.fixRedgifsApiPatch
import app.revanced.patcher.extensions.typeReference
import app.revanced.patches.reddit.customclients.INSTALL_NEW_CLIENT_METHOD
import app.revanced.patches.reddit.customclients.baconreader.misc.extension.sharedExtensionPatch
import app.revanced.patches.reddit.customclients.fixRedgifsApiPatch
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
import com.android.tools.smali.dexlib2.iface.reference.TypeReference
internal const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/baconreader/FixRedgifsApiPatch;"
@@ -29,15 +29,16 @@ val fixRedgifsApi = fixRedgifsApiPatch(
// Remove conflicting OkHttp interceptors.
val originalInterceptorInstallIndex = getOkHttpClientMethod.indexOfFirstInstructionOrThrow {
opcode == Opcode.NEW_INSTANCE && getReference<TypeReference>()?.type == "Lcom/onelouder/baconreader/media/gfycat/RedGifsManager\$HeaderInterceptor;"
opcode == Opcode.NEW_INSTANCE && typeReference?.type == $$"Lcom/onelouder/baconreader/media/gfycat/RedGifsManager$HeaderInterceptor;"
}
getOkHttpClientMethod.removeInstructions(originalInterceptorInstallIndex, 5)
val index = getOkHttpClientMethod.indexOfFirstInstructionOrThrow {
val reference = getReference<MethodReference>()
reference?.name == "build" && reference.definingClass == "Lokhttp3/OkHttpClient\$Builder;"
reference?.name == "build" && reference.definingClass == $$"Lokhttp3/OkHttpClient$Builder;"
}
val register = getOkHttpClientMethod.getInstruction<FiveRegisterInstruction>(index).registerC
getOkHttpClientMethod.replaceInstruction(
index,
"""

View File

@@ -1,6 +1,6 @@
package app.revanced.patches.reddit.customclients.boostforreddit.ads
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.patch.BytecodePatchContext
internal val BytecodePatchContext.maxMediationMethod by gettingFirstMutableMethodDeclaratively(

View File

@@ -1,6 +1,6 @@
package app.revanced.patches.reddit.customclients.boostforreddit.api
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.definingClass
import app.revanced.patcher.name
import app.revanced.patcher.patch.BytecodePatchContext

View File

@@ -1,7 +1,7 @@
package app.revanced.patches.reddit.customclients.boostforreddit.fix.redgifs
import app.revanced.patcher.*
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.patch.BytecodePatchContext
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode

View File

@@ -1,6 +1,6 @@
package app.revanced.patches.reddit.customclients.boostforreddit.fix.slink
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.accessFlags
import app.revanced.patcher.definingClass
import app.revanced.patcher.patch.BytecodePatchContext

View File

@@ -1,6 +1,6 @@
package app.revanced.patches.reddit.customclients.infinityforreddit.api
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethod
import app.revanced.patcher.gettingFirstMutableMethod
import app.revanced.patcher.patch.BytecodePatchContext
internal val BytecodePatchContext.apiUtilsMethod by gettingFirstMutableMethod("native-lib")

View File

@@ -1,8 +1,8 @@
package app.revanced.patches.reddit.customclients.infinityforreddit.subscription
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethod
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.InstructionMatchingFunctions.invoke
import app.revanced.patcher.gettingFirstMutableMethod
import app.revanced.patcher.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.invoke
import app.revanced.patcher.instructions
import app.revanced.patcher.patch.BytecodePatchContext

View File

@@ -1,6 +1,6 @@
package app.revanced.patches.reddit.customclients.joeyforreddit.ads
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.accessFlags
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.returnType

View File

@@ -1,7 +1,7 @@
package app.revanced.patches.reddit.customclients.joeyforreddit.api
import app.revanced.patcher.*
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.patch.BytecodePatchContext
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode

View File

@@ -1,7 +1,7 @@
package app.revanced.patches.reddit.customclients.joeyforreddit.detection.piracy
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.InstructionMatchingFunctions.invoke
import app.revanced.patcher.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.invoke
import app.revanced.patcher.accessFlags
import app.revanced.patcher.definingClass
import app.revanced.patcher.instructions

View File

@@ -1,7 +1,7 @@
package app.revanced.patches.reddit.customclients.redditisfun.api
import app.revanced.patcher.*
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.patch.BytecodePatchContext
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode

View File

@@ -1,6 +1,6 @@
package app.revanced.patches.reddit.customclients.relayforreddit.api
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.firstMethodComposite
import app.revanced.patcher.instructions
import app.revanced.patcher.invoke

View File

@@ -1,6 +1,6 @@
package app.revanced.patches.reddit.customclients.slide.api
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.definingClass
import app.revanced.patcher.name
import app.revanced.patcher.patch.BytecodePatchContext

View File

@@ -1,6 +1,6 @@
package app.revanced.patches.reddit.customclients.sync.ads
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.accessFlags
import com.android.tools.smali.dexlib2.AccessFlags
import app.revanced.patcher.patch.BytecodePatchContext

View File

@@ -1,7 +1,7 @@
package app.revanced.patches.reddit.customclients.sync.detection.piracy
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclarativelyOrNull
import app.revanced.patcher.InstructionMatchingFunctions.invoke
import app.revanced.patcher.gettingFirstMutableMethodDeclarativelyOrNull
import app.revanced.patcher.invoke
import app.revanced.patcher.accessFlags
import app.revanced.patcher.custom
import app.revanced.patcher.extensions.instructions

View File

@@ -1,6 +1,6 @@
package app.revanced.patches.reddit.customclients.sync.syncforreddit.annoyances.startup
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.definingClass
import app.revanced.patcher.name
import app.revanced.patcher.patch.BytecodePatchContext

View File

@@ -1,11 +1,11 @@
package app.revanced.patches.reddit.customclients.sync.syncforreddit.api
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethod
import app.revanced.patcher.gettingFirstMutableMethod
import app.revanced.patcher.invoke
import app.revanced.patcher.string
import app.revanced.patcher.firstMethodComposite
import app.revanced.patcher.instructions
import app.revanced.patcher.invoke
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.string
internal val getAuthorizationStringMethodMatch = firstMethodComposite {
instructions(string("authorize.compact?client_id"::startsWith))

View File

@@ -1,40 +1,39 @@
package app.revanced.patches.reddit.customclients.sync.syncforreddit.fix.redgifs
import app.revanced.patcher.*
import app.revanced.patcher.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.extensions.instructions
import app.revanced.patcher.fingerprint
import app.revanced.patcher.opcode
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.util.indexOfFirstInstruction
import app.revanced.util.writeRegister
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction11n
import com.android.tools.smali.dexlib2.iface.instruction.NarrowLiteralInstruction
internal val createOkHttpClientFingerprint = fingerprint {
internal val BytecodePatchContext.createOkHttpClientMethod by gettingFirstMutableMethodDeclaratively {
accessFlags(AccessFlags.PRIVATE, AccessFlags.STATIC)
returns("V")
parameters()
custom { method, classDef ->
returnType("V")
parameterTypes()
custom {
// There are four functions (each creating a client) defined in this file with very similar fingerprints.
// We're looking for the one that only creates one object (the builder) and sets client options true
// (thus never reloading the register with a 0).
classDef.sourceFile == "OkHttpHelper.java" &&
method.instructions.count { it.opcode == Opcode.NEW_INSTANCE } == 1 &&
method.indexOfFirstInstruction {
opcode == Opcode.CONST_4 && writeRegister == 1 && (this as Instruction11n).narrowLiteral == 0
immutableClassDef.sourceFile == "OkHttpHelper.java" && instructions.count {
it.opcode == Opcode.NEW_INSTANCE
} == 1 && indexOfFirstInstruction {
opcode == Opcode.CONST_4 && writeRegister == 1 && (this as NarrowLiteralInstruction).narrowLiteral == 0
} == -1
}
}
internal val getDefaultUserAgentFingerprint = fingerprint {
custom { method, classDef ->
method.name == "getDefaultUserAgent" && classDef.type == EXTENSION_CLASS_DESCRIPTOR
}
internal val BytecodePatchContext.getDefaultUserAgentMethod by gettingFirstMutableMethodDeclaratively {
name("getDefaultUserAgent")
definingClass(EXTENSION_CLASS_DESCRIPTOR)
}
internal val getOriginalUserAgentFingerprint = fingerprint {
internal val BytecodePatchContext.getOriginalUserAgentMethod by gettingFirstMutableMethodDeclaratively {
accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC)
returns("Ljava/lang/String;")
parameters()
custom { _, classDef -> classDef.sourceFile == "AccountSingleton.java" }
returnType("Ljava/lang/String;"::startsWith)
parameterTypes()
custom { immutableClassDef.sourceFile == "AccountSingleton.java" }
}

View File

@@ -26,30 +26,27 @@ val fixRedgifsApi = fixRedgifsApiPatch(
apply {
// region Patch Redgifs OkHttp3 client.
createOkHttpClientFingerprint.method.apply {
val index = indexOfFirstInstructionOrThrow {
val reference = getReference<MethodReference>()
reference?.name == "build" && reference.definingClass == "Lokhttp3/OkHttpClient\$Builder;"
}
val register = getInstruction<FiveRegisterInstruction>(index).registerC
replaceInstruction(
index,
"""
invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->$INSTALL_NEW_CLIENT_METHOD
"""
)
val index = createOkHttpClientMethod.indexOfFirstInstructionOrThrow {
val reference = getReference<MethodReference>()
reference?.name == "build" && reference.definingClass == $$"Lokhttp3/OkHttpClient$Builder;"
}
val register = createOkHttpClientMethod.getInstruction<FiveRegisterInstruction>(index).registerC
getDefaultUserAgentFingerprint.method.apply {
addInstructions(
0,
"""
invoke-static { }, ${getOriginalUserAgentFingerprint.method}
move-result-object v0
return-object v0
"""
)
}
createOkHttpClientMethod.replaceInstruction(
index,
"""
invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->$INSTALL_NEW_CLIENT_METHOD
"""
)
getDefaultUserAgentMethod.addInstructions(
0,
"""
invoke-static { }, $getOriginalUserAgentMethod
move-result-object v0
return-object v0
"""
)
// endregion
}

View File

@@ -1,13 +1,17 @@
package app.revanced.patches.reddit.customclients.sync.syncforreddit.fix.slink
import app.revanced.patcher.fingerprint
import app.revanced.patcher.gettingFirstMutableMethod
import app.revanced.patcher.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.definingClass
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.returnType
internal val linkHelperOpenLinkFingerprint = fingerprint {
strings("Link title: ")
}
internal val setAuthorizationHeaderFingerprint = fingerprint {
returns("Ljava/util/HashMap;")
strings("Authorization", "bearer ")
custom { method, _ -> method.definingClass == "Lcom/laurencedawson/reddit_sync/singleton/a;" }
internal val BytecodePatchContext.linkHelperOpenLinkMethod by gettingFirstMutableMethod("Link title: ")
internal val BytecodePatchContext.setAuthorizationHeaderMethod by gettingFirstMutableMethodDeclaratively(
"Authorization", "bearer "
) {
definingClass("Lcom/laurencedawson/reddit_sync/singleton/a;")
returnType("Ljava/util/HashMap;"::equals)
}

View File

@@ -1,9 +1,9 @@
package app.revanced.patches.reddit.customclients.sync.syncforreddit.fix.slink
import app.revanced.patcher.extensions.ExternalLabel
import app.revanced.patcher.extensions.addInstruction
import app.revanced.patcher.extensions.addInstructionsWithLabels
import app.revanced.patcher.extensions.getInstruction
import app.revanced.patcher.extensions.ExternalLabel
import app.revanced.patches.reddit.customclients.RESOLVE_S_LINK_METHOD
import app.revanced.patches.reddit.customclients.SET_ACCESS_TOKEN_METHOD
import app.revanced.patches.reddit.customclients.fixSLinksPatch
@@ -24,27 +24,25 @@ val fixSLinksPatch = fixSLinksPatch(
apply {
// region Patch navigation handler.
linkHelperOpenLinkFingerprint.method.apply {
val urlRegister = "p3"
val tempRegister = "v2"
val urlRegister = "p3"
val tempRegister = "v2"
addInstructionsWithLabels(
0,
"""
invoke-static { $urlRegister }, $EXTENSION_CLASS_DESCRIPTOR->$RESOLVE_S_LINK_METHOD
move-result $tempRegister
if-eqz $tempRegister, :continue
return $tempRegister
""",
ExternalLabel("continue", getInstruction(0)),
)
}
linkHelperOpenLinkMethod.addInstructionsWithLabels(
0,
"""
invoke-static { $urlRegister }, $EXTENSION_CLASS_DESCRIPTOR->$RESOLVE_S_LINK_METHOD
move-result $tempRegister
if-eqz $tempRegister, :continue
return $tempRegister
""",
ExternalLabel("continue", linkHelperOpenLinkMethod.getInstruction(0)),
)
// endregion
// region Patch set access token.
setAuthorizationHeaderFingerprint.method.addInstruction(
setAuthorizationHeaderMethod.addInstruction(
0,
"invoke-static { p0 }, $EXTENSION_CLASS_DESCRIPTOR->$SET_ACCESS_TOKEN_METHOD",
)

View File

@@ -1,12 +1,14 @@
package app.revanced.patches.reddit.customclients.sync.syncforreddit.fix.thumbnail
import app.revanced.patcher.fingerprint
import app.revanced.patcher.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.accessFlags
import app.revanced.patcher.definingClass
import app.revanced.patcher.parameterTypes
import app.revanced.patcher.patch.BytecodePatchContext
import com.android.tools.smali.dexlib2.AccessFlags
internal val customImageViewLoadFingerprint = fingerprint {
internal val BytecodePatchContext.customImageViewLoadMethod by gettingFirstMutableMethodDeclaratively {
definingClass("CustomImageView;"::endsWith)
accessFlags(AccessFlags.PUBLIC)
parameters("Ljava/lang/String;", "Z", "Z", "I", "I")
custom { _, classDef ->
classDef.endsWith("CustomImageView;")
}
parameterTypes("Ljava/lang/String;", "Z", "Z", "I", "I")
}

View File

@@ -1,11 +1,10 @@
package app.revanced.patches.reddit.customclients.sync.syncforreddit.fix.thumbnail
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.patch.creatingBytecodePatch
@Suppress("unused")
val fixPostThumbnailsPatch = bytecodePatch(
name = "Fix post thumbnails",
@Suppress("unused", "ObjectPropertyName")
val `Fix post thumbnails` by creatingBytecodePatch(
description = "Fixes loading post thumbnails by correcting their URLs.",
) {
@@ -17,7 +16,7 @@ val fixPostThumbnailsPatch = bytecodePatch(
// Image URLs contain escaped ampersands (&amp;), let's replace these with unescaped ones (&).
apply {
customImageViewLoadFingerprint.method.addInstructions(
customImageViewLoadMethod.addInstructions(
0,
"""
# url = url.replace("&amp;", "&");

View File

@@ -1,36 +1,39 @@
package app.revanced.patches.reddit.customclients.sync.syncforreddit.fix.user
import app.revanced.patcher.fingerprint
import app.revanced.patcher.*
import com.android.tools.smali.dexlib2.AccessFlags
internal fun userEndpointFingerprint(source: String, accessFlags: Set<AccessFlags>? = null) = fingerprint {
strings("u/")
custom { _, classDef -> classDef.sourceFile == source }
accessFlags(*accessFlags?.toTypedArray() ?: return@fingerprint)
internal fun userEndpointMethodMatch(
source: String,
accessFlags: Set<AccessFlags>? = null
) = firstMethodComposite {
instructions("u/"(String::contains))
custom { immutableClassDef.sourceFile == source }
accessFlags(*accessFlags?.toTypedArray() ?: return@firstMethodComposite)
}
internal val oAuthFriendRequestFingerprint = userEndpointFingerprint(
internal val oAuthFriendRequestMethodMatch = userEndpointMethodMatch(
"OAuthFriendRequest.java",
)
internal val oAuthUnfriendRequestFingerprint = userEndpointFingerprint(
internal val oAuthUnfriendRequestMethodMatch = userEndpointMethodMatch(
"OAuthUnfriendRequest.java",
)
internal val oAuthUserIdRequestFingerprint = userEndpointFingerprint(
internal val oAuthUserIdRequestMethodMatch = userEndpointMethodMatch(
"OAuthUserIdRequest.java",
)
internal val oAuthUserInfoRequestFingerprint = userEndpointFingerprint(
internal val oAuthUserInfoRequestMethodMatch = userEndpointMethodMatch(
"OAuthUserInfoRequest.java",
)
internal val oAuthSubredditInfoRequestConstructorFingerprint = userEndpointFingerprint(
internal val oAuthSubredditInfoRequestConstructorMethodMatch = userEndpointMethodMatch(
"OAuthSubredditInfoRequest.java",
setOf(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR),
)
internal val oAuthSubredditInfoRequestHelperFingerprint = userEndpointFingerprint(
internal val oAuthSubredditInfoRequestHelperMethodMatch = userEndpointMethodMatch(
"OAuthSubredditInfoRequest.java",
setOf(AccessFlags.PRIVATE, AccessFlags.STATIC),
)

View File

@@ -2,10 +2,9 @@ package app.revanced.patches.reddit.customclients.sync.syncforreddit.fix.user
import app.revanced.patcher.extensions.getInstruction
import app.revanced.patcher.extensions.replaceInstruction
import app.revanced.patcher.extensions.stringReference
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.util.getReference
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.StringReference
@Suppress("unused")
val useUserEndpointPatch = bytecodePatch(
@@ -13,7 +12,7 @@ val useUserEndpointPatch = bytecodePatch(
description = "Replaces the deprecated endpoint for viewing user profiles /u with /user, that used to fix a bug.",
use = false,
) {
) {
compatibleWith(
"com.laurencedawson.reddit_sync",
"com.laurencedawson.reddit_sync.pro",
@@ -22,20 +21,19 @@ val useUserEndpointPatch = bytecodePatch(
apply {
arrayOf(
oAuthFriendRequestFingerprint,
oAuthSubredditInfoRequestConstructorFingerprint,
oAuthSubredditInfoRequestHelperFingerprint,
oAuthUnfriendRequestFingerprint,
oAuthUserIdRequestFingerprint,
oAuthUserInfoRequestFingerprint,
).map { fingerprint ->
fingerprint.stringMatches.first().index to fingerprint.method
oAuthFriendRequestMethodMatch,
oAuthSubredditInfoRequestConstructorMethodMatch,
oAuthSubredditInfoRequestHelperMethodMatch,
oAuthUnfriendRequestMethodMatch,
oAuthUserIdRequestMethodMatch,
oAuthUserInfoRequestMethodMatch
).map { match ->
match.stringIndices.values.first() to match.method
}.forEach { (userPathStringIndex, method) ->
val userPathStringInstruction = method.getInstruction<OneRegisterInstruction>(userPathStringIndex)
val userPathStringRegister = userPathStringInstruction.registerA
val fixedUserPathString = userPathStringInstruction.getReference<StringReference>()!!
.string.replace("u/", "user/")
val fixedUserPathString = userPathStringInstruction.stringReference!!.string.replace("u/", "user/")
method.replaceInstruction(
userPathStringIndex,

View File

@@ -1,16 +1,15 @@
package app.revanced.patches.reddit.customclients.sync.syncforreddit.fix.video
import app.revanced.patcher.fingerprint
import app.revanced.patcher.*
import com.android.tools.smali.dexlib2.Opcode
internal val parseRedditVideoNetworkResponseFingerprint = fingerprint {
internal val parseRedditVideoNetworkResponseMethodMatch = firstMethodComposite {
name("parseNetworkResponse")
opcodes(
Opcode.NEW_INSTANCE,
Opcode.IGET_OBJECT,
Opcode.INVOKE_DIRECT,
Opcode.CONST_WIDE_32,
)
custom { methodDef, classDef ->
classDef.sourceFile == "RedditVideoRequest.java" && methodDef.name == "parseNetworkResponse"
}
custom { immutableClassDef.sourceFile == "RedditVideoRequest.java" }
}

View File

@@ -24,14 +24,14 @@ val fixVideoDownloadsPatch = bytecodePatch(
)
apply {
val scanResult = parseRedditVideoNetworkResponseFingerprint.instructionMatches
val newInstanceIndex = scanResult.first().index
val invokeDirectIndex = scanResult.last().index - 1
val scanResult = parseRedditVideoNetworkResponseMethodMatch.indices
val newInstanceIndex = scanResult.first()
val invokeDirectIndex = scanResult.last() - 1
val buildResponseInstruction =
parseRedditVideoNetworkResponseFingerprint.method.getInstruction<Instruction35c>(invokeDirectIndex)
parseRedditVideoNetworkResponseMethodMatch.method.getInstruction<Instruction35c>(invokeDirectIndex)
parseRedditVideoNetworkResponseFingerprint.method.addInstructions(
parseRedditVideoNetworkResponseMethodMatch.method.addInstructions(
newInstanceIndex + 1,
"""
# Get byte array from response.

View File

@@ -1,16 +1,15 @@
package app.revanced.patches.reddit.layout.disablescreenshotpopup
import app.revanced.patcher.extensions.addInstruction
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.patch.creatingBytecodePatch
@Suppress("unused")
val disableScreenshotPopupPatch = bytecodePatch(
name = "Disable screenshot popup",
@Suppress("unused", "ObjectPropertyName")
val `Disable screenshot popup` by creatingBytecodePatch(
description = "Disables the popup that shows up when taking a screenshot.",
) {
compatibleWith("com.reddit.frontpage")
apply {
disableScreenshotPopupFingerprint.method.addInstruction(0, "return-void")
disableScreenshotPopupMethod.addInstruction(0, "return-void")
}
}

View File

@@ -1,15 +1,15 @@
package app.revanced.patches.reddit.layout.disablescreenshotpopup
import app.revanced.patcher.fingerprint
import app.revanced.patcher.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 val disableScreenshotPopupFingerprint = fingerprint {
returns("V")
parameters("Landroidx/compose/runtime/", "I")
custom { method, classDef ->
if (!classDef.endsWith("\$ScreenshotTakenBannerKt\$lambda-1\$1;")) {
return@custom false
}
method.name == "invoke"
}
internal val BytecodePatchContext.disableScreenshotPopupMethod by gettingFirstMutableMethodDeclaratively {
name("invoke")
definingClass($$"$ScreenshotTakenBannerKt$lambda-1$1;"::endsWith)
returnType("V")
parameterTypes("Landroidx/compose/runtime/", "I")
}

View File

@@ -1,10 +1,13 @@
package app.revanced.patches.reddit.layout.premiumicon
import app.revanced.patcher.fingerprint
import app.revanced.patcher.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.definingClass
import app.revanced.patcher.name
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.returnType
internal val hasPremiumIconAccessFingerprint = fingerprint {
returns("Z")
custom { method, classDef ->
classDef.endsWith("MyAccount;") && method.name == "isPremiumSubscriber"
}
internal val BytecodePatchContext.hasPremiumIconAccessMethod by gettingFirstMutableMethodDeclaratively {
name("isPremiumSubscriber")
definingClass("MyAccount;"::endsWith)
returnType("Z")
}

View File

@@ -1,17 +1,16 @@
package app.revanced.patches.reddit.layout.premiumicon
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.patch.creatingBytecodePatch
@Suppress("unused")
val unlockPremiumIconsPatch = bytecodePatch(
name = "Unlock Premium icons",
@Suppress("unused", "ObjectPropertyName")
val `Unlock Premium icons` by creatingBytecodePatch(
description = "Unlocks the Reddit Premium icons.",
) {
compatibleWith("com.reddit.frontpage")
apply {
hasPremiumIconAccessFingerprint.method.addInstructions(
hasPremiumIconAccessMethod.addInstructions(
0,
"""
const/4 v0, 0x1

View File

@@ -1,9 +1,12 @@
package app.revanced.patches.reddit.misc.tracking.url
import app.revanced.patcher.fingerprint
import app.revanced.patcher.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.custom
import app.revanced.patcher.definingClass
import app.revanced.patcher.immutableClassDef
import app.revanced.patcher.patch.BytecodePatchContext
internal val shareLinkFormatterFingerprint = fingerprint {
custom { _, classDef ->
classDef.startsWith("Lcom/reddit/sharing/") && classDef.sourceFile == "UrlUtil.kt"
}
}
internal val BytecodePatchContext.shareLinkFormatterMethod by gettingFirstMutableMethodDeclaratively {
definingClass("Lcom/reddit/sharing/"::startsWith)
custom { immutableClassDef.sourceFile == "UrlUtil.kt" }
}

View File

@@ -10,9 +10,6 @@ val `Sanitize sharing links` by creatingBytecodePatch(
compatibleWith("com.reddit.frontpage")
apply {
shareLinkFormatterFingerprint.method.addInstructions(
0,
"return-object p0",
)
shareLinkFormatterMethod.addInstructions(0, "return-object p0",)
}
}

View File

@@ -6,7 +6,6 @@ import org.w3c.dom.Element
@Suppress("unused")
internal val addManifestPermissionsPatch = resourcePatch {
val requiredPermissions = listOf(
"android.permission.READ_PHONE_STATE",
"android.permission.FOREGROUND_SERVICE_MICROPHONE",

View File

@@ -5,7 +5,7 @@ package app.revanced.patches.samsung.radio.misc.fix.crash
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.getInstruction
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patches.samsung.radio.restrictions.device.bypassDeviceChecksPatch
import app.revanced.patches.samsung.radio.restrictions.device.`Bypass device checks`
import app.revanced.util.findInstructionIndicesReversedOrThrow
import app.revanced.util.indexOfFirstInstruction
import com.android.tools.smali.dexlib2.Opcode
@@ -16,7 +16,7 @@ private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/samsung/
val fixCrashPatch = bytecodePatch(
name = "Fix crashes", description = "Prevents the app from crashing because of missing system permissions."
) {
dependsOn(addManifestPermissionsPatch, bypassDeviceChecksPatch)
dependsOn(addManifestPermissionsPatch, `Bypass device checks`)
extendWith("extensions/samsung/radio.rve")
compatibleWith("com.sec.android.app.fm"("12.4.00.7", "12.3.00.13", "12.3.00.11"))

View File

@@ -2,7 +2,7 @@ package app.revanced.patches.samsung.radio.restrictions.device
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.removeInstructions
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.patch.creatingBytecodePatch
import app.revanced.util.findFreeRegister
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow
@@ -12,9 +12,8 @@ import com.android.tools.smali.dexlib2.iface.reference.StringReference
private const val EXTENSION_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/samsung/radio/restrictions/device/BypassDeviceChecksPatch;"
@Suppress("unused")
val bypassDeviceChecksPatch = bytecodePatch(
name = "Bypass device checks",
@Suppress("unused", "ObjectPropertyName")
val `Bypass device checks` by creatingBytecodePatch(
description = "Removes firmware and region blacklisting. " +
"This patch will still not allow the app to run on devices that do not have the required hardware.",
) {
@@ -22,34 +21,33 @@ val bypassDeviceChecksPatch = bytecodePatch(
compatibleWith("com.sec.android.app.fm"("12.4.00.7", "12.3.00.13", "12.3.00.11"))
apply {
// Return false = The device is not blacklisted.
checkDeviceFingerprint.method.apply {
// Find the first string that start with "SM-", that's the list of incompatible devices.
val firstStringIndex = indexOfFirstInstructionOrThrow {
opcode == Opcode.CONST_STRING &&
getReference<StringReference>()?.string?.startsWith("SM-") == true
}
// Find the first string that start with "SM-", that's the list of incompatible devices.
val firstStringIndex = checkDeviceMethod.indexOfFirstInstructionOrThrow {
opcode == Opcode.CONST_STRING &&
getReference<StringReference>()?.string?.startsWith("SM-") == true
}
// Find the following filled-new-array (or filled-new-array/range) instruction.
val filledNewArrayIndex = indexOfFirstInstructionOrThrow(firstStringIndex + 1) {
opcode == Opcode.FILLED_NEW_ARRAY || opcode == Opcode.FILLED_NEW_ARRAY_RANGE
}
// Find the following filled-new-array (or filled-new-array/range) instruction.
val filledNewArrayIndex = checkDeviceMethod.indexOfFirstInstructionOrThrow(firstStringIndex + 1) {
opcode == Opcode.FILLED_NEW_ARRAY || opcode == Opcode.FILLED_NEW_ARRAY_RANGE
}
val resultRegister = findFreeRegister(filledNewArrayIndex + 1)
val resultRegister = checkDeviceMethod.findFreeRegister(filledNewArrayIndex + 1)
// Store the array there and invoke the method that we added to the class earlier.
addInstructions(
filledNewArrayIndex + 1,
"""
// Store the array there and invoke the method that we added to the class earlier.
checkDeviceMethod.addInstructions(
filledNewArrayIndex + 1,
"""
move-result-object v$resultRegister
invoke-static { v$resultRegister }, $EXTENSION_CLASS_DESCRIPTOR->checkIfDeviceIsIncompatible([Ljava/lang/String;)Z
move-result v$resultRegister
return v$resultRegister
"""
)
)
// Remove the instructions before our strings.
removeInstructions(0, firstStringIndex)
}
// Remove the instructions before our strings.
// Return false = The device is not blacklisted.
checkDeviceMethod.removeInstructions(0, firstStringIndex)
}
}

View File

@@ -1,61 +1,30 @@
package app.revanced.patches.samsung.radio.restrictions.device
import app.revanced.patcher.fingerprint
import app.revanced.patches.all.misc.transformation.IMethodCall
import app.revanced.patches.all.misc.transformation.fromMethodReference
import app.revanced.util.getReference
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
import app.revanced.patcher.*
import app.revanced.patcher.patch.BytecodePatchContext
import com.android.tools.smali.dexlib2.immutable.reference.ImmutableMethodReference
import com.android.tools.smali.dexlib2.util.MethodUtil
internal val checkDeviceFingerprint = fingerprint {
returns("Z")
custom { method, _ ->
/* Check for methods call to:
- Landroid/os/SemSystemProperties;->getSalesCode()Ljava/lang/String;
- Landroid/os/SemSystemProperties;->getCountryIso()Ljava/lang/String;
*/
val impl = method.implementation ?: return@custom false
// Track which target methods we've found
val foundMethods = mutableSetOf<MethodCall>()
// Scan method instructions for calls to our target methods
for (instr in impl.instructions) {
val ref = instr.getReference<MethodReference>() ?: continue
val mc = fromMethodReference<MethodCall>(ref) ?: continue
if (mc == MethodCall.GetSalesCode || mc == MethodCall.GetCountryIso) {
foundMethods.add(mc)
// If we found both methods, return success
if (foundMethods.size == 2) {
return@custom true
}
}
}
// Only match if both methods are present
return@custom false
}
internal val BytecodePatchContext.checkDeviceMethod by gettingFirstMutableMethodDeclaratively {
returnType("Z")
instructions(
predicates = unorderedAllOf(
method { MethodUtil.methodSignaturesMatch(getSalesCodeMethodReference, this) },
method { MethodUtil.methodSignaturesMatch(getCountryIsoMethodReference, this) }
))
}
// Information about method calls we want to replace
private enum class MethodCall(
override val definedClassName: String,
override val methodName: String,
override val methodParams: Array<String>,
override val returnType: String,
) : IMethodCall {
GetSalesCode(
"Landroid/os/SemSystemProperties;",
"getSalesCode",
arrayOf(),
"Ljava/lang/String;",
),
GetCountryIso(
"Landroid/os/SemSystemProperties;",
"getCountryIso",
arrayOf(),
"Ljava/lang/String;",
)
}
val getSalesCodeMethodReference = ImmutableMethodReference(
"Landroid/os/SemSystemProperties;",
"getSalesCode",
emptyList(),
"Ljava/lang/String;",
)
val getCountryIsoMethodReference = ImmutableMethodReference(
"Landroid/os/SemSystemProperties;",
"getCountryIso",
emptyList(),
"Ljava/lang/String;",
)

View File

@@ -1,6 +1,6 @@
package app.revanced.patches.shared
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.patch.BytecodePatchContext
internal val BytecodePatchContext.castContextFetchMethod by gettingFirstMutableMethodDeclaratively(

View File

@@ -1,6 +1,6 @@
package app.revanced.patches.shared.misc.checks
import app.revanced.patcher.BytecodePatchContextClassDefMatching.gettingFirstMutableClassDefDeclaratively
import app.revanced.patcher.gettingFirstMutableClassDefDeclaratively
import app.revanced.patcher.patch.BytecodePatchContext
internal val BytecodePatchContext.patchInfoClassDef by gettingFirstMutableClassDefDeclaratively(

View File

@@ -1,7 +1,7 @@
package app.revanced.patches.shared.misc.debugging
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMethodDeclaratively
import app.revanced.patcher.ClassDefMethodMatching.firstMutableMethodDeclaratively
import app.revanced.patcher.gettingFirstMethodDeclaratively
import app.revanced.patcher.firstMutableMethodDeclaratively
import app.revanced.patcher.accessFlags
import app.revanced.patcher.parameterTypes
import app.revanced.patcher.patch.BytecodePatchContext

View File

@@ -1,7 +1,7 @@
package app.revanced.patches.shared.misc.extension
import app.revanced.patcher.*
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.patch.BytecodePatchContext
import com.android.tools.smali.dexlib2.AccessFlags

View File

@@ -1,8 +1,8 @@
package app.revanced.patches.shared.misc.extension
import app.revanced.patcher.*
import app.revanced.patcher.BytecodePatchContextClassDefMatching.firstMutableClassDef
import app.revanced.patcher.BytecodePatchContextMethodMatching.firstMutableMethodDeclaratively
import app.revanced.patcher.firstMutableClassDef
import app.revanced.patcher.firstMutableMethodDeclaratively
import app.revanced.patcher.extensions.addInstruction
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.patch.bytecodePatch

View File

@@ -48,7 +48,7 @@ fun gmsCoreSupportPatch(
fromPackageName: String,
toPackageName: String,
getPrimeMethod: (BytecodePatchContext.() -> MutableMethod)? = null,
getEarlyReturnMethods: BytecodePatchContext.() -> Set<MutableMethod> = { setOf() },
getEarlyReturnMethods: Set<BytecodePatchContext.() -> MutableMethod> = emptySet(),
getMainActivityOnCreateMethod: BytecodePatchContext.() -> MutableMethod,
extensionPatch: Patch,
gmsCoreSupportResourcePatchFactory: (gmsCoreVendorGroupIdOption: Option<String>) -> Patch,

View File

@@ -1,5 +1,7 @@
package app.revanced.patches.shared.misc.spoof
import app.revanced.patcher.invoke
import app.revanced.patcher.method
import app.revanced.patcher.accessFlags
import app.revanced.patcher.fingerprint
import app.revanced.util.indexOfFirstInstruction
@@ -8,8 +10,6 @@ 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

View File

@@ -1,6 +1,6 @@
package app.revanced.patches.spotify.shared
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.accessFlags
import app.revanced.patcher.definingClass
import app.revanced.patcher.fingerprint

View File

@@ -1,6 +1,6 @@
package app.revanced.patches.strava.mediaupload
import app.revanced.patcher.BytecodePatchContextClassDefMatching.firstClassDef
import app.revanced.patcher.firstClassDef
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.patch.intOption
import app.revanced.patcher.patch.longOption

View File

@@ -1,8 +1,8 @@
package app.revanced.patches.twitter.misc.hook.json
import app.revanced.patcher.*
import app.revanced.patcher.BytecodePatchContextClassDefMatching.gettingFirstClassDef
import app.revanced.patcher.ClassDefMethodMatching.firstMutableMethodDeclaratively
import app.revanced.patcher.gettingFirstClassDef
import app.revanced.patcher.firstMutableMethodDeclaratively
import app.revanced.patcher.patch.BytecodePatchContext
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.ClassDef

View File

@@ -1,6 +1,6 @@
package app.revanced.patches.twitter.misc.hook.json
import app.revanced.patcher.BytecodePatchContextClassDefMatching.firstClassDef
import app.revanced.patcher.firstClassDef
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.removeInstructions
import app.revanced.patcher.patch.BytecodePatchContext

View File

@@ -1,11 +1,13 @@
package app.revanced.patches.youtube.misc.gms
import app.revanced.patcher.patch.BytecodePatchContext
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.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
import app.revanced.patches.youtube.layout.buttons.overlay.hidePlayerOverlayButtonsPatch
import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
import app.revanced.patches.youtube.misc.gms.Constants.REVANCED_YOUTUBE_PACKAGE_NAME
@@ -13,16 +15,15 @@ import app.revanced.patches.youtube.misc.gms.Constants.YOUTUBE_PACKAGE_NAME
import app.revanced.patches.youtube.misc.settings.PreferenceScreen
import app.revanced.patches.youtube.misc.settings.settingsPatch
import app.revanced.patches.youtube.misc.spoof.spoofVideoStreamsPatch
import app.revanced.patches.youtube.shared.mainActivityOnCreateMethod
@Suppress("unused")
val gmsCoreSupportPatch = gmsCoreSupportPatch(
fromPackageName = YOUTUBE_PACKAGE_NAME,
toPackageName = REVANCED_YOUTUBE_PACKAGE_NAME,
getPrimeMethod = primeMethodFingerprint,
getEarlyReturnMethods = setOf(
castContextFetchFingerprint,
),
getMainActivityOnCreateMethod = mainActivityOnCreateFingerprint,
getPrimeMethod = BytecodePatchContext::primeMethod::get,
getEarlyReturnMethods = setOf(BytecodePatchContext::castContextFetchMethod::get),
getMainActivityOnCreateMethod = BytecodePatchContext::mainActivityOnCreateMethod::get,
extensionPatch = sharedExtensionPatch,
gmsCoreSupportResourcePatchFactory = ::gmsCoreSupportResourcePatch,
) {

View File

@@ -1,20 +1,25 @@
package app.revanced.patches.youtube.shared
import app.revanced.patcher.BytecodePatchContextMethodMatching.firstMutableMethodDeclaratively
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.InstructionLocation.MatchAfterImmediately
import app.revanced.patcher.fieldAccess
import app.revanced.patcher.accessFlags
import app.revanced.patcher.fingerprint
import app.revanced.patcher.literal
import app.revanced.patcher.methodCall
import app.revanced.patcher.newInstance
import app.revanced.patcher.opcode
import app.revanced.patcher.addString
import app.revanced.patcher.after
import app.revanced.patcher.allOf
import app.revanced.patcher.definingClass
import app.revanced.patcher.field
import app.revanced.patcher.firstMethodComposite
import app.revanced.patcher.instructions
import app.revanced.patcher.invoke
import app.revanced.patcher.name
import app.revanced.patcher.parameterTypes
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.returnType
import app.revanced.patcher.type
import app.revanced.patches.shared.misc.mapping.ResourceType
import app.revanced.patches.shared.misc.mapping.resourceLiteral
import com.android.tools.smali.dexlib2.AccessFlags
@@ -126,18 +131,14 @@ internal val subtitleButtonControllerFingerprint = fingerprint {
)
}
internal val videoQualityChangedFingerprint = fingerprint {
internal val videoQualityChangedMethodMatch = firstMethodComposite {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("L")
parameters("L")
returnType("L")
parameterTypes("L")
instructions(
newInstance("Lcom/google/android/libraries/youtube/innertube/model/media/VideoQuality;"),
opcode(Opcode.IGET_OBJECT),
opcode(Opcode.CHECK_CAST),
fieldAccess(
type = "I",
opcode = Opcode.IGET,
location = MatchAfterImmediately()
), // Video resolution (human readable).
allOf(Opcode.NEW_INSTANCE(), type("Lcom/google/android/libraries/youtube/innertube/model/media/VideoQuality;")),
Opcode.IGET_OBJECT(),
Opcode.CHECK_CAST(),
after(allOf(Opcode.IGET(), field { type == "I" })) // Video resolution (human-readable).
)
}

View File

@@ -1,58 +1,50 @@
package app.revanced.patches.youtube.video.information
import app.revanced.patcher.InstructionLocation.MatchAfterWithin
import app.revanced.patcher.fieldAccess
import app.revanced.patcher.fingerprint
import app.revanced.patcher.literal
import app.revanced.patcher.methodCall
import app.revanced.patcher.addString
import app.revanced.patches.youtube.shared.videoQualityChangedFingerprint
import app.revanced.util.getReference
import app.revanced.patcher.*
import app.revanced.patcher.extensions.instructions
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patches.youtube.shared.videoQualityChangedMethodMatch
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
import com.android.tools.smali.dexlib2.iface.ClassDef
internal val createVideoPlayerSeekbarFingerprint = fingerprint {
returns("V")
instructions(
addString("timed_markers_width"),
)
internal val BytecodePatchContext.createVideoPlayerSeekbarMethod by gettingFirstMethodDeclaratively {
returnType("V")
instructions("timed_markers_width"())
}
internal val onPlaybackSpeedItemClickFingerprint = fingerprint {
internal val BytecodePatchContext.onPlaybackSpeedItemClickMethod by gettingFirstMutableMethodDeclaratively {
name("onItemClick")
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("V")
parameters("L", "L", "I", "J")
custom { method, _ ->
method.name == "onItemClick" &&
method.implementation?.instructions?.find {
it.opcode == Opcode.IGET_OBJECT &&
it.getReference<FieldReference>()!!.type == "Lcom/google/android/libraries/youtube/innertube/model/player/PlayerResponseModel;"
} != null
}
}
internal val playerControllerSetTimeReferenceFingerprint = fingerprint {
opcodes(Opcode.INVOKE_DIRECT_RANGE, Opcode.IGET_OBJECT)
strings("Media progress reported outside media playback: ")
}
internal val playerInitFingerprint = fingerprint {
returnType("V")
parameterTypes("L", "L", "I", "J")
instructions(
addString("playVideo called on player response with no videoStreamingData."),
allOf(
Opcode.IGET_OBJECT(),
field { type == "Lcom/google/android/libraries/youtube/innertube/model/player/PlayerResponseModel;" })
)
}
internal val playerControllerSetTimeReferenceMethodMatch =
firstMethodComposite("Media progress reported outside media playback: ") {
opcodes(
Opcode.INVOKE_DIRECT_RANGE,
Opcode.IGET_OBJECT
)
}
internal val BytecodePatchContext.playVideoCheckVideoStreamingDataResponseMethod by gettingFirstMethodDeclaratively {
instructions("playVideo called on player response with no videoStreamingData."())
}
/**
* Matched using class found in [playerInitFingerprint].
* Matched using class found in [playVideoCheckVideoStreamingDataResponseMethod].
*/
internal val seekFingerprint = fingerprint {
instructions(
addString("Attempting to seek during an ad"),
)
internal fun ClassDef.getSeekMethod() = firstMethodDeclaratively {
instructions("Attempting to seek during an ad"())
}
internal val videoLengthFingerprint = fingerprint {
internal val videoLengthMethodMatch = firstMethodComposite {
opcodes(
Opcode.MOVE_RESULT_WIDE,
Opcode.CMP_LONG,
@@ -70,38 +62,38 @@ internal val videoLengthFingerprint = fingerprint {
}
/**
* Matches using class found in [mdxPlayerDirectorSetVideoStageFingerprint].
* Matches using class found in [mdxPlayerDirectorSetVideoStageMethod].
*/
internal val mdxSeekFingerprint = fingerprint {
context(_: BytecodePatchContext)
internal fun ClassDef.getMdxSeekMethod() = firstMethodDeclaratively {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("Z")
parameters("J", "L")
returnType("Z")
parameterTypes("J", "L")
opcodes(
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT,
Opcode.RETURN,
)
custom { methodDef, _ ->
custom {
// The instruction count is necessary here to avoid matching the relative version
// of the seek method we're after, which has the same function signature as the
// regular one, is in the same class, and even has the exact same 3 opcodes pattern.
methodDef.implementation!!.instructions.count() == 3
instructions.count() == 3
}
}
internal val mdxPlayerDirectorSetVideoStageFingerprint = fingerprint {
instructions(
addString("MdxDirector setVideoStage ad should be null when videoStage is not an Ad state "),
)
internal val BytecodePatchContext.mdxPlayerDirectorSetVideoStageMethod by gettingFirstMethodDeclaratively {
instructions("MdxDirector setVideoStage ad should be null when videoStage is not an Ad state "())
}
/**
* Matches using class found in [mdxPlayerDirectorSetVideoStageFingerprint].
* Matches using class found in [mdxPlayerDirectorSetVideoStageMethod].
*/
internal val mdxSeekRelativeFingerprint = fingerprint {
context(_: BytecodePatchContext)
internal fun ClassDef.getMdxSeekRelativeMethod() = firstMethodDeclaratively {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
// Return type is boolean up to 19.39, and void with 19.39+.
parameters("J", "L")
parameterTypes("J", "L")
opcodes(
Opcode.IGET_OBJECT,
Opcode.INVOKE_INTERFACE,
@@ -109,91 +101,85 @@ internal val mdxSeekRelativeFingerprint = fingerprint {
}
/**
* Matches using class found in [playerInitFingerprint].
* Matches using class found in [playVideoCheckVideoStreamingDataResponseMethod].
*/
internal val seekRelativeFingerprint = fingerprint {
context(_: BytecodePatchContext)
internal fun ClassDef.getSeekRelativeMethod() = firstMutableMethodDeclaratively {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
// Return type is boolean up to 19.39, and void with 19.39+.
parameters("J", "L")
parameterTypes("J", "L")
opcodes(
Opcode.ADD_LONG_2ADDR,
Opcode.INVOKE_VIRTUAL,
)
}
internal val videoEndFingerprint = fingerprint {
internal val videoEndMethodMatch = firstMethodComposite {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("Z")
parameters("J", "L")
returnType("Z")
parameterTypes("J", "L")
instructions(
methodCall(
parameters = listOf(),
returnType = "V"
),
literal(45368273L, location = MatchAfterWithin(5)),
addString("Attempting to seek when video is not playing"),
method { parameterTypes.isEmpty() && returnType == "V" },
afterAtMost(5, 45368273L()),
"Attempting to seek when video is not playing"(),
)
}
/**
* Resolves with the class found in [videoQualityChangedFingerprint].
* Matches with the class found in [videoQualityChangedMethodMatch].
*/
internal val playbackSpeedMenuSpeedChangedFingerprint = fingerprint {
internal val playbackSpeedMenuSpeedChangedMethodMatch = firstMethodComposite {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("L")
parameters("L")
instructions(
fieldAccess(opcode = Opcode.IGET, type = "F")
)
returnType("L")
parameterTypes("L")
instructions(allOf(Opcode.IGET(), field { type == "F" }))
}
internal val playbackSpeedClassFingerprint = fingerprint {
internal val BytecodePatchContext.playbackSpeedClassMethod by gettingFirstMutableMethodDeclaratively(
"PLAYBACK_RATE_MENU_BOTTOM_SHEET_FRAGMENT"
) {
accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC)
returns("L")
parameters("L")
opcodes(
Opcode.RETURN_OBJECT
)
strings("PLAYBACK_RATE_MENU_BOTTOM_SHEET_FRAGMENT")
returnType("L")
parameterTypes("L")
opcodes(Opcode.RETURN_OBJECT)
}
internal const val YOUTUBE_VIDEO_QUALITY_CLASS_TYPE = "Lcom/google/android/libraries/youtube/innertube/model/media/VideoQuality;"
internal const val YOUTUBE_VIDEO_QUALITY_CLASS_TYPE =
"Lcom/google/android/libraries/youtube/innertube/model/media/VideoQuality;"
/**
* YouTube 20.19 and lower.
*/
internal val videoQualityLegacyFingerprint = fingerprint {
internal val BytecodePatchContext.videoQualityLegacyMethod by gettingFirstMutableMethodDeclaratively {
definingClass(YOUTUBE_VIDEO_QUALITY_CLASS_TYPE)
accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR)
parameters(
parameterTypes(
"I", // Resolution.
"Ljava/lang/String;", // Human readable resolution: "480p", "1080p Premium", etc
"Z",
"L"
)
custom { _, classDef ->
classDef.type == YOUTUBE_VIDEO_QUALITY_CLASS_TYPE
}
}
internal val videoQualityFingerprint = fingerprint {
internal val BytecodePatchContext.videoQualityMethod by gettingFirstMutableMethodDeclaratively {
definingClass(YOUTUBE_VIDEO_QUALITY_CLASS_TYPE)
accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR)
parameters(
parameterTypes(
"I", // Resolution.
"L",
"Ljava/lang/String;", // Human readable resolution: "480p", "1080p Premium", etc
"Z",
"L"
)
custom { _, classDef ->
classDef.type == YOUTUBE_VIDEO_QUALITY_CLASS_TYPE
}
}
internal val videoQualitySetterFingerprint = fingerprint {
internal val BytecodePatchContext.videoQualitySetterMethod by gettingFirstMutableMethodDeclaratively(
"menu_item_video_quality"
) {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("V")
parameters("[L", "I", "Z")
returnType("V")
parameterTypes("[L", "I", "Z")
opcodes(
Opcode.IF_EQZ,
Opcode.INVOKE_VIRTUAL,
@@ -201,15 +187,15 @@ internal val videoQualitySetterFingerprint = fingerprint {
Opcode.INVOKE_VIRTUAL,
Opcode.IPUT_BOOLEAN,
)
strings("menu_item_video_quality")
}
/**
* Matches with the class found in [videoQualitySetterFingerprint].
* Matches with the class found in [videoQualitySetterMethod].
*/
internal val setVideoQualityFingerprint = fingerprint {
returns("V")
parameters("L")
context(_: BytecodePatchContext)
internal fun ClassDef.getSetVideoQualityMethod() = firstMutableMethodDeclaratively {
returnType("V")
parameterTypes("L")
opcodes(
Opcode.IGET_OBJECT,
Opcode.IPUT_OBJECT,

View File

@@ -1,18 +1,15 @@
package app.revanced.patches.youtube.video.information
import app.revanced.patcher.BytecodePatchContextClassDefMatching.firstMutableClassDef
import com.android.tools.smali.dexlib2.mutable.MutableClassDef
import com.android.tools.smali.dexlib2.mutable.MutableMethod
import com.android.tools.smali.dexlib2.mutable.MutableMethod.Companion.toMutable
import app.revanced.patcher.extensions.addInstruction
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.getInstruction
import app.revanced.patcher.classDef
import app.revanced.patcher.extensions.*
import app.revanced.patcher.firstMutableClassDef
import app.revanced.patcher.immutableClassDef
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
import app.revanced.patches.youtube.misc.playservice.is_20_19_or_greater
import app.revanced.patches.youtube.misc.playservice.is_20_20_or_greater
import app.revanced.patches.youtube.misc.playservice.versionCheckPatch
import app.revanced.patches.youtube.shared.videoQualityChangedFingerprint
import app.revanced.patches.youtube.shared.videoQualityChangedMethodMatch
import app.revanced.patches.youtube.video.playerresponse.Hook
import app.revanced.patches.youtube.video.playerresponse.addPlayerResponseMethodHook
import app.revanced.patches.youtube.video.playerresponse.playerResponseMethodHookPatch
@@ -37,6 +34,9 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference
import com.android.tools.smali.dexlib2.immutable.ImmutableMethod
import com.android.tools.smali.dexlib2.immutable.ImmutableMethodImplementation
import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter
import com.android.tools.smali.dexlib2.mutable.MutableClassDef
import com.android.tools.smali.dexlib2.mutable.MutableMethod
import com.android.tools.smali.dexlib2.mutable.MutableMethod.Companion.toMutable
import com.android.tools.smali.dexlib2.util.MethodUtil
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/VideoInformation;"
@@ -91,27 +91,26 @@ val videoInformationPatch = bytecodePatch(
)
apply {
playerInitMethod = playerInitFingerprint.classDef.methods.first { MethodUtil.isConstructor(it) }
with(playVideoCheckVideoStreamingDataResponseMethod) {
playerInitMethod = classDef.methods.first { MethodUtil.isConstructor(it) }
// Find the location of the first invoke-direct call and extract the register storing the 'this' object reference.
val initThisIndex = playerInitMethod.indexOfFirstInstructionOrThrow {
opcode == Opcode.INVOKE_DIRECT && getReference<MethodReference>()?.name == "<init>"
// Find the location of the first invoke-direct call
// and extract the register storing the 'this' object reference.
val initThisIndex = indexOfFirstInstructionOrThrow {
opcode == Opcode.INVOKE_DIRECT && getReference<MethodReference>()?.name == "<init>"
}
playerInitInsertRegister = getInstruction<FiveRegisterInstruction>(initThisIndex).registerC
playerInitInsertIndex = initThisIndex + 1
// Create extension interface methods.
addSeekInterfaceMethods(
playVideoCheckVideoStreamingDataResponseMethod.classDef,
classDef.getSeekMethod(),
classDef.getSeekRelativeMethod()
)
}
playerInitInsertRegister = playerInitMethod.getInstruction<FiveRegisterInstruction>(initThisIndex).registerC
playerInitInsertIndex = initThisIndex + 1
val seekFingerprintResultMethod = seekFingerprint.match(playerInitFingerprint.originalClassDef).method
val seekRelativeFingerprintResultMethod =
seekRelativeFingerprint.match(playerInitFingerprint.originalClassDef).method
// Create extension interface methods.
addSeekInterfaceMethods(
playerInitFingerprint.classDef,
seekFingerprintResultMethod,
seekRelativeFingerprintResultMethod,
)
with(mdxPlayerDirectorSetVideoStageFingerprint) {
with(mdxPlayerDirectorSetVideoStageMethod) {
mdxInitMethod = classDef.methods.first { MethodUtil.isConstructor(it) }
val initThisIndex = mdxInitMethod.indexOfFirstInstructionOrThrow {
@@ -123,31 +122,31 @@ val videoInformationPatch = bytecodePatch(
// Hook the MDX director for use through the extension.
onCreateHookMdx(EXTENSION_CLASS_DESCRIPTOR, "initializeMdx")
val mdxSeekFingerprintResultMethod = mdxSeekFingerprint.match(classDef).method
val mdxSeekRelativeFingerprintResultMethod = mdxSeekRelativeFingerprint.match(classDef).method
addSeekInterfaceMethods(classDef, mdxSeekFingerprintResultMethod, mdxSeekRelativeFingerprintResultMethod)
addSeekInterfaceMethods(
classDef,
classDef.getMdxSeekMethod(),
classDef.getMdxSeekRelativeMethod()
)
}
with(createVideoPlayerSeekbarFingerprint) {
val videoLengthMethodMatch = videoLengthFingerprint.match(originalClassDef)
with(createVideoPlayerSeekbarMethod) {
val videoLengthMethodMatch = videoLengthMethodMatch.match(immutableClassDef)
videoLengthMethodMatch.method.apply {
val videoLengthRegisterIndex = videoLengthMethodMatch.instructionMatches.last().index - 2
val videoLengthRegisterIndex = videoLengthMethodMatch.indices.last()
val videoLengthRegister = getInstruction<OneRegisterInstruction>(videoLengthRegisterIndex).registerA
val dummyRegisterForLong = videoLengthRegister + 1 // required for long values since they are wide
addInstruction(
videoLengthMethodMatch.instructionMatches.last().index,
videoLengthMethodMatch.indices.last(),
"invoke-static {v$videoLengthRegister, v$dummyRegisterForLong}, " +
"$EXTENSION_CLASS_DESCRIPTOR->setVideoLength(J)V",
)
}
}
videoEndFingerprint.let {
videoEndMethod = navigate(it.originalMethod).to(it.instructionMatches[0].index).stop()
}
videoEndMethod = navigate(videoEndMethodMatch.immutableMethod)
.to(videoEndMethodMatch.indices.first()).stop()
/*
* Inject call for video ids
@@ -170,9 +169,8 @@ val videoInformationPatch = bytecodePatch(
/*
* Set the video time method
*/
timeMethod = navigate(playerControllerSetTimeReferenceFingerprint.originalMethod)
.to(playerControllerSetTimeReferenceFingerprint.instructionMatches.first().index)
.stop()
timeMethod = navigate(playerControllerSetTimeReferenceMethodMatch.immutableMethod)
.to(playerControllerSetTimeReferenceMethodMatch.indices.first()).stop()
/*
* Hook the methods which set the time
@@ -182,7 +180,7 @@ val videoInformationPatch = bytecodePatch(
/*
* Hook the user playback speed selection.
*/
onPlaybackSpeedItemClickFingerprint.method.apply {
onPlaybackSpeedItemClickMethod.apply {
val speedSelectionValueInstructionIndex = indexOfFirstInstructionOrThrow(Opcode.IGET)
legacySpeedSelectionInsertMethod = this
@@ -203,7 +201,7 @@ val videoInformationPatch = bytecodePatch(
setPlaybackSpeedMethodIndex = 0
// Add override playback speed method.
onPlaybackSpeedItemClickFingerprint.classDef.methods.add(
onPlaybackSpeedItemClickMethod.classDef.methods.add(
ImmutableMethod(
definingClass,
"overridePlaybackSpeed",
@@ -240,7 +238,7 @@ val videoInformationPatch = bytecodePatch(
)
}
playbackSpeedClassFingerprint.method.apply {
playbackSpeedClassMethod.apply {
val index = indexOfFirstInstructionOrThrow(Opcode.RETURN_OBJECT)
val register = getInstruction<OneRegisterInstruction>(index).registerA
val playbackSpeedClass = this.returnType
@@ -270,11 +268,9 @@ val videoInformationPatch = bytecodePatch(
}
// Handle new playback speed menu.
playbackSpeedMenuSpeedChangedFingerprint.match(
videoQualityChangedFingerprint.originalClassDef,
).let {
playbackSpeedMenuSpeedChangedMethodMatch.match(videoQualityChangedMethodMatch.immutableClassDef).let {
it.method.apply {
val index = it.instructionMatches.first().index
val index = it.indices.first()
speedSelectionInsertMethod = this
speedSelectionInsertIndex = index + 1
@@ -282,10 +278,10 @@ val videoInformationPatch = bytecodePatch(
}
}
(if (is_20_19_or_greater) videoQualityFingerprint else videoQualityLegacyFingerprint).let {
(if (is_20_19_or_greater) videoQualityMethod else videoQualityLegacyMethod).apply {
// Fix bad data used by YouTube.
val nameRegister = if (is_20_20_or_greater) "p3" else "p2"
it.method.addInstructions(
addInstructions(
0,
"""
invoke-static { $nameRegister, p1 }, $EXTENSION_CLASS_DESCRIPTOR->fixVideoQualityResolution(Ljava/lang/String;I)I
@@ -294,7 +290,7 @@ val videoInformationPatch = bytecodePatch(
)
// Add methods to access obfuscated quality fields.
it.classDef.apply {
classDef.apply {
methods.add(
ImmutableMethod(
type,
@@ -349,16 +345,13 @@ val videoInformationPatch = bytecodePatch(
}
// Detect video quality changes and override the current quality.
setVideoQualityFingerprint.match(
videoQualitySetterFingerprint.originalClassDef
).let { match ->
videoQualitySetterMethod.immutableClassDef.getSetVideoQualityMethod().let {
it
// This instruction refers to the field with the type that contains the setQuality method.
val onItemClickListenerClassReference = match.method
.getInstruction<ReferenceInstruction>(0).reference
val setQualityFieldReference = match.method
.getInstruction<ReferenceInstruction>(1).reference as FieldReference
val onItemClickListenerClassReference = it.getInstruction<ReferenceInstruction>(0).reference
val setQualityFieldReference = it.getInstruction<ReferenceInstruction>(1).fieldReference!!
firstClassDefMutable(setQualityFieldReference.type).apply {
firstMutableClassDef(setQualityFieldReference.type).apply {
// Add interface and helper methods to allow extension code to call obfuscated methods.
interfaces.add(EXTENSION_VIDEO_QUALITY_MENU_INTERFACE)
@@ -390,7 +383,7 @@ val videoInformationPatch = bytecodePatch(
)
}
videoQualitySetterFingerprint.method.addInstructions(
videoQualitySetterMethod.addInstructions(
0,
"""
# Get object instance to invoke setQuality method.

View File

@@ -9,10 +9,9 @@ import app.revanced.patches.shared.misc.settings.preference.ListPreference
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
import app.revanced.patches.youtube.misc.playertype.playerTypeHookPatch
import app.revanced.patches.youtube.misc.playservice.is_20_20_or_greater
import app.revanced.patches.youtube.misc.playservice.versionCheckPatch
import app.revanced.patches.youtube.misc.settings.settingsPatch
import app.revanced.patches.youtube.shared.videoQualityChangedFingerprint
import app.revanced.patches.youtube.shared.videoQualityChangedMethodMatch
import app.revanced.patches.youtube.video.information.onCreateHook
import app.revanced.patches.youtube.video.information.videoInformationPatch
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
@@ -33,32 +32,34 @@ val rememberVideoQualityPatch = bytecodePatch {
apply {
addResources("youtube", "video.quality.rememberVideoQualityPatch")
settingsMenuVideoQualityGroup.addAll(listOf(
ListPreference(
key = "revanced_video_quality_default_mobile",
entriesKey = "revanced_video_quality_default_entries",
entryValuesKey = "revanced_video_quality_default_entry_values"
),
ListPreference(
key = "revanced_video_quality_default_wifi",
entriesKey = "revanced_video_quality_default_entries",
entryValuesKey = "revanced_video_quality_default_entry_values"
),
SwitchPreference("revanced_remember_video_quality_last_selected"),
settingsMenuVideoQualityGroup.addAll(
listOf(
ListPreference(
key = "revanced_video_quality_default_mobile",
entriesKey = "revanced_video_quality_default_entries",
entryValuesKey = "revanced_video_quality_default_entry_values"
),
ListPreference(
key = "revanced_video_quality_default_wifi",
entriesKey = "revanced_video_quality_default_entries",
entryValuesKey = "revanced_video_quality_default_entry_values"
),
SwitchPreference("revanced_remember_video_quality_last_selected"),
ListPreference(
key = "revanced_shorts_quality_default_mobile",
entriesKey = "revanced_shorts_quality_default_entries",
entryValuesKey = "revanced_shorts_quality_default_entry_values",
),
ListPreference(
key = "revanced_shorts_quality_default_wifi",
entriesKey = "revanced_shorts_quality_default_entries",
entryValuesKey = "revanced_shorts_quality_default_entry_values"
),
SwitchPreference("revanced_remember_shorts_quality_last_selected"),
SwitchPreference("revanced_remember_video_quality_last_selected_toast")
))
ListPreference(
key = "revanced_shorts_quality_default_mobile",
entriesKey = "revanced_shorts_quality_default_entries",
entryValuesKey = "revanced_shorts_quality_default_entry_values",
),
ListPreference(
key = "revanced_shorts_quality_default_wifi",
entriesKey = "revanced_shorts_quality_default_entries",
entryValuesKey = "revanced_shorts_quality_default_entry_values"
),
SwitchPreference("revanced_remember_shorts_quality_last_selected"),
SwitchPreference("revanced_remember_video_quality_last_selected_toast")
)
)
onCreateHook(EXTENSION_CLASS_DESCRIPTOR, "newVideoStarted")
@@ -71,14 +72,13 @@ val rememberVideoQualityPatch = bytecodePatch {
)
// Inject a call to remember the user selected quality for regular videos.
videoQualityChangedFingerprint.method.apply {
val index = videoQualityChangedFingerprint.instructionMatches[3].index
val register = getInstruction<TwoRegisterInstruction>(index).registerA
videoQualityChangedMethodMatch.let { match ->
val index = match.indices[3]
val register = match.method.getInstruction<TwoRegisterInstruction>(index).registerA
addInstruction(
match.method.addInstruction(
index + 1,
"invoke-static { v$register }, " +
"$EXTENSION_CLASS_DESCRIPTOR->userChangedQuality(I)V",
"invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->userChangedQuality(I)V",
)
}
}

View File

@@ -1,7 +1,7 @@
package app.revanced.util
import app.revanced.patcher.BytecodePatchContextClassDefMatching.firstMutableClassDef
import app.revanced.patcher.BytecodePatchContextClassDefMatching.firstMutableClassDefOrNull
import app.revanced.patcher.firstMutableClassDef
import app.revanced.patcher.firstMutableClassDefOrNull
import app.revanced.patcher.FingerprintBuilder
import app.revanced.patcher.extensions.*
import app.revanced.patcher.patch.BytecodePatchContext