feat: Publish as a library (#3356)
This commit is contained in:
@@ -2,10 +2,10 @@ package app.revanced.patches.all.connectivity.wifi.spoof
|
||||
|
||||
import app.revanced.patcher.patch.annotation.Patch
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||
import app.revanced.util.patch.AbstractTransformInstructionsPatch
|
||||
import app.revanced.util.patch.IMethodCall
|
||||
import app.revanced.util.patch.Instruction35cInfo
|
||||
import app.revanced.util.patch.filterMapInstruction35c
|
||||
import app.revanced.patches.all.misc.transformation.AbstractTransformInstructionsPatch
|
||||
import app.revanced.patches.all.misc.transformation.IMethodCall
|
||||
import app.revanced.patches.all.misc.transformation.Instruction35cInfo
|
||||
import app.revanced.patches.all.misc.transformation.filterMapInstruction35c
|
||||
import com.android.tools.smali.dexlib2.iface.ClassDef
|
||||
import com.android.tools.smali.dexlib2.iface.Method
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.Instruction
|
||||
@@ -40,7 +40,7 @@ object SpoofWifiPatch : AbstractTransformInstructionsPatch<Instruction35cInfo>()
|
||||
|
||||
|
||||
// Information about method calls we want to replace
|
||||
enum class MethodCall(
|
||||
private enum class MethodCall(
|
||||
override val definedClassName: String,
|
||||
override val methodName: String,
|
||||
override val methodParams: Array<String>,
|
||||
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
package app.revanced.patches.all.misc.transformation
|
||||
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||
import app.revanced.util.findMutableMethodOf
|
||||
import com.android.tools.smali.dexlib2.iface.ClassDef
|
||||
import com.android.tools.smali.dexlib2.iface.Method
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.Instruction
|
||||
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
abstract class AbstractTransformInstructionsPatch<T> : BytecodePatch() {
|
||||
|
||||
abstract fun filterMap(
|
||||
classDef: ClassDef,
|
||||
method: Method,
|
||||
instruction: Instruction,
|
||||
instructionIndex: Int
|
||||
): T?
|
||||
|
||||
abstract fun transform(mutableMethod: MutableMethod, entry: T)
|
||||
|
||||
// Returns the patch indices as a Sequence, which will execute lazily.
|
||||
fun findPatchIndices(classDef: ClassDef, method: Method): Sequence<T>? {
|
||||
return method.implementation?.instructions?.asSequence()?.withIndex()?.mapNotNull { (index, instruction) ->
|
||||
filterMap(classDef, method, instruction, index)
|
||||
}
|
||||
}
|
||||
|
||||
override fun execute(context: BytecodeContext) {
|
||||
// Find all methods to patch
|
||||
buildMap {
|
||||
context.classes.forEach { classDef ->
|
||||
val methods = buildList {
|
||||
classDef.methods.forEach { method ->
|
||||
// Since the Sequence executes lazily,
|
||||
// using any() results in only calling
|
||||
// filterMap until the first index has been found.
|
||||
if (findPatchIndices(classDef, method)?.any() == true) add(method)
|
||||
}
|
||||
}
|
||||
|
||||
if (methods.isNotEmpty()) {
|
||||
put(classDef, methods)
|
||||
}
|
||||
}
|
||||
}.forEach { (classDef, methods) ->
|
||||
// And finally transform the methods...
|
||||
val mutableClass = context.proxy(classDef).mutableClass
|
||||
|
||||
methods.map(mutableClass::findMutableMethodOf).forEach methods@{ mutableMethod ->
|
||||
val patchIndices = findPatchIndices(mutableClass, mutableMethod)?.toCollection(ArrayDeque())
|
||||
?: return@methods
|
||||
|
||||
while (!patchIndices.isEmpty()) transform(mutableMethod, patchIndices.removeLast())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
package app.revanced.patches.all.misc.transformation
|
||||
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.iface.ClassDef
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.Instruction
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction35c
|
||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||
|
||||
typealias Instruction35cInfo = Triple<IMethodCall, Instruction35c, Int>
|
||||
|
||||
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}"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
&& search.returnType == methodReference.returnType
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
+4
-4
@@ -2,10 +2,10 @@ package app.revanced.patches.all.screencapture.removerestriction
|
||||
|
||||
import app.revanced.patcher.patch.annotation.Patch
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||
import app.revanced.util.patch.AbstractTransformInstructionsPatch
|
||||
import app.revanced.util.patch.IMethodCall
|
||||
import app.revanced.util.patch.Instruction35cInfo
|
||||
import app.revanced.util.patch.filterMapInstruction35c
|
||||
import app.revanced.patches.all.misc.transformation.AbstractTransformInstructionsPatch
|
||||
import app.revanced.patches.all.misc.transformation.IMethodCall
|
||||
import app.revanced.patches.all.misc.transformation.Instruction35cInfo
|
||||
import app.revanced.patches.all.misc.transformation.filterMapInstruction35c
|
||||
import com.android.tools.smali.dexlib2.iface.ClassDef
|
||||
import com.android.tools.smali.dexlib2.iface.Method
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.Instruction
|
||||
|
||||
+4
-4
@@ -4,10 +4,10 @@ import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.patch.annotation.Patch
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||
import app.revanced.util.patch.AbstractTransformInstructionsPatch
|
||||
import app.revanced.util.patch.IMethodCall
|
||||
import app.revanced.util.patch.Instruction35cInfo
|
||||
import app.revanced.util.patch.filterMapInstruction35c
|
||||
import app.revanced.patches.all.misc.transformation.AbstractTransformInstructionsPatch
|
||||
import app.revanced.patches.all.misc.transformation.IMethodCall
|
||||
import app.revanced.patches.all.misc.transformation.Instruction35cInfo
|
||||
import app.revanced.patches.all.misc.transformation.filterMapInstruction35c
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.iface.ClassDef
|
||||
import com.android.tools.smali.dexlib2.iface.Method
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@ import app.revanced.patcher.patch.annotation.Patch
|
||||
import app.revanced.patcher.patch.options.PatchOption
|
||||
import app.revanced.patcher.patch.options.PatchOption.PatchExtensions.stringPatchOption
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||
import app.revanced.util.patch.AbstractTransformInstructionsPatch
|
||||
import app.revanced.patches.all.misc.transformation.AbstractTransformInstructionsPatch
|
||||
import com.android.tools.smali.dexlib2.iface.ClassDef
|
||||
import com.android.tools.smali.dexlib2.iface.Method
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.Instruction
|
||||
|
||||
Reference in New Issue
Block a user