feat(Google News): Add Enable CustomTabs and GmsCore support patch (#3111)

Co-authored-by: benjy3gg <benjy3gg@gmail.com>
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
This commit is contained in:
benjy3gg 2024-07-20 04:55:08 +02:00 committed by GitHub
parent 5bc925107f
commit ad59096227
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
20 changed files with 249 additions and 55 deletions

View File

@ -217,6 +217,24 @@ public final class app/revanced/patches/finanzonline/detection/root/RootDetectio
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
}
public final class app/revanced/patches/googlenews/customtabs/EnableCustomTabs : app/revanced/patcher/patch/BytecodePatch {
public static final field INSTANCE Lapp/revanced/patches/googlenews/customtabs/EnableCustomTabs;
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
}
public final class app/revanced/patches/googlenews/misc/gms/GmsCoreSupportPatch : app/revanced/patches/shared/misc/gms/BaseGmsCoreSupportPatch {
public static final field INSTANCE Lapp/revanced/patches/googlenews/misc/gms/GmsCoreSupportPatch;
}
public final class app/revanced/patches/googlenews/misc/gms/GmsCoreSupportResourcePatch : app/revanced/patches/shared/misc/gms/BaseGmsCoreSupportResourcePatch {
public static final field INSTANCE Lapp/revanced/patches/googlenews/misc/gms/GmsCoreSupportResourcePatch;
}
public final class app/revanced/patches/googlenews/misc/integrations/IntegrationsPatch : app/revanced/patches/shared/misc/integrations/BaseIntegrationsPatch {
public static final field INSTANCE Lapp/revanced/patches/googlenews/misc/integrations/IntegrationsPatch;
}
public final class app/revanced/patches/googlerecorder/restrictions/RemoveDeviceRestrictions : app/revanced/patcher/patch/BytecodePatch {
public static final field INSTANCE Lapp/revanced/patches/googlerecorder/restrictions/RemoveDeviceRestrictions;
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
@ -2033,7 +2051,11 @@ public final class app/revanced/util/BytecodeUtilsKt {
public static final fun indexOfIdResourceOrThrow (Lcom/android/tools/smali/dexlib2/iface/Method;Ljava/lang/String;)I
public static final fun injectHideViewCall (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;IILjava/lang/String;Ljava/lang/String;)V
public static final fun resultOrThrow (Lapp/revanced/patcher/fingerprint/MethodFingerprint;)Lapp/revanced/patcher/fingerprint/MethodFingerprintResult;
public static final fun returnEarly (Lapp/revanced/patcher/fingerprint/MethodFingerprint;Z)V
public static final fun returnEarly (Ljava/lang/Iterable;Z)V
public static final fun returnEarly (Ljava/util/List;Z)V
public static synthetic fun returnEarly$default (Lapp/revanced/patcher/fingerprint/MethodFingerprint;ZILjava/lang/Object;)V
public static synthetic fun returnEarly$default (Ljava/lang/Iterable;ZILjava/lang/Object;)V
public static synthetic fun returnEarly$default (Ljava/util/List;ZILjava/lang/Object;)V
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

View File

@ -0,0 +1,32 @@
package app.revanced.patches.googlenews.customtabs
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.annotation.CompatiblePackage
import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patches.googlenews.customtabs.fingerprints.LaunchCustomTabFingerprint
import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
@Patch(
name = "Enable CustomTabs",
description = "Enables CustomTabs to open articles in your default browser.",
compatiblePackages = [CompatiblePackage("com.google.android.apps.magazines")],
)
@Suppress("unused")
object EnableCustomTabs : BytecodePatch(
setOf(LaunchCustomTabFingerprint)
) {
override fun execute(context: BytecodeContext) {
LaunchCustomTabFingerprint.resultOrThrow().let { result ->
result.mutableMethod.apply {
val checkIndex = result.scanResult.patternScanResult!!.endIndex + 1
val register = getInstruction<OneRegisterInstruction>(checkIndex).registerA
replaceInstruction(checkIndex, "const/4 v$register, 0x1")
}
}
}
}

View File

@ -0,0 +1,18 @@
package app.revanced.patches.googlenews.customtabs.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
internal object LaunchCustomTabFingerprint : MethodFingerprint(
accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
opcodes = listOf(
Opcode.IPUT_OBJECT,
Opcode.CONST_4,
Opcode.IPUT,
Opcode.CONST_4,
Opcode.IPUT_BOOLEAN,
),
customFingerprint = { _, classDef -> classDef.endsWith("CustomTabsArticleLauncher;") },
)

View File

@ -0,0 +1,6 @@
package app.revanced.patches.googlenews.misc.gms
internal object Constants {
const val MAGAZINES_PACKAGE_NAME = "com.google.android.apps.magazines"
const val REVANCED_MAGAZINES_PACKAGE_NAME = "app.revanced.android.magazines"
}

View File

@ -0,0 +1,26 @@
package app.revanced.patches.googlenews.misc.gms
import app.revanced.patches.googlenews.misc.gms.Constants.MAGAZINES_PACKAGE_NAME
import app.revanced.patches.googlenews.misc.gms.Constants.REVANCED_MAGAZINES_PACKAGE_NAME
import app.revanced.patches.googlenews.misc.gms.GmsCoreSupportResourcePatch.gmsCoreVendorGroupIdOption
import app.revanced.patches.googlenews.misc.gms.fingerprints.MagazinesActivityOnCreateFingerprint
import app.revanced.patches.googlenews.misc.gms.fingerprints.ServiceCheckFingerprint
import app.revanced.patches.googlenews.misc.integrations.IntegrationsPatch
import app.revanced.patches.shared.misc.gms.BaseGmsCoreSupportPatch
@Suppress("unused")
object GmsCoreSupportPatch : BaseGmsCoreSupportPatch(
fromPackageName = MAGAZINES_PACKAGE_NAME,
toPackageName = REVANCED_MAGAZINES_PACKAGE_NAME,
primeMethodFingerprint = null,
earlyReturnFingerprints = setOf(ServiceCheckFingerprint),
mainActivityOnCreateFingerprint = MagazinesActivityOnCreateFingerprint,
integrationsPatchDependency = IntegrationsPatch::class,
gmsCoreSupportResourcePatch = GmsCoreSupportResourcePatch,
// Remove version constraint,
// once https://github.com/ReVanced/revanced-patches/pull/3111#issuecomment-2240877277 is resolved.
compatiblePackages = setOf(CompatiblePackage(MAGAZINES_PACKAGE_NAME, setOf("5.108.0.644447823"))),
fingerprints = setOf(ServiceCheckFingerprint),
) {
override val gmsCoreVendorGroupId by gmsCoreVendorGroupIdOption
}

View File

@ -0,0 +1,11 @@
package app.revanced.patches.googlenews.misc.gms
import app.revanced.patches.googlenews.misc.gms.Constants.MAGAZINES_PACKAGE_NAME
import app.revanced.patches.googlenews.misc.gms.Constants.REVANCED_MAGAZINES_PACKAGE_NAME
import app.revanced.patches.shared.misc.gms.BaseGmsCoreSupportResourcePatch
object GmsCoreSupportResourcePatch : BaseGmsCoreSupportResourcePatch(
fromPackageName = MAGAZINES_PACKAGE_NAME,
toPackageName = REVANCED_MAGAZINES_PACKAGE_NAME,
spoofedPackageSignature = "24bb24c05e47e0aefa68a58a766179d9b613a666",
)

View File

@ -0,0 +1,9 @@
package app.revanced.patches.googlenews.misc.gms.fingerprints
import app.revanced.patcher.fingerprint.MethodFingerprint
internal object MagazinesActivityOnCreateFingerprint : MethodFingerprint(
customFingerprint = { methodDef, classDef ->
methodDef.name == "onCreate" && classDef.endsWith("/StartActivity;")
},
)

View File

@ -0,0 +1,7 @@
package app.revanced.patches.googlenews.misc.gms.fingerprints
import app.revanced.patcher.fingerprint.MethodFingerprint
internal object PrimeMethodFingerprint : MethodFingerprint(
strings = listOf("com.google.android.GoogleCamera", "com.android.vending"),
)

View File

@ -0,0 +1,12 @@
package app.revanced.patches.googlenews.misc.gms.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
internal object ServiceCheckFingerprint : MethodFingerprint(
returnType = "V",
accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC,
parameters = listOf("L", "I"),
strings = listOf("Google Play Services not available", "GooglePlayServices not available due to error "),
)

View File

@ -0,0 +1,10 @@
package app.revanced.patches.googlenews.misc.integrations
import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patches.googlenews.misc.integrations.fingerprints.StartActivityInitFingerprint
import app.revanced.patches.shared.misc.integrations.BaseIntegrationsPatch
@Patch(requiresIntegrations = true)
object IntegrationsPatch : BaseIntegrationsPatch(
setOf(StartActivityInitFingerprint),
)

View File

@ -0,0 +1,41 @@
package app.revanced.patches.googlenews.misc.integrations.fingerprints
import app.revanced.patches.googlenews.misc.integrations.fingerprints.StartActivityInitFingerprint.getApplicationContextIndex
import app.revanced.patches.shared.misc.integrations.BaseIntegrationsPatch.IntegrationsFingerprint
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
internal object StartActivityInitFingerprint : IntegrationsFingerprint(
opcodes = listOf(
Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT,
Opcode.CONST_4,
Opcode.IF_EQZ,
Opcode.CONST,
Opcode.INVOKE_VIRTUAL,
Opcode.IPUT_OBJECT,
Opcode.IPUT_BOOLEAN,
Opcode.INVOKE_VIRTUAL, // Calls startActivity.getApplicationContext().
Opcode.MOVE_RESULT_OBJECT,
),
insertIndexResolver = { method ->
getApplicationContextIndex = method.indexOfFirstInstructionOrThrow {
getReference<MethodReference>()?.name == "getApplicationContext"
}
getApplicationContextIndex + 2 // Below the move-result-object instruction
},
contextRegisterResolver = { method ->
val moveResultInstruction = method.implementation!!.instructions.elementAt(getApplicationContextIndex + 1)
as OneRegisterInstruction
moveResultInstruction.registerA
},
customFingerprint = { methodDef, classDef ->
methodDef.name == "onCreate" && classDef.endsWith("/StartActivity;")
},
) {
private var getApplicationContextIndex = -1
}

View File

@ -12,15 +12,15 @@ import app.revanced.util.returnEarly
@Patch(
name = "Remove root detection",
description = "Removes the check for root permissions and unlocked bootloader.",
compatiblePackages = [CompatiblePackage("at.gv.oe.app")]
compatiblePackages = [CompatiblePackage("at.gv.oe.app")],
)
@Suppress("unused")
object RootDetectionPatch : BytecodePatch(
setOf(AttestationSupportedCheckFingerprint, BootloaderCheckFingerprint, RootCheckFingerprint)
setOf(AttestationSupportedCheckFingerprint, BootloaderCheckFingerprint, RootCheckFingerprint),
) {
override fun execute(context: BytecodeContext) = listOf(
override fun execute(context: BytecodeContext) = setOf(
AttestationSupportedCheckFingerprint,
BootloaderCheckFingerprint,
RootCheckFingerprint
RootCheckFingerprint,
).returnEarly(true)
}

View File

@ -15,7 +15,6 @@ object GmsCoreSupportPatch : BaseGmsCoreSupportPatch(
primeMethodFingerprint = PrimeMethodFingerprint,
earlyReturnFingerprints = setOf(
ServiceCheckFingerprint,
GooglePlayUtilityFingerprint,
CastDynamiteModuleFingerprint,
CastDynamiteModuleV2Fingerprint,
CastContextFetchFingerprint,
@ -32,12 +31,11 @@ object GmsCoreSupportPatch : BaseGmsCoreSupportPatch(
"7.01.53",
"7.02.52",
"7.03.52",
)
)
),
),
),
fingerprints = setOf(
ServiceCheckFingerprint,
GooglePlayUtilityFingerprint,
CastDynamiteModuleFingerprint,
CastDynamiteModuleV2Fingerprint,
CastContextFetchFingerprint,

View File

@ -1,18 +0,0 @@
package app.revanced.patches.music.misc.gms.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
internal object GooglePlayUtilityFingerprint : MethodFingerprint(
"I",
AccessFlags.PUBLIC or AccessFlags.STATIC,
listOf("L", "I"),
strings = listOf(
"This should never happen.",
"MetadataValueReader",
"GooglePlayServicesUtil",
"com.android.vending",
"android.hardware.type.embedded"
)
)

View File

@ -15,5 +15,5 @@ abstract class BaseDisableAdsPatch(
compatiblePackages = compatiblePackages,
fingerprints = setOf(IsAdsEnabledFingerprint),
) {
override fun execute(context: BytecodeContext) = listOf(IsAdsEnabledFingerprint).returnEarly()
override fun execute(context: BytecodeContext) = IsAdsEnabledFingerprint.returnEarly()
}

View File

@ -22,5 +22,5 @@ object UnlockSubscriptionPatch : BytecodePatch(
setOf(StartSubscriptionActivityFingerprint, BillingClientOnServiceConnected),
) {
override fun execute(context: BytecodeContext) =
listOf(StartSubscriptionActivityFingerprint, BillingClientOnServiceConnected).returnEarly()
setOf(StartSubscriptionActivityFingerprint, BillingClientOnServiceConnected).returnEarly()
}

View File

@ -13,6 +13,7 @@ import app.revanced.patches.shared.misc.gms.BaseGmsCoreSupportPatch.Constants.AU
import app.revanced.patches.shared.misc.gms.BaseGmsCoreSupportPatch.Constants.PERMISSIONS
import app.revanced.patches.shared.misc.gms.fingerprints.GmsCoreSupportFingerprint
import app.revanced.patches.shared.misc.gms.fingerprints.GmsCoreSupportFingerprint.GET_GMS_CORE_VENDOR_GROUP_ID_METHOD_NAME
import app.revanced.patches.shared.misc.gms.fingerprints.GooglePlayUtilityFingerprint
import app.revanced.util.exception
import app.revanced.util.getReference
import app.revanced.util.returnEarly
@ -42,7 +43,7 @@ import com.android.tools.smali.dexlib2.util.MethodUtil
abstract class BaseGmsCoreSupportPatch(
private val fromPackageName: String,
private val toPackageName: String,
private val primeMethodFingerprint: MethodFingerprint,
private val primeMethodFingerprint: MethodFingerprint?,
private val earlyReturnFingerprints: Set<MethodFingerprint>,
private val mainActivityOnCreateFingerprint: MethodFingerprint,
private val integrationsPatchDependency: PatchClass,
@ -62,6 +63,7 @@ abstract class BaseGmsCoreSupportPatch(
compatiblePackages = compatiblePackages,
fingerprints = setOf(
GmsCoreSupportFingerprint,
GooglePlayUtilityFingerprint,
mainActivityOnCreateFingerprint,
) + fingerprints,
requiresIntegrations = true,
@ -91,10 +93,13 @@ abstract class BaseGmsCoreSupportPatch(
}
// Specific method that needs to be patched.
transformPrimeMethod(packageName)
primeMethodFingerprint?.let { transformPrimeMethod(packageName) }
// Return these methods early to prevent the app from crashing.
earlyReturnFingerprints.toList().returnEarly()
earlyReturnFingerprints.returnEarly()
if (GooglePlayUtilityFingerprint.result != null) {
GooglePlayUtilityFingerprint.returnEarly()
}
// Verify GmsCore is installed and whitelisted for power optimizations and background usage.
mainActivityOnCreateFingerprint.result?.mutableMethod?.addInstructions(
@ -192,7 +197,7 @@ abstract class BaseGmsCoreSupportPatch(
}
private fun transformPrimeMethod(packageName: String) {
primeMethodFingerprint.result?.mutableMethod?.apply {
primeMethodFingerprint!!.result?.mutableMethod?.apply {
var register = 2
val index = getInstructions().indexOfFirst {
@ -305,6 +310,7 @@ abstract class BaseGmsCoreSupportPatch(
"com.google.android.gms.languageprofile.service.START",
"com.google.android.gms.clearcut.service.START",
"com.google.android.gms.icing.LIGHTWEIGHT_INDEX_SERVICE",
"com.google.android.gms.accountsettings.action.VIEW_SETTINGS",
// potoken
"com.google.android.gms.potokens.service.START",

View File

@ -1,4 +1,4 @@
package app.revanced.patches.youtube.misc.gms.fingerprints
package app.revanced.patches.shared.misc.gms.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
@ -8,5 +8,5 @@ internal object GooglePlayUtilityFingerprint : MethodFingerprint(
returnType = "I",
accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC,
parameters = listOf("L", "I"),
strings = listOf("This should never happen.", "MetadataValueReader", "com.google.android.gms")
strings = listOf("This should never happen.", "MetadataValueReader", "com.google.android.gms"),
)

View File

@ -7,7 +7,10 @@ import app.revanced.patches.youtube.misc.fix.playback.SpoofClientPatch
import app.revanced.patches.youtube.misc.gms.Constants.REVANCED_YOUTUBE_PACKAGE_NAME
import app.revanced.patches.youtube.misc.gms.Constants.YOUTUBE_PACKAGE_NAME
import app.revanced.patches.youtube.misc.gms.GmsCoreSupportResourcePatch.gmsCoreVendorGroupIdOption
import app.revanced.patches.youtube.misc.gms.fingerprints.*
import app.revanced.patches.youtube.misc.gms.fingerprints.CastDynamiteModuleFingerprint
import app.revanced.patches.youtube.misc.gms.fingerprints.CastDynamiteModuleV2Fingerprint
import app.revanced.patches.youtube.misc.gms.fingerprints.PrimeMethodFingerprint
import app.revanced.patches.youtube.misc.gms.fingerprints.ServiceCheckFingerprint
import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch
import app.revanced.patches.youtube.shared.fingerprints.MainActivityOnCreateFingerprint
@ -18,7 +21,6 @@ object GmsCoreSupportPatch : BaseGmsCoreSupportPatch(
primeMethodFingerprint = PrimeMethodFingerprint,
earlyReturnFingerprints = setOf(
ServiceCheckFingerprint,
GooglePlayUtilityFingerprint,
CastDynamiteModuleFingerprint,
CastDynamiteModuleV2Fingerprint,
CastContextFetchFingerprint,
@ -62,7 +64,6 @@ object GmsCoreSupportPatch : BaseGmsCoreSupportPatch(
),
fingerprints = setOf(
ServiceCheckFingerprint,
GooglePlayUtilityFingerprint,
CastDynamiteModuleFingerprint,
CastDynamiteModuleV2Fingerprint,
CastContextFetchFingerprint,

View File

@ -114,7 +114,7 @@ fun Method.indexOfFirstWideLiteralInstructionValue(literal: Long) = implementati
*
* @return the first literal instruction with the value, or throws [PatchException] if not found.
*/
fun Method.indexOfFirstWideLiteralInstructionValueOrThrow(literal: Long) : Int {
fun Method.indexOfFirstWideLiteralInstructionValueOrThrow(literal: Long): Int {
val index = indexOfFirstWideLiteralInstructionValue(literal)
if (index < 0) throw PatchException("Could not find literal value: $literal")
return index
@ -160,7 +160,7 @@ inline fun <reified T : Reference> Instruction.getReference() = (this as? Refere
// TODO: delete this on next major release, the overloaded method with an optional start index serves the same purposes.
// Method is deprecated, but annotation is commented out otherwise during compilation usage of the replacement is
// incorrectly flagged as deprecated.
//@Deprecated("Use the overloaded method with an optional start index.", ReplaceWith("indexOfFirstInstruction(predicate)"))
// @Deprecated("Use the overloaded method with an optional start index.", ReplaceWith("indexOfFirstInstruction(predicate)"))
fun Method.indexOfFirstInstruction(predicate: Instruction.() -> Boolean) = indexOfFirstInstruction(0, predicate)
/**
@ -211,12 +211,11 @@ fun Method.findOpcodeIndicesReversed(opcode: Opcode): List<Int> {
}
/**
* Return the resolved methods of [MethodFingerprint]s early.
* Return the resolved method early.
*/
fun List<MethodFingerprint>.returnEarly(bool: Boolean = false) {
fun MethodFingerprint.returnEarly(bool: Boolean = false) {
val const = if (bool) "0x1" else "0x0"
this.forEach { fingerprint ->
fingerprint.result?.let { result ->
result?.let { result ->
val stringInstructions = when (result.method.returnType.first()) {
'L' ->
"""
@ -233,6 +232,20 @@ fun List<MethodFingerprint>.returnEarly(bool: Boolean = false) {
}
result.mutableMethod.addInstructions(0, stringInstructions)
} ?: throw fingerprint.exception
}
} ?: throw exception
}
/**
* Return the resolved methods early.
*/
fun Iterable<MethodFingerprint>.returnEarly(bool: Boolean = false) = forEach { fingerprint ->
fingerprint.returnEarly(bool)
}
/**
* Return the resolved methods early.
*/
@Deprecated("Use the Iterable version")
fun List<MethodFingerprint>.returnEarly(bool: Boolean = false) = forEach { fingerprint ->
fingerprint.returnEarly(bool)
}