This commit is contained in:
oSumAtrIX 2026-01-14 02:23:45 +01:00
parent 8c0c3b44e5
commit 50f95543f1
No known key found for this signature in database
GPG key ID: A9B3094ACDB604B4
81 changed files with 393 additions and 588 deletions

View file

@ -2,13 +2,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
@Suppress("unused")
val rootDetectionPatch = bytecodePatch(
name = PATCH_NAME_REMOVE_ROOT_DETECTION,
description = PATCH_DESCRIPTION_REMOVE_ROOT_DETECTION,
name = "Remove root detection",
description = "Removes the check for root permissions and unlocked bootloader.",
) {
compatibleWith("at.gv.bmf.bmf2go")

View file

@ -5,7 +5,6 @@ import app.revanced.patcher.fingerprint
import app.revanced.patcher.patch.booleanOption
import app.revanced.patcher.patch.bytecodePatch
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
@ -21,7 +20,7 @@ private const val EXTENSION_CLASS_DESCRIPTOR =
@Suppress("unused")
val hideNavigationButtonsPatch = bytecodePatch(
name = PATCH_NAME_HIDE_NAVIGATION_BUTTONS,
name = "Hide navigation buttons",
description = "Hides navigation bar buttons, such as the Reels and Create button.",
use = false
) {

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

@ -4,16 +4,14 @@ import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.patch.bytecodePatch
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,
name = "Sanitize sharing links",
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

@ -8,8 +8,8 @@ import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.returnType
internal val BytecodePatchContext.googleApiActivityMethod by gettingFirstMutableMethodDeclaratively {
name("onCreate")
definingClass("GoogleApiActivity;"::endsWith)
returnType("V")
parameterTypes("Landroid/os/Bundle;")
definingClass("GoogleApiActivity;"::endsWith)
name("onCreate")
}

View file

@ -1,7 +1,7 @@
package app.revanced.patches.music.misc.settings
import app.revanced.patcher.classDef
import app.revanced.patcher.patch.creatingBytecodePatch
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.patch.resourcePatch
import app.revanced.patches.all.misc.packagename.setOrGetFallbackPackageName
import app.revanced.patches.all.misc.resources.addResources
@ -65,7 +65,7 @@ private val settingsResourcePatch = resourcePatch {
}
}
val Settings by creatingBytecodePatch(
val settingsPatch = bytecodePatch(
description = "Adds settings for ReVanced to YouTube Music."
) {
dependsOn(

View file

@ -2,7 +2,7 @@
package app.revanced.patches.music.playservice
import app.revanced.patcher.patch.creatingResourcePatch
import app.revanced.patcher.patch.resourcePatch
import app.revanced.util.findPlayStoreServicesVersion
import kotlin.properties.Delegates
@ -21,8 +21,8 @@ var is_8_11_or_greater: Boolean by Delegates.notNull()
var is_8_15_or_greater: Boolean by Delegates.notNull()
private set
@Suppress("unused", "ObjectPropertyName")
val `Version check` by creatingResourcePatch(
@Suppress("unused")
val versionCheckPatch = resourcePatch(
description = "Uses the Play Store service version to find the major/minor version of the YouTube Music target app."
) {
apply {

View file

@ -9,14 +9,14 @@ import app.revanced.patcher.returnType
import com.android.tools.smali.dexlib2.AccessFlags
internal val BytecodePatchContext.isPremiumUseCaseImplMethod by gettingFirstMutableMethodDeclaratively {
accessFlags(AccessFlags.PUBLIC)
definingClass("IsPremiumUseCaseImpl;")
name("doWork")
definingClass("IsPremiumUseCaseImpl;"::endsWith)
accessFlags(AccessFlags.PUBLIC)
}
internal val BytecodePatchContext.mainActivityNavigateToNativePremiumUpsellMethod by gettingFirstMutableMethodDeclaratively {
name("navigateToNativePremiumUpsell")
definingClass("MainActivity;"::endsWith)
accessFlags(AccessFlags.PRIVATE, AccessFlags.FINAL)
returnType("V")
definingClass("MainActivity;")
name("navigateToNativePremiumUpsell")
}

View file

@ -1,32 +1,23 @@
package app.revanced.patches.nunl.ads
import app.revanced.patcher.*
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.accessFlags
import app.revanced.patcher.definingClass
import app.revanced.patcher.firstMethodComposite
import app.revanced.patcher.instructions
import app.revanced.patcher.invoke
import app.revanced.patcher.name
import app.revanced.patcher.parameterTypes
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.returnType
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
internal val BytecodePatchContext.jwPlayerConfigMethod by gettingFirstMutableMethodDeclaratively {
accessFlags(AccessFlags.PUBLIC)
definingClass($$"Lcom/jwplayer/pub/api/configuration/PlayerConfig$Builder;")
name("advertisingConfig")
definingClass($$"Lcom/jwplayer/pub/api/configuration/PlayerConfig$Builder;")
accessFlags(AccessFlags.PUBLIC)
}
internal val screenMapperMethodMatch = firstMethodComposite {
name("map")
definingClass("Lnl/nu/android/bff/data/mappers/ScreenMapper;")
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returnType("Lnl/nu/android/bff/domain/models/screen/ScreenEntity;")
parameterTypes("Lnl/nu/performance/api/client/objects/Screen;")
definingClass("Lnl/nu/android/bff/data/mappers/ScreenMapper;")
name("map")
instructions(
Opcode.MOVE_RESULT_OBJECT(),
Opcode.IF_EQZ(),

View file

@ -27,19 +27,17 @@ val `Hide ads` by creatingBytecodePatch(
arrayOf(screenMapperMethodMatch, nextPageRepositoryImplMethodMatch).forEach { match ->
// Index of instruction moving result of BlockPage;->getBlocks(...).
val moveGetBlocksResultObjectIndex = match.indices.first()
match.method.apply {
val moveInstruction = getInstruction<OneRegisterInstruction>(moveGetBlocksResultObjectIndex)
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,24 +1,20 @@
package app.revanced.patches.nunl.firebase
import app.revanced.patcher.*
import app.revanced.patcher.BytecodePatchContextMethodMatching.firstMutableMethodDeclaratively
import app.revanced.patcher.accessFlags
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
import com.android.tools.smali.dexlib2.AccessFlags
internal val firebaseClasses = arrayOf(
internal fun BytecodePatchContext.getFingerprintHashForPackageMethods() = arrayOf(
"Lcom/google/firebase/installations/remote/FirebaseInstallationServiceClient;",
"Lcom/google/firebase/remoteconfig/internal/ConfigFetchHttpClient;",
"Lcom/google/firebase/remoteconfig/internal/ConfigRealtimeHttpClient;"
)
internal fun BytecodePatchContext.getFingerprintHashForPackageMethod(className: String) = firstMutableMethodDeclaratively {
accessFlags(AccessFlags.PRIVATE)
definingClass(className)
name("getFingerprintHashForPackage")
returnType("Ljava/lang/String;")
parameterTypes()
).map {
firstMutableMethodDeclaratively {
name("getFingerprintHashForPackage")
definingClass(it)
accessFlags(AccessFlags.PRIVATE)
returnType("Ljava/lang/String;")
parameterTypes()
}
}

View file

@ -10,8 +10,8 @@ val `Spoof certificate` by creatingBytecodePatch(
compatibleWith("nl.sanomamedia.android.nu")
apply {
firebaseClasses.forEach { className ->
getFingerprintHashForPackageMethod(className).returnEarly("eae41fc018df2731a9b6ae1ac327da44a288667b")
getFingerprintHashForPackageMethods().forEach {
it.returnEarly("eae41fc018df2731a9b6ae1ac327da44a288667b")
}
}
}

View file

@ -9,8 +9,8 @@ import app.revanced.patcher.returnType
import com.android.tools.smali.dexlib2.AccessFlags
internal val BytecodePatchContext.isDeviceRootedMethod by gettingFirstMutableMethodDeclaratively {
accessFlags(AccessFlags.PUBLIC)
name("isDeviceRooted")
definingClass("/RootChecker;"::endsWith)
accessFlags(AccessFlags.PUBLIC)
returnType("Z")
}

View file

@ -1,12 +1,11 @@
package app.revanced.patches.orfon.detection.root
import app.revanced.patcher.patch.creatingBytecodePatch
import app.revanced.patches.shared.PATCH_DESCRIPTION_REMOVE_ROOT_DETECTION
import app.revanced.util.returnEarly
@Suppress("unused", "ObjectPropertyName")
val `Remove root detection` by creatingBytecodePatch(
description = PATCH_DESCRIPTION_REMOVE_ROOT_DETECTION
description = "Removes the check for root permissions and unlocked bootloader."
) {
compatibleWith("com.nousguide.android.orftvthek")

View file

@ -4,12 +4,10 @@ import app.revanced.patcher.patch.creatingBytecodePatch
import app.revanced.util.returnEarly
@Suppress("unused", "ObjectPropertyName")
val `Enable Unlimited Skips` by creatingBytecodePatch(
description = "Enable unlimited skips"
) {
val `Enable Unlimited Skips` by creatingBytecodePatch {
compatibleWith("com.pandora.android")
apply {
skipLimitBehaviorMethod.returnEarly("unlimited")
getSkipLimitBehaviorMethod.returnEarly("unlimited")
}
}

View file

@ -5,7 +5,7 @@ import app.revanced.patcher.definingClass
import app.revanced.patcher.name
import app.revanced.patcher.patch.BytecodePatchContext
internal val BytecodePatchContext.skipLimitBehaviorMethod by gettingFirstMutableMethodDeclaratively {
internal val BytecodePatchContext.getSkipLimitBehaviorMethod by gettingFirstMutableMethodDeclaratively {
name("getSkipLimitBehavior")
definingClass("UserData;"::endsWith)
}

View file

@ -4,7 +4,7 @@ import app.revanced.patcher.patch.creatingBytecodePatch
import app.revanced.util.returnEarly
@Suppress("unused", "ObjectPropertyName")
val `Hide Ads` by creatingBytecodePatch(
val `Hide ads` by creatingBytecodePatch(
description = "Hides all video ads."
) {
compatibleWith("com.peacocktv.peacockandroid")

View file

@ -1,6 +1,5 @@
package app.revanced.patches.photomath.detection.signature
import app.revanced.patcher.allOf
import app.revanced.patcher.firstMethodComposite
import app.revanced.patcher.instructions
import app.revanced.patcher.invoke
@ -8,7 +7,7 @@ import com.android.tools.smali.dexlib2.Opcode
internal val checkSignatureMethodMatch = firstMethodComposite("SHA") {
instructions(
allOf(Opcode.CONST_STRING(), "SHA"()),
Opcode.CONST_STRING(),
Opcode.INVOKE_STATIC(),
Opcode.INVOKE_STATIC(),
Opcode.MOVE_RESULT_OBJECT(),

View file

@ -12,9 +12,8 @@ val `Signature detection` by creatingBytecodePatch(
apply {
val replacementIndex = checkSignatureMethodMatch.indices.last()
checkSignatureMethodMatch.method.apply {
val checkRegister = getInstruction<OneRegisterInstruction>(replacementIndex).registerA
replaceInstruction(replacementIndex, "const/4 v$checkRegister, 0x1")
}
val checkRegister = checkSignatureMethodMatch.method.getInstruction<OneRegisterInstruction>(replacementIndex)
.registerA
checkSignatureMethodMatch.method.replaceInstruction(replacementIndex, "const/4 v$checkRegister, 0x1")
}
}

View file

@ -1,20 +1,15 @@
package app.revanced.patches.photomath.misc.annoyances
import app.revanced.patcher.*
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.accessFlags
import app.revanced.patcher.definingClass
import app.revanced.patcher.fingerprint
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.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
internal val BytecodePatchContext.hideUpdatePopupMethod by gettingFirstMutableMethodDeclaratively {
definingClass("Lcom/microblink/photomath/main/activity/MainActivity;")
accessFlags(AccessFlags.FINAL, AccessFlags.PUBLIC)
returnType("V")
definingClass("Lcom/microblink/photomath/main/activity/MainActivity;")
instructions(
Opcode.CONST_HIGH16(),
Opcode.INVOKE_VIRTUAL(), // ViewPropertyAnimator.alpha(1.0f)

View file

@ -1,10 +1,10 @@
package app.revanced.patches.photomath.misc.unlock.bookpoint
import app.revanced.patcher.extensions.replaceInstructions
import app.revanced.patcher.patch.creatingBytecodePatch
import app.revanced.patcher.patch.bytecodePatch
@Suppress("unused")
val `Enable bookpoint` by creatingBytecodePatch(
val enableBookpointPatch = bytecodePatch(
description = "Enables textbook access",
) {

View file

@ -2,21 +2,18 @@ package app.revanced.patches.photomath.misc.unlock.bookpoint
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.accessFlags
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.AccessFlags
internal val BytecodePatchContext.isBookpointEnabledMethod by gettingFirstMutableMethodDeclaratively {
internal val BytecodePatchContext.isBookpointEnabledMethod by gettingFirstMutableMethodDeclaratively(
"NoGeoData",
"NoCountryInGeo",
"RemoteConfig",
"GeoRCMismatch"
) {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returnType("Z")
parameterTypes()
instructions(
"NoGeoData"(),
"NoCountryInGeo"(),
"RemoteConfig"(),
"GeoRCMismatch"()
)
}

View file

@ -5,12 +5,10 @@ import app.revanced.patcher.accessFlags
import app.revanced.patcher.definingClass
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.returnType
import app.revanced.patcher.string
import com.android.tools.smali.dexlib2.AccessFlags
internal val BytecodePatchContext.isPlusUnlockedMethod by gettingFirstMutableMethodDeclaratively {
internal val BytecodePatchContext.isPlusUnlockedMethod by gettingFirstMutableMethodDeclaratively("genius") {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returnType("Z")
string("genius")
definingClass("/User;"::endsWith)
}

View file

@ -3,11 +3,11 @@ package app.revanced.patches.photomath.misc.unlock.plus
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.patch.creatingBytecodePatch
import app.revanced.patches.photomath.detection.signature.`Signature detection`
import app.revanced.patches.photomath.misc.unlock.bookpoint.`Enable bookpoint`
import app.revanced.patches.photomath.misc.unlock.bookpoint.enableBookpointPatch
@Suppress("unused")
val `Unlock plus` by creatingBytecodePatch {
dependsOn(`Signature detection`, `Enable bookpoint`)
dependsOn(`Signature detection`, enableBookpointPatch)
compatibleWith("com.microblink.photomath")

View file

@ -33,34 +33,31 @@ val `Disable tracking` by creatingBytecodePatch(
)
apply {
facebookSDKMethod.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\"",
)
}
firebaseInstallMethod.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\"",
)
}
appMeasurementMethod.addInstruction(0, "return-void")
}
}

View file

@ -12,7 +12,7 @@ internal val BytecodePatchContext.appMeasurementMethod by gettingFirstMutableMet
}
internal val BytecodePatchContext.facebookSDKMethod by gettingFirstMutableMethodDeclaratively("instagram.com", "facebook.com") {
accessFlags(AccessFlags.PRIVATE, AccessFlags.CONSTRUCTOR)
accessFlags(AccessFlags.STATIC, AccessFlags.CONSTRUCTOR)
}
internal val BytecodePatchContext.firebaseInstallMethod by gettingFirstMutableMethodDeclaratively("https://%s/%s/%s", "firebaseinstallations.googleapis.com") {

View file

@ -9,8 +9,8 @@ import app.revanced.patcher.returnType
import com.android.tools.smali.dexlib2.AccessFlags
internal val BytecodePatchContext.shouldShowAdsMethod by gettingFirstMutableMethodDeclaratively {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returnType("Z")
definingClass("AdUtils;"::endsWith)
name("shouldShowAds")
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returnType("Z")
}

View file

@ -1,18 +1,14 @@
package app.revanced.patches.primevideo.ads
import app.revanced.patcher.*
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.accessFlags
import app.revanced.patcher.definingClass
import app.revanced.patcher.instructions
import app.revanced.patcher.invoke
import app.revanced.patcher.name
import app.revanced.patcher.parameterTypes
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.returnType
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
internal val BytecodePatchContext.enterServerInsertedAdBreakStateMethod by gettingFirstMutableMethodDeclaratively {
name("enter")
definingClass("Lcom/amazon/avod/media/ads/internal/state/ServerInsertedAdBreakState;")
accessFlags(AccessFlags.PUBLIC)
parameterTypes("Lcom/amazon/avod/fsm/Trigger;")
returnType("V")
@ -22,11 +18,11 @@ internal val BytecodePatchContext.enterServerInsertedAdBreakStateMethod by getti
Opcode.CONST_4(),
Opcode.CONST_4()
)
name("enter")
definingClass("Lcom/amazon/avod/media/ads/internal/state/ServerInsertedAdBreakState;")
}
internal val BytecodePatchContext.doTriggerMethod by gettingFirstMutableMethodDeclaratively {
name("doTrigger")
definingClass("Lcom/amazon/avod/fsm/StateBase;")
accessFlags(AccessFlags.PROTECTED)
returnType("V")
instructions(
@ -34,6 +30,4 @@ internal val BytecodePatchContext.doTriggerMethod by gettingFirstMutableMethodDe
Opcode.INVOKE_INTERFACE(),
Opcode.RETURN_VOID()
)
name("doTrigger")
definingClass("Lcom/amazon/avod/fsm/StateBase;")
}

View file

@ -1,26 +1,22 @@
package app.revanced.patches.primevideo.video.speed
import app.revanced.patcher.*
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.parameterTypes
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.returnType
import com.android.tools.smali.dexlib2.AccessFlags
internal val BytecodePatchContext.playbackUserControlsInitializeMethod by gettingFirstMutableMethodDeclaratively {
name("initialize")
definingClass("Lcom/amazon/avod/playbackclient/activity/feature/PlaybackUserControlsFeature;")
accessFlags(AccessFlags.PUBLIC)
parameterTypes("Lcom/amazon/avod/playbackclient/PlaybackInitializationContext;")
returnType("V")
name("initialize")
definingClass("Lcom/amazon/avod/playbackclient/activity/feature/PlaybackUserControlsFeature;")
}
internal val BytecodePatchContext.playbackUserControlsPrepareForPlaybackMethod by gettingFirstMutableMethodDeclaratively {
name("prepareForPlayback")
definingClass("Lcom/amazon/avod/playbackclient/activity/feature/PlaybackUserControlsFeature;")
accessFlags(AccessFlags.PUBLIC)
parameterTypes("Lcom/amazon/avod/playbackclient/PlaybackContext;")
returnType("V")
name("prepareForPlayback")
definingClass("Lcom/amazon/avod/playbackclient/activity/feature/PlaybackUserControlsFeature;")
}

View file

@ -9,8 +9,8 @@ import app.revanced.patcher.returnType
import com.android.tools.smali.dexlib2.AccessFlags
internal val BytecodePatchContext.showReminderMethod by gettingFirstMutableMethodDeclaratively {
accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC)
returnType("V")
definingClass("AdsNotify;"::endsWith)
name("show")
accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC)
returnType("V")
}

View file

@ -1,35 +0,0 @@
package app.revanced.patches.reddit.ad.banner
import app.revanced.patcher.patch.creatingResourcePatch
// 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
@Suppress("unused")
val `Hide banner` = creatingResourcePatch(
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,4 +1,4 @@
package app.revanced.patches.nunl.ads
package app.revanced.patches.reddit.ad.general
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.definingClass
@ -9,16 +9,13 @@ import app.revanced.patcher.returnType
import com.android.tools.smali.dexlib2.Opcode
internal val BytecodePatchContext.adPostMethod by gettingFirstMutableMethodDeclaratively("children") {
definingClass("Listing;"::endsWith)
returnType("V")
// "children" are present throughout multiple versions
instructions("children"())
definingClass { endsWith("Listing;") }
}
internal val BytecodePatchContext.newAdPostMethod by gettingFirstMutableMethodDeclaratively(
"feedElement", "com.reddit.cookie"
"feedElement",
"com.reddit.cookie"
) {
instructions(Opcode.INVOKE_VIRTUAL())
instructions("feedElement"())
instructions("com.reddit.cookie"())
}

View file

@ -3,10 +3,10 @@ package app.revanced.patches.reddit.ad.general
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.removeInstruction
import app.revanced.patcher.patch.creatingBytecodePatch
import app.revanced.patches.nunl.ads.adPostMethod
import app.revanced.patches.nunl.ads.newAdPostMethod
import app.revanced.patches.reddit.ad.comments.`Hide comment ads`
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
@ -14,9 +14,7 @@ import com.android.tools.smali.dexlib2.iface.reference.FieldReference
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
@Suppress("unused", "ObjectPropertyName")
val `Hide ads` by creatingBytecodePatch(
description = "Hide ads"
) {
val `Hide ads` by creatingBytecodePatch {
dependsOn(`Hide comment ads`, sharedExtensionPatch)
compatibleWith("com.reddit.frontpage")
@ -26,32 +24,30 @@ val `Hide ads` by creatingBytecodePatch(
val filterMethodDescriptor =
"Lapp/revanced/extension/reddit/patches/FilterPromotedLinksPatch;" +
"->filterChildren(Ljava/lang/Iterable;)Ljava/util/List;"
"->filterChildren(Ljava/lang/Iterable;)Ljava/util/List;"
adPostMethod.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
@ -60,10 +56,8 @@ val `Hide ads` by creatingBytecodePatch(
// AdElementConverter is conveniently responsible for inserting all feed ads.
// By removing the appending instruction no ad posts gets appended to the feed.
val index = newAdPostMethod.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;"
}

View file

@ -2,15 +2,15 @@ package app.revanced.patches.reddit.customclients
import app.revanced.patcher.patch.BytecodePatchBuilder
import app.revanced.patcher.patch.Patch
import app.revanced.patcher.patch.creatingBytecodePatch
import app.revanced.patcher.patch.bytecodePatch
const val INSTALL_NEW_CLIENT_METHOD = "install(Lokhttp3/OkHttpClient${'$'}Builder;)Lokhttp3/OkHttpClient;"
const val CREATE_NEW_CLIENT_METHOD = "createClient()Lokhttp3/OkHttpClient;"
fun `Fix Redgifs API`(
fun fixRedgifsApi(
extensionPatch: Patch,
block: BytecodePatchBuilder.() -> Unit = {},
) = creatingBytecodePatch {
) = bytecodePatch("Fix Redgifs API") {
dependsOn(extensionPatch)
block()

View file

@ -2,15 +2,17 @@ package app.revanced.patches.reddit.customclients
import app.revanced.patcher.patch.BytecodePatchBuilder
import app.revanced.patcher.patch.Patch
import app.revanced.patcher.patch.creatingBytecodePatch
import app.revanced.patcher.patch.bytecodePatch
const val RESOLVE_S_LINK_METHOD = "patchResolveSLink(Ljava/lang/String;)Z"
const val SET_ACCESS_TOKEN_METHOD = "patchSetAccessToken(Ljava/lang/String;)V"
fun `Fix s links`(
fun fixSLinksPatch(
extensionPatch: Patch,
block: BytecodePatchBuilder.() -> Unit = {},
) = creatingBytecodePatch {
) = bytecodePatch(
"Fix /s/ links",
) {
dependsOn(extensionPatch)
block()

View file

@ -2,7 +2,7 @@ package app.revanced.patches.reddit.customclients
import app.revanced.patcher.patch.BytecodePatchBuilder
import app.revanced.patcher.patch.Option
import app.revanced.patcher.patch.creatingBytecodePatch
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.patch.stringOption
/**
@ -11,10 +11,11 @@ import app.revanced.patcher.patch.stringOption
* @param redirectUri The redirect URI of the Reddit OAuth client.
* @param block The patch block. It is called with the client ID option.
*/
fun `Spoof client`(
fun spoofClientPatch(
redirectUri: String,
block: BytecodePatchBuilder.(Option<String>) -> Unit = {},
) = creatingBytecodePatch(
) = bytecodePatch(
name = "Spoof client",
description = "Restores functionality of the app by using custom client ID.",
) {
block(

View file

@ -1,20 +1,16 @@
package app.revanced.patches.reddit.customclients.baconreader.api
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.definingClass
import app.revanced.patcher.name
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.firstMethodComposite
import app.revanced.patcher.instructions
import app.revanced.patcher.invoke
internal val BytecodePatchContext.getAuthorizationUrlMethod by gettingFirstMutableMethodDeclaratively(
"client_id=zACVn0dSFGdWqQ"
)
internal val BytecodePatchContext.getClientIdMethod by gettingFirstMutableMethodDeclaratively("client_id=zACVn0dSFGdWqQ") {
name("getAuthorizeUrl")
definingClass { endsWith("RedditOAuth;") }
internal val getAuthorizationUrlMethodMatch = firstMethodComposite {
instructions("client_id=zACVn0dSFGdWqQ"())
}
internal val BytecodePatchContext.requestTokenMethod by gettingFirstMutableMethodDeclaratively(
"zACVn0dSFGdWqQ",
"kDm2tYpu9DqyWFFyPlNcXGEni4k"
)
internal val requestTokenMethodMatch = firstMethodComposite {
instructions(
"zACVn0dSFGdWqQ"(),
"kDm2tYpu9DqyWFFyPlNcXGEni4k"(String::contains)
)
}

View file

@ -1,17 +1,13 @@
package app.revanced.patches.reddit.customclients.baconreader.api
import app.revanced.patcher.MatchBuilder
import app.revanced.patcher.extensions.getInstruction
import app.revanced.patcher.extensions.replaceInstruction
import app.revanced.patches.reddit.customclients.`Spoof client`
import app.revanced.patches.reddit.customclients.spoofClientPatch
import app.revanced.patches.shared.misc.string.replaceStringPatch
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.StringReference
import com.android.tools.smali.dexlib2.mutable.MutableMethod
val spoofClientPatch = `Spoof client`(redirectUri = "http://baconreader.com/auth") { clientIdOption ->
val spoofClientPatch = spoofClientPatch(redirectUri = "http://baconreader.com/auth") { clientIdOption ->
dependsOn(
// Redirects from SSL to WWW domain are bugged causing auth problems.
// Manually rewrite the URLs to fix this.
@ -26,22 +22,20 @@ val spoofClientPatch = `Spoof client`(redirectUri = "http://baconreader.com/auth
val clientId by clientIdOption
apply {
fun MutableMethod.patch(targetString: String, replacementString: String) {
val clientIdIndex = indexOfFirstInstructionOrThrow {
opcode == Opcode.CONST_STRING && getReference<StringReference>()?.string == targetString
}
fun MatchBuilder.patch(replacementString: String) {
val clientIdIndex = indices.first()
val clientIdRegister = getInstruction<OneRegisterInstruction>(clientIdIndex).registerA
replaceInstruction(
val clientIdRegister = method.getInstruction<OneRegisterInstruction>(clientIdIndex).registerA
method.replaceInstruction(
clientIdIndex,
"const-string v$clientIdRegister, \"$replacementString\"",
)
}
// Patch client id in authorization url.
getAuthorizationUrlMethod.patch("client_id=zACVn0dSFGdWqQ", "client_id=$clientId")
getAuthorizationUrlMethodMatch.patch("client_id=$clientId")
// Patch client id for access token request.
requestTokenMethod.patch("zACVn0dSFGdWqQ", clientId!!)
requestTokenMethodMatch.patch(clientId!!)
}
}

View file

@ -8,8 +8,8 @@ import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.returnType
internal val BytecodePatchContext.getOkHttpClientMethod by gettingFirstMutableMethodDeclaratively {
returnType("Lokhttp3/OkHttpClient;")
parameterTypes()
definingClass("Lcom/onelouder/baconreader/media/gfycat/RedGifsManager;")
name("getOkhttpClient")
returnType("Lokhttp3/OkHttpClient;")
parameterTypes()
}

View file

@ -3,9 +3,9 @@ package app.revanced.patches.reddit.customclients.baconreader.fix.redgifs
import app.revanced.patcher.extensions.getInstruction
import app.revanced.patcher.extensions.removeInstructions
import app.revanced.patcher.extensions.replaceInstruction
import app.revanced.patches.reddit.customclients.fixRedgifsApi
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.`Fix Redgifs API`
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow
import com.android.tools.smali.dexlib2.Opcode
@ -16,7 +16,7 @@ import com.android.tools.smali.dexlib2.iface.reference.TypeReference
internal const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/baconreader/FixRedgifsApiPatch;"
@Suppress("unused")
val fixRedgifsApi = `Fix Redgifs API`(
val fixRedgifsApi = fixRedgifsApi(
extensionPatch = sharedExtensionPatch
) {
compatibleWith(
@ -27,26 +27,25 @@ val fixRedgifsApi = `Fix Redgifs API`(
apply {
// region Patch Redgifs OkHttp3 client.
getOkHttpClientMethod.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,15 +1,14 @@
package app.revanced.patches.reddit.customclients.boostforreddit.ads
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.patch.creatingBytecodePatch
import app.revanced.util.returnEarly
@Suppress("unused", "ObjectPropertyName")
val `Disable ads` by creatingBytecodePatch {
compatibleWith("com.rubenmayayo.reddit")
apply {
arrayOf(maxMediationMethod, admobMediationMethod).forEach { method ->
method.addInstructions(0, "return-void")
}
maxMediationMethod.returnEarly()
admobMediationMethod.returnEarly()
}
}

View file

@ -11,5 +11,5 @@ internal val BytecodePatchContext.buildUserAgentMethod by gettingFirstMutableMet
internal val BytecodePatchContext.getClientIdMethod by gettingFirstMutableMethodDeclaratively {
name("getClientId")
definingClass { endsWith("Credentials;") }
definingClass("Credentials;"::endsWith)
}

View file

@ -2,7 +2,7 @@ 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.`Spoof client`
import app.revanced.patches.reddit.customclients.spoofClientPatch
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.returnEarly
@ -11,7 +11,7 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.StringReference
@Suppress("unused")
val spoofClientPatch = `Spoof client`(redirectUri = "http://rubenmayayo.com") { clientIdOption ->
val spoofClientPatch = spoofClientPatch(redirectUri = "http://rubenmayayo.com") { clientIdOption ->
compatibleWith("com.rubenmayayo.reddit")
val clientId by clientIdOption
@ -29,14 +29,12 @@ val spoofClientPatch = `Spoof client`(redirectUri = "http://rubenmayayo.com") {
val randomName = (0..100000).random()
val userAgent = "$randomName:app.revanced.$randomName:v1.0.0 (by /u/revanced)"
buildUserAgentMethod.apply {
val userAgentTemplateIndex = indexOfFirstInstructionOrThrow {
opcode == Opcode.CONST_STRING && getReference<StringReference>()?.string == "%s:%s:%s (by /u/%s)"
}
val register = getInstruction<OneRegisterInstruction>(userAgentTemplateIndex).registerA
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,9 +1,12 @@
package app.revanced.patches.reddit.customclients.boostforreddit.fix.downloads
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.firstMethodComposite
import app.revanced.patcher.instructions
import app.revanced.patcher.invoke
internal val BytecodePatchContext.downloadAudioMethod by gettingFirstMutableMethodDeclaratively(
"/DASH_audio.mp4",
"/audio"
)
internal val downloadAudioMethodMatch = firstMethodComposite {
instructions(
"/DASH_audio.mp4"(),
"/audio"()
)
}

View file

@ -3,11 +3,7 @@ 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.creatingBytecodePatch
import app.revanced.util.findInstructionIndicesReversed
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", "ObjectPropertyName")
val `Fix missing audio in video downloads` by creatingBytecodePatch(
@ -16,21 +12,16 @@ val `Fix missing audio in video downloads` by creatingBytecodePatch(
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",
)
downloadAudioMethod.apply {
endpointReplacements.forEach { (target, replacement) ->
// Find all occurrences of the target string in the method
findInstructionIndicesReversed {
opcode == Opcode.CONST_STRING && getReference<StringReference>()?.string == target
}.forEach { index ->
val register = getInstruction<OneRegisterInstruction>(index).registerA
replaceInstruction(index, "const-string v$register, \"$replacement\"")
}
}
downloadAudioMethodMatch.indices.forEachIndexed { index, i ->
val replacement = endpointReplacements[i]
val register = downloadAudioMethodMatch.method.getInstruction<OneRegisterInstruction>(index).registerA
downloadAudioMethodMatch.method.replaceInstruction(index, "const-string v$register, \"$replacement\"")
}
}
}

View file

@ -1,15 +1,10 @@
package app.revanced.patches.reddit.customclients.boostforreddit.fix.redgifs
import app.revanced.patcher.*
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.accessFlags
import app.revanced.patcher.classDef
import app.revanced.patcher.custom
import app.revanced.patcher.instructions
import app.revanced.patcher.invoke
import app.revanced.patcher.patch.BytecodePatchContext
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.Method
internal val BytecodePatchContext.createOkHttpClientMethod by gettingFirstMutableMethodDeclaratively {
accessFlags(AccessFlags.PRIVATE)
@ -23,8 +18,5 @@ internal val BytecodePatchContext.createOkHttpClientMethod by gettingFirstMutabl
Opcode.INVOKE_VIRTUAL(),
Opcode.MOVE_RESULT_OBJECT()
)
// Helper to capture the BytecodePatchContext for classDef access
fun Method.isTargetSourceFile() = classDef.sourceFile == "RedGifsAPIv2.java"
custom { isTargetSourceFile() }
custom { immutableClassDef.sourceFile == "RedGifsAPIv2.java" }
}

View file

@ -1,17 +1,16 @@
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.fixRedgifsApi
import app.revanced.patches.reddit.customclients.boostforreddit.misc.extension.sharedExtensionPatch
import app.revanced.patches.reddit.customclients.`Fix Redgifs API`
import app.revanced.util.getReference
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;"
@Suppress("unused")
val fixRedgifsApi = `Fix Redgifs API`(
val fixRedgifsApi = fixRedgifsApi(
extensionPatch = sharedExtensionPatch
) {
compatibleWith("com.rubenmayayo.reddit")
@ -19,16 +18,14 @@ val fixRedgifsApi = `Fix Redgifs API`(
apply {
// region Patch Redgifs OkHttp3 client.
createOkHttpClientMethod.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

@ -8,9 +8,9 @@ import app.revanced.patcher.returnType
import com.android.tools.smali.dexlib2.AccessFlags
internal val BytecodePatchContext.getOAuthAccessTokenMethod by gettingFirstMutableMethodDeclaratively("access_token") {
definingClass("Lnet/dean/jraw/http/oauth/OAuthData;")
accessFlags(AccessFlags.PUBLIC)
returnType("Ljava/lang/String;")
definingClass("Lnet/dean/jraw/http/oauth/OAuthData;")
}
internal val BytecodePatchContext.handleNavigationMethod by gettingFirstMutableMethodDeclaratively(

View file

@ -20,21 +20,20 @@ val fixSlinksPatch = fixSLinksPatch(
apply {
// region Patch navigation handler.
handleNavigationMethod.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

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

@ -1,13 +1,13 @@
package app.revanced.patches.reddit.customclients.infinityforreddit.api
import app.revanced.patcher.extensions.toInstructions
import app.revanced.patches.reddit.customclients.`Spoof client`
import app.revanced.patches.reddit.customclients.spoofClientPatch
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.immutable.ImmutableMethod
import com.android.tools.smali.dexlib2.immutable.ImmutableMethodImplementation
import com.android.tools.smali.dexlib2.mutable.MutableMethod.Companion.toMutable
val spoofClientPatch = `Spoof client`(redirectUri = "infinity://localhost") { clientIdOption ->
val spoofClientPatch = spoofClientPatch(redirectUri = "infinity://localhost") { clientIdOption ->
compatibleWith(
"ml.docilealligator.infinityforreddit",
"ml.docilealligator.infinityforreddit.plus",
@ -17,7 +17,7 @@ val spoofClientPatch = `Spoof client`(redirectUri = "infinity://localhost") { cl
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.BytecodePatchContextMethodMatching.gettingFirstMutableMethod
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.instructions
import app.revanced.patcher.literal
import app.revanced.patcher.invoke
import app.revanced.patcher.patch.BytecodePatchContext
internal val BytecodePatchContext.billingClientOnServiceConnectedMethod by gettingFirstMutableMethodDeclaratively("Billing service connected")
internal val BytecodePatchContext.billingClientOnServiceConnectedMethod by gettingFirstMutableMethod("Billing service connected")
internal val BytecodePatchContext.startSubscriptionActivityMethod by gettingFirstMutableMethodDeclaratively {
instructions(
literal(0x10008000)
)
instructions(0x10008000L())
}

View file

@ -17,9 +17,7 @@ val `Unlock subscription` by creatingBytecodePatch(
)
apply {
setOf(
billingClientOnServiceConnectedMethod,
startSubscriptionActivityMethod,
).forEach { it.returnEarly() }
billingClientOnServiceConnectedMethod.returnEarly()
startSubscriptionActivityMethod.returnEarly()
}
}

View file

@ -1,8 +1,8 @@
package app.revanced.patches.reddit.customclients.joeyforreddit.ads
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.patch.creatingBytecodePatch
import app.revanced.patches.reddit.customclients.joeyforreddit.detection.piracy.`Disable piracy detection`
import app.revanced.util.returnEarly
@Suppress("unused", "ObjectPropertyName")
val `Disable ads` by creatingBytecodePatch {
@ -11,12 +11,6 @@ val `Disable ads` by creatingBytecodePatch {
compatibleWith("o.o.joey")
apply {
isAdFreeUserMethod.addInstructions(
0,
"""
const/4 v0, 0x1
return v0
""",
)
isAdFreeUserMethod.returnEarly(true)
}
}

View file

@ -4,11 +4,9 @@ import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutab
import app.revanced.patcher.accessFlags
import app.revanced.patcher.patch.BytecodePatchContext
import app.revanced.patcher.returnType
import app.revanced.patcher.string
import com.android.tools.smali.dexlib2.AccessFlags
internal val BytecodePatchContext.isAdFreeUserMethod by gettingFirstMutableMethodDeclaratively {
internal val BytecodePatchContext.isAdFreeUserMethod by gettingFirstMutableMethodDeclaratively("AD_FREE_USER") {
accessFlags(AccessFlags.PUBLIC)
returnType("Z")
string("AD_FREE_USER")
}

View file

@ -1,13 +1,8 @@
package app.revanced.patches.reddit.customclients.infinity.api
package app.revanced.patches.reddit.customclients.joeyforreddit.api
import app.revanced.patcher.*
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.accessFlags
import app.revanced.patcher.classDef
import app.revanced.patcher.custom
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.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
@ -15,7 +10,7 @@ internal val BytecodePatchContext.authUtilityUserAgentMethod by gettingFirstMuta
accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC)
returnType("Ljava/lang/String;")
instructions(Opcode.APUT_OBJECT())
custom { classDef.sourceFile == "AuthUtility.java" }
custom { immutableClassDef.sourceFile == "AuthUtility.java" }
}
internal val BytecodePatchContext.getClientIdMethod by gettingFirstMutableMethodDeclaratively {
@ -27,5 +22,5 @@ internal val BytecodePatchContext.getClientIdMethod by gettingFirstMutableMethod
Opcode.MOVE_RESULT_OBJECT(),
Opcode.RETURN_OBJECT(),
)
custom { classDef.sourceFile == "AuthUtility.java" }
custom { immutableClassDef.sourceFile == "AuthUtility.java" }
}

View file

@ -1,13 +1,11 @@
package app.revanced.patches.reddit.customclients.joeyforreddit.api
import app.revanced.patches.reddit.customclients.infinity.api.authUtilityUserAgentMethod
import app.revanced.patches.reddit.customclients.infinity.api.getClientIdMethod
import app.revanced.patches.reddit.customclients.`Spoof client`
import app.revanced.patches.reddit.customclients.sync.detection.piracy.`Disable piracy detection`
import app.revanced.patches.reddit.customclients.spoofClientPatch
import app.revanced.patches.reddit.customclients.sync.detection.piracy.disablePiracyDetectionPatch
import app.revanced.util.returnEarly
val spoofClientPatch = `Spoof client`(redirectUri = "https://127.0.0.1:65023/authorize_callback") { clientIdOption ->
dependsOn(`Disable piracy detection`)
val spoofClientPatch = spoofClientPatch(redirectUri = "https://127.0.0.1:65023/authorize_callback") { clientIdOption ->
dependsOn(disablePiracyDetectionPatch)
compatibleWith(
"o.o.joey",

View file

@ -1,12 +1,8 @@
package app.revanced.patches.reddit.customclients.joeyforreddit.detection.piracy
import app.revanced.patcher.*
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.accessFlags
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.AccessFlags
import com.android.tools.smali.dexlib2.Opcode

View file

@ -1,24 +1,24 @@
package app.revanced.patches.reddit.customclients.redditisfun.api
import app.revanced.patcher.*
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.accessFlags
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.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
internal val BytecodePatchContext.basicAuthorizationMethod by gettingFirstMutableMethodDeclaratively(
"yyOCBp.RHJhDKd",
"fJOxVwBUyo*=f:<OoejWs:AqmIJ" // Encrypted basic authorization string.
)
internal val basicAuthorizationMethodMatch = firstMethodComposite {
instructions(
"yyOCBp.RHJhDKd"(),
"fJOxVwBUyo*=f:<OoejWs:AqmIJ"() // Encrypted basic authorization string.
)
}
internal val BytecodePatchContext.buildAuthorizationStringMethod by gettingFirstMutableMethodDeclaratively(
"yyOCBp.RHJhDKd",
"client_id"
)
internal val buildAuthorizationStringMethodMatch = firstMethodComposite {
instructions(
"yyOCBp.RHJhDKd"(),
"client_id"()
)
}
internal val BytecodePatchContext.getUserAgentMethod by gettingFirstMutableMethodDeclaratively {
accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC)

View file

@ -1,18 +1,18 @@
package app.revanced.patches.reddit.customclients.redditisfun.api
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.`Spoof client`
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
import com.android.tools.smali.dexlib2.mutable.MutableMethod
@Suppress("unused")
val spoofClientPatch = `Spoof client`(redirectUri = "redditisfun://auth") { clientIdOption ->
val spoofClientPatch = spoofClientPatch(redirectUri = "redditisfun://auth") { clientIdOption ->
compatibleWith(
"com.andrewshu.android.reddit",
"com.andrewshu.android.redditdonation",
@ -29,36 +29,23 @@ val spoofClientPatch = `Spoof client`(redirectUri = "redditisfun://auth") { clie
*
* @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 MutableMethod.replaceWith(
fun MatchBuilder.replaceWith(
string: String,
offset: Int,
getReplacementIndex: String
) {
val anchorIndex = indexOfFirstInstructionOrThrow {
opcode == Opcode.CONST_STRING && getReference<StringReference>()?.string == string
}
getReplacementIndex: List<Int>.() -> Int,
) = method.apply {
val replacementIndex = indices.getReplacementIndex()
val clientIdRegister = getInstruction<OneRegisterInstruction>(replacementIndex).registerA
val targetIndex = anchorIndex + offset
val clientIdRegister = getInstruction<OneRegisterInstruction>(targetIndex).registerA
replaceInstruction(targetIndex, "const-string v$clientIdRegister, \"$getReplacementIndex\"")
replaceInstruction(replacementIndex, "const-string v$clientIdRegister, \"$string\"")
}
// Patch OAuth authorization.
buildAuthorizationStringMethod.replaceWith(
string = "yyOCBp.RHJhDKd",
offset = 4,
getReplacementIndex = clientId!!
)
buildAuthorizationStringMethodMatch.replaceWith(clientId!!) { first() + 4 }
// Path basic authorization.
basicAuthorizationMethod.replaceWith(
string = "fJOxVwBUyo*=f:<OoejWs:AqmIJ",
offset = 7,
getReplacementIndex = "$clientId:"
)
basicAuthorizationMethodMatch.replaceWith("$clientId:") { last() + 7 }
// endregion
@ -76,9 +63,9 @@ val spoofClientPatch = `Spoof client`(redirectUri = "redditisfun://auth") { clie
// 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.
buildAuthorizationStringMethod.apply {
buildAuthorizationStringMethodMatch.method.apply {
val index = indexOfFirstInstructionOrThrow {
getReference<StringReference>()?.string?.contains("old.reddit.com") == true
getReference<StringReference>()?.contains("old.reddit.com") == true
}
val targetRegister = getInstruction<OneRegisterInstruction>(index).registerA

View file

@ -1,27 +1,28 @@
package app.revanced.patches.reddit.customclients.relayforreddit.api
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 val BytecodePatchContext.getLoggedInBearerTokenMethod by gettingFirstMutableMethodDeclaratively(
"dj-xCIZQYiLbEg", "authorization_code"
)
internal val BytecodePatchContext.getLoggedOutBearerTokenMethod by gettingFirstMutableMethodDeclaratively(
"dj-xCIZQYiLbEg", "https://oauth.reddit.com/grants/installed_client"
)
internal fun baseClientIdMethod(string: String) = firstMethodComposite {
instructions(
"dj-xCIZQYiLbEg"(),
string()
)
}
internal val BytecodePatchContext.getRefreshTokenMethod by gettingFirstMutableMethodDeclaratively(
"dj-xCIZQYiLbEg", "refresh_token"
)
internal val getLoggedInBearerTokenMethodMatch = baseClientIdMethod("authorization_code")
internal val BytecodePatchContext.loginActivityClientIdMethod by gettingFirstMutableMethodDeclaratively(
"dj-xCIZQYiLbEg", "&duration=permanent"
)
internal val getLoggedOutBearerTokenMethodMatch = baseClientIdMethod("https://oauth.reddit.com/grants/installed_client")
internal val getRefreshTokenMethodMatch = baseClientIdMethod("refresh_token")
internal val loginActivityClientIdMethodMatch = baseClientIdMethod("&duration=permanent")
internal val BytecodePatchContext.redditCheckDisableAPIMethod by gettingFirstMutableMethodDeclaratively("Reddit Disabled") {
instructions(Opcode.IF_EQZ())

View file

@ -1,19 +1,17 @@
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.`Spoof client`
import app.revanced.util.getReference
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
import com.android.tools.smali.dexlib2.iface.reference.StringReference
@Suppress("unused")
val spoofClientPatch = `Spoof client`(redirectUri = "dbrady://relay") { clientIdOption ->
val spoofClientPatch = spoofClientPatch(redirectUri = "dbrady://relay") { clientIdOption ->
compatibleWith(
"free.reddit.news",
"reddit.news",
@ -25,22 +23,15 @@ val spoofClientPatch = `Spoof client`(redirectUri = "dbrady://relay") { clientId
// region Patch client id.
listOf(
loginActivityClientIdMethod,
getLoggedInBearerTokenMethod,
getLoggedOutBearerTokenMethod,
getRefreshTokenMethod,
).forEach { method ->
method.apply {
val clientIdIndex = indexOfFirstInstructionOrThrow {
opcode == Opcode.CONST_STRING && getReference<StringReference>()?.string == "dj-xCIZQYiLbEg"
}
val clientIdRegister = getInstruction<OneRegisterInstruction>(clientIdIndex).registerA
loginActivityClientIdMethodMatch,
getLoggedInBearerTokenMethodMatch,
getLoggedOutBearerTokenMethodMatch,
getRefreshTokenMethodMatch,
).forEach { match ->
val clientIdIndex = match.indices.first()
val clientIdRegister = match.method.getInstruction<OneRegisterInstruction>(clientIdIndex).registerA
replaceInstruction(
clientIdIndex,
"const-string v$clientIdRegister, \"$clientId\"",
)
}
match.method.replaceInstruction(clientIdIndex, "const-string v$clientIdRegister, \"$clientId\"")
}
// endregion
@ -48,7 +39,7 @@ val spoofClientPatch = `Spoof client`(redirectUri = "dbrady://relay") { clientId
// region Patch miscellaneous.
// Do not load remote config which disables OAuth login remotely.
setRemoteConfigMethod.addInstructions(0, "return-void")
setRemoteConfigMethod.returnEarly()
// Prevent OAuth login being disabled remotely.
redditCheckDisableAPIMethod.apply {

View file

@ -7,5 +7,5 @@ import app.revanced.patcher.patch.BytecodePatchContext
internal val BytecodePatchContext.getClientIdMethod by gettingFirstMutableMethodDeclaratively {
name("getClientId")
definingClass { endsWith("Credentials;") }
definingClass("Credentials;"::endsWith)
}

View file

@ -1,9 +1,9 @@
package app.revanced.patches.reddit.customclients.slide.api
import app.revanced.patches.reddit.customclients.`Spoof client`
import app.revanced.patches.reddit.customclients.spoofClientPatch
import app.revanced.util.returnEarly
val spoofClientPatch = `Spoof client`(redirectUri = "http://www.ccrama.me") { clientIdOption ->
val spoofClientPatch = spoofClientPatch(redirectUri = "http://www.ccrama.me") { clientIdOption ->
compatibleWith("me.ccrama.redditslide")
val clientId by clientIdOption

View file

@ -1,9 +1,9 @@
package app.revanced.patches.reddit.customclients.sync.detection.piracy
import app.revanced.patcher.extensions.addInstruction
import app.revanced.patcher.patch.creatingBytecodePatch
import app.revanced.patcher.patch.bytecodePatch
val `Disable piracy detection` by creatingBytecodePatch(
val disablePiracyDetectionPatch = bytecodePatch(
description = "Disables detection of modified versions.",
) {

View file

@ -1,11 +1,10 @@
package app.revanced.patches.reddit.customclients.sync.detection.piracy
import app.revanced.patcher.*
import app.revanced.patcher.BytecodePatchContextMethodMatching.gettingFirstMutableMethodDeclaratively
import app.revanced.patcher.accessFlags
import app.revanced.patcher.instructions
import app.revanced.patcher.invoke
import app.revanced.patcher.extensions.instructions
import app.revanced.patcher.extensions.reference
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
@ -21,4 +20,10 @@ internal val BytecodePatchContext.piracyDetectionMethod by gettingFirstMutableMe
Opcode.INVOKE_DIRECT(),
Opcode.INVOKE_VIRTUAL(),
)
}
// 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.syncforlemmy.ads
import app.revanced.patches.reddit.customclients.sync.ads.disableAdsPatch
import app.revanced.patches.reddit.customclients.sync.detection.piracy.`Disable piracy detection`
import app.revanced.patches.reddit.customclients.sync.detection.piracy.disablePiracyDetectionPatch
@Suppress("unused")
val disableAdsPatch = disableAdsPatch {
dependsOn(`Disable piracy detection`)
dependsOn(disablePiracyDetectionPatch)
compatibleWith("com.laurencedawson.reddit_sync")
}

View file

@ -6,6 +6,6 @@ import app.revanced.patcher.name
import app.revanced.patcher.patch.BytecodePatchContext
internal val BytecodePatchContext.mainActivityOnCreateMethod by gettingFirstMutableMethodDeclaratively {
definingClass("MainActivity;")
name("onCreate")
definingClass("MainActivity;"::endsWith)
}

View file

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

View file

@ -2,23 +2,20 @@ package app.revanced.patches.reddit.customclients.sync.syncforreddit.api
import app.revanced.patcher.extensions.getInstruction
import app.revanced.patcher.extensions.replaceInstruction
import app.revanced.patches.reddit.customclients.`Spoof client`
import app.revanced.patches.reddit.customclients.sync.detection.piracy.`Disable piracy detection`
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.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
import java.util.Base64
import java.util.*
@Suppress("unused")
val spoofClientPatch = `Spoof client`(
val spoofClientPatch = spoofClientPatch(
redirectUri = "http://redditsync/auth",
) { clientIdOption ->
dependsOn(
`Disable piracy detection`,
disablePiracyDetectionPatch,
// Redirects from SSL to WWW domain are bugged causing auth problems.
// Manually rewrite the URLs to fix this.
replaceStringPatch("ssl.reddit.com", "www.reddit.com")
@ -35,30 +32,26 @@ val spoofClientPatch = `Spoof client`(
apply {
// region Patch client id.
getBearerTokenMethod.apply {
getBearerTokenMethodMatch.match(getAuthorizationStringMethodMatch.immutableClassDef).method.apply {
val auth = Base64.getEncoder().encodeToString("$clientId:".toByteArray(Charsets.UTF_8))
returnEarly("Basic $auth")
}
getAuthorizationStringMethod.apply {
val occurrenceIndex = indexOfFirstInstructionOrThrow {
opcode == Opcode.CONST_STRING &&
getReference<StringReference>()?.string?.contains("client_id=") == true
val occurrenceIndex = getAuthorizationStringMethodMatch.indices.first()
getAuthorizationStringMethodMatch.method.apply {
val authorizationStringInstruction = getInstruction<OneRegisterInstruction>(occurrenceIndex)
val targetRegister = authorizationStringInstruction.registerA
val newAuthorizationUrl = authorizationStringInstruction.stringReference!!.string.replace(
"client_id=.*?&".toRegex(),
"client_id=$clientId&",
)
replaceInstruction(
occurrenceIndex,
"const-string v$targetRegister, \"$newAuthorizationUrl\"",
)
}
val authorizationStringInstruction = getInstruction<OneRegisterInstruction>(occurrenceIndex)
val targetRegister = authorizationStringInstruction.registerA
val reference = authorizationStringInstruction.getReference<StringReference>()!!
val newAuthorizationUrl = reference.string.replace(
"client_id=.*?&".toRegex(),
"client_id=$clientId&",
)
replaceInstruction(
occurrenceIndex,
"const-string v$targetRegister, \"$newAuthorizationUrl\"",
)
}
// endregion
@ -75,17 +68,11 @@ val spoofClientPatch = `Spoof client`(
// region Patch Imgur API URL.
imgurImageAPIMethod.apply {
val apiUrlIndex = indexOfFirstInstructionOrThrow {
opcode == Opcode.CONST_STRING &&
getReference<StringReference>()?.string == "https://api.imgur.com/3/image"
}
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

@ -4,7 +4,7 @@ import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.getInstruction
import app.revanced.patcher.extensions.replaceInstruction
import app.revanced.patches.reddit.customclients.INSTALL_NEW_CLIENT_METHOD
import app.revanced.patches.reddit.customclients.`Fix Redgifs API`
import app.revanced.patches.reddit.customclients.fixRedgifsApi
import app.revanced.patches.reddit.customclients.sync.syncforreddit.extension.sharedExtensionPatch
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow
@ -14,7 +14,7 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference
internal const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/syncforreddit/FixRedgifsApiPatch;"
@Suppress("unused")
val fixRedgifsApi = `Fix Redgifs API`(
val fixRedgifsApi = fixRedgifsApi(
extensionPatch = sharedExtensionPatch
) {
compatibleWith(

View file

@ -2,13 +2,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
@Suppress("unused")
val sanitizeUrlQueryPatch = 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.",
) {
compatibleWith("com.reddit.frontpage")

View file

@ -2,13 +2,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
@Suppress("unused")
val rootDetectionPatch = bytecodePatch(
name = PATCH_NAME_REMOVE_ROOT_DETECTION,
description = PATCH_DESCRIPTION_REMOVE_ROOT_DETECTION
name = "Remove root detection",
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,6 @@ 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.patches.spotify.misc.extension.sharedExtensionPatch
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow
@ -17,8 +15,8 @@ private const val EXTENSION_CLASS_DESCRIPTOR =
@Suppress("unused")
val sanitizeSharingLinksPatch = 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.",
) {
compatibleWith("com.spotify.music")

View file

@ -1,11 +1,8 @@
package app.revanced.patches.tiktok.misc.share
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.addInstructionsWithLabels
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.patches.tiktok.misc.extension.sharedExtensionPatch
import app.revanced.util.findFreeRegister
import app.revanced.util.getReference
@ -20,8 +17,8 @@ private const val EXTENSION_CLASS_DESCRIPTOR =
@Suppress("unused")
val sanitizeShareUrlsPatch = 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.",
) {
dependsOn(sharedExtensionPatch)

View file

@ -5,8 +5,6 @@ import app.revanced.patcher.extensions.getInstruction
import app.revanced.patcher.extensions.replaceInstruction
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.patch.stringOption
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.patches.twitter.misc.extension.sharedExtensionPatch
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.returnEarly
@ -62,8 +60,8 @@ internal val changeLinkSharingDomainResourcePatch = resourcePatch {
@Suppress("unused")
val changeLinkSharingDomainPatch = bytecodePatch(
name = PATCH_NAME_CHANGE_LINK_SHARING_DOMAIN,
description = "$PATCH_DESCRIPTION_CHANGE_LINK_SHARING_DOMAIN Including this patch can prevent making posts that quote other posts.",
name = "Change link sharing domain",
description = "Replaces the domain name of shared links. Using this patch can prevent making posts that quote other posts.",
use = false
) {
dependsOn(

View file

@ -2,13 +2,11 @@ package app.revanced.patches.twitter.misc.links
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
@Suppress("unused")
val sanitizeSharingLinksPatch = 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.",
) {
compatibleWith(
"com.twitter.android"(

View file

@ -3,12 +3,11 @@ package app.revanced.patches.viber.misc.navbar
import app.revanced.patcher.extensions.addInstructionsWithLabels
import app.revanced.patcher.patch.booleanOption
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patches.shared.PATCH_NAME_HIDE_NAVIGATION_BUTTONS
import java.util.logging.Logger
@Suppress("unused")
val hideNavigationButtonsPatch = bytecodePatch(
name = PATCH_NAME_HIDE_NAVIGATION_BUTTONS,
name = "Hide navigation buttons",
description = "Permanently hides navigation bar buttons, such as Explore and Marketplace.",
use = false
) {