feat: Modernise APIs (#6476)

This commit is contained in:
oSumAtrIX
2026-01-17 18:28:00 +01:00
committed by GitHub
104 changed files with 882 additions and 943 deletions

View File

@@ -1,14 +1,11 @@
package app.revanced.patches.finanzonline.detection.root
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patches.shared.PATCH_DESCRIPTION_REMOVE_ROOT_DETECTION
import app.revanced.patches.shared.PATCH_NAME_REMOVE_ROOT_DETECTION
import app.revanced.patcher.patch.creatingBytecodePatch
@Suppress("unused")
val rootDetectionPatch = bytecodePatch(
name = PATCH_NAME_REMOVE_ROOT_DETECTION,
description = PATCH_DESCRIPTION_REMOVE_ROOT_DETECTION,
@Suppress("unused", "ObjectPropertyName")
val `Remove root detection` by creatingBytecodePatch(
description = "Removes the check for root permissions and unlocked bootloader.",
) {
compatibleWith("at.gv.bmf.bmf2go")

View File

@@ -3,9 +3,8 @@ package app.revanced.patches.instagram.hide.navigation
import app.revanced.patcher.extensions.getInstruction
import app.revanced.patcher.fingerprint
import app.revanced.patcher.patch.booleanOption
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.patch.creatingBytecodePatch
import app.revanced.patches.instagram.misc.extension.sharedExtensionPatch
import app.revanced.patches.shared.PATCH_NAME_HIDE_NAVIGATION_BUTTONS
import app.revanced.util.addInstructionsAtControlFlowLabel
import app.revanced.util.findFreeRegister
import app.revanced.util.getReference
@@ -19,9 +18,8 @@ import java.util.logging.Logger
private const val EXTENSION_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/instagram/hide/navigation/HideNavigationButtonsPatch;"
@Suppress("unused")
val hideNavigationButtonsPatch = bytecodePatch(
name = PATCH_NAME_HIDE_NAVIGATION_BUTTONS,
@Suppress("unused", "ObjectPropertyName")
val `Hide navigation buttons` by creatingBytecodePatch(
description = "Hides navigation bar buttons, such as the Reels and Create button.",
use = false
) {
@@ -66,7 +64,7 @@ val hideNavigationButtonsPatch = bytecodePatch(
)
apply {
if (!hideHome!! &&!hideReels!! && !hideDirect!! && !hideSearch!! && !hideProfile!! && !hideCreate!!) {
if (!hideHome!! && !hideReels!! && !hideDirect!! && !hideSearch!! && !hideProfile!! && !hideCreate!!) {
return@apply Logger.getLogger(this::class.java.name).warning(
"No hide navigation buttons options are enabled. No changes made."
)

View File

@@ -5,8 +5,6 @@ import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.patch.stringOption
import app.revanced.patches.instagram.misc.extension.sharedExtensionPatch
import app.revanced.patches.instagram.misc.share.editShareLinksPatch
import app.revanced.patches.shared.PATCH_DESCRIPTION_CHANGE_LINK_SHARING_DOMAIN
import app.revanced.patches.shared.PATCH_NAME_CHANGE_LINK_SHARING_DOMAIN
import app.revanced.util.returnEarly
internal const val EXTENSION_CLASS_DESCRIPTOR =
@@ -14,8 +12,8 @@ internal const val EXTENSION_CLASS_DESCRIPTOR =
@Suppress("unused")
val changeLinkSharingDomainPatch = bytecodePatch(
name = PATCH_NAME_CHANGE_LINK_SHARING_DOMAIN,
description = PATCH_DESCRIPTION_CHANGE_LINK_SHARING_DOMAIN,
name = "Change link sharing domain",
description = "Replaces the domain name of shared links.",
use = false
) {
compatibleWith("com.instagram.android")

View File

@@ -1,19 +1,16 @@
package app.revanced.patches.instagram.misc.share.privacy
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.patch.creatingBytecodePatch
import app.revanced.patches.instagram.misc.extension.sharedExtensionPatch
import app.revanced.patches.instagram.misc.share.editShareLinksPatch
import app.revanced.patches.shared.PATCH_DESCRIPTION_SANITIZE_SHARING_LINKS
import app.revanced.patches.shared.PATCH_NAME_SANITIZE_SHARING_LINKS
private const val EXTENSION_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/instagram/misc/share/privacy/SanitizeSharingLinksPatch;"
@Suppress("unused")
val sanitizeSharingLinksPatch = bytecodePatch(
name = PATCH_NAME_SANITIZE_SHARING_LINKS,
description = PATCH_DESCRIPTION_SANITIZE_SHARING_LINKS,
@Suppress("unused", "ObjectPropertyName")
val `Sanitize sharing links` by creatingBytecodePatch(
description = "Removes the tracking query parameters from shared links.",
) {
compatibleWith("com.instagram.android")

View File

@@ -7,7 +7,7 @@ import app.revanced.util.returnEarly
val signatureCheckPatch = bytecodePatch(
name = "Disable signature check",
description = "Disables the signature check that can cause the app to crash on startup. " +
"Including this patch may cause issues with sharing or opening external Instagram links.",
"Using this patch may cause issues with sharing or opening external Instagram links.",
use = false
) {
compatibleWith("com.instagram.android")

View File

@@ -1,11 +1,15 @@
package app.revanced.patches.music.misc.settings
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 val googleApiActivityFingerprint = fingerprint {
returns("V")
parameters("Landroid/os/Bundle;")
custom { method, classDef ->
classDef.endsWith("GoogleApiActivity;") && method.name == "onCreate"
}
internal val BytecodePatchContext.googleApiActivityMethod by gettingFirstMutableMethodDeclaratively {
name("onCreate")
definingClass("GoogleApiActivity;"::endsWith)
returnType("V")
parameterTypes("Landroid/os/Bundle;")
}

View File

@@ -1,5 +1,6 @@
package app.revanced.patches.music.misc.settings
import app.revanced.patcher.classDef
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.patch.resourcePatch
import app.revanced.patches.all.misc.packagename.setOrGetFallbackPackageName
@@ -65,7 +66,7 @@ private val settingsResourcePatch = resourcePatch {
}
val settingsPatch = bytecodePatch(
description = "Adds settings for ReVanced to YouTube Music.",
description = "Adds settings for ReVanced to YouTube Music."
) {
dependsOn(
sharedExtensionPatch,
@@ -100,8 +101,8 @@ val settingsPatch = bytecodePatch(
)
modifyActivityForSettingsInjection(
googleApiActivityFingerprint.classDef,
googleApiActivityFingerprint.method,
googleApiActivityMethod.classDef,
googleApiActivityMethod,
GOOGLE_API_ACTIVITY_HOOK_CLASS_DESCRIPTOR,
true
)

View File

@@ -21,12 +21,14 @@ var is_8_11_or_greater: Boolean by Delegates.notNull()
var is_8_15_or_greater: Boolean by Delegates.notNull()
private set
@Suppress("unused")
val versionCheckPatch = resourcePatch(
description = "Uses the Play Store service version to find the major/minor version of the YouTube Music target app.",
description = "Uses the Play Store service version to find the major/minor version of the YouTube Music target app."
) {
apply {
// The app version is missing from the decompiled manifest,
// so instead use the Google Play services version and compare against specific releases.
// This requires ResourcePatchContext, which creatingResourcePatch provides.
val playStoreServicesVersion = findPlayStoreServicesVersion()
// All bug fix releases always seem to use the same play store version as the minor version.

View File

@@ -1,8 +1,9 @@
package app.revanced.patches.myexpenses.misc.pro
import app.revanced.patcher.fingerprint
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.returnType
internal val isEnabledFingerprint = fingerprint {
returns("Z")
strings("feature", "feature.licenceStatus")
internal val BytecodePatchContext.isEnabledMethod by gettingFirstMutableMethodDeclaratively("feature", "feature.licenceStatus") {
returnType("Z")
}

View File

@@ -1,16 +1,14 @@
package app.revanced.patches.myexpenses.misc.pro
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.patch.creatingBytecodePatch
@Suppress("unused")
val unlockProPatch = bytecodePatch(
name = "Unlock pro",
) {
@Suppress("unused", "ObjectPropertyName")
val `Unlock pro` by creatingBytecodePatch {
compatibleWith("org.totschnig.myexpenses"("3.4.9"))
apply {
isEnabledFingerprint.method.addInstructions(
isEnabledMethod.addInstructions(
0,
"""
const/4 v0, 0x1

View File

@@ -1,19 +1,22 @@
package app.revanced.patches.myfitnesspal.ads
import app.revanced.patcher.fingerprint
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.accessFlags
import app.revanced.patcher.definingClass
import app.revanced.patcher.name
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.returnType
import com.android.tools.smali.dexlib2.AccessFlags
internal val isPremiumUseCaseImplFingerprint = fingerprint {
internal val BytecodePatchContext.isPremiumUseCaseImplMethod by gettingFirstMutableMethodDeclaratively {
name("doWork")
definingClass("IsPremiumUseCaseImpl;"::endsWith)
accessFlags(AccessFlags.PUBLIC)
custom { method, classDef ->
classDef.endsWith("IsPremiumUseCaseImpl;") && method.name == "doWork"
}
}
internal val mainActivityNavigateToNativePremiumUpsellFingerprint = fingerprint {
internal val BytecodePatchContext.mainActivityNavigateToNativePremiumUpsellMethod by gettingFirstMutableMethodDeclaratively {
name("navigateToNativePremiumUpsell")
definingClass("MainActivity;"::endsWith)
accessFlags(AccessFlags.PRIVATE, AccessFlags.FINAL)
returns("V")
custom { method, classDef ->
classDef.endsWith("MainActivity;") && method.name == "navigateToNativePremiumUpsell"
}
returnType("V")
}

View File

@@ -1,18 +1,17 @@
package app.revanced.patches.myfitnesspal.ads
import app.revanced.patcher.extensions.replaceInstructions
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.patch.creatingBytecodePatch
@Suppress("unused")
val hideAdsPatch = bytecodePatch(
name = "Hide ads",
description = "Hides most of the ads across the app.",
@Suppress("unused", "ObjectPropertyName")
val `Hide ads` by creatingBytecodePatch(
description = "Hides most of the ads across the app."
) {
compatibleWith("com.myfitnesspal.android"("24.14.2"))
apply {
// Overwrite the premium status specifically for ads.
isPremiumUseCaseImplFingerprint.method.replaceInstructions(
isPremiumUseCaseImplMethod.replaceInstructions(
0,
"""
sget-object v0, Ljava/lang/Boolean;->TRUE:Ljava/lang/Boolean;
@@ -22,7 +21,7 @@ val hideAdsPatch = bytecodePatch(
// Prevent the premium upsell dialog from showing when the main activity is launched.
// In other places that are premium-only the dialog will still show.
mainActivityNavigateToNativePremiumUpsellFingerprint.method.replaceInstructions(
mainActivityNavigateToNativePremiumUpsellMethod.replaceInstructions(
0,
"return-void",
)

View File

@@ -1,11 +1,10 @@
package app.revanced.patches.netguard.broadcasts.removerestriction
import app.revanced.patcher.patch.resourcePatch
import app.revanced.patcher.patch.creatingResourcePatch
import org.w3c.dom.Element
@Suppress("unused")
val removeBroadcastsRestrictionPatch = resourcePatch(
name = "Remove broadcasts restriction",
@Suppress("unused", "ObjectPropertyName")
val `Remove broadcasts restriction` by creatingResourcePatch(
description = "Enables starting/stopping NetGuard via broadcasts.",
) {
compatibleWith("eu.faircode.netguard")

View File

@@ -1,44 +1,41 @@
package app.revanced.patches.nunl.ads
import app.revanced.patcher.fingerprint
import app.revanced.patcher.*
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.patch.BytecodePatchContext
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
internal val jwPlayerConfigFingerprint = fingerprint {
internal val BytecodePatchContext.jwPlayerConfigMethod by gettingFirstMutableMethodDeclaratively {
name("advertisingConfig")
definingClass($$"Lcom/jwplayer/pub/api/configuration/PlayerConfig$Builder;")
accessFlags(AccessFlags.PUBLIC)
custom { methodDef, classDef ->
classDef.type == "Lcom/jwplayer/pub/api/configuration/PlayerConfig${'$'}Builder;" && methodDef.name == "advertisingConfig"
}
}
internal val screenMapperFingerprint = fingerprint {
internal val screenMapperMethodMatch = firstMethodComposite {
name("map")
definingClass("Lnl/nu/android/bff/data/mappers/ScreenMapper;")
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("Lnl/nu/android/bff/domain/models/screen/ScreenEntity;")
parameters("Lnl/nu/performance/api/client/objects/Screen;")
opcodes(
Opcode.MOVE_RESULT_OBJECT,
Opcode.IF_EQZ,
Opcode.CHECK_CAST
returnType("Lnl/nu/android/bff/domain/models/screen/ScreenEntity;")
parameterTypes("Lnl/nu/performance/api/client/objects/Screen;")
instructions(
Opcode.MOVE_RESULT_OBJECT(),
Opcode.IF_EQZ(),
Opcode.CHECK_CAST(),
)
custom { methodDef, classDef ->
classDef.type == "Lnl/nu/android/bff/data/mappers/ScreenMapper;" && methodDef.name == "map"
}
}
internal val nextPageRepositoryImplFingerprint = fingerprint {
internal val nextPageRepositoryImplMethodMatch = firstMethodComposite {
accessFlags(AccessFlags.PRIVATE, AccessFlags.FINAL)
returns("Lnl/nu/android/bff/domain/models/Page;")
parameters("Lnl/nu/performance/api/client/PacResponse;", "Ljava/lang/String;")
returnType("Lnl/nu/android/bff/domain/models/Page;")
parameterTypes("Lnl/nu/performance/api/client/PacResponse;", "Ljava/lang/String;")
opcodes(
Opcode.MOVE_RESULT_OBJECT,
Opcode.IF_EQZ,
Opcode.CHECK_CAST
definingClass("Lnl/nu/android/bff/data/repositories/NextPageRepositoryImpl;")
name("mapToPage")
instructions(
Opcode.MOVE_RESULT_OBJECT(),
Opcode.IF_EQZ(),
Opcode.CHECK_CAST(),
)
custom { methodDef, classDef ->
classDef.type == "Lnl/nu/android/bff/data/repositories/NextPageRepositoryImpl;" && methodDef.name == "mapToPage"
}
}

View File

@@ -3,15 +3,14 @@ package app.revanced.patches.nunl.ads
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.getInstruction
import app.revanced.patcher.extensions.removeInstructions
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.patch.creatingBytecodePatch
import app.revanced.patches.shared.misc.extension.sharedExtensionPatch
import app.revanced.util.indexOfFirstInstructionOrThrow
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
@Suppress("unused")
val hideAdsPatch = bytecodePatch(
name = "Hide ads",
@Suppress("ObjectPropertyName")
val `Hide ads` by creatingBytecodePatch(
description = "Hide ads and sponsored articles in list pages and remove pre-roll ads on videos.",
) {
compatibleWith("nl.sanomamedia.android.nu")
@@ -21,26 +20,24 @@ val hideAdsPatch = bytecodePatch(
apply {
// Disable video pre-roll ads.
// Whenever the app tries to define the advertising config for JWPlayer, don't set the advertising config and directly return.
val iputInstructionIndex = jwPlayerConfigFingerprint.method.indexOfFirstInstructionOrThrow(Opcode.IPUT_OBJECT)
jwPlayerConfigFingerprint.method.removeInstructions(iputInstructionIndex, 1)
val iputInstructionIndex = jwPlayerConfigMethod.indexOfFirstInstructionOrThrow(Opcode.IPUT_OBJECT)
jwPlayerConfigMethod.removeInstructions(iputInstructionIndex, 1)
// Filter injected content from API calls out of lists.
arrayOf(screenMapperFingerprint, nextPageRepositoryImplFingerprint).forEach {
arrayOf(screenMapperMethodMatch, nextPageRepositoryImplMethodMatch).forEach { match ->
// Index of instruction moving result of BlockPage;->getBlocks(...).
val moveGetBlocksResultObjectIndex = it.patternMatch.startIndex
it.method.apply {
val moveInstruction = getInstruction<OneRegisterInstruction>(moveGetBlocksResultObjectIndex)
val moveGetBlocksResultObjectIndex = match.indices.first()
val moveInstruction = match.method.getInstruction<OneRegisterInstruction>(moveGetBlocksResultObjectIndex)
val listRegister = moveInstruction.registerA
val listRegister = moveInstruction.registerA
// Add instruction after moving List<Block> to register and then filter this List<Block> in place.
addInstructions(
moveGetBlocksResultObjectIndex + 1,
"""
// Add instruction after moving List<Block> to register and then filter this List<Block> in place.
match.method.addInstructions(
moveGetBlocksResultObjectIndex + 1,
"""
invoke-static { v$listRegister }, Lapp/revanced/extension/nunl/ads/HideAdsPatch;->filterAds(Ljava/util/List;)V
""",
)
}
)
}
}
}

View File

@@ -1,20 +1,20 @@
package app.revanced.patches.nunl.firebase
import app.revanced.patcher.fingerprint
import app.revanced.patcher.*
import app.revanced.patcher.BytecodePatchContextMethodMatching.firstMutableMethodDeclaratively
import app.revanced.patcher.patch.BytecodePatchContext
import com.android.tools.smali.dexlib2.AccessFlags
internal val getFingerprintHashForPackageFingerprints = arrayOf(
internal fun BytecodePatchContext.getFingerprintHashForPackageMethods() = arrayOf(
"Lcom/google/firebase/installations/remote/FirebaseInstallationServiceClient;",
"Lcom/google/firebase/remoteconfig/internal/ConfigFetchHttpClient;",
"Lcom/google/firebase/remoteconfig/internal/ConfigRealtimeHttpClient;"
).map { className ->
fingerprint {
).map {
firstMutableMethodDeclaratively {
name("getFingerprintHashForPackage")
definingClass(it)
accessFlags(AccessFlags.PRIVATE)
parameters()
returns("Ljava/lang/String;")
custom { methodDef, classDef ->
classDef.type == className && methodDef.name == "getFingerprintHashForPackage"
}
returnType("Ljava/lang/String;")
parameterTypes()
}
}

View File

@@ -1,18 +1,17 @@
package app.revanced.patches.nunl.firebase
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.patch.creatingBytecodePatch
import app.revanced.util.returnEarly
@Suppress("unused")
val spoofCertificatePatch = bytecodePatch(
name = "Spoof certificate",
@Suppress("unused", "ObjectPropertyName")
val `Spoof certificate` by creatingBytecodePatch(
description = "Spoofs the X-Android-Cert header to allow push messages.",
) {
compatibleWith("nl.sanomamedia.android.nu")
apply {
getFingerprintHashForPackageFingerprints.forEach { fingerprint ->
fingerprint.method.returnEarly("eae41fc018df2731a9b6ae1ac327da44a288667b")
getFingerprintHashForPackageMethods().forEach {
it.returnEarly("eae41fc018df2731a9b6ae1ac327da44a288667b")
}
}
}

View File

@@ -1,12 +1,15 @@
package app.revanced.patches.openinghours.misc.fix.crash
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 val setPlaceFingerprint = fingerprint {
returns("V")
parameters("Lde/simon/openinghours/models/Place;")
custom { method, _ ->
method.name == "setPlace" &&
method.definingClass == "Lde/simon/openinghours/views/custom/PlaceCard;"
}
internal val BytecodePatchContext.setPlaceMethod by gettingFirstMutableMethodDeclaratively {
name("setPlace")
definingClass("Lde/simon/openinghours/views/custom/PlaceCard;")
returnType("V")
parameterTypes("Lde/simon/openinghours/models/Place;")
}

View File

@@ -1,9 +1,9 @@
package app.revanced.patches.openinghours.misc.fix.crash
import app.revanced.patcher.extensions.instructions
import app.revanced.patcher.extensions.replaceInstruction
import app.revanced.patcher.extensions.newLabel
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.extensions.replaceInstruction
import app.revanced.patcher.patch.creatingBytecodePatch
import app.revanced.util.getReference
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction21t
@@ -11,14 +11,14 @@ import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.Instruction
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
@Suppress("unused")
val fixCrashPatch = bytecodePatch(
name = "Fix crash",
@Suppress("unused", "ObjectPropertyName")
val `Fix crash` by creatingBytecodePatch(
description = "Fixes a crash when opening a place.",
) {
compatibleWith("de.simon.openinghours"("1.0"))
apply {
val indexedInstructions = setPlaceFingerprint.method.instructions.withIndex().toList()
val indexedInstructions = setPlaceMethod.instructions.withIndex().toList()
/**
* This function replaces all `checkNotNull` instructions in the integer interval
@@ -27,7 +27,7 @@ val fixCrashPatch = bytecodePatch(
* the value is indeed null, we jump to a newly created label at `endIndex + 1`.
*/
fun avoidNullPointerException(startIndex: Int, endIndex: Int) {
val continueLabel = setPlaceFingerprint.method.newLabel(endIndex + 1)
val continueLabel = setPlaceMethod.newLabel(endIndex + 1)
for (index in startIndex..endIndex) {
val instruction = indexedInstructions[index].value
@@ -39,7 +39,7 @@ val fixCrashPatch = bytecodePatch(
val checkNotNullInstruction = instruction as FiveRegisterInstruction
val originalRegister = checkNotNullInstruction.registerC
setPlaceFingerprint.method.replaceInstruction(
setPlaceMethod.replaceInstruction(
index,
BuilderInstruction21t(
Opcode.IF_EQZ,

View File

@@ -1,13 +1,16 @@
package app.revanced.patches.orfon.detection.root
import app.revanced.patcher.fingerprint
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.accessFlags
import app.revanced.patcher.definingClass
import app.revanced.patcher.name
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.returnType
import com.android.tools.smali.dexlib2.AccessFlags
internal val isDeviceRootedFingeprint = fingerprint {
internal val BytecodePatchContext.isDeviceRootedMethod by gettingFirstMutableMethodDeclaratively {
name("isDeviceRooted")
definingClass("/RootChecker;"::endsWith)
accessFlags(AccessFlags.PUBLIC)
returns("Z")
custom { method, classDef ->
method.name == "isDeviceRooted" &&
classDef.endsWith("/RootChecker;")
}
returnType("Z")
}

View File

@@ -1,18 +1,15 @@
package app.revanced.patches.orfon.detection.root
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patches.shared.PATCH_DESCRIPTION_REMOVE_ROOT_DETECTION
import app.revanced.patches.shared.PATCH_NAME_REMOVE_ROOT_DETECTION
import app.revanced.patcher.patch.creatingBytecodePatch
import app.revanced.util.returnEarly
@Suppress("unused")
val removeRootDetectionPatch = bytecodePatch(
name = PATCH_NAME_REMOVE_ROOT_DETECTION,
description = PATCH_DESCRIPTION_REMOVE_ROOT_DETECTION
@Suppress("unused", "ObjectPropertyName")
val `Remove root detection` by creatingBytecodePatch(
description = "Removes the check for root permissions and unlocked bootloader."
) {
compatibleWith("com.nousguide.android.orftvthek")
apply {
isDeviceRootedFingeprint.method.returnEarly(false)
isDeviceRootedMethod.returnEarly(false)
}
}
}

View File

@@ -1,16 +1,14 @@
package app.revanced.patches.pandora.ads
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.patch.creatingBytecodePatch
import app.revanced.util.returnEarly
@Suppress("unused")
val disableAudioAdsPatch = bytecodePatch(
name = "Disable audio ads",
) {
@Suppress("unused", "ObjectPropertyName")
val `Disable Audio Ads` by creatingBytecodePatch {
compatibleWith("com.pandora.android")
apply {
getIsAdSupportedFingerprint.method.returnEarly(false)
requestAudioAdFingerprint.method.returnEarly()
getIsAdSupportedMethod.returnEarly(false)
requestAudioAdMethod.returnEarly()
}
}

View File

@@ -1,15 +1,16 @@
package app.revanced.patches.pandora.ads
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.patch.BytecodePatchContext
internal val getIsAdSupportedFingerprint = fingerprint {
custom { method, classDef ->
method.name == "getIsAdSupported" && classDef.endsWith("UserData;")
}
internal val BytecodePatchContext.getIsAdSupportedMethod by gettingFirstMutableMethodDeclaratively {
name("getIsAdSupported")
definingClass("UserData;")
}
internal val requestAudioAdFingerprint = fingerprint {
custom { method, classDef ->
method.name == "requestAudioAdFromAdSDK" && classDef.endsWith("ContentServiceOpsImpl;")
}
}
internal val BytecodePatchContext.requestAudioAdMethod by gettingFirstMutableMethodDeclaratively {
name("requestAudioAdFromAdSDK")
definingClass("ContentServiceOpsImpl;"::endsWith)
}

View File

@@ -1,15 +1,13 @@
package app.revanced.patches.pandora.misc
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.patch.creatingBytecodePatch
import app.revanced.util.returnEarly
@Suppress("unused")
val enableUnlimitedSkipsPatch = bytecodePatch(
name = "Enable unlimited skips",
) {
@Suppress("unused", "ObjectPropertyName")
val `Enable unlimited skips` by creatingBytecodePatch {
compatibleWith("com.pandora.android")
apply {
skipLimitBehaviorFingerprint.method.returnEarly("unlimited")
getSkipLimitBehaviorMethod.returnEarly("unlimited")
}
}

View File

@@ -1,9 +1,11 @@
package app.revanced.patches.pandora.misc
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.patch.BytecodePatchContext
internal val skipLimitBehaviorFingerprint = fingerprint {
custom { method, classDef ->
method.name == "getSkipLimitBehavior" && classDef.endsWith("UserData;")
}
}
internal val BytecodePatchContext.getSkipLimitBehaviorMethod by gettingFirstMutableMethodDeclaratively {
name("getSkipLimitBehavior")
definingClass("UserData;"::endsWith)
}

View File

@@ -1,10 +1,12 @@
package app.revanced.patches.peacocktv.ads
import app.revanced.patcher.fingerprint
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.accessFlags
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.returnType
import com.android.tools.smali.dexlib2.AccessFlags
internal val mediaTailerAdServiceFingerprint = fingerprint {
internal val BytecodePatchContext.mediaTailerAdServiceMethod by gettingFirstMutableMethodDeclaratively("Could not build MT Advertising service") {
accessFlags(AccessFlags.PUBLIC)
returns("Ljava/lang/Object")
strings("Could not build MT Advertising service")
returnType("Ljava/lang/Object;")
}

View File

@@ -1,16 +1,15 @@
package app.revanced.patches.peacocktv.ads
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.patch.creatingBytecodePatch
import app.revanced.util.returnEarly
@Suppress("unused")
val hideAdsPatch = bytecodePatch(
name = "Hide ads",
description = "Hides all video ads.",
@Suppress("unused", "ObjectPropertyName")
val `Hide ads` by creatingBytecodePatch(
description = "Hides all video ads."
) {
compatibleWith("com.peacocktv.peacockandroid")
apply {
mediaTailerAdServiceFingerprint.method.returnEarly(false)
mediaTailerAdServiceMethod.returnEarly(false)
}
}

View File

@@ -1,21 +1,26 @@
package app.revanced.patches.photomath.detection.deviceid
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.instructions
import app.revanced.patcher.invoke
import app.revanced.patcher.parameterTypes
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.returnType
import com.android.tools.smali.dexlib2.Opcode
import app.revanced.patcher.fingerprint
internal val getDeviceIdFingerprint = fingerprint {
returns("Ljava/lang/String;")
parameters()
opcodes(
Opcode.SGET_OBJECT,
Opcode.IGET_OBJECT,
Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT_OBJECT,
Opcode.IF_NEZ,
Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT_OBJECT,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT,
Opcode.INVOKE_VIRTUAL,
internal val BytecodePatchContext.getDeviceIdMethod by gettingFirstMutableMethodDeclaratively {
returnType("Ljava/lang/String;")
parameterTypes()
instructions(
Opcode.SGET_OBJECT(),
Opcode.IGET_OBJECT(),
Opcode.INVOKE_STATIC(),
Opcode.MOVE_RESULT_OBJECT(),
Opcode.IF_NEZ(),
Opcode.INVOKE_STATIC(),
Opcode.MOVE_RESULT_OBJECT(),
Opcode.INVOKE_VIRTUAL(),
Opcode.MOVE_RESULT_OBJECT(),
Opcode.INVOKE_VIRTUAL(),
)
}
}

View File

@@ -1,13 +1,12 @@
package app.revanced.patches.photomath.detection.deviceid
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.patch.creatingBytecodePatch
import app.revanced.patches.photomath.detection.signature.signatureDetectionPatch
import app.revanced.util.returnEarly
import kotlin.random.Random
@Suppress("unused")
val getDeviceIdPatch = bytecodePatch(
name = "Spoof device ID",
val `Spoof device ID` by creatingBytecodePatch(
description = "Spoofs device ID to mitigate manual bans by developers.",
) {
dependsOn(signatureDetectionPatch)
@@ -15,6 +14,6 @@ val getDeviceIdPatch = bytecodePatch(
compatibleWith("com.microblink.photomath")
apply {
getDeviceIdFingerprint.method.returnEarly(Random.nextLong().toString(16))
getDeviceIdMethod.returnEarly(Random.nextLong().toString(16))
}
}

View File

@@ -1,18 +1,19 @@
package app.revanced.patches.photomath.detection.signature
import app.revanced.patcher.firstMethodComposite
import app.revanced.patcher.instructions
import app.revanced.patcher.invoke
import com.android.tools.smali.dexlib2.Opcode
import app.revanced.patcher.fingerprint
internal val checkSignatureFingerprint = fingerprint {
opcodes(
Opcode.CONST_STRING,
Opcode.INVOKE_STATIC,
Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT_OBJECT,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT,
Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT,
internal val checkSignatureMethodMatch = firstMethodComposite("SHA") {
instructions(
Opcode.CONST_STRING(),
Opcode.INVOKE_STATIC(),
Opcode.INVOKE_STATIC(),
Opcode.MOVE_RESULT_OBJECT(),
Opcode.INVOKE_VIRTUAL(),
Opcode.MOVE_RESULT_OBJECT(),
Opcode.INVOKE_STATIC(),
Opcode.MOVE_RESULT(),
)
strings("SHA")
}

View File

@@ -5,14 +5,15 @@ import app.revanced.patcher.extensions.replaceInstruction
import app.revanced.patcher.patch.bytecodePatch
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
@Suppress("unused")
val signatureDetectionPatch = bytecodePatch(
description = "Disables detection of incorrect signature.",
) {
apply {
val replacementIndex = checkSignatureFingerprint.instructionMatches.last().index
val checkRegister =
checkSignatureFingerprint.method.getInstruction<OneRegisterInstruction>(replacementIndex).registerA
checkSignatureFingerprint.method.replaceInstruction(replacementIndex, "const/4 v$checkRegister, 0x1")
val replacementIndex = checkSignatureMethodMatch.indices.last()
val checkRegister = checkSignatureMethodMatch.method.getInstruction<OneRegisterInstruction>(replacementIndex)
.registerA
checkSignatureMethodMatch.method.replaceInstruction(replacementIndex, "const/4 v$checkRegister, 0x1")
}
}

View File

@@ -1,21 +1,20 @@
package app.revanced.patches.photomath.misc.annoyances
import app.revanced.patcher.fingerprint
import app.revanced.patcher.*
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.patch.BytecodePatchContext
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
internal val hideUpdatePopupFingerprint = fingerprint {
internal val BytecodePatchContext.hideUpdatePopupMethod by gettingFirstMutableMethodDeclaratively {
definingClass("Lcom/microblink/photomath/main/activity/MainActivity;")
accessFlags(AccessFlags.FINAL, AccessFlags.PUBLIC)
returns("V")
opcodes(
Opcode.CONST_HIGH16,
Opcode.INVOKE_VIRTUAL, // ViewPropertyAnimator.alpha(1.0f)
Opcode.MOVE_RESULT_OBJECT,
Opcode.CONST_WIDE_16,
Opcode.INVOKE_VIRTUAL, // ViewPropertyAnimator.setDuration(1000L)
returnType("V")
instructions(
Opcode.CONST_HIGH16(),
Opcode.INVOKE_VIRTUAL(), // ViewPropertyAnimator.alpha(1.0f)
Opcode.MOVE_RESULT_OBJECT(),
Opcode.CONST_WIDE_16(),
Opcode.INVOKE_VIRTUAL(), // ViewPropertyAnimator.setDuration(1000L)
)
custom { method, _ ->
// The popup is shown only in the main activity
method.definingClass == "Lcom/microblink/photomath/main/activity/MainActivity;"
}
}

View File

@@ -1,12 +1,12 @@
package app.revanced.patches.photomath.misc.annoyances
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.patch.creatingBytecodePatch
import app.revanced.patches.photomath.detection.signature.signatureDetectionPatch
@Suppress("unused")
val hideUpdatePopupPatch = bytecodePatch(
name = "Hide update popup",
val `Hide update popup` by creatingBytecodePatch(
description = "Prevents the update popup from showing up.",
) {
dependsOn(signatureDetectionPatch)
@@ -14,7 +14,7 @@ val hideUpdatePopupPatch = bytecodePatch(
compatibleWith("com.microblink.photomath")
apply {
hideUpdatePopupFingerprint.method.addInstructions(
hideUpdatePopupMethod.addInstructions(
2, // Insert after the null check.
"return-void",
)

View File

@@ -3,12 +3,13 @@ package app.revanced.patches.photomath.misc.unlock.bookpoint
import app.revanced.patcher.extensions.replaceInstructions
import app.revanced.patcher.patch.bytecodePatch
@Suppress("unused")
val enableBookpointPatch = bytecodePatch(
description = "Enables textbook access",
) {
apply {
isBookpointEnabledFingerprint.method.replaceInstructions(
isBookpointEnabledMethod.replaceInstructions(
0,
"""
const/4 v0, 0x1

View File

@@ -1,16 +1,19 @@
package app.revanced.patches.photomath.misc.unlock.bookpoint
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.accessFlags
import app.revanced.patcher.parameterTypes
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.returnType
import com.android.tools.smali.dexlib2.AccessFlags
import app.revanced.patcher.fingerprint
internal val isBookpointEnabledFingerprint = fingerprint {
internal val BytecodePatchContext.isBookpointEnabledMethod by gettingFirstMutableMethodDeclaratively(
"NoGeoData",
"NoCountryInGeo",
"RemoteConfig",
"GeoRCMismatch"
) {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("Z")
parameters()
strings(
"NoGeoData",
"NoCountryInGeo",
"RemoteConfig",
"GeoRCMismatch"
)
}
returnType("Z")
parameterTypes()
}

View File

@@ -1,13 +1,14 @@
package app.revanced.patches.photomath.misc.unlock.plus
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.accessFlags
import app.revanced.patcher.definingClass
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.returnType
import com.android.tools.smali.dexlib2.AccessFlags
import app.revanced.patcher.fingerprint
internal val isPlusUnlockedFingerprint = fingerprint {
internal val BytecodePatchContext.isPlusUnlockedMethod by gettingFirstMutableMethodDeclaratively("genius") {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("Z")
strings("genius")
custom { _, classDef ->
classDef.endsWith("/User;")
}
}
returnType("Z")
definingClass("/User;"::endsWith)
}

View File

@@ -1,20 +1,18 @@
package app.revanced.patches.photomath.misc.unlock.plus
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.patch.creatingBytecodePatch
import app.revanced.patches.photomath.detection.signature.signatureDetectionPatch
import app.revanced.patches.photomath.misc.unlock.bookpoint.enableBookpointPatch
@Suppress("unused")
val unlockPlusPatch = bytecodePatch(
name = "Unlock plus",
) {
val `Unlock plus` by creatingBytecodePatch {
dependsOn(signatureDetectionPatch, enableBookpointPatch)
compatibleWith("com.microblink.photomath")
apply {
isPlusUnlockedFingerprint.method.addInstructions(
isPlusUnlockedMethod.addInstructions(
0,
"""
const/4 v0, 0x1

View File

@@ -3,16 +3,15 @@ package app.revanced.patches.piccomafr.tracking
import app.revanced.patcher.extensions.addInstruction
import app.revanced.patcher.extensions.instructions
import app.revanced.patcher.extensions.replaceInstruction
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.patch.creatingBytecodePatch
import app.revanced.util.getReference
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.StringReference
@Suppress("unused")
val disableTrackingPatch = bytecodePatch(
name = "Disable tracking",
description = "Disables tracking by replacing tracking URLs with example.com.",
@Suppress("unused", "ObjectPropertyName")
val `Disable tracking` by creatingBytecodePatch(
description = "Disables tracking by replacing tracking URLs with example.com."
) {
compatibleWith(
"com.piccomaeurope.fr"(
@@ -34,34 +33,31 @@ val disableTrackingPatch = bytecodePatch(
)
apply {
facebookSDKFingerprint.method.apply {
instructions.filter { instruction ->
instruction.opcode == Opcode.CONST_STRING
}.forEach { instruction ->
instruction as OneRegisterInstruction
facebookSDKMethod.instructions.filter { instruction ->
instruction.opcode == Opcode.CONST_STRING
}.forEach { instruction ->
instruction as OneRegisterInstruction
replaceInstruction(
instruction.location.index,
"const-string v${instruction.registerA}, \"example.com\"",
)
}
facebookSDKMethod.replaceInstruction(
instruction.location.index,
"const-string v${instruction.registerA}, \"example.com\"",
)
}
firebaseInstallFingerprint.method.apply {
instructions.filter {
it.opcode == Opcode.CONST_STRING
}.filter {
it.getReference<StringReference>()?.string == "firebaseinstallations.googleapis.com"
}.forEach { instruction ->
instruction as OneRegisterInstruction
firebaseInstallMethod.instructions.filter {
it.opcode == Opcode.CONST_STRING
}.filter {
it.getReference<StringReference>()?.string == "firebaseinstallations.googleapis.com"
}.forEach { instruction ->
instruction as OneRegisterInstruction
replaceInstruction(
instruction.location.index,
"const-string v${instruction.registerA}, \"example.com\"",
)
}
firebaseInstallMethod.replaceInstruction(
instruction.location.index,
"const-string v${instruction.registerA}, \"example.com\"",
)
}
appMeasurementFingerprint.method.addInstruction(0, "return-void")
appMeasurementMethod.addInstruction(0, "return-void")
}
}

View File

@@ -1,23 +1,20 @@
package app.revanced.patches.piccomafr.tracking
import app.revanced.patcher.fingerprint
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.accessFlags
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.returnType
import com.android.tools.smali.dexlib2.AccessFlags
internal val appMeasurementFingerprint = fingerprint {
internal val BytecodePatchContext.appMeasurementMethod by gettingFirstMutableMethodDeclaratively("config/app/", "Fetching remote configuration") {
accessFlags(AccessFlags.PRIVATE, AccessFlags.FINAL)
returns("V")
strings("config/app/", "Fetching remote configuration")
returnType("V")
}
internal val facebookSDKFingerprint = fingerprint {
internal val BytecodePatchContext.facebookSDKMethod by gettingFirstMutableMethodDeclaratively("instagram.com", "facebook.com") {
accessFlags(AccessFlags.STATIC, AccessFlags.CONSTRUCTOR)
strings("instagram.com", "facebook.com")
}
internal val firebaseInstallFingerprint = fingerprint {
internal val BytecodePatchContext.firebaseInstallMethod by gettingFirstMutableMethodDeclaratively("https://%s/%s/%s", "firebaseinstallations.googleapis.com") {
accessFlags(AccessFlags.PRIVATE)
strings(
"https://%s/%s/%s",
"firebaseinstallations.googleapis.com",
)
}

View File

@@ -1,12 +1,16 @@
package app.revanced.patches.pixiv.ads
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.accessFlags
import app.revanced.patcher.definingClass
import app.revanced.patcher.name
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.returnType
import com.android.tools.smali.dexlib2.AccessFlags
import app.revanced.patcher.fingerprint
internal val shouldShowAdsFingerprint = fingerprint {
internal val BytecodePatchContext.shouldShowAdsMethod by gettingFirstMutableMethodDeclaratively {
definingClass("AdUtils;"::endsWith)
name("shouldShowAds")
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("Z")
custom { methodDef, classDef ->
classDef.type.endsWith("AdUtils;") && methodDef.name == "shouldShowAds"
}
returnType("Z")
}

View File

@@ -1,15 +1,13 @@
package app.revanced.patches.pixiv.ads
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.patch.creatingBytecodePatch
import app.revanced.util.returnEarly
@Suppress("unused")
val hideAdsPatch = bytecodePatch(
name = "Hide ads",
) {
@Suppress("unused", "ObjectPropertyName")
val `Hide ads` by creatingBytecodePatch {
compatibleWith("jp.pxv.android"("6.141.1"))
apply {
shouldShowAdsFingerprint.method.returnEarly(false)
shouldShowAdsMethod.returnEarly(false)
}
}

View File

@@ -1,33 +1,33 @@
package app.revanced.patches.primevideo.ads
import app.revanced.patcher.fingerprint
import app.revanced.patcher.*
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.patch.BytecodePatchContext
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
internal val enterServerInsertedAdBreakStateFingerprint = fingerprint {
internal val BytecodePatchContext.enterServerInsertedAdBreakStateMethod by gettingFirstMutableMethodDeclaratively {
name("enter")
definingClass("Lcom/amazon/avod/media/ads/internal/state/ServerInsertedAdBreakState;")
accessFlags(AccessFlags.PUBLIC)
parameters("Lcom/amazon/avod/fsm/Trigger;")
returns("V")
opcodes(
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT,
Opcode.CONST_4,
Opcode.CONST_4
parameterTypes("Lcom/amazon/avod/fsm/Trigger;")
returnType("V")
instructions(
Opcode.INVOKE_VIRTUAL(),
Opcode.MOVE_RESULT_OBJECT(),
Opcode.CONST_4(),
Opcode.CONST_4()
)
custom { method, classDef ->
method.name == "enter" && classDef.type == "Lcom/amazon/avod/media/ads/internal/state/ServerInsertedAdBreakState;"
}
}
internal val doTriggerFingerprint = fingerprint {
internal val BytecodePatchContext.doTriggerMethod by gettingFirstMutableMethodDeclaratively {
name("doTrigger")
definingClass("Lcom/amazon/avod/fsm/StateBase;")
accessFlags(AccessFlags.PROTECTED)
returns("V")
opcodes(
Opcode.IGET_OBJECT,
Opcode.INVOKE_INTERFACE,
Opcode.RETURN_VOID
returnType("V")
instructions(
Opcode.IGET_OBJECT(),
Opcode.INVOKE_INTERFACE(),
Opcode.RETURN_VOID()
)
custom { method, classDef ->
method.name == "doTrigger" && classDef.type == "Lcom/amazon/avod/fsm/StateBase;"
}
}
}

View File

@@ -2,14 +2,17 @@ package app.revanced.patches.primevideo.ads
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.getInstruction
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.patch.creatingBytecodePatch
import app.revanced.patches.primevideo.misc.extension.sharedExtensionPatch
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
@Suppress("unused")
val skipAdsPatch = bytecodePatch(
name = "Skip ads",
@Suppress("unused", "ObjectPropertyName")
val `Skip ads` by creatingBytecodePatch(
description = "Automatically skips video stream ads.",
) {
compatibleWith("com.amazon.avod.thirdpartyclient"("3.0.412.2947"))
@@ -20,13 +23,17 @@ val skipAdsPatch = bytecodePatch(
// ad break. Instead, force the video player to seek over the entire break and reset the state machine.
apply {
// Force doTrigger() access to public so we can call it from our extension.
doTriggerFingerprint.method.accessFlags = AccessFlags.PUBLIC.value;
doTriggerMethod.accessFlags = AccessFlags.PUBLIC.value
val getPlayerIndex = enterServerInsertedAdBreakStateFingerprint.patternMatch.startIndex
enterServerInsertedAdBreakStateFingerprint.method.apply {
enterServerInsertedAdBreakStateMethod.apply {
// Get register that stores VideoPlayer:
// invoke-virtual ->getPrimaryPlayer()
// move-result-object { playerRegister }
val getPlayerIndex = indexOfFirstInstructionOrThrow {
opcode == Opcode.INVOKE_VIRTUAL &&
getReference<MethodReference>()?.name == "getPrimaryPlayer"
}
val playerRegister = getInstruction<OneRegisterInstruction>(getPlayerIndex + 1).registerA
// Reuse the params from the original method:
@@ -42,4 +49,3 @@ val skipAdsPatch = bytecodePatch(
}
}
}

View File

@@ -1,14 +1,14 @@
package app.revanced.patches.primevideo.misc.permissions
import app.revanced.patcher.patch.PatchException
import app.revanced.patcher.patch.creatingResourcePatch
import app.revanced.patcher.patch.resourcePatch
import app.revanced.util.asSequence
import app.revanced.util.getNode
import org.w3c.dom.Element
@Suppress("unused")
val renamePermissionsPatch = resourcePatch(
name = "Rename shared permissions",
@Suppress("unused", "ObjectPropertyName")
val `Rename shared permissions` by creatingResourcePatch(
description = "Rename certain permissions shared across Amazon apps. " +
"Applying this patch can fix installation errors, but can also break features in certain apps.",
use = false

View File

@@ -1,23 +1,22 @@
package app.revanced.patches.primevideo.video.speed
import app.revanced.patcher.fingerprint
import app.revanced.patcher.*
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.patch.BytecodePatchContext
import com.android.tools.smali.dexlib2.AccessFlags
internal val playbackUserControlsInitializeFingerprint = fingerprint {
internal val BytecodePatchContext.playbackUserControlsInitializeMethod by gettingFirstMutableMethodDeclaratively {
name("initialize")
definingClass("Lcom/amazon/avod/playbackclient/activity/feature/PlaybackUserControlsFeature;")
accessFlags(AccessFlags.PUBLIC)
parameters("Lcom/amazon/avod/playbackclient/PlaybackInitializationContext;")
returns("V")
custom { method, classDef ->
method.name == "initialize" && classDef.type == "Lcom/amazon/avod/playbackclient/activity/feature/PlaybackUserControlsFeature;"
}
parameterTypes("Lcom/amazon/avod/playbackclient/PlaybackInitializationContext;")
returnType("V")
}
internal val playbackUserControlsPrepareForPlaybackFingerprint = fingerprint {
internal val BytecodePatchContext.playbackUserControlsPrepareForPlaybackMethod by gettingFirstMutableMethodDeclaratively {
name("prepareForPlayback")
definingClass("Lcom/amazon/avod/playbackclient/activity/feature/PlaybackUserControlsFeature;")
accessFlags(AccessFlags.PUBLIC)
parameters("Lcom/amazon/avod/playbackclient/PlaybackContext;")
returns("V")
custom { method, classDef ->
method.name == "prepareForPlayback" &&
classDef.type == "Lcom/amazon/avod/playbackclient/activity/feature/PlaybackUserControlsFeature;"
}
parameterTypes("Lcom/amazon/avod/playbackclient/PlaybackContext;")
returnType("V")
}

View File

@@ -3,6 +3,7 @@ package app.revanced.patches.primevideo.video.speed
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.getInstruction
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.patch.creatingBytecodePatch
import app.revanced.patches.primevideo.misc.extension.sharedExtensionPatch
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow
@@ -13,8 +14,8 @@ import com.android.tools.smali.dexlib2.iface.reference.FieldReference
private const val EXTENSION_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/primevideo/videoplayer/PlaybackSpeedPatch;"
val playbackSpeedPatch = bytecodePatch(
name = "Playback speed",
@Suppress("unused", "ObjectPropertyName")
val `Playback speed` by creatingBytecodePatch(
description = "Adds playback speed controls to the video player.",
) {
dependsOn(
@@ -26,7 +27,7 @@ val playbackSpeedPatch = bytecodePatch(
)
apply {
playbackUserControlsInitializeFingerprint.method.apply {
playbackUserControlsInitializeMethod.apply {
val getIndex = indexOfFirstInstructionOrThrow {
opcode == Opcode.IPUT_OBJECT &&
getReference<FieldReference>()?.name == "mUserControls"
@@ -42,7 +43,7 @@ val playbackSpeedPatch = bytecodePatch(
)
}
playbackUserControlsPrepareForPlaybackFingerprint.method.apply {
playbackUserControlsPrepareForPlaybackMethod.apply {
addInstructions(
0,
"""

View File

@@ -1,12 +1,11 @@
package app.revanced.patches.protonmail.account
import app.revanced.patcher.patch.resourcePatch
import app.revanced.patcher.patch.creatingResourcePatch
import app.revanced.util.findElementByAttributeValueOrThrow
@Suppress("unused")
val removeFreeAccountsLimitPatch = resourcePatch(
name = "Remove free accounts limit",
description = "Removes the limit for maximum free accounts logged in.",
@Suppress("unused", "ObjectPropertyName")
val `Remove free accounts limit` by creatingResourcePatch(
description = "Removes the limit for maximum free accounts logged in."
) {
compatibleWith("ch.protonmail.android"("4.15.0"))

View File

@@ -1,14 +1,14 @@
package app.revanced.patches.protonmail.signature
import app.revanced.patcher.patch.PatchException
import app.revanced.patcher.patch.creatingResourcePatch
import app.revanced.patcher.patch.resourcePatch
import app.revanced.util.findElementByAttributeValue
import java.io.File
@Suppress("unused")
val removeSentFromSignaturePatch = resourcePatch(
name = "Remove 'Sent from' signature",
description = "Removes the 'Sent from Proton Mail mobile' signature from emails.",
@Suppress("unused", "ObjectPropertyName")
val `Remove 'Sent from' signature` by creatingResourcePatch(
description = "Removes the 'Sent from Proton Mail mobile' signature from emails."
) {
compatibleWith("ch.protonmail.android"("4.15.0"))

View File

@@ -1,16 +1,13 @@
package app.revanced.patches.protonvpn.delay
import app.revanced.patcher.fingerprint
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.name
import app.revanced.patcher.patch.BytecodePatchContext
internal val longDelayFingerprint = fingerprint {
custom { method, _ ->
method.name == "getChangeServerLongDelayInSeconds"
}
internal val BytecodePatchContext.longDelayMethod by gettingFirstMutableMethodDeclaratively {
name("getChangeServerLongDelayInSeconds")
}
internal val shortDelayFingerprint = fingerprint {
custom { method, _ ->
method.name == "getChangeServerShortDelayInSeconds"
}
}
internal val BytecodePatchContext.shortDelayMethod by gettingFirstMutableMethodDeclaratively {
name("getChangeServerShortDelayInSeconds")
}

View File

@@ -1,17 +1,16 @@
package app.revanced.patches.protonvpn.delay
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.patch.creatingBytecodePatch
import app.revanced.util.returnEarly
@Suppress("unused")
val removeDelayPatch = bytecodePatch(
name = "Remove delay",
description = "Removes the delay when changing servers.",
@Suppress("unused", "ObjectPropertyName")
val `Remove delay` by creatingBytecodePatch(
description = "Removes the delay when changing servers."
) {
compatibleWith("ch.protonvpn.android")
apply {
longDelayFingerprint.method.returnEarly(0)
shortDelayFingerprint.method.returnEarly(0)
longDelayMethod.returnEarly(0)
shortDelayMethod.returnEarly(0)
}
}
}

View File

@@ -1,12 +1,16 @@
package app.revanced.patches.rar.misc.annoyances.purchasereminder
import app.revanced.patcher.fingerprint
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.accessFlags
import app.revanced.patcher.definingClass
import app.revanced.patcher.name
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.returnType
import com.android.tools.smali.dexlib2.AccessFlags
internal val showReminderFingerprint = fingerprint {
internal val BytecodePatchContext.showReminderMethod by gettingFirstMutableMethodDeclaratively {
definingClass("AdsNotify;"::endsWith)
name("show")
accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC)
returns("V")
custom { method, _ ->
method.definingClass.endsWith("AdsNotify;") && method.name == "show"
}
returnType("V")
}

View File

@@ -1,17 +1,15 @@
package app.revanced.patches.rar.misc.annoyances.purchasereminder
import app.revanced.patcher.extensions.addInstruction
import app.revanced.patcher.patch.bytecodePatch
@Suppress("unused")
val hidePurchaseReminderPatch = bytecodePatch(
name = "Hide purchase reminder",
description = "Hides the popup that reminds you to purchase the app.",
import app.revanced.patcher.patch.creatingBytecodePatch
@Suppress("unused", "ObjectPropertyName")
val `Hide purchase reminder` by creatingBytecodePatch(
description = "Hides the popup that reminds you to purchase the app."
) {
compatibleWith("com.rarlab.rar")
apply {
showReminderFingerprint.method.addInstruction(0, "return-void")
showReminderMethod.addInstruction(0, "return-void")
}
}

View File

@@ -1,34 +0,0 @@
package app.revanced.patches.reddit.ad.banner
import app.revanced.patcher.patch.resourcePatch
// Note that for now, this patch and anything using it will only work on
// Reddit 2024.17.0 or older. Newer versions will crash during patching.
// See https://github.com/ReVanced/revanced-patches/issues/3099
val hideBannerPatch = resourcePatch(
description = "Hides banner ads from comments on subreddits.",
) {
apply {
val resourceFilePath = "res/layout/merge_listheader_link_detail.xml"
document(resourceFilePath).use { document ->
document.getElementsByTagName("merge").item(0).childNodes.apply {
val attributes = arrayOf("height", "width")
for (i in 1 until length) {
val view = item(i)
if (
view.hasAttributes() &&
view.attributes.getNamedItem("android:id").nodeValue.endsWith("ad_view_stub")
) {
attributes.forEach { attribute ->
view.attributes.getNamedItem("android:layout_$attribute").nodeValue = "0.0dip"
}
break
}
}
}
}
}
}

View File

@@ -1,10 +1,11 @@
package app.revanced.patches.reddit.ad.comments
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.patch.BytecodePatchContext
internal val hideCommentAdsFingerprint = fingerprint {
custom { method, classDef ->
method.name == "invokeSuspend" &&
classDef.contains("LoadAdsCombinedCall")
}
internal val BytecodePatchContext.hideCommentAdsMethod by gettingFirstMutableMethodDeclaratively {
name("invokeSuspend")
definingClass("LoadAdsCombinedCall"::contains)
}

View File

@@ -3,11 +3,12 @@ package app.revanced.patches.reddit.ad.comments
import app.revanced.patcher.extensions.replaceInstructions
import app.revanced.patcher.patch.bytecodePatch
@Suppress("unused")
val hideCommentAdsPatch = bytecodePatch(
description = "Removes ads in the comments.",
description = "Removes ads in the comments."
) {
apply {
hideCommentAdsFingerprint.method.replaceInstructions(0, "return-object p1")
hideCommentAdsMethod.replaceInstructions(0, "return-object p1")
}
}

View File

@@ -1,16 +1,21 @@
package app.revanced.patches.reddit.ad.general
import app.revanced.patcher.fingerprint
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.definingClass
import app.revanced.patcher.instructions
import app.revanced.patcher.invoke
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.returnType
import com.android.tools.smali.dexlib2.Opcode
internal val adPostFingerprint = fingerprint {
returns("V")
// "children" are present throughout multiple versions
strings("children")
custom { _, classDef -> classDef.endsWith("Listing;") }
internal val BytecodePatchContext.adPostMethod by gettingFirstMutableMethodDeclaratively("children") {
definingClass("Listing;"::endsWith)
returnType("V")
}
internal val newAdPostFingerprint = fingerprint {
opcodes(Opcode.INVOKE_VIRTUAL)
strings("feedElement", "com.reddit.cookie")
internal val BytecodePatchContext.newAdPostMethod by gettingFirstMutableMethodDeclaratively(
"feedElement",
"com.reddit.cookie"
) {
instructions(Opcode.INVOKE_VIRTUAL())
}

View File

@@ -2,19 +2,19 @@ package app.revanced.patches.reddit.ad.general
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.removeInstruction
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.patch.creatingBytecodePatch
import app.revanced.patches.reddit.ad.comments.hideCommentAdsPatch
import app.revanced.patches.reddit.misc.extension.sharedExtensionPatch
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstruction
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction22c
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
@Suppress("unused")
val hideAdsPatch = bytecodePatch(
name = "Hide ads",
) {
@Suppress("unused", "ObjectPropertyName")
val `Hide ads` by creatingBytecodePatch {
dependsOn(hideCommentAdsPatch, sharedExtensionPatch)
compatibleWith("com.reddit.frontpage")
@@ -24,32 +24,30 @@ val hideAdsPatch = bytecodePatch(
val filterMethodDescriptor =
"Lapp/revanced/extension/reddit/patches/FilterPromotedLinksPatch;" +
"->filterChildren(Ljava/lang/Iterable;)Ljava/util/List;"
"->filterChildren(Ljava/lang/Iterable;)Ljava/util/List;"
adPostFingerprint.method.apply {
val setPostsListChildren = implementation!!.instructions.first { instruction ->
if (instruction.opcode != Opcode.IPUT_OBJECT) return@first false
val setPostsListChildren = adPostMethod.implementation!!.instructions.first { instruction ->
if (instruction.opcode != Opcode.IPUT_OBJECT) return@first false
val reference = (instruction as ReferenceInstruction).reference as FieldReference
reference.name == "children"
}
val castedInstruction = setPostsListChildren as Instruction22c
val itemsRegister = castedInstruction.registerA
val listInstanceRegister = castedInstruction.registerB
// postsList.children = filterChildren(postListItems)
removeInstruction(setPostsListChildren.location.index)
addInstructions(
setPostsListChildren.location.index,
"""
invoke-static {v$itemsRegister}, $filterMethodDescriptor
move-result-object v0
iput-object v0, v$listInstanceRegister, ${castedInstruction.reference}
""",
)
val reference = (instruction as ReferenceInstruction).reference as FieldReference
reference.name == "children"
}
val castedInstruction = setPostsListChildren as Instruction22c
val itemsRegister = castedInstruction.registerA
val listInstanceRegister = castedInstruction.registerB
// postsList.children = filterChildren(postListItems)
adPostMethod.removeInstruction(setPostsListChildren.location.index)
adPostMethod.addInstructions(
setPostsListChildren.location.index,
"""
invoke-static {v$itemsRegister}, $filterMethodDescriptor
move-result-object v0
iput-object v0, v$listInstanceRegister, ${castedInstruction.reference}
""",
)
// endregion
// region Remove ads from popular and latest feed
@@ -58,15 +56,13 @@ val hideAdsPatch = bytecodePatch(
// AdElementConverter is conveniently responsible for inserting all feed ads.
// By removing the appending instruction no ad posts gets appended to the feed.
val index = newAdPostFingerprint.originalMethod.implementation!!.instructions.indexOfFirst {
if (it.opcode != Opcode.INVOKE_VIRTUAL) return@indexOfFirst false
val reference = (it as ReferenceInstruction).reference as MethodReference
val index = newAdPostMethod.indexOfFirstInstruction {
val reference = getReference<MethodReference>() ?: return@indexOfFirstInstruction false
reference.name == "add" && reference.definingClass == "Ljava/util/ArrayList;"
}
newAdPostFingerprint.method.removeInstruction(index)
newAdPostMethod.removeInstruction(index)
}
// endregion

View File

@@ -10,7 +10,7 @@ const val CREATE_NEW_CLIENT_METHOD = "createClient()Lokhttp3/OkHttpClient;"
fun fixRedgifsApiPatch(
extensionPatch: Patch,
block: BytecodePatchBuilder.() -> Unit = {},
) = bytecodePatch(name = "Fix Redgifs API") {
) = bytecodePatch("Fix Redgifs API") {
dependsOn(extensionPatch)
block()

View File

@@ -10,7 +10,7 @@ const val SET_ACCESS_TOKEN_METHOD = "patchSetAccessToken(Ljava/lang/String;)V"
fun fixSLinksPatch(
extensionPatch: Patch,
block: BytecodePatchBuilder.() -> Unit = {},
) = bytecodePatch(name = "Fix /s/ links") {
) = bytecodePatch("Fix /s/ links") {
dependsOn(extensionPatch)
block()

View File

@@ -1,19 +1,16 @@
package app.revanced.patches.reddit.customclients.baconreader.api
import app.revanced.patcher.fingerprint
import app.revanced.patcher.firstMethodComposite
import app.revanced.patcher.instructions
import app.revanced.patcher.invoke
internal val getAuthorizationUrlFingerprint = fingerprint {
strings("client_id=zACVn0dSFGdWqQ")
}
internal val getClientIdFingerprint = fingerprint {
strings("client_id=zACVn0dSFGdWqQ")
custom { method, classDef ->
if (!classDef.endsWith("RedditOAuth;")) return@custom false
method.name == "getAuthorizeUrl"
}
internal val getAuthorizationUrlMethodMatch = firstMethodComposite {
instructions("client_id=zACVn0dSFGdWqQ"())
}
internal val requestTokenFingerprint = fingerprint {
strings("zACVn0dSFGdWqQ", "kDm2tYpu9DqyWFFyPlNcXGEni4k") // App ID and secret.
}
internal val requestTokenMethodMatch = firstMethodComposite {
instructions(
"zACVn0dSFGdWqQ"(),
"kDm2tYpu9DqyWFFyPlNcXGEni4k"(String::contains)
)
}

View File

@@ -1,6 +1,6 @@
package app.revanced.patches.reddit.customclients.baconreader.api
import app.revanced.patcher.Fingerprint
import app.revanced.patcher.MatchBuilder
import app.revanced.patcher.extensions.getInstruction
import app.revanced.patcher.extensions.replaceInstruction
import app.revanced.patches.reddit.customclients.spoofClientPatch
@@ -22,22 +22,20 @@ val spoofClientPatch = spoofClientPatch(redirectUri = "http://baconreader.com/au
val clientId by clientIdOption
apply {
fun Fingerprint.patch(replacementString: String) {
val clientIdIndex = stringMatches.first().index
fun MatchBuilder.patch(replacementString: String) {
val clientIdIndex = indices.first()
method.apply {
val clientIdRegister = getInstruction<OneRegisterInstruction>(clientIdIndex).registerA
replaceInstruction(
clientIdIndex,
"const-string v$clientIdRegister, \"$replacementString\"",
)
}
val clientIdRegister = method.getInstruction<OneRegisterInstruction>(clientIdIndex).registerA
method.replaceInstruction(
clientIdIndex,
"const-string v$clientIdRegister, \"$replacementString\"",
)
}
// Patch client id in authorization url.
getAuthorizationUrlFingerprint.patch("client_id=$clientId")
getAuthorizationUrlMethodMatch.patch("client_id=$clientId")
// Patch client id for access token request.
requestTokenFingerprint.patch(clientId!!)
requestTokenMethodMatch.patch(clientId!!)
}
}

View File

@@ -1,11 +1,15 @@
package app.revanced.patches.reddit.customclients.baconreader.fix.redgifs
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 val getOkHttpClientFingerprint = fingerprint {
returns("Lokhttp3/OkHttpClient;")
parameters()
custom { method, classDef ->
classDef.type == "Lcom/onelouder/baconreader/media/gfycat/RedGifsManager;" && method.name == "getOkhttpClient"
}
}
internal val BytecodePatchContext.getOkHttpClientMethod by gettingFirstMutableMethodDeclaratively {
definingClass("Lcom/onelouder/baconreader/media/gfycat/RedGifsManager;")
name("getOkhttpClient")
returnType("Lokhttp3/OkHttpClient;")
parameterTypes()
}

View File

@@ -1,12 +1,11 @@
package app.revanced.patches.reddit.customclients.baconreader.fix.redgifs
import app.revanced.patcher.extensions.getInstruction
import app.revanced.patcher.extensions.removeInstruction
import app.revanced.patcher.extensions.removeInstructions
import app.revanced.patcher.extensions.replaceInstruction
import app.revanced.patches.reddit.customclients.fixRedgifsApiPatch
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
@@ -28,26 +27,25 @@ val fixRedgifsApi = fixRedgifsApiPatch(
apply {
// region Patch Redgifs OkHttp3 client.
getOkHttpClientFingerprint.method.apply {
// Remove conflicting OkHttp interceptors.
val originalInterceptorInstallIndex = indexOfFirstInstructionOrThrow {
opcode == Opcode.NEW_INSTANCE && getReference<TypeReference>()?.type == "Lcom/onelouder/baconreader/media/gfycat/RedGifsManager\$HeaderInterceptor;"
}
removeInstructions(originalInterceptorInstallIndex, 5)
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
"""
)
// Remove conflicting OkHttp interceptors.
val originalInterceptorInstallIndex = getOkHttpClientMethod.indexOfFirstInstructionOrThrow {
opcode == Opcode.NEW_INSTANCE && getReference<TypeReference>()?.type == "Lcom/onelouder/baconreader/media/gfycat/RedGifsManager\$HeaderInterceptor;"
}
getOkHttpClientMethod.removeInstructions(originalInterceptorInstallIndex, 5)
// endregion
val index = getOkHttpClientMethod.indexOfFirstInstructionOrThrow {
val reference = getReference<MethodReference>()
reference?.name == "build" && reference.definingClass == "Lokhttp3/OkHttpClient\$Builder;"
}
val register = getOkHttpClientMethod.getInstruction<FiveRegisterInstruction>(index).registerC
getOkHttpClientMethod.replaceInstruction(
index,
"""
invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->$INSTALL_NEW_CLIENT_METHOD
"""
)
}
// endregion
}

View File

@@ -1,17 +1,14 @@
package app.revanced.patches.reddit.customclients.boostforreddit.ads
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.patch.creatingBytecodePatch
import app.revanced.util.returnEarly
@Suppress("unused")
val disableAdsPatch = bytecodePatch(
name = "Disable ads",
) {
@Suppress("unused", "ObjectPropertyName")
val `Disable ads` by creatingBytecodePatch {
compatibleWith("com.rubenmayayo.reddit")
apply {
arrayOf(maxMediationFingerprint, admobMediationFingerprint).forEach { fingerprint ->
fingerprint.method.addInstructions(0, "return-void")
}
maxMediationMethod.returnEarly()
admobMediationMethod.returnEarly()
}
}

View File

@@ -1,11 +1,12 @@
package app.revanced.patches.reddit.customclients.boostforreddit.ads
import app.revanced.patcher.fingerprint
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.patch.BytecodePatchContext
internal val maxMediationFingerprint = fingerprint {
strings("MaxMediation: Attempting to initialize SDK")
}
internal val BytecodePatchContext.maxMediationMethod by gettingFirstMutableMethodDeclaratively(
"MaxMediation: Attempting to initialize SDK"
)
internal val admobMediationFingerprint = fingerprint {
strings("AdmobMediation: Attempting to initialize SDK")
}
internal val BytecodePatchContext.admobMediationMethod by gettingFirstMutableMethodDeclaratively(
"AdmobMediation: Attempting to initialize SDK"
)

View File

@@ -1,15 +1,15 @@
package app.revanced.patches.reddit.customclients.boostforreddit.api
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.patch.BytecodePatchContext
internal val buildUserAgentFingerprint = fingerprint {
strings("%s:%s:%s (by /u/%s)")
}
internal val getClientIdFingerprint = fingerprint {
custom { method, classDef ->
if (!classDef.endsWith("Credentials;")) return@custom false
method.name == "getClientId"
}
internal val BytecodePatchContext.buildUserAgentMethod by gettingFirstMutableMethodDeclaratively(
"%s:%s:%s (by /u/%s)"
)
internal val BytecodePatchContext.getClientIdMethod by gettingFirstMutableMethodDeclaratively {
name("getClientId")
definingClass("Credentials;"::endsWith)
}

View File

@@ -3,9 +3,14 @@ package app.revanced.patches.reddit.customclients.boostforreddit.api
import app.revanced.patcher.extensions.getInstruction
import app.revanced.patcher.extensions.replaceInstruction
import app.revanced.patches.reddit.customclients.spoofClientPatch
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.returnEarly
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.StringReference
@Suppress("unused")
val spoofClientPatch = spoofClientPatch(redirectUri = "http://rubenmayayo.com") { clientIdOption ->
compatibleWith("com.rubenmayayo.reddit")
@@ -14,7 +19,7 @@ val spoofClientPatch = spoofClientPatch(redirectUri = "http://rubenmayayo.com")
apply {
// region Patch client id.
getClientIdFingerprint.method.returnEarly(clientId!!)
getClientIdMethod.returnEarly(clientId!!)
// endregion
@@ -23,12 +28,13 @@ val spoofClientPatch = spoofClientPatch(redirectUri = "http://rubenmayayo.com")
// Use a random user agent.
val randomName = (0..100000).random()
val userAgent = "$randomName:app.revanced.$randomName:v1.0.0 (by /u/revanced)"
buildUserAgentFingerprint.let {
val userAgentTemplateIndex = it.stringMatches.first().index
val register = it.method.getInstruction<OneRegisterInstruction>(userAgentTemplateIndex).registerA
it.method.replaceInstruction(userAgentTemplateIndex, "const-string v$register, \"$userAgent\"")
val userAgentTemplateIndex = buildUserAgentMethod.indexOfFirstInstructionOrThrow {
opcode == Opcode.CONST_STRING && getReference<StringReference>()?.string == "%s:%s:%s (by /u/%s)"
}
val register = buildUserAgentMethod.getInstruction<OneRegisterInstruction>(userAgentTemplateIndex).registerA
buildUserAgentMethod.replaceInstruction(userAgentTemplateIndex, "const-string v$register, \"$userAgent\"")
// endregion
}

View File

@@ -1,7 +1,12 @@
package app.revanced.patches.reddit.customclients.boostforreddit.fix.downloads
import app.revanced.patcher.fingerprint
import app.revanced.patcher.firstMethodComposite
import app.revanced.patcher.instructions
import app.revanced.patcher.invoke
internal val downloadAudioFingerprint = fingerprint {
strings("/DASH_audio.mp4", "/audio")
internal val downloadAudioMethodMatch = firstMethodComposite {
instructions(
"/DASH_audio.mp4"(),
"/audio"()
)
}

View File

@@ -2,29 +2,26 @@ package app.revanced.patches.reddit.customclients.boostforreddit.fix.downloads
import app.revanced.patcher.extensions.getInstruction
import app.revanced.patcher.extensions.replaceInstruction
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.patch.creatingBytecodePatch
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
@Suppress("unused")
val fixAudioMissingInDownloadsPatch = bytecodePatch(
name = "Fix missing audio in video downloads",
@Suppress("unused", "ObjectPropertyName")
val `Fix missing audio in video downloads` by creatingBytecodePatch(
description = "Fixes audio missing in videos downloaded from v.redd.it.",
) {
compatibleWith("com.rubenmayayo.reddit")
apply {
val endpointReplacements = mapOf(
"/DASH_audio.mp4" to "/DASH_AUDIO_128.mp4",
"/audio" to "/DASH_AUDIO_64.mp4",
val endpointReplacements = arrayOf(
"/DASH_AUDIO_128.mp4",
"/DASH_AUDIO_64.mp4",
)
downloadAudioFingerprint.method.apply {
downloadAudioFingerprint.stringMatches.forEach { match ->
val replacement = endpointReplacements[match.string]
val register = getInstruction<OneRegisterInstruction>(match.index).registerA
downloadAudioMethodMatch.indices.forEachIndexed { index, i ->
val replacement = endpointReplacements[i]
val register = downloadAudioMethodMatch.method.getInstruction<OneRegisterInstruction>(index).registerA
replaceInstruction(match.index, "const-string v$register, \"$replacement\"")
}
downloadAudioMethodMatch.method.replaceInstruction(index, "const-string v$register, \"$replacement\"")
}
}
}

View File

@@ -1,20 +1,22 @@
package app.revanced.patches.reddit.customclients.boostforreddit.fix.redgifs
import app.revanced.patcher.fingerprint
import app.revanced.patcher.*
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.patch.BytecodePatchContext
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
internal val createOkHttpClientFingerprint = fingerprint {
internal val BytecodePatchContext.createOkHttpClientMethod by gettingFirstMutableMethodDeclaratively {
accessFlags(AccessFlags.PRIVATE)
opcodes(
Opcode.NEW_INSTANCE,
Opcode.INVOKE_DIRECT,
Opcode.NEW_INSTANCE,
Opcode.INVOKE_DIRECT,
Opcode.NEW_INSTANCE,
Opcode.INVOKE_DIRECT,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT
instructions(
Opcode.NEW_INSTANCE(),
Opcode.INVOKE_DIRECT(),
Opcode.NEW_INSTANCE(),
Opcode.INVOKE_DIRECT(),
Opcode.NEW_INSTANCE(),
Opcode.INVOKE_DIRECT(),
Opcode.INVOKE_VIRTUAL(),
Opcode.MOVE_RESULT_OBJECT()
)
custom { _, classDef -> classDef.sourceFile == "RedGifsAPIv2.java" }
custom { immutableClassDef.sourceFile == "RedGifsAPIv2.java" }
}

View File

@@ -1,12 +1,11 @@
package app.revanced.patches.reddit.customclients.boostforreddit.fix.redgifs
import app.revanced.patcher.extensions.methodReference
import app.revanced.patcher.extensions.replaceInstruction
import app.revanced.patches.reddit.customclients.CREATE_NEW_CLIENT_METHOD
import app.revanced.patches.reddit.customclients.boostforreddit.misc.extension.sharedExtensionPatch
import app.revanced.patches.reddit.customclients.fixRedgifsApiPatch
import app.revanced.util.getReference
import app.revanced.patches.reddit.customclients.boostforreddit.misc.extension.sharedExtensionPatch
import app.revanced.util.indexOfFirstInstructionOrThrow
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/boostforreddit/FixRedgifsApiPatch;"
@@ -19,16 +18,14 @@ 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;"
}
replaceInstruction(
index,
"invoke-static { }, $EXTENSION_CLASS_DESCRIPTOR->$CREATE_NEW_CLIENT_METHOD"
)
val index = createOkHttpClientMethod.indexOfFirstInstructionOrThrow {
val reference = methodReference
reference?.name == "build" && reference.definingClass == "Lokhttp3/OkHttpClient\$Builder;"
}
createOkHttpClientMethod.replaceInstruction(
index,
"invoke-static { }, $EXTENSION_CLASS_DESCRIPTOR->$CREATE_NEW_CLIENT_METHOD"
)
// endregion
}

View File

@@ -1,21 +1,22 @@
package app.revanced.patches.reddit.customclients.boostforreddit.fix.slink
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.accessFlags
import app.revanced.patcher.definingClass
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.returnType
import com.android.tools.smali.dexlib2.AccessFlags
import app.revanced.patcher.fingerprint
internal val getOAuthAccessTokenFingerprint = fingerprint {
internal val BytecodePatchContext.getOAuthAccessTokenMethod by gettingFirstMutableMethodDeclaratively("access_token") {
definingClass("Lnet/dean/jraw/http/oauth/OAuthData;")
accessFlags(AccessFlags.PUBLIC)
returns("Ljava/lang/String")
strings("access_token")
custom { method, _ -> method.definingClass == "Lnet/dean/jraw/http/oauth/OAuthData;" }
returnType("Ljava/lang/String;")
}
internal val handleNavigationFingerprint = fingerprint {
strings(
"android.intent.action.SEARCH",
"subscription",
"sort",
"period",
"boostforreddit.com/themes",
)
}
internal val BytecodePatchContext.handleNavigationMethod by gettingFirstMutableMethodDeclaratively(
"android.intent.action.SEARCH",
"subscription",
"sort",
"period",
"boostforreddit.com/themes"
)

View File

@@ -20,27 +20,26 @@ val fixSlinksPatch = fixSLinksPatch(
apply {
// region Patch navigation handler.
handleNavigationFingerprint.method.apply {
val urlRegister = "p1"
val tempRegister = "v1"
val urlRegister = "p1"
val tempRegister = "v1"
handleNavigationMethod.addInstructionsWithLabels(
0,
"""
invoke-static { $urlRegister }, $EXTENSION_CLASS_DESCRIPTOR->$RESOLVE_S_LINK_METHOD
move-result $tempRegister
if-eqz $tempRegister, :continue
return $tempRegister
""",
ExternalLabel("continue", handleNavigationMethod.getInstruction(0)),
)
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)),
)
}
// endregion
// region Patch set access token.
getOAuthAccessTokenFingerprint.method.addInstruction(
getOAuthAccessTokenMethod.addInstruction(
3,
"invoke-static { v0 }, $EXTENSION_CLASS_DESCRIPTOR->$SET_ACCESS_TOKEN_METHOD",
)

View File

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

View File

@@ -17,7 +17,7 @@ val spoofClientPatch = spoofClientPatch(redirectUri = "infinity://localhost") {
val clientId by clientIdOption
apply {
apiUtilsFingerprint.classDef.methods.apply {
apiUtilsMethod.classDef.methods.apply {
val getClientIdMethod = single { it.name == "getId" }.also(::remove)
val newGetClientIdMethod = ImmutableMethod(

View File

@@ -1,14 +1,13 @@
package app.revanced.patches.reddit.customclients.infinityforreddit.subscription
import app.revanced.patcher.fingerprint
import app.revanced.patcher.literal
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethod
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.InstructionMatchingFunctions.invoke
import app.revanced.patcher.instructions
import app.revanced.patcher.patch.BytecodePatchContext
internal val billingClientOnServiceConnectedFingerprint = fingerprint {
strings("Billing service connected")
}
internal val BytecodePatchContext.billingClientOnServiceConnectedMethod by gettingFirstMutableMethod("Billing service connected")
internal val startSubscriptionActivityFingerprint = fingerprint {
instructions(
literal(0x10008000) // Intent start flag only used in the subscription activity
)
internal val BytecodePatchContext.startSubscriptionActivityMethod by gettingFirstMutableMethodDeclaratively {
instructions(0x10008000L())
}

View File

@@ -1,12 +1,11 @@
package app.revanced.patches.reddit.customclients.infinityforreddit.subscription
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.patch.creatingBytecodePatch
import app.revanced.patches.reddit.customclients.infinityforreddit.api.spoofClientPatch
import app.revanced.util.returnEarly
@Suppress("unused")
val unlockSubscriptionPatch = bytecodePatch(
name = "Unlock subscription",
@Suppress("unused", "ObjectPropertyName")
val `Unlock subscription` by creatingBytecodePatch(
description = "Unlocks the subscription feature but requires a custom client ID.",
) {
dependsOn(spoofClientPatch)
@@ -18,9 +17,7 @@ val unlockSubscriptionPatch = bytecodePatch(
)
apply {
setOf(
startSubscriptionActivityFingerprint,
billingClientOnServiceConnectedFingerprint,
).forEach { it.method.returnEarly() }
billingClientOnServiceConnectedMethod.returnEarly()
startSubscriptionActivityMethod.returnEarly()
}
}

View File

@@ -1,24 +1,16 @@
package app.revanced.patches.reddit.customclients.joeyforreddit.ads
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.patch.creatingBytecodePatch
import app.revanced.patches.reddit.customclients.joeyforreddit.detection.piracy.disablePiracyDetectionPatch
import app.revanced.util.returnEarly
@Suppress("unused")
val disableAdsPatch = bytecodePatch(
name = "Disable ads",
) {
@Suppress("unused", "ObjectPropertyName")
val `Disable ads` by creatingBytecodePatch {
dependsOn(disablePiracyDetectionPatch)
compatibleWith("o.o.joey")
apply {
isAdFreeUserFingerprint.method.addInstructions(
0,
"""
const/4 v0, 0x1
return v0
""",
)
isAdFreeUserMethod.returnEarly(true)
}
}

View File

@@ -1,10 +1,12 @@
package app.revanced.patches.reddit.customclients.joeyforreddit.ads
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.accessFlags
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.returnType
import com.android.tools.smali.dexlib2.AccessFlags
import app.revanced.patcher.fingerprint
internal val isAdFreeUserFingerprint = fingerprint {
internal val BytecodePatchContext.isAdFreeUserMethod by gettingFirstMutableMethodDeclaratively("AD_FREE_USER") {
accessFlags(AccessFlags.PUBLIC)
returns("Z")
strings("AD_FREE_USER")
}
returnType("Z")
}

View File

@@ -1,28 +1,26 @@
package app.revanced.patches.reddit.customclients.joeyforreddit.api
import com.android.tools.smali.dexlib2.Opcode
import app.revanced.patcher.*
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.patch.BytecodePatchContext
import com.android.tools.smali.dexlib2.AccessFlags
import app.revanced.patcher.fingerprint
import com.android.tools.smali.dexlib2.Opcode
internal val authUtilityUserAgentFingerprint = fingerprint {
internal val BytecodePatchContext.authUtilityUserAgentMethod by gettingFirstMutableMethodDeclaratively {
accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC)
returns("Ljava/lang/String;")
opcodes(Opcode.APUT_OBJECT)
custom { method, classDef ->
classDef.sourceFile == "AuthUtility.java"
}
returnType("Ljava/lang/String;")
instructions(Opcode.APUT_OBJECT())
custom { immutableClassDef.sourceFile == "AuthUtility.java" }
}
internal val getClientIdFingerprint = fingerprint {
internal val BytecodePatchContext.getClientIdMethod by gettingFirstMutableMethodDeclaratively {
accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC)
returns("L")
opcodes(
Opcode.CONST, // R.string.valuable_cid
Opcode.INVOKE_STATIC, // StringMaster.decrypt
Opcode.MOVE_RESULT_OBJECT,
Opcode.RETURN_OBJECT
returnType("L")
instructions(
Opcode.CONST(),
Opcode.INVOKE_STATIC(),
Opcode.MOVE_RESULT_OBJECT(),
Opcode.RETURN_OBJECT(),
)
custom { _, classDef ->
classDef.sourceFile == "AuthUtility.java"
}
}
custom { immutableClassDef.sourceFile == "AuthUtility.java" }
}

View File

@@ -1,7 +1,7 @@
package app.revanced.patches.reddit.customclients.joeyforreddit.api
import app.revanced.patches.reddit.customclients.joeyforreddit.detection.piracy.disablePiracyDetectionPatch
import app.revanced.patches.reddit.customclients.spoofClientPatch
import app.revanced.patches.reddit.customclients.sync.detection.piracy.disablePiracyDetectionPatch
import app.revanced.util.returnEarly
val spoofClientPatch = spoofClientPatch(redirectUri = "https://127.0.0.1:65023/authorize_callback") { clientIdOption ->
@@ -18,7 +18,7 @@ val spoofClientPatch = spoofClientPatch(redirectUri = "https://127.0.0.1:65023/a
apply {
// region Patch client id.
getClientIdFingerprint.method.returnEarly(clientId!!)
getClientIdMethod.returnEarly(clientId!!)
// endregion
@@ -28,7 +28,7 @@ val spoofClientPatch = spoofClientPatch(redirectUri = "https://127.0.0.1:65023/a
val randomName = (0..100000).random()
val userAgent = "$randomName:app.revanced.$randomName:v1.0.0 (by /u/revanced)"
authUtilityUserAgentFingerprint.method.returnEarly(userAgent)
authUtilityUserAgentMethod.returnEarly(userAgent)
// endregion
}

View File

@@ -1,11 +1,11 @@
package app.revanced.patches.reddit.customclients.joeyforreddit.detection.piracy
import app.revanced.patcher.extensions.addInstruction
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.util.returnEarly
@Suppress("unused")
val disablePiracyDetectionPatch = bytecodePatch {
apply {
piracyDetectionFingerprint.method.addInstruction(0, "return-void")
detectPiracyMethod.returnEarly()
}
}

View File

@@ -1,21 +1,25 @@
package app.revanced.patches.reddit.customclients.joeyforreddit.detection.piracy
import com.android.tools.smali.dexlib2.Opcode
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.InstructionMatchingFunctions.invoke
import app.revanced.patcher.accessFlags
import app.revanced.patcher.definingClass
import app.revanced.patcher.instructions
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.returnType
import com.android.tools.smali.dexlib2.AccessFlags
import app.revanced.patcher.fingerprint
import com.android.tools.smali.dexlib2.Opcode
internal val piracyDetectionFingerprint = fingerprint {
internal val BytecodePatchContext.detectPiracyMethod by gettingFirstMutableMethodDeclaratively {
accessFlags(AccessFlags.PRIVATE, AccessFlags.STATIC)
returns("V")
opcodes(
Opcode.NEW_INSTANCE,
Opcode.CONST_16,
Opcode.CONST_WIDE_16,
Opcode.INVOKE_DIRECT,
Opcode.INVOKE_VIRTUAL,
Opcode.RETURN_VOID
returnType("V")
instructions(
Opcode.NEW_INSTANCE(),
Opcode.CONST_16(),
Opcode.CONST_WIDE_16(),
Opcode.INVOKE_DIRECT(),
Opcode.INVOKE_VIRTUAL(),
Opcode.RETURN_VOID()
)
custom { _, classDef ->
classDef.endsWith("ProcessLifeCyleListener;")
}
}
definingClass("ProcessLifeCyleListener;"::endsWith)
}

View File

@@ -1,31 +1,35 @@
package app.revanced.patches.reddit.customclients.redditisfun.api
import app.revanced.patcher.fingerprint
import app.revanced.patcher.*
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.patch.BytecodePatchContext
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
internal fun baseClientIdFingerprint(string: String) = fingerprint {
strings("yyOCBp.RHJhDKd", string)
}
internal val basicAuthorizationFingerprint = baseClientIdFingerprint(
string = "fJOxVwBUyo*=f:<OoejWs:AqmIJ", // Encrypted basic authorization string.
)
internal val buildAuthorizationStringFingerprint = baseClientIdFingerprint(
string = "client_id",
)
internal val getUserAgentFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC)
returns("Ljava/lang/String;")
parameters()
opcodes(
Opcode.NEW_ARRAY,
Opcode.CONST_4,
Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT_OBJECT,
Opcode.APUT_OBJECT,
Opcode.CONST,
internal val basicAuthorizationMethodMatch = firstMethodComposite {
instructions(
"yyOCBp.RHJhDKd"(),
"fJOxVwBUyo*=f:<OoejWs:AqmIJ"() // Encrypted basic authorization string.
)
}
internal val buildAuthorizationStringMethodMatch = firstMethodComposite {
instructions(
"yyOCBp.RHJhDKd"(),
"client_id"()
)
}
internal val BytecodePatchContext.getUserAgentMethod by gettingFirstMutableMethodDeclaratively {
accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC)
returnType("Ljava/lang/String;")
parameterTypes()
instructions(
Opcode.NEW_ARRAY(),
Opcode.CONST_4(),
Opcode.INVOKE_STATIC(),
Opcode.MOVE_RESULT_OBJECT(),
Opcode.APUT_OBJECT(),
Opcode.CONST(),
)
}

View File

@@ -1,7 +1,7 @@
package app.revanced.patches.reddit.customclients.redditisfun.api
import app.revanced.patcher.Fingerprint
import app.revanced.patcher.Match
import app.revanced.patcher.MatchBuilder
import app.revanced.patcher.extensions.getInstruction
import app.revanced.patcher.extensions.replaceInstruction
import app.revanced.patches.reddit.customclients.spoofClientPatch
@@ -11,6 +11,7 @@ import app.revanced.util.returnEarly
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.StringReference
@Suppress("unused")
val spoofClientPatch = spoofClientPatch(redirectUri = "redditisfun://auth") { clientIdOption ->
compatibleWith(
"com.andrewshu.android.reddit",
@@ -28,23 +29,23 @@ val spoofClientPatch = spoofClientPatch(redirectUri = "redditisfun://auth") { cl
*
* @param string The string to replace the instruction with.
* @param getReplacementIndex A function that returns the index of the instruction to replace
* using the [Match.StringMatch] list from the [Match].
* using the [Match.indices] list from the [Match].
*/
fun Fingerprint.replaceWith(
fun MatchBuilder.replaceWith(
string: String,
getReplacementIndex: List<Match.StringMatch>.() -> Int,
getReplacementIndex: List<Int>.() -> Int,
) = method.apply {
val replacementIndex = stringMatches.getReplacementIndex()
val replacementIndex = indices.getReplacementIndex()
val clientIdRegister = getInstruction<OneRegisterInstruction>(replacementIndex).registerA
replaceInstruction(replacementIndex, "const-string v$clientIdRegister, \"$string\"")
}
// Patch OAuth authorization.
buildAuthorizationStringFingerprint.replaceWith(clientId!!) { first().index + 4 }
buildAuthorizationStringMethodMatch.replaceWith(clientId!!) { first() + 4 }
// Path basic authorization.
basicAuthorizationFingerprint.replaceWith("$clientId:") { last().index + 7 }
basicAuthorizationMethodMatch.replaceWith("$clientId:") { last() + 7 }
// endregion
@@ -54,7 +55,7 @@ val spoofClientPatch = spoofClientPatch(redirectUri = "redditisfun://auth") { cl
val randomName = (0..100000).random()
val userAgent = "$randomName:app.revanced.$randomName:v1.0.0 (by /u/revanced)"
getUserAgentFingerprint.method.returnEarly(userAgent)
getUserAgentMethod.returnEarly(userAgent)
// endregion
@@ -62,7 +63,7 @@ val spoofClientPatch = spoofClientPatch(redirectUri = "redditisfun://auth") { cl
// Reddit messed up and does not append a redirect uri to the authorization url to old.reddit.com/login.
// Replace old.reddit.com with www.reddit.com to fix this.
buildAuthorizationStringFingerprint.method.apply {
buildAuthorizationStringMethodMatch.method.apply {
val index = indexOfFirstInstructionOrThrow {
getReference<StringReference>()?.contains("old.reddit.com") == true
}

View File

@@ -1,27 +1,33 @@
package app.revanced.patches.reddit.customclients.relayforreddit.api
import app.revanced.patcher.fingerprint
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.firstMethodComposite
import app.revanced.patcher.instructions
import app.revanced.patcher.invoke
import app.revanced.patcher.parameterTypes
import app.revanced.patcher.patch.BytecodePatchContext
import com.android.tools.smali.dexlib2.Opcode
internal fun baseClientIdFingerprint(string: String) = fingerprint {
strings("dj-xCIZQYiLbEg", string)
internal fun baseClientIdMethod(string: String) = firstMethodComposite {
instructions(
"dj-xCIZQYiLbEg"(),
string()
)
}
internal val getLoggedInBearerTokenFingerprint = baseClientIdFingerprint("authorization_code")
internal val getLoggedInBearerTokenMethodMatch = baseClientIdMethod("authorization_code")
internal val getLoggedOutBearerTokenFingerprint = baseClientIdFingerprint("https://oauth.reddit.com/grants/installed_client")
internal val getLoggedOutBearerTokenMethodMatch = baseClientIdMethod("https://oauth.reddit.com/grants/installed_client")
internal val getRefreshTokenFingerprint = baseClientIdFingerprint("refresh_token")
internal val getRefreshTokenMethodMatch = baseClientIdMethod("refresh_token")
internal val loginActivityClientIdFingerprint = baseClientIdFingerprint("&duration=permanent")
internal val loginActivityClientIdMethodMatch = baseClientIdMethod("&duration=permanent")
internal val redditCheckDisableAPIFingerprint = fingerprint {
opcodes(Opcode.IF_EQZ)
strings("Reddit Disabled")
internal val BytecodePatchContext.redditCheckDisableAPIMethod by gettingFirstMutableMethodDeclaratively("Reddit Disabled") {
instructions(Opcode.IF_EQZ())
}
internal val setRemoteConfigFingerprint = fingerprint {
parameters("Lcom/google/firebase/remoteconfig/FirebaseRemoteConfig;")
strings("reddit_oauth_url")
internal val BytecodePatchContext.setRemoteConfigMethod by gettingFirstMutableMethodDeclaratively("reddit_oauth_url") {
parameterTypes("Lcom/google/firebase/remoteconfig/FirebaseRemoteConfig;")
}

View File

@@ -1,40 +1,37 @@
package app.revanced.patches.reddit.customclients.relayforreddit.api
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.getInstruction
import app.revanced.patcher.extensions.replaceInstruction
import app.revanced.patches.reddit.customclients.spoofClientPatch
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.returnEarly
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction10t
import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction21t
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
val spoofClientPatch = spoofClientPatch(redirectUri = "dbrady://relay") {
@Suppress("unused")
val spoofClientPatch = spoofClientPatch(redirectUri = "dbrady://relay") { clientIdOption ->
compatibleWith(
"free.reddit.news",
"reddit.news",
)
val clientId by it
val clientId by clientIdOption
apply {
// region Patch client id.
setOf(
loginActivityClientIdFingerprint,
getLoggedInBearerTokenFingerprint,
getLoggedOutBearerTokenFingerprint,
getRefreshTokenFingerprint,
).forEach { fingerprint ->
val clientIdIndex = fingerprint.stringMatches.first().index
fingerprint.method.apply {
val clientIdRegister = getInstruction<OneRegisterInstruction>(clientIdIndex).registerA
listOf(
loginActivityClientIdMethodMatch,
getLoggedInBearerTokenMethodMatch,
getLoggedOutBearerTokenMethodMatch,
getRefreshTokenMethodMatch,
).forEach { match ->
val clientIdIndex = match.indices.first()
val clientIdRegister = match.method.getInstruction<OneRegisterInstruction>(clientIdIndex).registerA
fingerprint.method.replaceInstruction(
clientIdIndex,
"const-string v$clientIdRegister, \"$clientId\"",
)
}
match.method.replaceInstruction(clientIdIndex, "const-string v$clientIdRegister, \"$clientId\"")
}
// endregion
@@ -42,12 +39,11 @@ val spoofClientPatch = spoofClientPatch(redirectUri = "dbrady://relay") {
// region Patch miscellaneous.
// Do not load remote config which disables OAuth login remotely.
setRemoteConfigFingerprint.method.addInstructions(0, "return-void")
setRemoteConfigMethod.returnEarly()
// Prevent OAuth login being disabled remotely.
val checkIsOAuthRequestIndex = redditCheckDisableAPIFingerprint.instructionMatches.first().index
redditCheckDisableAPIFingerprint.method.apply {
redditCheckDisableAPIMethod.apply {
val checkIsOAuthRequestIndex = indexOfFirstInstructionOrThrow(Opcode.IF_EQZ)
val returnNextChain = getInstruction<BuilderInstruction21t>(checkIsOAuthRequestIndex).target
replaceInstruction(checkIsOAuthRequestIndex, BuilderInstruction10t(Opcode.GOTO, returnNextChain))
}

View File

@@ -1,11 +1,11 @@
package app.revanced.patches.reddit.customclients.slide.api
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.patch.BytecodePatchContext
internal val getClientIdFingerprint = fingerprint {
custom { method, classDef ->
if (!classDef.endsWith("Credentials;")) return@custom false
method.name == "getClientId"
}
internal val BytecodePatchContext.getClientIdMethod by gettingFirstMutableMethodDeclaratively {
name("getClientId")
definingClass("Credentials;"::endsWith)
}

View File

@@ -9,6 +9,6 @@ val spoofClientPatch = spoofClientPatch(redirectUri = "http://www.ccrama.me") {
val clientId by clientIdOption
apply {
getClientIdFingerprint.method.returnEarly(clientId!!)
getClientIdMethod.returnEarly(clientId!!)
}
}

View File

@@ -1,7 +1,7 @@
package app.revanced.patches.reddit.customclients.sync.detection.piracy
import app.revanced.patcher.extensions.addInstruction
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.util.returnEarly
val disablePiracyDetectionPatch = bytecodePatch(
description = "Disables detection of modified versions.",
@@ -10,6 +10,6 @@ val disablePiracyDetectionPatch = bytecodePatch(
apply {
// Do not throw an error if the fingerprint is not resolved.
// This is fine because new versions of the target app do not need this patch.
piracyDetectionFingerprint.methodOrNull?.addInstruction(0, "return-void")
detectPiracyMethodOrNull?.returnEarly()
}
}

View File

@@ -1,26 +1,33 @@
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.accessFlags
import app.revanced.patcher.custom
import app.revanced.patcher.extensions.instructions
import app.revanced.patcher.fingerprint
import app.revanced.util.getReference
import app.revanced.patcher.extensions.reference
import app.revanced.patcher.instructions
import app.revanced.patcher.patch.BytecodePatchContext
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.reference.Reference
internal val piracyDetectionFingerprint = fingerprint {
internal val BytecodePatchContext.detectPiracyMethodOrNull by gettingFirstMutableMethodDeclarativelyOrNull(
"Lcom/github/javiersantos/piracychecker/PiracyChecker;"
) {
accessFlags(AccessFlags.PRIVATE, AccessFlags.FINAL)
returns("V")
opcodes(
Opcode.NEW_INSTANCE,
Opcode.INVOKE_DIRECT,
Opcode.NEW_INSTANCE,
Opcode.INVOKE_DIRECT,
Opcode.INVOKE_VIRTUAL,
returnType("V")
instructions(
Opcode.NEW_INSTANCE(),
Opcode.INVOKE_DIRECT(),
Opcode.NEW_INSTANCE(),
Opcode.INVOKE_DIRECT(),
Opcode.INVOKE_VIRTUAL(),
)
custom { method, _ ->
method.implementation ?: return@custom false
method.instructions.any {
it.getReference<Reference>()?.toString() == "Lcom/github/javiersantos/piracychecker/PiracyChecker;"
// TODO: Convert to instructions() extension.
custom {
instructions.any {
it.reference.toString() == "Lcom/github/javiersantos/piracychecker/PiracyChecker;"
}
}
}
}

View File

@@ -1,11 +1,11 @@
package app.revanced.patches.reddit.customclients.sync.syncforreddit.annoyances.startup
import app.revanced.patcher.extensions.instructions
import app.revanced.patcher.extensions.removeInstruction
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.patch.creatingBytecodePatch
@Suppress("unused")
val disableSyncForLemmyBottomSheetPatch = bytecodePatch(
name = "Disable Sync for Lemmy bottom sheet",
@Suppress("unused", "ObjectPropertyName")
val `Disable Sync for Lemmy bottom sheet` = creatingBytecodePatch(
description = "Disables the bottom sheet at the startup that asks you to signup to \"Sync for Lemmy\".",
) {
compatibleWith(
@@ -15,10 +15,8 @@ val disableSyncForLemmyBottomSheetPatch = bytecodePatch(
)
apply {
mainActivityOnCreateFingerprint.method.apply {
val showBottomSheetIndex = implementation!!.instructions.lastIndex - 1
val showBottomSheetIndex = mainActivityOnCreateMethod.instructions.lastIndex - 1
removeInstruction(showBottomSheetIndex)
}
mainActivityOnCreateMethod.removeInstruction(showBottomSheetIndex)
}
}

View File

@@ -1,9 +1,11 @@
package app.revanced.patches.reddit.customclients.sync.syncforreddit.annoyances.startup
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.patch.BytecodePatchContext
internal val mainActivityOnCreateFingerprint = fingerprint {
custom { method, classDef ->
classDef.endsWith("MainActivity;") && method.name == "onCreate"
}
internal val BytecodePatchContext.mainActivityOnCreateMethod by gettingFirstMutableMethodDeclaratively {
name("onCreate")
definingClass("MainActivity;"::endsWith)
}

View File

@@ -1,19 +1,24 @@
package app.revanced.patches.reddit.customclients.sync.syncforreddit.api
import app.revanced.patcher.fingerprint
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethod
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 getAuthorizationStringFingerprint = fingerprint {
strings("authorize.compact?client_id")
internal val getAuthorizationStringMethodMatch = firstMethodComposite {
instructions(string("authorize.compact?client_id"::startsWith))
}
internal val getBearerTokenFingerprint = fingerprint {
strings("Basic")
internal val getBearerTokenMethodMatch = firstMethodComposite {
instructions(string("Basic"::startsWith))
}
internal val getUserAgentFingerprint = fingerprint {
strings("android:com.laurencedawson.reddit_sync")
}
internal val BytecodePatchContext.getUserAgentMethod by gettingFirstMutableMethod(
"android:com.laurencedawson.reddit_sync"
)
internal val imgurImageAPIFingerprint = fingerprint {
strings("https://imgur-apiv3.p.rapidapi.com/3/image")
internal val imgurImageAPIMethodMatch = firstMethodComposite {
instructions("https://imgur-apiv3.p.rapidapi.com/3/image"())
}

View File

@@ -2,15 +2,15 @@ package app.revanced.patches.reddit.customclients.sync.syncforreddit.api
import app.revanced.patcher.extensions.getInstruction
import app.revanced.patcher.extensions.replaceInstruction
import app.revanced.patcher.extensions.stringReference
import app.revanced.patches.reddit.customclients.spoofClientPatch
import app.revanced.patches.reddit.customclients.sync.detection.piracy.disablePiracyDetectionPatch
import app.revanced.patches.shared.misc.string.replaceStringPatch
import app.revanced.util.returnEarly
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
import com.android.tools.smali.dexlib2.iface.reference.StringReference
import java.util.Base64
import java.util.*
@Suppress("unused")
val spoofClientPatch = spoofClientPatch(
redirectUri = "http://redditsync/auth",
) { clientIdOption ->
@@ -32,19 +32,17 @@ val spoofClientPatch = spoofClientPatch(
apply {
// region Patch client id.
getBearerTokenFingerprint.match(getAuthorizationStringFingerprint.originalClassDef).method.apply {
getBearerTokenMethodMatch.match(getAuthorizationStringMethodMatch.immutableClassDef).method.apply {
val auth = Base64.getEncoder().encodeToString("$clientId:".toByteArray(Charsets.UTF_8))
returnEarly("Basic $auth")
val occurrenceIndex =
getAuthorizationStringFingerprint.stringMatches.first().index
val occurrenceIndex = getAuthorizationStringMethodMatch.indices.first()
getAuthorizationStringFingerprint.method.apply {
val authorizationStringInstruction = getInstruction<ReferenceInstruction>(occurrenceIndex)
val targetRegister = (authorizationStringInstruction as OneRegisterInstruction).registerA
val reference = authorizationStringInstruction.reference as StringReference
getAuthorizationStringMethodMatch.method.apply {
val authorizationStringInstruction = getInstruction<OneRegisterInstruction>(occurrenceIndex)
val targetRegister = authorizationStringInstruction.registerA
val newAuthorizationUrl = reference.string.replace(
val newAuthorizationUrl = authorizationStringInstruction.stringReference!!.string.replace(
"client_id=.*?&".toRegex(),
"client_id=$clientId&",
)
@@ -64,19 +62,17 @@ val spoofClientPatch = spoofClientPatch(
val randomName = (0..100000).random()
val userAgent = "$randomName:app.revanced.$randomName:v1.0.0 (by /u/revanced)"
getUserAgentFingerprint.method.returnEarly(userAgent)
getUserAgentMethod.returnEarly(userAgent)
// endregion
// region Patch Imgur API URL.
imgurImageAPIFingerprint.let {
val apiUrlIndex = it.stringMatches.first().index
it.method.replaceInstruction(
apiUrlIndex,
"const-string v1, \"https://api.imgur.com/3/image\"",
)
}
val apiUrlIndex = imgurImageAPIMethodMatch.indices.first()
imgurImageAPIMethodMatch.method.replaceInstruction(
apiUrlIndex,
"const-string v1, \"https://api.imgur.com/3/image\"",
)
// endregion
}

View File

@@ -1,14 +1,11 @@
package app.revanced.patches.reddit.misc.tracking.url
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patches.shared.PATCH_DESCRIPTION_SANITIZE_SHARING_LINKS
import app.revanced.patches.shared.PATCH_NAME_SANITIZE_SHARING_LINKS
import app.revanced.patcher.patch.creatingBytecodePatch
@Suppress("unused")
val sanitizeUrlQueryPatch = bytecodePatch(
name = PATCH_NAME_SANITIZE_SHARING_LINKS,
description = PATCH_DESCRIPTION_SANITIZE_SHARING_LINKS,
@Suppress("unused", "ObjectPropertyName")
val `Sanitize sharing links` by creatingBytecodePatch(
description = "Removes the tracking query parameters from shared links.",
) {
compatibleWith("com.reddit.frontpage")

View File

@@ -1,14 +1,11 @@
package app.revanced.patches.serviceportalbund.detection.root
import app.revanced.patcher.extensions.addInstruction
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patches.shared.PATCH_DESCRIPTION_REMOVE_ROOT_DETECTION
import app.revanced.patches.shared.PATCH_NAME_REMOVE_ROOT_DETECTION
import app.revanced.patcher.patch.creatingBytecodePatch
@Suppress("unused")
val rootDetectionPatch = bytecodePatch(
name = PATCH_NAME_REMOVE_ROOT_DETECTION,
description = PATCH_DESCRIPTION_REMOVE_ROOT_DETECTION
@Suppress("unused", "ObjectPropertyName")
val `Remove root detection` by creatingBytecodePatch(
description = "Removes the check for root permissions and unlocked bootloader."
) {
compatibleWith("at.gv.bka.serviceportal")

View File

@@ -1,16 +0,0 @@
package app.revanced.patches.shared
//
// Names and descriptions used by different patches implementing the same feature.
//
internal const val PATCH_NAME_REMOVE_ROOT_DETECTION = "Remove root detection"
internal const val PATCH_DESCRIPTION_REMOVE_ROOT_DETECTION = "Removes the check for root permissions and unlocked bootloader."
internal const val PATCH_NAME_SANITIZE_SHARING_LINKS = "Sanitize sharing links"
internal const val PATCH_DESCRIPTION_SANITIZE_SHARING_LINKS = "Removes the tracking query parameters from shared links."
internal const val PATCH_NAME_CHANGE_LINK_SHARING_DOMAIN = "Change link sharing domain"
internal const val PATCH_DESCRIPTION_CHANGE_LINK_SHARING_DOMAIN = "Replaces the domain name of shared links."
internal const val PATCH_NAME_HIDE_NAVIGATION_BUTTONS = "Hide navigation buttons"

View File

@@ -8,8 +8,6 @@ import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patches.all.misc.resources.addResources
import app.revanced.patches.all.misc.resources.addResourcesPatch
import app.revanced.patches.shared.PATCH_DESCRIPTION_SANITIZE_SHARING_LINKS
import app.revanced.patches.shared.PATCH_NAME_SANITIZE_SHARING_LINKS
import app.revanced.patches.shared.misc.settings.preference.BasePreferenceScreen
import app.revanced.patches.shared.misc.settings.preference.PreferenceCategory
import app.revanced.patches.shared.misc.settings.preference.PreferenceScreenPreference.Sorting
@@ -30,8 +28,8 @@ internal fun sanitizeSharingLinksPatch(
preferenceScreen: BasePreferenceScreen.Screen,
replaceMusicLinksWithYouTube: Boolean = false
) = bytecodePatch(
name = PATCH_NAME_SANITIZE_SHARING_LINKS,
description = PATCH_DESCRIPTION_SANITIZE_SHARING_LINKS,
name = "Sanitize sharing links",
description = "Removes the tracking query parameters from shared links.",
) {
block()

View File

@@ -3,8 +3,7 @@ package app.revanced.patches.spotify.misc.privacy
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.getInstruction
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patches.shared.PATCH_DESCRIPTION_SANITIZE_SHARING_LINKS
import app.revanced.patches.shared.PATCH_NAME_SANITIZE_SHARING_LINKS
import app.revanced.patcher.patch.creatingBytecodePatch
import app.revanced.patches.spotify.misc.extension.sharedExtensionPatch
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow
@@ -15,10 +14,9 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference
private const val EXTENSION_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/spotify/misc/privacy/SanitizeSharingLinksPatch;"
@Suppress("unused")
val sanitizeSharingLinksPatch = bytecodePatch(
name = PATCH_NAME_SANITIZE_SHARING_LINKS,
description = PATCH_DESCRIPTION_SANITIZE_SHARING_LINKS,
@Suppress("unused", "ObjectPropertyName")
val `Sanitize sharing links` by creatingBytecodePatch(
description = "Removes the tracking query parameters from shared links.",
) {
compatibleWith("com.spotify.music")

Some files were not shown because too many files have changed in this diff Show More