mirror of
https://github.com/ReVanced/revanced-patches.git
synced 2026-01-23 10:41:03 +00:00
feat: Modernise APIs (#6476)
This commit is contained in:
@@ -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")
|
||||
|
||||
|
||||
@@ -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."
|
||||
)
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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")
|
||||
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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;")
|
||||
}
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
)
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
""",
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;")
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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;")
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
@@ -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,
|
||||
"""
|
||||
|
||||
@@ -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"))
|
||||
|
||||
|
||||
@@ -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"))
|
||||
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
)
|
||||
}
|
||||
@@ -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!!)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
)
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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"()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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\"")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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" }
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
)
|
||||
|
||||
@@ -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",
|
||||
)
|
||||
|
||||
@@ -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")
|
||||
@@ -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(
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
@@ -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" }
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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(),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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;")
|
||||
}
|
||||
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -9,6 +9,6 @@ val spoofClientPatch = spoofClientPatch(redirectUri = "http://www.ccrama.me") {
|
||||
val clientId by clientIdOption
|
||||
|
||||
apply {
|
||||
getClientIdFingerprint.method.returnEarly(clientId!!)
|
||||
getClientIdMethod.returnEarly(clientId!!)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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"())
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
|
||||
|
||||
@@ -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")
|
||||
|
||||
|
||||
@@ -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"
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user