mirror of
https://github.com/revanced/revanced-patches.git
synced 2025-06-13 05:37:41 +02:00
feat: Add Disable pairip license check
patch (#4927)
Co-authored-by: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com>
This commit is contained in:
@ -652,6 +652,10 @@ public final class app/revanced/patches/shared/misc/mapping/ResourceMappingPatch
|
|||||||
public static final fun getResourceMappings ()Ljava/util/List;
|
public static final fun getResourceMappings ()Ljava/util/List;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final class app/revanced/patches/shared/misc/pairip/license/DisableLicenseCheckPatchKt {
|
||||||
|
public static final fun getDisableLicenseCheckPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||||
|
}
|
||||||
|
|
||||||
public final class app/revanced/patches/shared/misc/settings/SettingsPatchKt {
|
public final class app/revanced/patches/shared/misc/settings/SettingsPatchKt {
|
||||||
public static final fun settingsPatch (Ljava/util/List;Ljava/util/Set;)Lapp/revanced/patcher/patch/ResourcePatch;
|
public static final fun settingsPatch (Ljava/util/List;Ljava/util/Set;)Lapp/revanced/patcher/patch/ResourcePatch;
|
||||||
public static final fun settingsPatch (Lkotlin/Pair;Ljava/util/Set;)Lapp/revanced/patcher/patch/ResourcePatch;
|
public static final fun settingsPatch (Lkotlin/Pair;Ljava/util/Set;)Lapp/revanced/patcher/patch/ResourcePatch;
|
||||||
@ -1615,8 +1619,24 @@ public final class app/revanced/util/BytecodeUtilsKt {
|
|||||||
public static final fun indexOfFirstResourceIdOrThrow (Lcom/android/tools/smali/dexlib2/iface/Method;Ljava/lang/String;)I
|
public static final fun indexOfFirstResourceIdOrThrow (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 injectHideViewCall (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;IILjava/lang/String;Ljava/lang/String;)V
|
||||||
public static final fun literal (Lapp/revanced/patcher/FingerprintBuilder;Lkotlin/jvm/functions/Function0;)V
|
public static final fun literal (Lapp/revanced/patcher/FingerprintBuilder;Lkotlin/jvm/functions/Function0;)V
|
||||||
|
public static final fun returnEarly (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;B)V
|
||||||
|
public static final fun returnEarly (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;C)V
|
||||||
|
public static final fun returnEarly (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;D)V
|
||||||
|
public static final fun returnEarly (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;F)V
|
||||||
|
public static final fun returnEarly (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;I)V
|
||||||
|
public static final fun returnEarly (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;J)V
|
||||||
|
public static final fun returnEarly (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;S)V
|
||||||
public static final fun returnEarly (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;Z)V
|
public static final fun returnEarly (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;Z)V
|
||||||
public static synthetic fun returnEarly$default (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;ZILjava/lang/Object;)V
|
public static synthetic fun returnEarly$default (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;ZILjava/lang/Object;)V
|
||||||
|
public static final fun returnLate (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;B)V
|
||||||
|
public static final fun returnLate (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;C)V
|
||||||
|
public static final fun returnLate (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;D)V
|
||||||
|
public static final fun returnLate (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;F)V
|
||||||
|
public static final fun returnLate (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;I)V
|
||||||
|
public static final fun returnLate (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;J)V
|
||||||
|
public static final fun returnLate (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;S)V
|
||||||
|
public static final fun returnLate (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;Z)V
|
||||||
|
public static synthetic fun returnLate$default (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;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 transformMethods (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableClass;Lkotlin/jvm/functions/Function1;)V
|
||||||
public static final fun traverseClassHierarchy (Lapp/revanced/patcher/patch/BytecodePatchContext;Lapp/revanced/patcher/util/proxy/mutableTypes/MutableClass;Lkotlin/jvm/functions/Function1;)V
|
public static final fun traverseClassHierarchy (Lapp/revanced/patcher/patch/BytecodePatchContext;Lapp/revanced/patcher/util/proxy/mutableTypes/MutableClass;Lkotlin/jvm/functions/Function1;)V
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,17 @@
|
|||||||
package app.revanced.patches.angulus.ads
|
package app.revanced.patches.angulus.ads
|
||||||
|
|
||||||
import app.revanced.patcher.patch.bytecodePatch
|
import app.revanced.patcher.patch.bytecodePatch
|
||||||
|
import app.revanced.patches.shared.misc.pairip.license.disableLicenseCheckPatch
|
||||||
import app.revanced.util.returnEarly
|
import app.revanced.util.returnEarly
|
||||||
|
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
val angulusPatch = bytecodePatch(name = "Hide ads") {
|
val angulusPatch = bytecodePatch(name = "Hide ads") {
|
||||||
compatibleWith("com.drinkplusplus.angulus")
|
compatibleWith("com.drinkplusplus.angulus")
|
||||||
|
|
||||||
|
dependsOn(disableLicenseCheckPatch)
|
||||||
|
|
||||||
execute {
|
execute {
|
||||||
// Always return 0 as the daily measurement count.
|
// Always return 0 as the daily measurement count.
|
||||||
getDailyMeasurementCountFingerprint.method.returnEarly()
|
getDailyMeasurementCountFingerprint.method.returnEarly(0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,26 @@
|
|||||||
|
package app.revanced.patches.shared.misc.pairip.license
|
||||||
|
|
||||||
|
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||||
|
import app.revanced.patcher.patch.bytecodePatch
|
||||||
|
import app.revanced.util.returnEarly
|
||||||
|
import java.util.logging.Logger
|
||||||
|
|
||||||
|
@Suppress("unused")
|
||||||
|
val disableLicenseCheckPatch = bytecodePatch(
|
||||||
|
name = "Disable pairip license check",
|
||||||
|
description = "Disable Play Integrity Protect (pairip) client-side license check."
|
||||||
|
) {
|
||||||
|
|
||||||
|
execute {
|
||||||
|
if (processLicenseResponseFingerprint.methodOrNull == null || validateLicenseResponseFingerprint.methodOrNull == null)
|
||||||
|
return@execute Logger.getLogger(this::class.java.name)
|
||||||
|
.warning("Could not find pairip licensing check. No changes applied.")
|
||||||
|
|
||||||
|
// Set first parameter (responseCode) to 0 (success status).
|
||||||
|
processLicenseResponseFingerprint.method.addInstruction(0, "const/4 p1, 0x0")
|
||||||
|
|
||||||
|
// Short-circuit the license response validation.
|
||||||
|
validateLicenseResponseFingerprint.method.returnEarly();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
package app.revanced.patches.shared.misc.pairip.license
|
||||||
|
|
||||||
|
import app.revanced.patcher.fingerprint
|
||||||
|
|
||||||
|
internal val processLicenseResponseFingerprint = fingerprint {
|
||||||
|
custom { method, classDef ->
|
||||||
|
classDef.type == "Lcom/pairip/licensecheck/LicenseClient;" &&
|
||||||
|
method.name == "processResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal val validateLicenseResponseFingerprint = fingerprint {
|
||||||
|
custom { method, classDef ->
|
||||||
|
classDef.type == "Lcom/pairip/licensecheck/ResponseValidator;" &&
|
||||||
|
method.name == "validateResponse"
|
||||||
|
}
|
||||||
|
}
|
@ -133,6 +133,7 @@ internal val Instruction.registersUsed: List<Int>
|
|||||||
else -> listOf(registerC, registerD, registerE, registerF, registerG)
|
else -> listOf(registerC, registerD, registerE, registerF, registerG)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
is ThreeRegisterInstruction -> listOf(registerA, registerB, registerC)
|
is ThreeRegisterInstruction -> listOf(registerA, registerB, registerC)
|
||||||
is TwoRegisterInstruction -> listOf(registerA, registerB)
|
is TwoRegisterInstruction -> listOf(registerA, registerB)
|
||||||
is OneRegisterInstruction -> listOf(registerA)
|
is OneRegisterInstruction -> listOf(registerA)
|
||||||
@ -170,7 +171,7 @@ internal val Instruction.isReturnInstruction: Boolean
|
|||||||
/**
|
/**
|
||||||
* Adds public [AccessFlags] and removes private and protected flags (if present).
|
* Adds public [AccessFlags] and removes private and protected flags (if present).
|
||||||
*/
|
*/
|
||||||
internal fun Int.toPublicAccessFlags() : Int {
|
internal fun Int.toPublicAccessFlags(): Int {
|
||||||
return this.or(AccessFlags.PUBLIC.value)
|
return this.or(AccessFlags.PUBLIC.value)
|
||||||
.and(AccessFlags.PROTECTED.value.inv())
|
.and(AccessFlags.PROTECTED.value.inv())
|
||||||
.and(AccessFlags.PRIVATE.value.inv())
|
.and(AccessFlags.PRIVATE.value.inv())
|
||||||
@ -489,9 +490,10 @@ fun Method.indexOfFirstInstruction(targetOpcode: Opcode): Int = indexOfFirstInst
|
|||||||
* @return The index of the first opcode specified, or -1 if not found.
|
* @return The index of the first opcode specified, or -1 if not found.
|
||||||
* @see indexOfFirstInstructionOrThrow
|
* @see indexOfFirstInstructionOrThrow
|
||||||
*/
|
*/
|
||||||
fun Method.indexOfFirstInstruction(startIndex: Int = 0, targetOpcode: Opcode): Int = indexOfFirstInstruction(startIndex) {
|
fun Method.indexOfFirstInstruction(startIndex: Int = 0, targetOpcode: Opcode): Int =
|
||||||
opcode == targetOpcode
|
indexOfFirstInstruction(startIndex) {
|
||||||
}
|
opcode == targetOpcode
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the index of the first [Instruction] that matches the predicate, starting from [startIndex].
|
* Get the index of the first [Instruction] that matches the predicate, starting from [startIndex].
|
||||||
@ -526,9 +528,10 @@ fun Method.indexOfFirstInstructionOrThrow(targetOpcode: Opcode): Int = indexOfFi
|
|||||||
* @throws PatchException
|
* @throws PatchException
|
||||||
* @see indexOfFirstInstruction
|
* @see indexOfFirstInstruction
|
||||||
*/
|
*/
|
||||||
fun Method.indexOfFirstInstructionOrThrow(startIndex: Int = 0, targetOpcode: Opcode): Int = indexOfFirstInstructionOrThrow(startIndex) {
|
fun Method.indexOfFirstInstructionOrThrow(startIndex: Int = 0, targetOpcode: Opcode): Int =
|
||||||
opcode == targetOpcode
|
indexOfFirstInstructionOrThrow(startIndex) {
|
||||||
}
|
opcode == targetOpcode
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the index of the first [Instruction] that matches the predicate, starting from [startIndex].
|
* Get the index of the first [Instruction] that matches the predicate, starting from [startIndex].
|
||||||
@ -554,9 +557,10 @@ fun Method.indexOfFirstInstructionOrThrow(startIndex: Int = 0, filter: Instructi
|
|||||||
* @return -1 if the instruction is not found.
|
* @return -1 if the instruction is not found.
|
||||||
* @see indexOfFirstInstructionReversedOrThrow
|
* @see indexOfFirstInstructionReversedOrThrow
|
||||||
*/
|
*/
|
||||||
fun Method.indexOfFirstInstructionReversed(startIndex: Int? = null, targetOpcode: Opcode): Int = indexOfFirstInstructionReversed(startIndex) {
|
fun Method.indexOfFirstInstructionReversed(startIndex: Int? = null, targetOpcode: Opcode): Int =
|
||||||
opcode == targetOpcode
|
indexOfFirstInstructionReversed(startIndex) {
|
||||||
}
|
opcode == targetOpcode
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the index of matching instruction,
|
* Get the index of matching instruction,
|
||||||
@ -593,9 +597,10 @@ fun Method.indexOfFirstInstructionReversed(targetOpcode: Opcode): Int = indexOfF
|
|||||||
* @return The index of the instruction.
|
* @return The index of the instruction.
|
||||||
* @see indexOfFirstInstructionReversed
|
* @see indexOfFirstInstructionReversed
|
||||||
*/
|
*/
|
||||||
fun Method.indexOfFirstInstructionReversedOrThrow(startIndex: Int? = null, targetOpcode: Opcode): Int = indexOfFirstInstructionReversedOrThrow(startIndex) {
|
fun Method.indexOfFirstInstructionReversedOrThrow(startIndex: Int? = null, targetOpcode: Opcode): Int =
|
||||||
opcode == targetOpcode
|
indexOfFirstInstructionReversedOrThrow(startIndex) {
|
||||||
}
|
opcode == targetOpcode
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the index of matching instruction,
|
* Get the index of matching instruction,
|
||||||
@ -652,7 +657,8 @@ fun Method.findInstructionIndicesReversedOrThrow(filter: Instruction.() -> Boole
|
|||||||
* _Returns an empty list if no indices are found_
|
* _Returns an empty list if no indices are found_
|
||||||
* @see findInstructionIndicesReversedOrThrow
|
* @see findInstructionIndicesReversedOrThrow
|
||||||
*/
|
*/
|
||||||
fun Method.findInstructionIndicesReversed(opcode: Opcode): List<Int> = findInstructionIndicesReversed { this.opcode == opcode }
|
fun Method.findInstructionIndicesReversed(opcode: Opcode): List<Int> =
|
||||||
|
findInstructionIndicesReversed { this.opcode == opcode }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return An immutable list of indices of the opcode in reverse order.
|
* @return An immutable list of indices of the opcode in reverse order.
|
||||||
@ -726,43 +732,222 @@ fun BytecodePatchContext.forEachLiteralValueInstruction(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private const val RETURN_TYPE_MISMATCH = "Mismatch between override type and Method return type"
|
||||||
* Overrides the first instruction of a method with a constant return value.
|
|
||||||
* None of the method code will ever execute.
|
|
||||||
*/
|
|
||||||
fun MutableMethod.returnEarly(overrideValue: Boolean = false) = overrideReturnValue(overrideValue, false)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Overrides all return statements with a constant value.
|
* Overrides the first instruction of a method with a constant `Boolean` return value.
|
||||||
|
* None of the method code will ever execute.
|
||||||
|
*
|
||||||
|
* For methods that return an object or any array type, calling this method with `false`
|
||||||
|
* will force the method to return a `null` value.
|
||||||
|
*/
|
||||||
|
fun MutableMethod.returnEarly(value: Boolean = false) {
|
||||||
|
val returnType = returnType.first()
|
||||||
|
check(returnType == 'Z' || (!value && (returnType in setOf('V', 'L', '[')))) { RETURN_TYPE_MISMATCH }
|
||||||
|
overrideReturnValue(value.toHexString(), false)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Overrides the first instruction of a method with a constant `Byte` return value.
|
||||||
|
* None of the method code will ever execute.
|
||||||
|
*/
|
||||||
|
fun MutableMethod.returnEarly(value: Byte) {
|
||||||
|
check(returnType.first() == 'B') { RETURN_TYPE_MISMATCH }
|
||||||
|
overrideReturnValue(value.toString(), false)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Overrides the first instruction of a method with a constant `Short` return value.
|
||||||
|
* None of the method code will ever execute.
|
||||||
|
*/
|
||||||
|
fun MutableMethod.returnEarly(value: Short) {
|
||||||
|
check(returnType.first() == 'S') { RETURN_TYPE_MISMATCH }
|
||||||
|
overrideReturnValue(value.toString(), false)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Overrides the first instruction of a method with a constant `Char` return value.
|
||||||
|
* None of the method code will ever execute.
|
||||||
|
*/
|
||||||
|
fun MutableMethod.returnEarly(value: Char) {
|
||||||
|
check(returnType.first() == 'C') { RETURN_TYPE_MISMATCH }
|
||||||
|
overrideReturnValue(value.code.toString(), false)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Overrides the first instruction of a method with a constant `Int` return value.
|
||||||
|
* None of the method code will ever execute.
|
||||||
|
*/
|
||||||
|
fun MutableMethod.returnEarly(value: Int) {
|
||||||
|
check(returnType.first() == 'I') { RETURN_TYPE_MISMATCH }
|
||||||
|
overrideReturnValue(value.toString(), false)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Overrides the first instruction of a method with a constant `Long` return value.
|
||||||
|
* None of the method code will ever execute.
|
||||||
|
*/
|
||||||
|
fun MutableMethod.returnEarly(value: Long) {
|
||||||
|
check(returnType.first() == 'J') { RETURN_TYPE_MISMATCH }
|
||||||
|
overrideReturnValue(value.toString(), false)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Overrides the first instruction of a method with a constant `Float` return value.
|
||||||
|
* None of the method code will ever execute.
|
||||||
|
*/
|
||||||
|
fun MutableMethod.returnEarly(value: Float) {
|
||||||
|
check(returnType.first() == 'F') { RETURN_TYPE_MISMATCH }
|
||||||
|
overrideReturnValue(value.toString(), false)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Overrides the first instruction of a method with a constant `Double` return value.
|
||||||
|
* None of the method code will ever execute.
|
||||||
|
*/
|
||||||
|
fun MutableMethod.returnEarly(value: Double) {
|
||||||
|
check(returnType.first() == 'J') { RETURN_TYPE_MISMATCH }
|
||||||
|
overrideReturnValue(value.toString(), false)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Overrides all return statements with a constant `Boolean` value.
|
||||||
|
* All method code is executed the same as unpatched.
|
||||||
|
*
|
||||||
|
* For methods that return an object or any array type, calling this method with `false`
|
||||||
|
* will force the method to return a `null` value.
|
||||||
|
*
|
||||||
|
* @see returnEarly
|
||||||
|
*/
|
||||||
|
fun MutableMethod.returnLate(value: Boolean) {
|
||||||
|
val returnType = returnType.first()
|
||||||
|
if (returnType == 'V') {
|
||||||
|
error("Cannot return late for Method of void type")
|
||||||
|
}
|
||||||
|
check(returnType == 'Z' || (!value && returnType in setOf('L', '['))) { RETURN_TYPE_MISMATCH }
|
||||||
|
|
||||||
|
overrideReturnValue(value.toHexString(), true)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Overrides all return statements with a constant `Byte` value.
|
||||||
* All method code is executed the same as unpatched.
|
* All method code is executed the same as unpatched.
|
||||||
*
|
*
|
||||||
* @see returnEarly
|
* @see returnEarly
|
||||||
*/
|
*/
|
||||||
internal fun MutableMethod.returnLate(overrideValue: Boolean = false) = overrideReturnValue(overrideValue, true)
|
fun MutableMethod.returnLate(value: Byte) {
|
||||||
|
check(returnType.first() == 'B') { RETURN_TYPE_MISMATCH }
|
||||||
|
overrideReturnValue(value.toString(), true)
|
||||||
|
}
|
||||||
|
|
||||||
private fun MutableMethod.overrideReturnValue(bool: Boolean, returnLate: Boolean) {
|
/**
|
||||||
val const = if (bool) "0x1" else "0x0"
|
* Overrides all return statements with a constant `Short` value.
|
||||||
|
* All method code is executed the same as unpatched.
|
||||||
|
*
|
||||||
|
* @see returnEarly
|
||||||
|
*/
|
||||||
|
fun MutableMethod.returnLate(value: Short) {
|
||||||
|
check(returnType.first() == 'S') { RETURN_TYPE_MISMATCH }
|
||||||
|
overrideReturnValue(value.toString(), true)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Overrides all return statements with a constant `Char` value.
|
||||||
|
* All method code is executed the same as unpatched.
|
||||||
|
*
|
||||||
|
* @see returnEarly
|
||||||
|
*/
|
||||||
|
fun MutableMethod.returnLate(value: Char) {
|
||||||
|
check(returnType.first() == 'C') { RETURN_TYPE_MISMATCH }
|
||||||
|
overrideReturnValue(value.code.toString(), true)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Overrides all return statements with a constant `Int` value.
|
||||||
|
* All method code is executed the same as unpatched.
|
||||||
|
*
|
||||||
|
* @see returnEarly
|
||||||
|
*/
|
||||||
|
fun MutableMethod.returnLate(value: Int) {
|
||||||
|
check(returnType.first() == 'I') { RETURN_TYPE_MISMATCH }
|
||||||
|
overrideReturnValue(value.toString(), true)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Overrides all return statements with a constant `Long` value.
|
||||||
|
* All method code is executed the same as unpatched.
|
||||||
|
*
|
||||||
|
* @see returnEarly
|
||||||
|
*/
|
||||||
|
fun MutableMethod.returnLate(value: Long) {
|
||||||
|
check(returnType.first() == 'J') { RETURN_TYPE_MISMATCH }
|
||||||
|
overrideReturnValue(value.toString(), true)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Overrides all return statements with a constant `Float` value.
|
||||||
|
* All method code is executed the same as unpatched.
|
||||||
|
*
|
||||||
|
* @see returnEarly
|
||||||
|
*/
|
||||||
|
fun MutableMethod.returnLate(value: Float) {
|
||||||
|
check(returnType.first() == 'F') { RETURN_TYPE_MISMATCH }
|
||||||
|
overrideReturnValue(value.toString(), true)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Overrides all return statements with a constant `Double` value.
|
||||||
|
* All method code is executed the same as unpatched.
|
||||||
|
*
|
||||||
|
* @see returnEarly
|
||||||
|
*/
|
||||||
|
fun MutableMethod.returnLate(value: Double) {
|
||||||
|
check(returnType.first() == 'D') { RETURN_TYPE_MISMATCH }
|
||||||
|
overrideReturnValue(value.toString(), true)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun MutableMethod.overrideReturnValue(value: String, returnLate: Boolean) {
|
||||||
val instructions = when (returnType.first()) {
|
val instructions = when (returnType.first()) {
|
||||||
'L' -> {
|
// If return type is an object, always return null.
|
||||||
|
'L', '[' -> {
|
||||||
"""
|
"""
|
||||||
const/4 v0, $const
|
const/4 v0, 0x0
|
||||||
return-object v0
|
return-object v0
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
|
||||||
'V' -> {
|
'V' -> {
|
||||||
if (returnLate) throw IllegalArgumentException("Cannot return late for method of void type")
|
|
||||||
"return-void"
|
"return-void"
|
||||||
}
|
}
|
||||||
|
|
||||||
'I', 'Z' -> {
|
'B', 'Z' -> {
|
||||||
"""
|
"""
|
||||||
const/4 v0, $const
|
const/4 v0, $value
|
||||||
return v0
|
return v0
|
||||||
"""
|
"""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
'S', 'C' -> {
|
||||||
|
"""
|
||||||
|
const/16 v0, $value
|
||||||
|
return v0
|
||||||
|
"""
|
||||||
|
}
|
||||||
|
|
||||||
|
'I', 'F' -> {
|
||||||
|
"""
|
||||||
|
const v0, $value
|
||||||
|
return v0
|
||||||
|
"""
|
||||||
|
}
|
||||||
|
|
||||||
|
'J', 'D' -> {
|
||||||
|
"""
|
||||||
|
const-wide v0, $value
|
||||||
|
return-wide v0
|
||||||
|
"""
|
||||||
|
}
|
||||||
|
|
||||||
else -> throw Exception("Return type is not supported: $this")
|
else -> throw Exception("Return type is not supported: $this")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,3 +6,5 @@ internal object Utils {
|
|||||||
.joinToString("\n") { it.trimIndent() } // Remove the leading whitespace from each line.
|
.joinToString("\n") { it.trimIndent() } // Remove the leading whitespace from each line.
|
||||||
.trimIndent() // Remove the leading newline.
|
.trimIndent() // Remove the leading newline.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal fun Boolean.toHexString(): String = if (this) "0x1" else "0x0"
|
Reference in New Issue
Block a user