diff --git a/CHANGELOG.md b/CHANGELOG.md index bfebce7e69..cbd1883bdf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,33 +1,3 @@ -# [6.1.0](https://github.com/ReVanced/revanced-patches/compare/v6.0.1...v6.1.0) (2026-03-18) - - -### Bug Fixes - -* **Export internal data documents provider:** Correct S_IFLNK constant and symlink detection mask ([#6819](https://github.com/ReVanced/revanced-patches/issues/6819)) ([252617b](https://github.com/ReVanced/revanced-patches/commit/252617b8dd3f24e1ff9a04ba1d91b43dc29bd757)) -* **YouTube - Custom branding:** Fix double icons and change default branding to ReVanced ([#6806](https://github.com/ReVanced/revanced-patches/issues/6806)) ([e51c529](https://github.com/ReVanced/revanced-patches/commit/e51c5292c171325e7cfa0f5ee85474d9b3961a34)) - - -### Features - -* Add `Spoof root of trust` and `Spoof keystore security level` patch ([#6751](https://github.com/ReVanced/revanced-patches/issues/6751)) ([4bc8c7c](https://github.com/ReVanced/revanced-patches/commit/4bc8c7c0f60a095533f07dc281f0320f8eb22f3c)) -* **Announcements:** Support ReVanced API v5 announcements ([a05386e](https://github.com/ReVanced/revanced-patches/commit/a05386e8bc24c085b5c74f3674c402c5dd5ad468)) -* Change contact email in patches about ([df1c3a4](https://github.com/ReVanced/revanced-patches/commit/df1c3a4a70fd2595d77b539299f1f7301bc60d24)) -* **Instagram:** Add `Enable location sticker redesign` patch ([#6808](https://github.com/ReVanced/revanced-patches/issues/6808)) ([4b699da](https://github.com/ReVanced/revanced-patches/commit/4b699da220e5d1527c390792b6228e2d9cffedb7)) -* **Spoof video streams:** Add Android Reel client to fix playback issues ([#6830](https://github.com/ReVanced/revanced-patches/issues/6830)) ([4b6c3e3](https://github.com/ReVanced/revanced-patches/commit/4b6c3e312328fbf6a1c7065e27d8ff04573e58be)) - -# [6.1.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v6.1.0-dev.3...v6.1.0-dev.4) (2026-03-18) - - -### Bug Fixes - -* **YouTube - Custom branding:** Fix double icons and change default branding to ReVanced ([#6806](https://github.com/ReVanced/revanced-patches/issues/6806)) ([e51c529](https://github.com/ReVanced/revanced-patches/commit/e51c5292c171325e7cfa0f5ee85474d9b3961a34)) - - -### Features - -* Add `Spoof root of trust` and `Spoof keystore security level` patch ([#6751](https://github.com/ReVanced/revanced-patches/issues/6751)) ([4bc8c7c](https://github.com/ReVanced/revanced-patches/commit/4bc8c7c0f60a095533f07dc281f0320f8eb22f3c)) -* **Instagram:** Add `Enable location sticker redesign` patch ([#6808](https://github.com/ReVanced/revanced-patches/issues/6808)) ([4b699da](https://github.com/ReVanced/revanced-patches/commit/4b699da220e5d1527c390792b6228e2d9cffedb7)) - # [6.1.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v6.1.0-dev.2...v6.1.0-dev.3) (2026-03-18) diff --git a/extensions/all/misc/disable-play-integrity/src/main/java/app/revanced/extension/play/DisablePlayIntegrityPatch.java b/extensions/all/misc/disable-play-integrity/src/main/java/app/revanced/extension/playintegrity/DisablePlayIntegrityPatch.java similarity index 92% rename from extensions/all/misc/disable-play-integrity/src/main/java/app/revanced/extension/play/DisablePlayIntegrityPatch.java rename to extensions/all/misc/disable-play-integrity/src/main/java/app/revanced/extension/playintegrity/DisablePlayIntegrityPatch.java index 4dd09f693f..a27e56be95 100644 --- a/extensions/all/misc/disable-play-integrity/src/main/java/app/revanced/extension/play/DisablePlayIntegrityPatch.java +++ b/extensions/all/misc/disable-play-integrity/src/main/java/app/revanced/extension/playintegrity/DisablePlayIntegrityPatch.java @@ -1,4 +1,4 @@ -package app.revanced.extension.play; +package app.revanced.extension.playintegrity; import android.content.Context; import android.content.Intent; diff --git a/extensions/shared/library/src/main/java/app/revanced/extension/shared/patches/CustomBrandingPatch.java b/extensions/shared/library/src/main/java/app/revanced/extension/shared/patches/CustomBrandingPatch.java index d13513e2df..0dc411f8b0 100644 --- a/extensions/shared/library/src/main/java/app/revanced/extension/shared/patches/CustomBrandingPatch.java +++ b/extensions/shared/library/src/main/java/app/revanced/extension/shared/patches/CustomBrandingPatch.java @@ -114,7 +114,7 @@ public class CustomBrandingPatch { /** * Injection point. - *

+ * * The total number of app name aliases, including dummy aliases. */ private static int numberOfPresetAppNames() { @@ -146,13 +146,13 @@ public class CustomBrandingPatch { public static int getDefaultAppNameIndex() { return userProvidedCustomName() ? numberOfPresetAppNames() - : 2; + : 1; } public static BrandingTheme getDefaultIconStyle() { return userProvidedCustomIcon() ? BrandingTheme.CUSTOM - : BrandingTheme.ROUNDED; + : BrandingTheme.ORIGINAL; } /** diff --git a/gradle.properties b/gradle.properties index d65f6857e0..1ec45a3285 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,4 +4,4 @@ org.gradle.parallel = true android.useAndroidX = true android.uniquePackageNames = false kotlin.code.style = official -version = 6.1.0 +version = 6.1.0-dev.3 diff --git a/patches/api/patches.api b/patches/api/patches.api index 4a8ed81323..be251e84a5 100644 --- a/patches/api/patches.api +++ b/patches/api/patches.api @@ -89,14 +89,10 @@ public final class app/revanced/patches/all/misc/packagename/ChangePackageNamePa public static final fun setOrGetFallbackPackageName (Ljava/lang/String;)Ljava/lang/String; } -public final class app/revanced/patches/all/misc/play/DisablePlayIntegrityKt { +public final class app/revanced/patches/all/misc/playintegrity/DisablePlayIntegrityKt { public static final fun getDisablePlayIntegrityPatch ()Lapp/revanced/patcher/patch/Patch; } -public final class app/revanced/patches/all/misc/play/SpoofPlayAgeSignalsKt { - public static final fun getSpoofPlayAgeSignalsPatch ()Lapp/revanced/patcher/patch/Patch; -} - public final class app/revanced/patches/all/misc/resources/AddResourcesPatchKt { public static final fun addResource (Ljava/lang/String;Lapp/revanced/util/resource/BaseResource;)Z public static final fun addResources (Lapp/revanced/patcher/patch/Patch;Lkotlin/jvm/functions/Function1;)Z @@ -129,14 +125,6 @@ public final class app/revanced/patches/all/misc/spoof/EnableRomSignatureSpoofin public static final fun getEnableROMSignatureSpoofingPatch ()Lapp/revanced/patcher/patch/Patch; } -public final class app/revanced/patches/all/misc/spoof/SpoofKeystoreSecurityLevelPatchKt { - public static final fun getSpoofKeystoreSecurityLevelPatch ()Lapp/revanced/patcher/patch/Patch; -} - -public final class app/revanced/patches/all/misc/spoof/SpoofRootOfTrustPatchKt { - public static final fun getSpoofRootOfTrustPatch ()Lapp/revanced/patcher/patch/Patch; -} - public final class app/revanced/patches/all/misc/targetSdk/SetTargetSdkVersion34Kt { public static final fun getSetTargetSDKVersion34Patch ()Lapp/revanced/patcher/patch/Patch; } @@ -377,10 +365,6 @@ public final class app/revanced/patches/instagram/story/flipping/DisableStoryAut public static final fun getDisableStoryAutoFlippingPatch ()Lapp/revanced/patcher/patch/Patch; } -public final class app/revanced/patches/instagram/story/locationsticker/EnableLocationStickerRedesignPatchKt { - public static final fun getEnableLocationStickerRedesignPatch ()Lapp/revanced/patcher/patch/Patch; -} - public final class app/revanced/patches/irplus/ad/RemoveAdsPatchKt { public static final fun getRemoveAdsPatch ()Lapp/revanced/patcher/patch/Patch; } diff --git a/patches/src/main/kotlin/app/revanced/patches/all/misc/connectivity/telephony/sim/spoof/SpoofSimProviderPatch.kt b/patches/src/main/kotlin/app/revanced/patches/all/misc/connectivity/telephony/sim/spoof/SpoofSimProviderPatch.kt index cb5723de76..a7dfdf7bf4 100644 --- a/patches/src/main/kotlin/app/revanced/patches/all/misc/connectivity/telephony/sim/spoof/SpoofSimProviderPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/all/misc/connectivity/telephony/sim/spoof/SpoofSimProviderPatch.kt @@ -6,8 +6,7 @@ import app.revanced.patcher.extensions.replaceInstruction import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.patch.intOption import app.revanced.patcher.patch.stringOption -import app.revanced.util.forEachInstructionAsSequence -import com.android.tools.smali.dexlib2.iface.instruction.Instruction +import app.revanced.patches.all.misc.transformation.transformInstructionsPatch 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.MethodReference @@ -34,8 +33,7 @@ val spoofSIMProviderPatch = bytecodePatch( validator = { it: String? -> it == null || it.uppercase() in countries.values }, ) - fun isMccMncValid(it: Int?) = it == null || (it in 10000..999999) - fun isNumericValid(it: String?, length: Int) = it.isNullOrBlank() || it.equals("random", true) || it.length == length + fun isMccMncValid(it: Int?): Boolean = it == null || (it >= 10000 && it <= 999999) val networkCountryIso by isoCountryPatchOption("Network ISO country code") @@ -63,119 +61,46 @@ val spoofSIMProviderPatch = bytecodePatch( description = "The full name of the SIM operator.", ) - val imei by stringOption( - name = "IMEI value", - description = "15-digit IMEI to spoof, blank to skip, or 'random'.", - validator = { isNumericValid(it, 15) }, - ) - - val meid by stringOption( - name = "MEID value", - description = "14-char hex MEID to spoof, blank to skip, or 'random'.", - validator = { isNumericValid(it, 14) }, - ) - - val imsi by stringOption( - name = "IMSI (Subscriber ID)", - description = "15-digit IMSI to spoof, blank to skip, or 'random'.", - validator = { isNumericValid(it, 15) }, - ) - - val iccid by stringOption( - name = "ICCID (SIM Serial)", - description = "19-digit ICCID to spoof, blank to skip, or 'random'.", - validator = { isNumericValid(it, 19) }, - ) - - val phone by stringOption( - name = "Phone number", - description = "Phone number to spoof, blank to skip, or 'random'.", - validator = { it.isNullOrBlank() || it.equals("random", ignoreCase = true) || it.startsWith("+") }, - ) - dependsOn( - bytecodePatch { - apply { - fun generateRandomNumeric(length: Int) = (1..length).map { ('0'..'9').random() }.joinToString("") + transformInstructionsPatch( + filterMap = { _, _, instruction, instructionIndex -> + if (instruction !is ReferenceInstruction) return@transformInstructionsPatch null - fun String?.computeSpoof(randomizer: () -> String): String? { - if (this.isNullOrBlank()) return null - if (this.equals("random", ignoreCase = true)) return randomizer() - return this + val reference = instruction.reference as? MethodReference ?: return@transformInstructionsPatch null + + val match = MethodCall.entries.firstOrNull { search -> + MethodUtil.methodSignaturesMatch(reference, search.reference) + } ?: return@transformInstructionsPatch null + + val replacement = when (match) { + MethodCall.NetworkCountryIso -> networkCountryIso?.lowercase() + MethodCall.NetworkOperator -> networkOperator?.toString() + MethodCall.NetworkOperatorName -> networkOperatorName + MethodCall.SimCountryIso -> simCountryIso?.lowercase() + MethodCall.SimOperator -> simOperator?.toString() + MethodCall.SimOperatorName -> simOperatorName } - - // Calculate the Luhn checksum (mod 10) to generate a valid 15th digit, standard for IMEI numbers. - // Structure of an IMEI is as follows: - // TAC (Type Allocation Code): First 8 digits (e.g., "86" + 6 digits) - // SNR (Serial Number): Next 6 digits - // CD (Check Digit): The 15th digit - val computedImei = imei.computeSpoof { - val prefix = "86" + generateRandomNumeric(12) - - val sum = prefix.mapIndexed { i, c -> - var d = c.digitToInt() - // Double every second digit (index 1, 3, 5...). - if (i % 2 != 0) { - d *= 2 - // If result is two digits (e.g. 14), sum them (1+4=5). - // This is mathematically equivalent to d - 9. - if (d > 9) d -= 9 - } - d - }.sum() - // Append the calculated check digit to the 14-digit prefix. - prefix + ((10 - (sum % 10)) % 10) - } - - val computedMeid = meid.computeSpoof { (1..14).map { "0123456789ABCDEF".random() }.joinToString("") }?.uppercase() - val computedImsi = imsi.computeSpoof { generateRandomNumeric(15) } - val computedIccid = iccid.computeSpoof { "89" + generateRandomNumeric(17) } - val computedPhone = phone.computeSpoof { "+" + generateRandomNumeric(11) } - - forEachInstructionAsSequence( - match = { _, _, instruction, instructionIndex -> - if (instruction !is ReferenceInstruction) return@forEachInstructionAsSequence null - - val reference = instruction.reference as? MethodReference ?: return@forEachInstructionAsSequence null - - val match = MethodCall.entries.firstOrNull { search -> - MethodUtil.methodSignaturesMatch(reference, search.reference) - } ?: return@forEachInstructionAsSequence null - - val replacement = when (match) { - MethodCall.NetworkCountryIso -> networkCountryIso?.lowercase() - MethodCall.NetworkOperator -> networkOperator?.toString() - MethodCall.NetworkOperatorName -> networkOperatorName - MethodCall.SimCountryIso -> simCountryIso?.lowercase() - MethodCall.SimOperator -> simOperator?.toString() - MethodCall.SimOperatorName -> simOperatorName - MethodCall.Imei, MethodCall.ImeiWithSlot, MethodCall.DeviceId, MethodCall.DeviceIdWithSlot -> computedImei - MethodCall.Meid, MethodCall.MeidWithSlot -> computedMeid - MethodCall.SubscriberId, MethodCall.SubscriberIdWithSlot -> computedImsi - MethodCall.SimSerialNumber, MethodCall.SimSerialNumberWithSlot -> computedIccid - MethodCall.Line1Number, MethodCall.Line1NumberWithSlot -> computedPhone - } - replacement?.let { instructionIndex to it } - }, - transform = ::transformMethodCall - ) - } - }, + replacement?.let { instructionIndex to it } + }, + transform = ::transformMethodCall, + ), ) } -private fun transformMethodCall(mutableMethod: MutableMethod, entry: Pair) { - val (index, value) = entry - val nextInstr = mutableMethod.getInstruction(index + 1) +private fun transformMethodCall( + mutableMethod: MutableMethod, + entry: Pair, +) { + val (instructionIndex, methodCallValue) = entry - if (nextInstr.opcode.name != "move-result-object") { - mutableMethod.replaceInstruction(index, "nop") - return - } + // Get the register which would have contained the return value + val register = mutableMethod.getInstruction(instructionIndex + 1).registerA - val register = (nextInstr as OneRegisterInstruction).registerA - mutableMethod.replaceInstruction(index, "const-string v$register, \"$value\"") - mutableMethod.replaceInstruction(index + 1, "nop") + // Replace the move-result instruction with our fake value + mutableMethod.replaceInstruction( + instructionIndex + 1, + "const-string v$register, \"$methodCallValue\"", + ) } private enum class MethodCall( @@ -229,100 +154,4 @@ private enum class MethodCall( "Ljava/lang/String;", ), ), - Imei( - ImmutableMethodReference( - "Landroid/telephony/TelephonyManager;", - "getImei", - emptyList(), - "Ljava/lang/String;" - ), - ), - ImeiWithSlot( - ImmutableMethodReference( - "Landroid/telephony/TelephonyManager;", - "getImei", - listOf("I"), - "Ljava/lang/String;" - ), - ), - DeviceId( - ImmutableMethodReference( - "Landroid/telephony/TelephonyManager;", - "getDeviceId", - emptyList(), - "Ljava/lang/String;" - ), - ), - DeviceIdWithSlot( - ImmutableMethodReference( - "Landroid/telephony/TelephonyManager;", - "getDeviceId", - listOf("I"), - "Ljava/lang/String;" - ), - ), - Meid( - ImmutableMethodReference( - "Landroid/telephony/TelephonyManager;", - "getMeid", - emptyList(), - "Ljava/lang/String;" - ), - ), - MeidWithSlot( - ImmutableMethodReference( - "Landroid/telephony/TelephonyManager;", - "getMeid", - listOf("I"), - "Ljava/lang/String;" - ), - ), - SubscriberId( - ImmutableMethodReference( - "Landroid/telephony/TelephonyManager;", - "getSubscriberId", - emptyList(), - "Ljava/lang/String;" - ) - ), - SubscriberIdWithSlot( - ImmutableMethodReference( - "Landroid/telephony/TelephonyManager;", - "getSubscriberId", - listOf("I"), - "Ljava/lang/String;" - ) - ), - SimSerialNumber( - ImmutableMethodReference( - "Landroid/telephony/TelephonyManager;", - "getSimSerialNumber", - emptyList(), - "Ljava/lang/String;" - ) - ), - SimSerialNumberWithSlot( - ImmutableMethodReference( - "Landroid/telephony/TelephonyManager;", - "getSimSerialNumber", - listOf("I"), - "Ljava/lang/String;" - ) - ), - Line1Number( - ImmutableMethodReference( - "Landroid/telephony/TelephonyManager;", - "getLine1Number", - emptyList(), - "Ljava/lang/String;" - ) - ), - Line1NumberWithSlot( - ImmutableMethodReference( - "Landroid/telephony/TelephonyManager;", - "getLine1Number", - listOf("I"), - "Ljava/lang/String;" - ) - ) } diff --git a/patches/src/main/kotlin/app/revanced/patches/all/misc/connectivity/wifi/spoof/SpoofWifiPatch.kt b/patches/src/main/kotlin/app/revanced/patches/all/misc/connectivity/wifi/spoof/SpoofWifiPatch.kt index e00f37feaf..1666a27a8d 100644 --- a/patches/src/main/kotlin/app/revanced/patches/all/misc/connectivity/wifi/spoof/SpoofWifiPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/all/misc/connectivity/wifi/spoof/SpoofWifiPatch.kt @@ -3,7 +3,7 @@ package app.revanced.patches.all.misc.connectivity.wifi.spoof import app.revanced.patcher.patch.bytecodePatch import app.revanced.patches.all.misc.transformation.IMethodCall import app.revanced.patches.all.misc.transformation.filterMapInstruction35c -import app.revanced.util.forEachInstructionAsSequence +import app.revanced.patches.all.misc.transformation.transformInstructionsPatch private const val EXTENSION_CLASS_DESCRIPTOR_PREFIX = "Lapp/revanced/extension/all/misc/connectivity/wifi/spoof/SpoofWifiPatch" @@ -19,32 +19,29 @@ val spoofWiFiConnectionPatch = bytecodePatch( extendWith("extensions/all/misc/connectivity/wifi/spoof/spoof-wifi.rve") dependsOn( - bytecodePatch { - apply { - forEachInstructionAsSequence( - match = { classDef, _, instruction, instructionIndex -> - filterMapInstruction35c( - EXTENSION_CLASS_DESCRIPTOR_PREFIX, - classDef, - instruction, - instructionIndex, - ) - }, - transform = { method, entry -> - val (methodType, instruction, instructionIndex) = entry - methodType.replaceInvokeVirtualWithExtension( - EXTENSION_CLASS_DESCRIPTOR, - method, - instruction, - instructionIndex, - ) - }) - } - }, + transformInstructionsPatch( + filterMap = { classDef, _, instruction, instructionIndex -> + filterMapInstruction35c( + EXTENSION_CLASS_DESCRIPTOR_PREFIX, + classDef, + instruction, + instructionIndex, + ) + }, + transform = { method, entry -> + val (methodType, instruction, instructionIndex) = entry + methodType.replaceInvokeVirtualWithExtension( + EXTENSION_CLASS_DESCRIPTOR, + method, + instruction, + instructionIndex, + ) + }, + ), ) } -// Information about method calls we want to replace. +// Information about method calls we want to replace @Suppress("unused") private enum class MethodCall( override val definedClassName: String, @@ -92,13 +89,13 @@ private enum class MethodCall( "Landroid/net/NetworkInfo;", "getState", arrayOf(), - $$"Landroid/net/NetworkInfo$State;", + "Landroid/net/NetworkInfo\$State;", ), GetDetailedState( "Landroid/net/NetworkInfo;", "getDetailedState", arrayOf(), - $$"Landroid/net/NetworkInfo$DetailedState;", + "Landroid/net/NetworkInfo\$DetailedState;", ), IsActiveNetworkMetered( "Landroid/net/ConnectivityManager;", @@ -135,7 +132,7 @@ private enum class MethodCall( "registerBestMatchingNetworkCallback", arrayOf( "Landroid/net/NetworkRequest;", - $$"Landroid/net/ConnectivityManager$NetworkCallback;", + "Landroid/net/ConnectivityManager\$NetworkCallback;", "Landroid/os/Handler;", ), "V", @@ -143,19 +140,19 @@ private enum class MethodCall( RegisterDefaultNetworkCallback1( "Landroid/net/ConnectivityManager;", "registerDefaultNetworkCallback", - arrayOf($$"Landroid/net/ConnectivityManager$NetworkCallback;"), + arrayOf("Landroid/net/ConnectivityManager\$NetworkCallback;"), "V", ), RegisterDefaultNetworkCallback2( "Landroid/net/ConnectivityManager;", "registerDefaultNetworkCallback", - arrayOf($$"Landroid/net/ConnectivityManager$NetworkCallback;", "Landroid/os/Handler;"), + arrayOf("Landroid/net/ConnectivityManager\$NetworkCallback;", "Landroid/os/Handler;"), "V", ), RegisterNetworkCallback1( "Landroid/net/ConnectivityManager;", "registerNetworkCallback", - arrayOf("Landroid/net/NetworkRequest;", $$"Landroid/net/ConnectivityManager$NetworkCallback;"), + arrayOf("Landroid/net/NetworkRequest;", "Landroid/net/ConnectivityManager\$NetworkCallback;"), "V", ), RegisterNetworkCallback2( @@ -169,7 +166,7 @@ private enum class MethodCall( "registerNetworkCallback", arrayOf( "Landroid/net/NetworkRequest;", - $$"Landroid/net/ConnectivityManager$NetworkCallback;", + "Landroid/net/ConnectivityManager\$NetworkCallback;", "Landroid/os/Handler;", ), "V", @@ -177,13 +174,13 @@ private enum class MethodCall( RequestNetwork1( "Landroid/net/ConnectivityManager;", "requestNetwork", - arrayOf("Landroid/net/NetworkRequest;", $$"Landroid/net/ConnectivityManager$NetworkCallback;"), + arrayOf("Landroid/net/NetworkRequest;", "Landroid/net/ConnectivityManager\$NetworkCallback;"), "V", ), RequestNetwork2( "Landroid/net/ConnectivityManager;", "requestNetwork", - arrayOf("Landroid/net/NetworkRequest;", $$"Landroid/net/ConnectivityManager$NetworkCallback;", "I"), + arrayOf("Landroid/net/NetworkRequest;", "Landroid/net/ConnectivityManager\$NetworkCallback;", "I"), "V", ), RequestNetwork3( @@ -191,7 +188,7 @@ private enum class MethodCall( "requestNetwork", arrayOf( "Landroid/net/NetworkRequest;", - $$"Landroid/net/ConnectivityManager$NetworkCallback;", + "Landroid/net/ConnectivityManager\$NetworkCallback;", "Landroid/os/Handler;", ), "V", @@ -207,7 +204,7 @@ private enum class MethodCall( "requestNetwork", arrayOf( "Landroid/net/NetworkRequest;", - $$"Landroid/net/ConnectivityManager$NetworkCallback;", + "Landroid/net/ConnectivityManager\$NetworkCallback;", "Landroid/os/Handler;", "I", ), @@ -216,7 +213,7 @@ private enum class MethodCall( UnregisterNetworkCallback1( "Landroid/net/ConnectivityManager;", "unregisterNetworkCallback", - arrayOf($$"Landroid/net/ConnectivityManager$NetworkCallback;"), + arrayOf("Landroid/net/ConnectivityManager\$NetworkCallback;"), "V", ), UnregisterNetworkCallback2( diff --git a/patches/src/main/kotlin/app/revanced/patches/all/misc/play/SpoofPlayAgeSignals.kt b/patches/src/main/kotlin/app/revanced/patches/all/misc/play/SpoofPlayAgeSignals.kt deleted file mode 100644 index ccb41b81b4..0000000000 --- a/patches/src/main/kotlin/app/revanced/patches/all/misc/play/SpoofPlayAgeSignals.kt +++ /dev/null @@ -1,138 +0,0 @@ -package app.revanced.patches.all.misc.play - -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.intOption -import app.revanced.patcher.patch.option -import app.revanced.util.forEachInstructionAsSequence -import app.revanced.util.getReference -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.MethodReference -import com.android.tools.smali.dexlib2.immutable.reference.ImmutableMethodReference - -@Suppress("unused") -val spoofPlayAgeSignalsPatch = bytecodePatch( - name = "Spoof Play Age Signals", - description = "Spoofs Google Play data about the user's age and verification status.", - use = false, -) { - val lowerAgeBound by intOption( - name = "Lower age bound", - description = "A positive integer.", - default = 18, - validator = { it == null || it > 0 }, - ) - - val upperAgeBound by intOption( - name = "Upper age bound", - description = "A positive integer. Must be greater than the lower age bound.", - default = Int.MAX_VALUE, - validator = { it == null || it > lowerAgeBound!! }, - ) - - val userStatus by intOption( - name = "User status", - description = "An integer representing the user status.", - default = UserStatus.VERIFIED.value, - values = UserStatus.entries.associate { it.name to it.value }, - ) - - apply { - forEachInstructionAsSequence(match = { classDef, _, instruction, instructionIndex -> - // Avoid patching the library itself. - if (classDef.type.startsWith("Lcom/google/android/play/agesignals/")) return@forEachInstructionAsSequence null - - // Keep method calls only. - val reference = instruction.getReference() - ?: return@forEachInstructionAsSequence null - - val match = MethodCall.entries.firstOrNull { - reference == it.reference - } ?: return@forEachInstructionAsSequence null - - val replacement = when (match) { - MethodCall.AgeLower -> lowerAgeBound!! - MethodCall.AgeUpper -> upperAgeBound!! - MethodCall.UserStatus -> userStatus!! - } - - replacement.let { instructionIndex to it } - }, transform = { method, entry -> - val (instructionIndex, replacement) = entry - - // Get the register which would have contained the return value. - val register = method.getInstruction(instructionIndex + 1).registerA - - // Replace the call instructions with the spoofed value. - method.removeInstructions(instructionIndex, 2) - method.addInstructions( - instructionIndex, - """ - const v$register, $replacement - invoke-static { v$register }, Ljava/lang/Integer;->valueOf(I)Ljava/lang/Integer; - move-result-object v$register - """.trimIndent(), - ) - }) - } -} - -/** - * See [AgeSignalsResult](https://developer.android.com/google/play/age-signals/reference/com/google/android/play/agesignals/AgeSignalsResult). - */ -private enum class MethodCall( - val reference: MethodReference, -) { - AgeLower( - ImmutableMethodReference( - "Lcom/google/android/play/agesignals/AgeSignalsResult;", - "ageLower", - emptyList(), - "Ljava/lang/Integer;", - ), - ), - AgeUpper( - ImmutableMethodReference( - "Lcom/google/android/play/agesignals/AgeSignalsResult;", - "ageUpper", - emptyList(), - "Ljava/lang/Integer;", - ), - ), - UserStatus( - ImmutableMethodReference( - "Lcom/google/android/play/agesignals/AgeSignalsResult;", - "userStatus", - emptyList(), - "Ljava/lang/Integer;", - ), - ), -} - -/** - * All possible user verification statuses. - * - * See [AgeSignalsVerificationStatus](https://developer.android.com/google/play/age-signals/reference/com/google/android/play/agesignals/model/AgeSignalsVerificationStatus). - */ -private enum class UserStatus(val value: Int) { - /** The user provided their age, but it hasn't been verified yet. */ - DECLARED(5), - - /** The user is 18+. */ - VERIFIED(0), - - /** The user's guardian has set the age for him. */ - SUPERVISED(1), - - /** The user's guardian hasn't approved the significant changes yet. */ - SUPERVISED_APPROVAL_PENDING(2), - - /** The user's guardian has denied approval for one or more pending significant changes. */ - SUPERVISED_APPROVAL_DENIED(3), - - /** The user is not verified or supervised. */ - UNKNOWN(4), -} diff --git a/patches/src/main/kotlin/app/revanced/patches/all/misc/play/DisablePlayIntegrity.kt b/patches/src/main/kotlin/app/revanced/patches/all/misc/playintegrity/DisablePlayIntegrity.kt similarity index 95% rename from patches/src/main/kotlin/app/revanced/patches/all/misc/play/DisablePlayIntegrity.kt rename to patches/src/main/kotlin/app/revanced/patches/all/misc/playintegrity/DisablePlayIntegrity.kt index dd5dad79e4..12461fc40a 100644 --- a/patches/src/main/kotlin/app/revanced/patches/all/misc/play/DisablePlayIntegrity.kt +++ b/patches/src/main/kotlin/app/revanced/patches/all/misc/playintegrity/DisablePlayIntegrity.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.all.misc.play +package app.revanced.patches.all.misc.playintegrity import app.revanced.patcher.extensions.replaceInstruction import app.revanced.patcher.patch.bytecodePatch @@ -9,7 +9,7 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference import com.android.tools.smali.dexlib2.immutable.reference.ImmutableMethodReference import com.android.tools.smali.dexlib2.util.MethodUtil -private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/play/DisablePlayIntegrityPatch;" +private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/playintegrity/DisablePlayIntegrityPatch;" private val CONTEXT_BIND_SERVICE_METHOD_REFERENCE = ImmutableMethodReference( "Landroid/content/Context;", diff --git a/patches/src/main/kotlin/app/revanced/patches/all/misc/spoof/SpoofKeystoreSecurityLevelPatch.kt b/patches/src/main/kotlin/app/revanced/patches/all/misc/spoof/SpoofKeystoreSecurityLevelPatch.kt deleted file mode 100644 index b45cfb4e0d..0000000000 --- a/patches/src/main/kotlin/app/revanced/patches/all/misc/spoof/SpoofKeystoreSecurityLevelPatch.kt +++ /dev/null @@ -1,28 +0,0 @@ -package app.revanced.patches.all.misc.spoof - -import app.revanced.patcher.extensions.replaceInstructions -import app.revanced.patcher.patch.bytecodePatch -import app.revanced.util.forEachInstructionAsSequence - -@Suppress("unused") -val spoofKeystoreSecurityLevelPatch = bytecodePatch( - name = "Spoof keystore security level", - description = "Forces apps to see Keymaster and Attestation security levels as 'StrongBox' (Level 2).", - use = false -) { - apply { - forEachInstructionAsSequence( - match = { _, method, _, _ -> - // Match methods by comparing the current method to a reference criteria. - val name = method.name.lowercase() - if (name.contains("securitylevel") && method.returnType == "I") method else null - }, - transform = { mutableMethod, _ -> - // Ensure the method has an implementation before replacing. - if (mutableMethod.implementation?.instructions?.iterator()?.hasNext() == true) { - mutableMethod.replaceInstructions(0, "const/4 v0, 0x2\nreturn v0") - } - } - ) - } -} \ No newline at end of file diff --git a/patches/src/main/kotlin/app/revanced/patches/all/misc/spoof/SpoofRootOfTrustPatch.kt b/patches/src/main/kotlin/app/revanced/patches/all/misc/spoof/SpoofRootOfTrustPatch.kt deleted file mode 100644 index 6177b7e317..0000000000 --- a/patches/src/main/kotlin/app/revanced/patches/all/misc/spoof/SpoofRootOfTrustPatch.kt +++ /dev/null @@ -1,70 +0,0 @@ -package app.revanced.patches.all.misc.spoof - -import app.revanced.patcher.extensions.replaceInstructions -import app.revanced.patcher.patch.bytecodePatch -import app.revanced.util.forEachInstructionAsSequence -import com.android.tools.smali.dexlib2.iface.reference.MethodReference -import com.android.tools.smali.dexlib2.immutable.reference.ImmutableMethodReference -import com.android.tools.smali.dexlib2.util.MethodUtil - -@Suppress("unused") -val spoofRootOfTrustPatch = bytecodePatch( - name = "Spoof root of trust", - description = "Spoofs device integrity states (Locked Bootloader, Verified OS) for apps that perform local certificate attestation.", - use = false -) { - apply { - forEachInstructionAsSequence( - match = { _, method, _, _ -> - MethodCall.entries.firstOrNull { MethodUtil.methodSignaturesMatch(method, it.reference) } - }, - transform = { mutableMethod, methodCall -> - if (mutableMethod.implementation?.instructions?.iterator()?.hasNext() == true) { - mutableMethod.replaceInstructions(0, methodCall.replacementInstructions) - } - } - ) - } -} - -private enum class MethodCall( - val reference: MethodReference, - val replacementInstructions: String, -) { - IsDeviceLockedRootOfTrust( - ImmutableMethodReference( - "LRootOfTrust;", - "isDeviceLocked", - emptyList(), - "Z" - ), - "const/4 v0, 0x1\nreturn v0", - ), - GetVerifiedBootStateRootOfTrust( - ImmutableMethodReference( - "LRootOfTrust;", - "getVerifiedBootState", - emptyList(), - "I" - ), - "const/4 v0, 0x0\nreturn v0", - ), - IsDeviceLockedAttestation( - ImmutableMethodReference( - "LAttestation;", - "isDeviceLocked", - emptyList(), - "Z" - ), - "const/4 v0, 0x1\nreturn v0", - ), - GetVerifiedBootStateAttestation( - ImmutableMethodReference( - "LAttestation;", - "getVerifiedBootState", - emptyList(), - "I" - ), - "const/4 v0, 0x0\nreturn v0", - ), -} \ No newline at end of file diff --git a/patches/src/main/kotlin/app/revanced/patches/instagram/story/locationsticker/EnableLocationStickerRedesignPatch.kt b/patches/src/main/kotlin/app/revanced/patches/instagram/story/locationsticker/EnableLocationStickerRedesignPatch.kt deleted file mode 100644 index 443d60d155..0000000000 --- a/patches/src/main/kotlin/app/revanced/patches/instagram/story/locationsticker/EnableLocationStickerRedesignPatch.kt +++ /dev/null @@ -1,20 +0,0 @@ -package app.revanced.patches.instagram.story.locationsticker - -import app.revanced.patcher.patch.bytecodePatch -import app.revanced.util.returnEarly - -@Suppress("unused") -val enableLocationStickerRedesignPatch = bytecodePatch( - name = "Enable location sticker redesign", - description = "Unlocks the redesigned location sticker with additional style options.", - use = false, -) { - compatibleWith("com.instagram.android") - - apply { - // The gate method reads a MobileConfig boolean flag and returns it directly. - // Returning early with true bypasses the flag check entirely, - // enabling the redesigned sticker styles regardless of server configuration. - locationStickerRedesignGateMethodMatch.method.returnEarly(true) - } -} diff --git a/patches/src/main/kotlin/app/revanced/patches/instagram/story/locationsticker/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/instagram/story/locationsticker/Fingerprints.kt deleted file mode 100644 index 0972d692c9..0000000000 --- a/patches/src/main/kotlin/app/revanced/patches/instagram/story/locationsticker/Fingerprints.kt +++ /dev/null @@ -1,16 +0,0 @@ -package app.revanced.patches.instagram.story.locationsticker - -import app.revanced.patcher.composingFirstMethod -import app.revanced.patcher.instructions -import app.revanced.patcher.invoke -import app.revanced.patcher.patch.BytecodePatchContext - -// MobileConfig boolean key that gates the redesigned location sticker styles. -// The method containing this constant reads the flag and returns it directly, -// making it the sole control point for the feature. The key is stable across -// app updates as MobileConfig keys are server-assigned constants. -private const val LOCATION_STICKER_REDESIGN_CONFIG_KEY = 0x8105a100041e0dL - -internal val BytecodePatchContext.locationStickerRedesignGateMethodMatch by composingFirstMethod { - instructions(LOCATION_STICKER_REDESIGN_CONFIG_KEY()) -} diff --git a/patches/src/main/kotlin/app/revanced/patches/shared/layout/branding/BaseCustomBrandingPatch.kt b/patches/src/main/kotlin/app/revanced/patches/shared/layout/branding/BaseCustomBrandingPatch.kt index 9a583e2c7a..35baad31cf 100644 --- a/patches/src/main/kotlin/app/revanced/patches/shared/layout/branding/BaseCustomBrandingPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/shared/layout/branding/BaseCustomBrandingPatch.kt @@ -3,6 +3,7 @@ package app.revanced.patches.shared.layout.branding import app.revanced.com.android.tools.smali.dexlib2.mutable.MutableMethod import app.revanced.patcher.extensions.addInstruction import app.revanced.patcher.extensions.getInstruction +import app.revanced.patcher.firstImmutableClassDef import app.revanced.patcher.patch.* import app.revanced.patches.all.misc.packagename.setOrGetFallbackPackageName import app.revanced.patches.all.misc.resources.addResources @@ -125,14 +126,14 @@ internal fun baseCustomBrandingPatch( val getBuilderIndex = if (isYouTubeMusic) { // YT Music the field is not a plain object type. indexOfFirstInstructionOrThrow { - getReference()?.type == $$"Landroid/app/Notification$Builder;" + getReference()?.type == "Landroid/app/Notification\$Builder;" } } else { // Find the field name of the notification builder. Field is an Object type. val builderCastIndex = indexOfFirstInstructionOrThrow { val reference = getReference() opcode == Opcode.CHECK_CAST && - reference?.type == $$"Landroid/app/Notification$Builder;" + reference?.type == "Landroid/app/Notification\$Builder;" } indexOfFirstInstructionReversedOrThrow(builderCastIndex) { getReference()?.type == "Ljava/lang/Object;" @@ -147,11 +148,11 @@ internal fun baseCustomBrandingPatch( ).forEach { index -> addInstructionsAtControlFlowLabel( index, - $$""" + """ move-object/from16 v0, p0 - iget-object v0, v0, $$builderFieldName - check-cast v0, Landroid/app/Notification$Builder; - invoke-static { v0 }, $$EXTENSION_CLASS_DESCRIPTOR->setNotificationIcon(Landroid/app/Notification$Builder;)V + iget-object v0, v0, $builderFieldName + check-cast v0, Landroid/app/Notification${'$'}Builder; + invoke-static { v0 }, $EXTENSION_CLASS_DESCRIPTOR->setNotificationIcon(Landroid/app/Notification${'$'}Builder;)V """, ) } @@ -161,37 +162,16 @@ internal fun baseCustomBrandingPatch( ) afterDependents { - val useCustomName = customName != null - val useCustomIcon = customIcon != null - val isRootInstall = setOrGetFallbackPackageName(originalAppPackageName) == originalAppPackageName - // Can only check if app is root installation by checking if change package name patch is in use. // and can only do that in the afterDependents block here. // The UI preferences cannot be selectively added here, because the settings afterDependents block // may have already run and the settings are already wrote to file. // Instead, show a warning if any patch option was used (A rooted device launcher ignores the manifest changes), // and the non-functional in-app settings are removed on app startup by extension code. - if (isRootInstall && (useCustomName || useCustomIcon)) { - Logger.getLogger(this::class.java.name).warning( - "Custom branding does not work with root installation. No changes applied." - ) - } - - if (!isRootInstall || useCustomName) { - document("AndroidManifest.xml").use { document -> - val application = document.getElementsByTagName("application").item(0) as Element - application.setAttribute( - "android:label", - if (useCustomName) { - // Use custom name everywhere. - customName - } else { - // The YT application name can appear in some places alongside the system - // YouTube app, such as the settings app list and in the "open with" file picker. - // Because the YouTube app cannot be completely uninstalled and only disabled, - // use a custom name for this situation to disambiguate which app is which. - "@string/revanced_custom_branding_name_entry_2" - } + if (customName != null || customIcon != null) { + if (setOrGetFallbackPackageName(originalAppPackageName) == originalAppPackageName) { + Logger.getLogger(this::class.java.name).warning( + "Custom branding does not work with root installation. No changes applied.", ) } } @@ -332,19 +312,16 @@ internal fun baseCustomBrandingPatch( activityAliasNameWithIntents, ).childNodes - // If user provides a custom icon, then change the application icon ('static' icon) - // which shows as the push notification for some devices, in the app settings, - // and as the icon for the apk before installing. - // This icon cannot be dynamically selected and this change must only be done if the - // user provides an icon otherwise there is no way to restore the original YouTube icon. - if (useCustomIcon) { - application.setAttribute( - "android:icon", - "@mipmap/revanced_launcher_custom" - ) - } + // The YT application name can appear in some places alongside the system + // YouTube app, such as the settings app list and in the "open with" file picker. + // Because the YouTube app cannot be completely uninstalled and only disabled, + // use a custom name for this situation to disambiguate which app is which. + application.setAttribute( + "android:label", + "@string/revanced_custom_branding_name_entry_2", + ) - val enabledNameIndex = if (useCustomName) numberOfPresetAppNames else 2 // 1 indexing. + val enabledNameIndex = if (useCustomName) numberOfPresetAppNames else 1 // 1 indexing. val enabledIconIndex = if (useCustomIcon) iconStyleNames.size else 0 // 0 indexing. for (appNameIndex in 1..numberOfPresetAppNames) { @@ -359,7 +336,7 @@ internal fun baseCustomBrandingPatch( iconMipmapName = originalLauncherIconName, appNameIndex = appNameIndex, useCustomName = useCustomNameLabel, - enabled = false, + enabled = (appNameIndex == 1), intentFilters, ), )