Skip to content

Commit

Permalink
feat(Gboard): Add Always-incognito mode for Gboard patch
Browse files Browse the repository at this point in the history
  • Loading branch information
jkennethcarino committed Apr 7, 2024
1 parent 32ca598 commit 2a98c21
Show file tree
Hide file tree
Showing 7 changed files with 142 additions and 8 deletions.
15 changes: 8 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,14 @@ block analytics and trackers, and much more.

Some of the features the patches provide are:

* **Remove internet permission**: Remove unnecessary internet permission from apps that can function without internet access.
* **Disable Firebase Analytics**: Permanently disable the collection of Analytics data, all associated
broadcast receivers and services will also be removed.
* **Disable WebView metrics collection**: Disable the collection of diagnostic data or usage statistics
that are uploaded to Google.
* **Bypass signature verification**: Bypass the signature verification when the app starts up.
* **And much more!**
* 🚫 **Remove internet permission**: Remove unnecessary internet permission from apps that can function without internet access.
* 📉 **Disable Firebase Analytics**: Permanently disable the collection of Analytics data, all associated
broadcast receivers and services will also be removed.
* 🌐 **Disable WebView metrics collection**: Disable the collection of diagnostic data or usage statistics
that are uploaded to Google.
* 🔓 **Bypass signature verification**: Bypass the signature verification when the app starts up.
* 🥸 **Always-incognito mode for Gboard**: Always open in incognito mode to disable typing history collection and personalization.
***And much more!**

## 🚀 Getting started

Expand Down
14 changes: 14 additions & 0 deletions api/privacy-revanced-patches.api
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,12 @@ public final class dev/jkcarino/revanced/patches/all/webview/DisableWebViewSafeB
public fun execute (Lapp/revanced/patcher/data/ResourceContext;)V
}

public final class dev/jkcarino/revanced/patches/gboard/AlwaysIncognitoModePatch : app/revanced/patcher/patch/BytecodePatch {
public static final field INSTANCE Ldev/jkcarino/revanced/patches/gboard/AlwaysIncognitoModePatch;
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
}

public abstract class dev/jkcarino/revanced/patches/shared/resource/BaseResourceElementRemovalPatch : app/revanced/patcher/patch/ResourcePatch {
public fun <init> ([Ldev/jkcarino/revanced/patches/shared/resource/ElementProcessor;)V
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
Expand Down Expand Up @@ -100,6 +106,9 @@ public final class dev/jkcarino/revanced/patches/shared/resource/ServiceElement
}

public final class dev/jkcarino/revanced/util/BytecodeUtilsKt {
public static final fun containsWideLiteralInstructionValue (Lcom/android/tools/smali/dexlib2/iface/Method;J)Z
public static final fun getException (Lapp/revanced/patcher/fingerprint/MethodFingerprint;)Lapp/revanced/patcher/patch/PatchException;
public static final fun indexOfFirstWideLiteralInstructionValue (Lcom/android/tools/smali/dexlib2/iface/Method;J)I
public static final fun transformMethods (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableClass;Lkotlin/jvm/functions/Function1;)V
public static final fun traverseClassHierarchy (Lapp/revanced/patcher/data/BytecodeContext;Lapp/revanced/patcher/util/proxy/mutableTypes/MutableClass;Lkotlin/jvm/functions/Function1;)V
}
Expand All @@ -113,3 +122,8 @@ public final class dev/jkcarino/revanced/util/ResourceUtilsKt {
public static final fun removeElements (Lorg/w3c/dom/Node;Ljava/util/List;)V
}

public abstract class dev/jkcarino/revanced/util/patch/LiteralValueFingerprint : app/revanced/patcher/fingerprint/MethodFingerprint {
public fun <init> (Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/Iterable;Ljava/lang/Iterable;Ljava/lang/Iterable;Lkotlin/jvm/functions/Function0;)V
public synthetic fun <init> (Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/Iterable;Ljava/lang/Iterable;Ljava/lang/Iterable;Lkotlin/jvm/functions/Function0;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
}

Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ import dev.jkcarino.revanced.util.traverseClassHierarchy

@Patch(
name = "Bypass signature verification checks",
description = "Bypasses the signature verification checks when the app starts up. This requires the original app to work properly.",
description = "Bypasses the signature verification checks when the app starts up. " +
"This requires the original, unmodified app to work properly.",
dependencies = [
ReplaceSubApplicationPatch::class,
EncodeCertificatePatch::class,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package dev.jkcarino.revanced.patches.gboard

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.CompatiblePackage
import app.revanced.patcher.patch.annotation.Patch
import dev.jkcarino.revanced.patches.all.signature.pmshook.BypassSignatureChecksPatch
import dev.jkcarino.revanced.patches.gboard.fingerprints.IsIncognitoModeFingerprint
import dev.jkcarino.revanced.util.exception

@Patch(
name = "Always-incognito mode for Gboard",
description = "Always opens Gboard in incognito mode to disable typing history collection and personalization. " +
"This requires the original, unmodified app to work properly.",
dependencies = [
BypassSignatureChecksPatch::class,
],
compatiblePackages = [CompatiblePackage("com.google.android.inputmethod.latin")],
use = false
)
@Suppress("unused")
object AlwaysIncognitoModePatch : BytecodePatch(
setOf(IsIncognitoModeFingerprint)
) {
override fun execute(context: BytecodeContext) {
IsIncognitoModeFingerprint.result?.mutableMethod?.addInstructions(
index = 0,
smaliInstructions = """
const/4 v0, 0x1
return v0
"""
) ?: throw IsIncognitoModeFingerprint.exception
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package dev.jkcarino.revanced.patches.gboard.fingerprints

import app.revanced.patcher.extensions.or
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
import dev.jkcarino.revanced.util.patch.LiteralValueFingerprint

internal object IsIncognitoModeFingerprint : LiteralValueFingerprint(
returnType = "Z",
accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC,
parameters = listOf("Landroid/view/inputmethod/EditorInfo;"),
opcodes = listOf(
Opcode.IF_EQZ,
Opcode.IGET,
Opcode.CONST_HIGH16,
Opcode.AND_INT_2ADDR,
Opcode.IF_EQZ,
Opcode.CONST_4,
Opcode.RETURN,
Opcode.CONST_4,
Opcode.RETURN,
),
literalSupplier = { 0x1000000 } // EditorInfo.IME_FLAG_NO_PERSONALIZED_LEARNING
)
25 changes: 25 additions & 0 deletions src/main/kotlin/dev/jkcarino/revanced/util/BytecodeUtils.kt
Original file line number Diff line number Diff line change
@@ -1,8 +1,33 @@
package dev.jkcarino.revanced.util

import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.fingerprint.MethodFingerprint
import app.revanced.patcher.patch.PatchException
import app.revanced.patcher.util.proxy.mutableTypes.MutableClass
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
import com.android.tools.smali.dexlib2.iface.Method
import com.android.tools.smali.dexlib2.iface.instruction.WideLiteralInstruction

/**
* The [PatchException] that is thrown when failing to resolve a [MethodFingerprint].
*/
val MethodFingerprint.exception
get() = PatchException("Failed to resolve ${this.javaClass.simpleName}")

/**
* Finds the index of the first wide literal instruction with the given value, or -1 if not found.
*/
fun Method.indexOfFirstWideLiteralInstructionValue(literal: Long) = implementation?.let {
it.instructions.indexOfFirst { instruction ->
(instruction as? WideLiteralInstruction)?.wideLiteral == literal
}
} ?: -1

/**
* Checks if the method contains a literal with the given value.
*/
fun Method.containsWideLiteralInstructionValue(literal: Long) =
indexOfFirstWideLiteralInstructionValue(literal) >= 0

/**
* Applies a transformation to all methods of the [MutableClass] instance.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package dev.jkcarino.revanced.util.patch

import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.Opcode
import dev.jkcarino.revanced.util.containsWideLiteralInstructionValue

/**
* A fingerprint to resolve methods that contain a specific literal value.
*
* @param returnType The method's return type compared using String.startsWith.
* @param accessFlags The method's exact access flags using values of AccessFlags.
* @param parameters The parameters of the method. Partial matches allowed and follow the same rules as returnType.
* @param opcodes An opcode pattern of the method's instructions. Wildcard or unknown opcodes can be specified by null.
* @param strings A list of the method's strings compared each using String.contains.
* @param literalSupplier A supplier for the literal value to check for.
*/
abstract class LiteralValueFingerprint(
returnType: String? = null,
accessFlags: Int? = null,
parameters: Iterable<String>? = null,
opcodes: Iterable<Opcode>? = null,
strings: Iterable<String>? = null,
// Has to be a supplier because the fingerprint is created before patches can set literals.
literalSupplier: () -> Long
) : MethodFingerprint(
returnType = returnType,
accessFlags = accessFlags,
parameters = parameters,
opcodes = opcodes,
strings = strings,
customFingerprint = { methodDef, _ ->
methodDef.containsWideLiteralInstructionValue(literalSupplier())
}
)

0 comments on commit 2a98c21

Please sign in to comment.