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.Context;
|
||||||
import android.content.Intent;
|
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 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 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 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 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
|
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.extensions.replaceInstruction
|
||||||
import app.revanced.patcher.patch.bytecodePatch
|
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.immutable.reference.ImmutableMethodReference
|
||||||
import com.android.tools.smali.dexlib2.util.MethodUtil
|
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(
|
private val CONTEXT_BIND_SERVICE_METHOD_REFERENCE = ImmutableMethodReference(
|
||||||
"Landroid/content/Context;",
|
"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