Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add Disable analytics and telemetry patches #3448

Draft
wants to merge 21 commits into
base: dev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ Some of the features the patches provide are:
* 🚫 **Block ads**: Say goodbye to ads
* ⭐ **Customize your app**: Personalize the appearance of apps with various layouts and themes
* 🪄 **Add new features**: Extend the functionality of apps with lots of new features
* 👁️‍🗨️ **Enhance your privacy**: Disable embedded trackers and privacy invasive components
LisoUseInAIKyrios marked this conversation as resolved.
Show resolved Hide resolved
* ⚙️ **Miscellaneous and general purpose**: Rename packages, enable debugging, disable screen capture restrictions,
export activities, etc.
* ✨ **And much more!**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package app.revanced.patches.all.analytics

import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patcher.patch.options.PatchOption
import app.revanced.patcher.patch.options.PatchOption.PatchExtensions.booleanPatchOption
import app.revanced.patches.all.analytics.google.DisableGoogleAnalytics
import app.revanced.patches.all.analytics.statsig.DisableStatsig
import java.util.logging.Logger

@Patch(
name = "Disable privacy invasive components",
description = "Disables multiple analytics and telemetry SDKs embedded in the app",
)
@Suppress("unused")
object UniversalPrivacyPatch : BytecodePatch(
setOf()
) {

// We have to create a copy of the map as a MutableMapIterator does not exist
private val subPatchesOptionsEvaluated = mutableMapOf<Pair<String, BytecodePatch>, PatchOption<Boolean?>>()

private val subPatchesOptions = mapOf(
Pair("Google Analytics", DisableGoogleAnalytics) to false,
Pair("Statsig", DisableStatsig) to true,
).forEach {
subPatchesOptionsEvaluated[it.key] = booleanPatchOption(
key = it.key.first,
default = it.value,
values = mapOf(
),
title = "Enabled patches",
description = "Which SDK to target",
required = true
)
}


override fun execute(context: BytecodeContext) {
subPatchesOptionsEvaluated.forEach {
LisoUseInAIKyrios marked this conversation as resolved.
Show resolved Hide resolved
if (it.value.value == true){
Logger.getLogger(this::class.java.name).warning("Applying patch to disable ${it.key.first}")
LisoUseInAIKyrios marked this conversation as resolved.
Show resolved Hide resolved
it.key.second.execute(context)
}
}

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package app.revanced.patches.all.analytics.appsflyer

import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patches.all.analytics.appsflyer.fingerprints.AppsFlyerInitFingerprint
import app.revanced.util.resultOrThrow

@Patch(
name = "Disable AppsFlyer analytics SDK",
use = false,
)
@Suppress("unused")
object DisableAppsFlyer : BytecodePatch(
setOf(AppsFlyerInitFingerprint)
) {
override fun execute(context: BytecodeContext) {
AppsFlyerInitFingerprint.resultOrThrow().mutableMethod.addInstructions(
0,
"""
sget-object p0, Lkotlin/Unit;->INSTANCE:Lkotlin/Unit;
return-object p0
"""
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package app.revanced.patches.all.analytics.appsflyer.fingerprints

import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags

object AppsFlyerInitFingerprint : MethodFingerprint(
LisoUseInAIKyrios marked this conversation as resolved.
Show resolved Hide resolved
returnType = "Ljava/lang/Object;",
accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC or AccessFlags.SYNTHETIC,
parameters = listOf("L", "L", "L"),
customFingerprint = { _, classDef ->
classDef.sourceFile == "CatchingAppsFlyerLibWrapper.kt"
}
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package app.revanced.patches.all.analytics.comscore

import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patches.all.analytics.comscore.fingerprints.ComScoreSetupFingerprint
import app.revanced.util.resultOrThrow

@Patch(
name = "Disable ComScore analytics SDK",
use = false,
)
@Suppress("unused")
object DisableComScore : BytecodePatch(
setOf(ComScoreSetupFingerprint)
) {
override fun execute(context: BytecodeContext) {
ComScoreSetupFingerprint.resultOrThrow().mutableMethod.addInstructions(0, "return-void")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package app.revanced.patches.all.analytics.comscore.fingerprints

import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags

object ComScoreSetupFingerprint : MethodFingerprint(
returnType = "V",
accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC,
customFingerprint = { methodDef, classDef ->
classDef.type == "Lcom/comscore/util/setup/Setup;" && methodDef.name == "setUp"
}
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package app.revanced.patches.all.analytics.crashlytics

import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patches.all.analytics.crashlytics.fingerprints.DoConfigFetchFingerprint
import app.revanced.patches.all.analytics.crashlytics.fingerprints.SettingsSpiCallFingerprint
import app.revanced.util.resultOrThrow

@Patch(
name = "Disable Crashlytics",
use = false,
)
@Suppress("unused")
object DisableCrashlytics : BytecodePatch(
setOf(SettingsSpiCallFingerprint, DoConfigFetchFingerprint)
) {
override fun execute(context: BytecodeContext) {
// Neutralize the two methods responsible for requesting Crashlytics' configuration
// which effectively disables the SDK

SettingsSpiCallFingerprint.resultOrThrow().mutableMethod.addInstructions(
0,
"""
const/4 p1, 0x0
return-object p1
"""
)

DoConfigFetchFingerprint.resultOrThrow().mutableMethod.addInstructions(
0,
"""
sget-object p1, Lkotlin/Unit;->INSTANCE:Lkotlin/Unit;
return-object p1
"""
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package app.revanced.patches.all.analytics.crashlytics.fingerprints

import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags

object DoConfigFetchFingerprint : MethodFingerprint(
returnType = "L",
accessFlags = AccessFlags.PUBLIC.value,
customFingerprint = { methodDef, classDef ->
classDef.sourceFile == "RemoteSettingsFetcher.kt" && methodDef.name == "doConfigFetch"
}
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package app.revanced.patches.all.analytics.crashlytics.fingerprints

import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags

object SettingsSpiCallFingerprint : MethodFingerprint(
returnType = "L",
accessFlags = AccessFlags.PUBLIC.value,
strings = listOf("Settings request failed."),
customFingerprint = { _, classDef ->
classDef.sourceFile == "DefaultSettingsSpiCall.java"
}
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package app.revanced.patches.all.analytics.firebase

import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patches.all.analytics.firebase.fingerprints.SendFingerprint
import app.revanced.util.resultOrThrow

@Patch(
name = "Disable Firebase transport",
description = "Prevents the sending of Firebase Logging and Firebase Crashlytics logs to Google's servers.",
use = false,
)
@Suppress("unused")
object DisableFirebaseTransport : BytecodePatch(
setOf(SendFingerprint)
) {
override fun execute(context: BytecodeContext) {
// Neutralize the method sending data to the backend
SendFingerprint.resultOrThrow().mutableMethod.addInstructions(0,"return-void")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package app.revanced.patches.all.analytics.firebase.fingerprints

import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags

object SendFingerprint : MethodFingerprint(
returnType = "V",
accessFlags = AccessFlags.PUBLIC.value,
customFingerprint = { methodDef, classDef ->
classDef.sourceFile == "TransportRuntime.java" && methodDef.name == "send"
}
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package app.revanced.patches.all.analytics.google

import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patches.all.analytics.google.fingerprints.AnalyticsInitFingerprint
import app.revanced.util.resultOrThrow

@Patch(
name = "Disable Google Analytics",
use = false,
)
@Suppress("unused")
object DisableGoogleAnalytics : BytecodePatch(
setOf(AnalyticsInitFingerprint)
) {
override fun execute(context: BytecodeContext) {
// Empties the "context" argument to force an exception
AnalyticsInitFingerprint.resultOrThrow().mutableMethod.addInstructions(0,"const/4 p0, 0x0")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package app.revanced.patches.all.analytics.google.fingerprints

import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags

object AnalyticsInitFingerprint : MethodFingerprint(
returnType = "L",
accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC,
parameters = listOf("Landroid/content/Context;"),
strings = listOf("Slow initialization (ms)"),
customFingerprint = { _, classDef ->
classDef.sourceFile?.startsWith("com.google.android.gms:play-services-analytics-impl") == true
}
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package app.revanced.patches.all.analytics.moengage

import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patches.all.analytics.moengage.fingerprints.MoEngageInitFingerprint
import app.revanced.util.resultOrThrow

@Patch(
name = "Disable MoEngage analytics SDK",
use = false,
)
@Suppress("unused")
object DisableMoEngage : BytecodePatch(
setOf(MoEngageInitFingerprint)
) {
override fun execute(context: BytecodeContext) {
MoEngageInitFingerprint.resultOrThrow().mutableMethod.addInstructions(0, "return-void")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package app.revanced.patches.all.analytics.moengage.fingerprints

import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags

object MoEngageInitFingerprint : MethodFingerprint(
returnType = "V",
accessFlags = AccessFlags.PUBLIC.value,
customFingerprint = { methodDef, classDef ->
classDef.sourceFile == "DefaultMoEngageSdk.kt" && methodDef.name == "init"
}
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package app.revanced.patches.all.analytics.segment

import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patches.all.analytics.segment.fingerprints.SegmentBuilderFingerprint
import app.revanced.util.resultOrThrow

@Patch(
name = "Disable Segment analytics SDK",
use = false,
)
@Suppress("unused")
object DisableSegment : BytecodePatch(
setOf(SegmentBuilderFingerprint)
) {
override fun execute(context: BytecodeContext) {
// Empties the writeKey parameter to abort initialization
SegmentBuilderFingerprint.resultOrThrow().mutableMethod.addInstructions(0,"const-string p2, \"\"")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package app.revanced.patches.all.analytics.segment.fingerprints

import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags

object SegmentBuilderFingerprint : MethodFingerprint(
returnType = "V",
accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
parameters = listOf("Landroid/content/Context;", "Ljava/lang/String;"),
strings = listOf("writeKey must not be empty.")
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package app.revanced.patches.all.analytics.statsig

import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patches.all.analytics.statsig.fingerprints.StatsigClientFingerprint
import app.revanced.util.resultOrThrow

@Patch(
name = "Disable Statsig analytics SDK",
use = false,
)
@Suppress("unused")
object DisableStatsig : BytecodePatch(
setOf(StatsigClientFingerprint)
) {
override fun execute(context: BytecodeContext) {
StatsigClientFingerprint.resultOrThrow().mutableMethod.addInstructions(0,"return-void")
}
}
Loading
Loading