feat!: Add Spoof Play Age Signals patch (#6692)
Co-authored-by: ADudeCalledLeo <7997354+Leo40Git@users.noreply.github.com> Co-authored-by: Dawid Krajcarz <80264606+drobotk@users.noreply.github.com> Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
This commit is contained in:
parent
4bc8c7c0f6
commit
e19275fb7d
4 changed files with 146 additions and 4 deletions
|
|
@ -1,4 +1,4 @@
|
|||
package app.revanced.extension.playintegrity;
|
||||
package app.revanced.extension.play;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
|
@ -89,10 +89,14 @@ 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/playintegrity/DisablePlayIntegrityKt {
|
||||
public final class app/revanced/patches/all/misc/play/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
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
package app.revanced.patches.all.misc.playintegrity
|
||||
package app.revanced.patches.all.misc.play
|
||||
|
||||
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/playintegrity/DisablePlayIntegrityPatch;"
|
||||
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/play/DisablePlayIntegrityPatch;"
|
||||
|
||||
private val CONTEXT_BIND_SERVICE_METHOD_REFERENCE = ImmutableMethodReference(
|
||||
"Landroid/content/Context;",
|
||||
|
|
@ -0,0 +1,138 @@
|
|||
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<MethodReference>()
|
||||
?: 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<OneRegisterInstruction>(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),
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue