feat: spoof-wifi-connection
patch (#1527)
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de> Co-authored-by: Linus789 <Linus789@users.noreply.github.com> Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
This commit is contained in:
parent
f8738a7292
commit
adce206d66
|
@ -0,0 +1,206 @@
|
||||||
|
package app.revanced.patches.all.connectivity.wifi.spoof.patch
|
||||||
|
|
||||||
|
import app.revanced.patcher.annotation.Description
|
||||||
|
import app.revanced.patcher.annotation.Name
|
||||||
|
import app.revanced.patcher.annotation.Version
|
||||||
|
import app.revanced.patcher.patch.annotations.Patch
|
||||||
|
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||||
|
import app.revanced.util.patch.*
|
||||||
|
import org.jf.dexlib2.iface.ClassDef
|
||||||
|
import org.jf.dexlib2.iface.Method
|
||||||
|
import org.jf.dexlib2.iface.instruction.Instruction
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
@Patch(false)
|
||||||
|
@Name("spoof-wifi-connection")
|
||||||
|
@Description("Spoofs an existing Wi-Fi connection.")
|
||||||
|
@Version("0.0.1")
|
||||||
|
internal class SpoofWifiPatch : AbstractTransformInstructionsPatch<Instruction35cInfo>() {
|
||||||
|
|
||||||
|
private companion object {
|
||||||
|
const val INTEGRATIONS_CLASS_DESCRIPTOR_PREFIX = "Lapp/revanced/all/connectivity/wifi/spoof/SpoofWifiPatch"
|
||||||
|
const val INTEGRATIONS_CLASS_DESCRIPTOR = "${INTEGRATIONS_CLASS_DESCRIPTOR_PREFIX};"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Information about method calls we want to replace
|
||||||
|
enum class MethodCall(
|
||||||
|
override val definedClassName: String,
|
||||||
|
override val methodName: String,
|
||||||
|
override val methodParams: Array<String>,
|
||||||
|
override val returnType: String,
|
||||||
|
): IMethodCall {
|
||||||
|
GetSystemService1(
|
||||||
|
"Landroid/content/Context;",
|
||||||
|
"getSystemService",
|
||||||
|
arrayOf("Ljava/lang/String;"),
|
||||||
|
"Ljava/lang/Object;",
|
||||||
|
),
|
||||||
|
GetSystemService2(
|
||||||
|
"Landroid/content/Context;",
|
||||||
|
"getSystemService",
|
||||||
|
arrayOf("Ljava/lang/Class;"),
|
||||||
|
"Ljava/lang/Object;",
|
||||||
|
),
|
||||||
|
GetActiveNetworkInfo(
|
||||||
|
"Landroid/net/ConnectivityManager;",
|
||||||
|
"getActiveNetworkInfo",
|
||||||
|
arrayOf(),
|
||||||
|
"Landroid/net/NetworkInfo;",
|
||||||
|
),
|
||||||
|
IsConnected(
|
||||||
|
"Landroid/net/NetworkInfo;",
|
||||||
|
"isConnected",
|
||||||
|
arrayOf(),
|
||||||
|
"Z",
|
||||||
|
),
|
||||||
|
IsConnectedOrConnecting(
|
||||||
|
"Landroid/net/NetworkInfo;",
|
||||||
|
"isConnectedOrConnecting",
|
||||||
|
arrayOf(),
|
||||||
|
"Z",
|
||||||
|
),
|
||||||
|
IsAvailable(
|
||||||
|
"Landroid/net/NetworkInfo;",
|
||||||
|
"isAvailable",
|
||||||
|
arrayOf(),
|
||||||
|
"Z",
|
||||||
|
),
|
||||||
|
GetState(
|
||||||
|
"Landroid/net/NetworkInfo;",
|
||||||
|
"getState",
|
||||||
|
arrayOf(),
|
||||||
|
"Landroid/net/NetworkInfo\$State;",
|
||||||
|
),
|
||||||
|
GetDetailedState(
|
||||||
|
"Landroid/net/NetworkInfo;",
|
||||||
|
"getDetailedState",
|
||||||
|
arrayOf(),
|
||||||
|
"Landroid/net/NetworkInfo\$DetailedState;",
|
||||||
|
),
|
||||||
|
IsActiveNetworkMetered(
|
||||||
|
"Landroid/net/ConnectivityManager;",
|
||||||
|
"isActiveNetworkMetered",
|
||||||
|
arrayOf(),
|
||||||
|
"Z",
|
||||||
|
),
|
||||||
|
GetActiveNetwork(
|
||||||
|
"Landroid/net/ConnectivityManager;",
|
||||||
|
"getActiveNetwork",
|
||||||
|
arrayOf(),
|
||||||
|
"Landroid/net/Network;",
|
||||||
|
),
|
||||||
|
GetNetworkInfo(
|
||||||
|
"Landroid/net/ConnectivityManager;",
|
||||||
|
"getNetworkInfo",
|
||||||
|
arrayOf("Landroid/net/Network;"),
|
||||||
|
"Landroid/net/NetworkInfo;",
|
||||||
|
),
|
||||||
|
HasTransport(
|
||||||
|
"Landroid/net/NetworkCapabilities;",
|
||||||
|
"hasTransport",
|
||||||
|
arrayOf("I"),
|
||||||
|
"Z",
|
||||||
|
),
|
||||||
|
HasCapability(
|
||||||
|
"Landroid/net/NetworkCapabilities;",
|
||||||
|
"hasCapability",
|
||||||
|
arrayOf("I"),
|
||||||
|
"Z",
|
||||||
|
),
|
||||||
|
RegisterBestMatchingNetworkCallback(
|
||||||
|
"Landroid/net/ConnectivityManager;",
|
||||||
|
"registerBestMatchingNetworkCallback",
|
||||||
|
arrayOf("Landroid/net/NetworkRequest;", "Landroid/net/ConnectivityManager\$NetworkCallback;", "Landroid/os/Handler;"),
|
||||||
|
"V",
|
||||||
|
),
|
||||||
|
RegisterDefaultNetworkCallback1(
|
||||||
|
"Landroid/net/ConnectivityManager;",
|
||||||
|
"registerDefaultNetworkCallback",
|
||||||
|
arrayOf("Landroid/net/ConnectivityManager\$NetworkCallback;"),
|
||||||
|
"V",
|
||||||
|
),
|
||||||
|
RegisterDefaultNetworkCallback2(
|
||||||
|
"Landroid/net/ConnectivityManager;",
|
||||||
|
"registerDefaultNetworkCallback",
|
||||||
|
arrayOf("Landroid/net/ConnectivityManager\$NetworkCallback;", "Landroid/os/Handler;"),
|
||||||
|
"V",
|
||||||
|
),
|
||||||
|
RegisterNetworkCallback1(
|
||||||
|
"Landroid/net/ConnectivityManager;",
|
||||||
|
"registerNetworkCallback",
|
||||||
|
arrayOf("Landroid/net/NetworkRequest;", "Landroid/net/ConnectivityManager\$NetworkCallback;"),
|
||||||
|
"V",
|
||||||
|
),
|
||||||
|
RegisterNetworkCallback2(
|
||||||
|
"Landroid/net/ConnectivityManager;",
|
||||||
|
"registerNetworkCallback",
|
||||||
|
arrayOf("Landroid/net/NetworkRequest;", "Landroid/app/PendingIntent;"),
|
||||||
|
"V",
|
||||||
|
),
|
||||||
|
RegisterNetworkCallback3(
|
||||||
|
"Landroid/net/ConnectivityManager;",
|
||||||
|
"registerNetworkCallback",
|
||||||
|
arrayOf("Landroid/net/NetworkRequest;", "Landroid/net/ConnectivityManager\$NetworkCallback;", "Landroid/os/Handler;"),
|
||||||
|
"V",
|
||||||
|
),
|
||||||
|
RequestNetwork1(
|
||||||
|
"Landroid/net/ConnectivityManager;",
|
||||||
|
"requestNetwork",
|
||||||
|
arrayOf("Landroid/net/NetworkRequest;", "Landroid/net/ConnectivityManager\$NetworkCallback;"),
|
||||||
|
"V",
|
||||||
|
),
|
||||||
|
RequestNetwork2(
|
||||||
|
"Landroid/net/ConnectivityManager;",
|
||||||
|
"requestNetwork",
|
||||||
|
arrayOf("Landroid/net/NetworkRequest;", "Landroid/net/ConnectivityManager\$NetworkCallback;", "I"),
|
||||||
|
"V",
|
||||||
|
),
|
||||||
|
RequestNetwork3(
|
||||||
|
"Landroid/net/ConnectivityManager;",
|
||||||
|
"requestNetwork",
|
||||||
|
arrayOf("Landroid/net/NetworkRequest;", "Landroid/net/ConnectivityManager\$NetworkCallback;", "Landroid/os/Handler;"),
|
||||||
|
"V",
|
||||||
|
),
|
||||||
|
RequestNetwork4(
|
||||||
|
"Landroid/net/ConnectivityManager;",
|
||||||
|
"requestNetwork",
|
||||||
|
arrayOf("Landroid/net/NetworkRequest;", "Landroid/app/PendingIntent;"),
|
||||||
|
"V",
|
||||||
|
),
|
||||||
|
RequestNetwork5(
|
||||||
|
"Landroid/net/ConnectivityManager;",
|
||||||
|
"requestNetwork",
|
||||||
|
arrayOf("Landroid/net/NetworkRequest;", "Landroid/net/ConnectivityManager\$NetworkCallback;", "Landroid/os/Handler;", "I"),
|
||||||
|
"V",
|
||||||
|
),
|
||||||
|
UnregisterNetworkCallback1(
|
||||||
|
"Landroid/net/ConnectivityManager;",
|
||||||
|
"unregisterNetworkCallback",
|
||||||
|
arrayOf("Landroid/net/ConnectivityManager\$NetworkCallback;"),
|
||||||
|
"V",
|
||||||
|
),
|
||||||
|
UnregisterNetworkCallback2(
|
||||||
|
"Landroid/net/ConnectivityManager;",
|
||||||
|
"unregisterNetworkCallback",
|
||||||
|
arrayOf("Landroid/app/PendingIntent;"),
|
||||||
|
"V",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun filterMap(
|
||||||
|
classDef: ClassDef,
|
||||||
|
method: Method,
|
||||||
|
instruction: Instruction,
|
||||||
|
instructionIndex: Int
|
||||||
|
) = filterMapInstruction35c<MethodCall>(
|
||||||
|
INTEGRATIONS_CLASS_DESCRIPTOR_PREFIX,
|
||||||
|
classDef,
|
||||||
|
instruction,
|
||||||
|
instructionIndex
|
||||||
|
)
|
||||||
|
|
||||||
|
override fun transform(mutableMethod: MutableMethod, entry: Instruction35cInfo) {
|
||||||
|
val (methodType, instruction, instructionIndex) = entry
|
||||||
|
methodType.replaceInvokeVirtualWithIntegrations(INTEGRATIONS_CLASS_DESCRIPTOR, mutableMethod, instruction, instructionIndex)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,106 +1,57 @@
|
||||||
package app.revanced.patches.all.screenshot.removerestriction.patch
|
package app.revanced.patches.all.screenshot.removerestriction.patch
|
||||||
|
|
||||||
import app.revanced.extensions.findMutableMethodOf
|
|
||||||
import app.revanced.patcher.annotation.Description
|
import app.revanced.patcher.annotation.Description
|
||||||
import app.revanced.patcher.annotation.Name
|
import app.revanced.patcher.annotation.Name
|
||||||
import app.revanced.patcher.annotation.Version
|
import app.revanced.patcher.annotation.Version
|
||||||
import app.revanced.patcher.data.BytecodeContext
|
|
||||||
import app.revanced.patcher.extensions.replaceInstruction
|
|
||||||
import app.revanced.patcher.patch.BytecodePatch
|
|
||||||
import app.revanced.patcher.patch.PatchResult
|
|
||||||
import app.revanced.patcher.patch.PatchResultSuccess
|
|
||||||
import app.revanced.patcher.patch.annotations.Patch
|
import app.revanced.patcher.patch.annotations.Patch
|
||||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||||
import org.jf.dexlib2.Opcode
|
import app.revanced.util.patch.*
|
||||||
import org.jf.dexlib2.iface.instruction.formats.Instruction35c
|
import org.jf.dexlib2.iface.ClassDef
|
||||||
import org.jf.dexlib2.iface.reference.MethodReference
|
import org.jf.dexlib2.iface.Method
|
||||||
|
import org.jf.dexlib2.iface.instruction.Instruction
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
@Patch(false)
|
@Patch(false)
|
||||||
@Name("remove-screenshot-restriction")
|
@Name("remove-screenshot-restriction")
|
||||||
@Description("Removes the restriction of taking screenshots in apps that normally wouldn't allow it.")
|
@Description("Removes the restriction of taking screenshots in apps that normally wouldn't allow it.")
|
||||||
@Version("0.0.1")
|
@Version("0.0.1")
|
||||||
class RemoveScreenshotRestrictionPatch : BytecodePatch() {
|
internal class RemoveScreenshotRestrictionPatch : AbstractTransformInstructionsPatch<Instruction35cInfo>() {
|
||||||
|
|
||||||
private companion object {
|
private companion object {
|
||||||
const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/all/screenshot/removerestriction/RemoveScreenshotRestrictionPatch;"
|
const val INTEGRATIONS_CLASS_DESCRIPTOR_PREFIX =
|
||||||
|
"Lapp/revanced/all/screenshot/removerestriction/RemoveScreenshotRestrictionPatch"
|
||||||
|
const val INTEGRATIONS_CLASS_DESCRIPTOR = "$INTEGRATIONS_CLASS_DESCRIPTOR_PREFIX;"
|
||||||
}
|
}
|
||||||
|
|
||||||
// Information about method calls we want to replace
|
// Information about method calls we want to replace
|
||||||
private enum class MethodCall(
|
enum class MethodCall(
|
||||||
val definedClassName: String,
|
override val definedClassName: String,
|
||||||
val methodName: String,
|
override val methodName: String,
|
||||||
val replacementMethodDefinition: String
|
override val methodParams: Array<String>,
|
||||||
) {
|
override val returnType: String
|
||||||
|
): IMethodCall {
|
||||||
SetFlags(
|
SetFlags(
|
||||||
"Landroid/view/Window;",
|
"Landroid/view/Window;",
|
||||||
"setFlags",
|
"setFlags",
|
||||||
"setFlags(Landroid/view/Window;II)V",
|
arrayOf("I", "I"),
|
||||||
|
"V",
|
||||||
);
|
);
|
||||||
|
|
||||||
fun replaceInstruction(method: MutableMethod, instruction: Instruction35c, instructionIndex: Int) {
|
|
||||||
when (this) {
|
|
||||||
SetFlags -> {
|
|
||||||
method.replaceInstruction(
|
|
||||||
instructionIndex,
|
|
||||||
"invoke-static { v${instruction.registerC}, v${instruction.registerD}, v${instruction.registerE} }, ${INTEGRATIONS_CLASS_DESCRIPTOR}->${replacementMethodDefinition}"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
fun fromMethodReference(methodReference: MethodReference) = values().firstOrNull { search ->
|
|
||||||
search.definedClassName == methodReference.definingClass && search.methodName == methodReference.name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun execute(context: BytecodeContext): PatchResult {
|
override fun filterMap(
|
||||||
// Find all instructions where one of the methods is called
|
classDef: ClassDef,
|
||||||
buildMap {
|
method: Method,
|
||||||
context.classes.forEach { classDef ->
|
instruction: Instruction,
|
||||||
if (classDef.type == INTEGRATIONS_CLASS_DESCRIPTOR) {
|
instructionIndex: Int
|
||||||
// avoid infinite recursion
|
) = filterMapInstruction35c<MethodCall>(
|
||||||
return@forEach
|
INTEGRATIONS_CLASS_DESCRIPTOR_PREFIX,
|
||||||
}
|
classDef,
|
||||||
|
instruction,
|
||||||
|
instructionIndex
|
||||||
|
)
|
||||||
|
|
||||||
classDef.methods.let { methods ->
|
override fun transform(mutableMethod: MutableMethod, entry: Instruction35cInfo) {
|
||||||
buildMap methodList@{
|
val (methodType, instruction, instructionIndex) = entry
|
||||||
methods.forEach methods@{ method ->
|
methodType.replaceInvokeVirtualWithIntegrations(INTEGRATIONS_CLASS_DESCRIPTOR, mutableMethod, instruction, instructionIndex)
|
||||||
with(method.implementation?.instructions ?: return@methods) {
|
|
||||||
ArrayDeque<Triple<MethodCall, Instruction35c, Int>>().also { patchIndices ->
|
|
||||||
this.forEachIndexed { index, instruction ->
|
|
||||||
if (instruction.opcode != Opcode.INVOKE_VIRTUAL) return@forEachIndexed
|
|
||||||
|
|
||||||
val invokeInstruction = instruction as Instruction35c
|
|
||||||
val methodRef = invokeInstruction.reference as MethodReference
|
|
||||||
val methodCall = MethodCall.fromMethodReference(methodRef) ?: return@forEachIndexed
|
|
||||||
|
|
||||||
patchIndices.add(Triple(methodCall, invokeInstruction, index))
|
|
||||||
}
|
|
||||||
}.also { if (it.isEmpty()) return@methods }.let { patches ->
|
|
||||||
put(method, patches)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}.also { if (it.isEmpty()) return@forEach }.let { methodPatches ->
|
|
||||||
put(classDef, methodPatches)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}.forEach { (classDef, methods) ->
|
|
||||||
// And finally replace the instructions...
|
|
||||||
with(context.proxy(classDef).mutableClass) {
|
|
||||||
methods.forEach { (method, patches) ->
|
|
||||||
val mutableMethod = findMutableMethodOf(method)
|
|
||||||
while (!patches.isEmpty()) {
|
|
||||||
val (methodType, instruction, instructionIndex) = patches.removeLast()
|
|
||||||
methodType.replaceInstruction(mutableMethod, instruction, instructionIndex)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return PatchResultSuccess()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
package app.revanced.util.patch
|
||||||
|
|
||||||
|
import app.revanced.extensions.findMutableMethodOf
|
||||||
|
import app.revanced.patcher.data.BytecodeContext
|
||||||
|
import app.revanced.patcher.patch.BytecodePatch
|
||||||
|
import app.revanced.patcher.patch.PatchResult
|
||||||
|
import app.revanced.patcher.patch.PatchResultSuccess
|
||||||
|
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||||
|
import org.jf.dexlib2.iface.ClassDef
|
||||||
|
import org.jf.dexlib2.iface.Method
|
||||||
|
import org.jf.dexlib2.iface.instruction.Instruction
|
||||||
|
|
||||||
|
internal abstract class AbstractTransformInstructionsPatch<T> : BytecodePatch() {
|
||||||
|
|
||||||
|
abstract fun filterMap(
|
||||||
|
classDef: ClassDef,
|
||||||
|
method: Method,
|
||||||
|
instruction: Instruction,
|
||||||
|
instructionIndex: Int
|
||||||
|
): T?
|
||||||
|
|
||||||
|
abstract fun transform(mutableMethod: MutableMethod, entry: T)
|
||||||
|
|
||||||
|
override fun execute(context: BytecodeContext): PatchResult {
|
||||||
|
// Find all instructions
|
||||||
|
buildMap {
|
||||||
|
context.classes.forEach { classDef ->
|
||||||
|
classDef.methods.let { methods ->
|
||||||
|
buildMap methodList@{
|
||||||
|
methods.forEach methods@{ method ->
|
||||||
|
with(method.implementation?.instructions ?: return@methods) {
|
||||||
|
ArrayDeque<T>().also { patchIndices ->
|
||||||
|
this.forEachIndexed { index, instruction ->
|
||||||
|
val result = filterMap(classDef, method, instruction, index)
|
||||||
|
if (result != null) {
|
||||||
|
patchIndices.add(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.also { if (it.isEmpty()) return@methods }.let { patches ->
|
||||||
|
put(method, patches)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.also { if (it.isEmpty()) return@forEach }.let { methodPatches ->
|
||||||
|
put(classDef, methodPatches)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.forEach { (classDef, methods) ->
|
||||||
|
// And finally transform the instructions...
|
||||||
|
with(context.proxy(classDef).mutableClass) {
|
||||||
|
methods.forEach { (method, patches) ->
|
||||||
|
val mutableMethod = findMutableMethodOf(method)
|
||||||
|
while (!patches.isEmpty()) {
|
||||||
|
transform(mutableMethod, patches.removeLast())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return PatchResultSuccess()
|
||||||
|
}
|
||||||
|
}
|
92
src/main/kotlin/app/revanced/util/patch/MethodCall.kt
Normal file
92
src/main/kotlin/app/revanced/util/patch/MethodCall.kt
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
package app.revanced.util.patch
|
||||||
|
|
||||||
|
import app.revanced.patcher.extensions.replaceInstruction
|
||||||
|
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||||
|
import org.jf.dexlib2.Opcode
|
||||||
|
import org.jf.dexlib2.iface.ClassDef
|
||||||
|
import org.jf.dexlib2.iface.instruction.Instruction
|
||||||
|
import org.jf.dexlib2.iface.instruction.formats.Instruction35c
|
||||||
|
import org.jf.dexlib2.iface.reference.MethodReference
|
||||||
|
|
||||||
|
internal typealias Instruction35cInfo = Triple<IMethodCall, Instruction35c, Int>
|
||||||
|
|
||||||
|
internal interface IMethodCall {
|
||||||
|
val definedClassName: String
|
||||||
|
val methodName: String
|
||||||
|
val methodParams: Array<String>
|
||||||
|
val returnType: String
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replaces an invoke-virtual instruction with an invoke-static instruction,
|
||||||
|
* which calls a static replacement method in the respective integrations class.
|
||||||
|
* The method definition in the integrations class is expected to be the same,
|
||||||
|
* except that the method should be static and take as a first parameter
|
||||||
|
* an instance of the class, in which the original method was defined in.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
*
|
||||||
|
* original method: Window#setFlags(int, int)
|
||||||
|
*
|
||||||
|
* replacement method: Integrations#setFlags(Window, int, int)
|
||||||
|
*/
|
||||||
|
fun replaceInvokeVirtualWithIntegrations(
|
||||||
|
definingClassDescriptor: String,
|
||||||
|
method: MutableMethod,
|
||||||
|
instruction: Instruction35c,
|
||||||
|
instructionIndex: Int
|
||||||
|
) {
|
||||||
|
val registers = arrayOf(
|
||||||
|
instruction.registerC,
|
||||||
|
instruction.registerD,
|
||||||
|
instruction.registerE,
|
||||||
|
instruction.registerF,
|
||||||
|
instruction.registerG
|
||||||
|
)
|
||||||
|
val argsNum = methodParams.size + 1 // + 1 for instance of definedClassName
|
||||||
|
if (argsNum > registers.size) {
|
||||||
|
// should never happen, but just to be sure (also for the future) a safety check
|
||||||
|
throw RuntimeException(
|
||||||
|
"Not enough registers for ${definedClassName}#${methodName}: " +
|
||||||
|
"Required $argsNum registers, but only got ${registers.size}."
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val args = registers.take(argsNum).joinToString(separator = ", ") { reg -> "v${reg}" }
|
||||||
|
val replacementMethodDefinition =
|
||||||
|
"${methodName}(${definedClassName}${methodParams.joinToString(separator = "")})${returnType}"
|
||||||
|
|
||||||
|
method.replaceInstruction(
|
||||||
|
instructionIndex,
|
||||||
|
"invoke-static { $args }, ${definingClassDescriptor}->${replacementMethodDefinition}"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal inline fun <reified E> fromMethodReference(methodReference: MethodReference)
|
||||||
|
where E : Enum<E>, E : IMethodCall = enumValues<E>().firstOrNull { search ->
|
||||||
|
search.definedClassName == methodReference.definingClass
|
||||||
|
&& search.methodName == methodReference.name
|
||||||
|
&& methodReference.parameterTypes.toTypedArray().contentEquals(search.methodParams)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal inline fun <reified E> filterMapInstruction35c(
|
||||||
|
integrationsClassDescriptorPrefix: String,
|
||||||
|
classDef: ClassDef,
|
||||||
|
instruction: Instruction,
|
||||||
|
instructionIndex: Int
|
||||||
|
): Instruction35cInfo? where E : Enum<E>, E : IMethodCall {
|
||||||
|
if (classDef.type.startsWith(integrationsClassDescriptorPrefix)) {
|
||||||
|
// avoid infinite recursion
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
if (instruction.opcode != Opcode.INVOKE_VIRTUAL) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
val invokeInstruction = instruction as Instruction35c
|
||||||
|
val methodRef = invokeInstruction.reference as MethodReference
|
||||||
|
val methodCall = fromMethodReference<E>(methodRef) ?: return null
|
||||||
|
|
||||||
|
return Instruction35cInfo(methodCall, invokeInstruction, instructionIndex)
|
||||||
|
}
|
Loading…
Reference in a new issue