diff --git a/build.gradle.kts b/build.gradle.kts index d68801fd..44c9e154 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -21,7 +21,7 @@ repositories { } dependencies { - api("app.revanced:multidexlib2:2.5.2.r2") + implementation("app.revanced:multidexlib2:2.5.2.r2") implementation("xpp3:xpp3:1.1.4c") implementation("org.smali:smali:2.5.2") @@ -45,6 +45,7 @@ java { publishing { repositories { + if (System.getenv("GITHUB_ACTOR") != null) maven { name = "GitHubPackages" url = uri("https://maven.pkg.github.com/revanced/revanced-patcher") @@ -53,6 +54,8 @@ publishing { password = System.getenv("GITHUB_TOKEN") } } + else + mavenLocal() } publications { register("gpr") { diff --git a/src/main/kotlin/app/revanced/patcher/Patcher.kt b/src/main/kotlin/app/revanced/patcher/Patcher.kt index 3701b4d0..d039a58c 100644 --- a/src/main/kotlin/app/revanced/patcher/Patcher.kt +++ b/src/main/kotlin/app/revanced/patcher/Patcher.kt @@ -1,19 +1,18 @@ package app.revanced.patcher +import app.revanced.patcher.data.Data import app.revanced.patcher.data.PackageMetadata -import app.revanced.patcher.data.PatcherData -import app.revanced.patcher.data.base.Data -import app.revanced.patcher.data.implementation.findIndexed +import app.revanced.patcher.data.impl.findIndexed import app.revanced.patcher.extensions.PatchExtensions.dependencies import app.revanced.patcher.extensions.PatchExtensions.patchName import app.revanced.patcher.extensions.nullOutputStream -import app.revanced.patcher.patch.base.Patch -import app.revanced.patcher.patch.implementation.BytecodePatch -import app.revanced.patcher.patch.implementation.ResourcePatch -import app.revanced.patcher.patch.implementation.misc.PatchResult -import app.revanced.patcher.patch.implementation.misc.PatchResultError -import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess -import app.revanced.patcher.signature.implementation.method.resolver.MethodSignatureResolver +import app.revanced.patcher.fingerprint.method.utils.MethodFingerprintUtils.resolve +import app.revanced.patcher.patch.Patch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultError +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.impl.BytecodePatch +import app.revanced.patcher.patch.impl.ResourcePatch import app.revanced.patcher.util.ListBackedSet import brut.androlib.Androlib import brut.androlib.meta.UsesFramework @@ -281,10 +280,9 @@ class Patcher(private val options: PatcherOptions) { val data = if (isResourcePatch) { data.resourceData } else { - MethodSignatureResolver( - data.bytecodeData.classes.internalClasses, (patchInstance as BytecodePatch).signatures - ).resolve(data) - data.bytecodeData + val bytecodeData = data.bytecodeData + (patchInstance as BytecodePatch).fingerprints.resolve(bytecodeData, bytecodeData.classes.internalClasses) + bytecodeData } logger.trace("Executing patch $patchName of type: ${if (isResourcePatch) "resource" else "bytecode"}") diff --git a/src/main/kotlin/app/revanced/patcher/data/PatcherData.kt b/src/main/kotlin/app/revanced/patcher/PatcherData.kt similarity index 62% rename from src/main/kotlin/app/revanced/patcher/data/PatcherData.kt rename to src/main/kotlin/app/revanced/patcher/PatcherData.kt index fec6f1d8..e35dbd09 100644 --- a/src/main/kotlin/app/revanced/patcher/data/PatcherData.kt +++ b/src/main/kotlin/app/revanced/patcher/PatcherData.kt @@ -1,9 +1,10 @@ -package app.revanced.patcher.data +package app.revanced.patcher -import app.revanced.patcher.data.base.Data -import app.revanced.patcher.data.implementation.BytecodeData -import app.revanced.patcher.data.implementation.ResourceData -import app.revanced.patcher.patch.base.Patch +import app.revanced.patcher.data.Data +import app.revanced.patcher.data.PackageMetadata +import app.revanced.patcher.data.impl.BytecodeData +import app.revanced.patcher.data.impl.ResourceData +import app.revanced.patcher.patch.Patch import org.jf.dexlib2.iface.ClassDef import java.io.File diff --git a/src/main/kotlin/app/revanced/patcher/PatcherOptions.kt b/src/main/kotlin/app/revanced/patcher/PatcherOptions.kt index c4470d3e..385b8350 100644 --- a/src/main/kotlin/app/revanced/patcher/PatcherOptions.kt +++ b/src/main/kotlin/app/revanced/patcher/PatcherOptions.kt @@ -1,7 +1,7 @@ package app.revanced.patcher -import app.revanced.patcher.logging.impl.NopLogger import app.revanced.patcher.logging.Logger +import app.revanced.patcher.logging.impl.NopLogger import java.io.File /** diff --git a/src/main/kotlin/app/revanced/patcher/annotation/CompatibilityAnnotation.kt b/src/main/kotlin/app/revanced/patcher/annotation/CompatibilityAnnotation.kt index 09e2df84..8ec104b4 100644 --- a/src/main/kotlin/app/revanced/patcher/annotation/CompatibilityAnnotation.kt +++ b/src/main/kotlin/app/revanced/patcher/annotation/CompatibilityAnnotation.kt @@ -1,11 +1,11 @@ package app.revanced.patcher.annotation -import app.revanced.patcher.patch.base.Patch -import app.revanced.patcher.signature.implementation.method.MethodSignature +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import app.revanced.patcher.patch.Patch /** - * Annotation to constrain a [Patch] or [MethodSignature] to compatible packages. - * @param compatiblePackages A list of packages a [Patch] or [MethodSignature] is compatible with. + * Annotation to constrain a [Patch] or [MethodFingerprint] to compatible packages. + * @param compatiblePackages A list of packages a [Patch] or [MethodFingerprint] is compatible with. */ @Target(AnnotationTarget.CLASS) @Retention(AnnotationRetention.RUNTIME) @@ -17,7 +17,7 @@ annotation class Compatibility( /** * Annotation to represent packages a patch can be compatible with. * @param name The package identifier name. - * @param versions The versions of the package the [Patch] or [MethodSignature]is compatible with. + * @param versions The versions of the package the [Patch] or [MethodFingerprint]is compatible with. */ @Target() @Retention(AnnotationRetention.RUNTIME) diff --git a/src/main/kotlin/app/revanced/patcher/annotation/MetadataAnnotation.kt b/src/main/kotlin/app/revanced/patcher/annotation/MetadataAnnotation.kt index d3c4820a..b8526ddd 100644 --- a/src/main/kotlin/app/revanced/patcher/annotation/MetadataAnnotation.kt +++ b/src/main/kotlin/app/revanced/patcher/annotation/MetadataAnnotation.kt @@ -1,11 +1,11 @@ package app.revanced.patcher.annotation -import app.revanced.patcher.patch.base.Patch -import app.revanced.patcher.signature.implementation.method.MethodSignature +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import app.revanced.patcher.patch.Patch /** - * Annotation to name a [Patch] or [MethodSignature]. - * @param name A suggestive name for the [Patch] or [MethodSignature]. + * Annotation to name a [Patch] or [MethodFingerprint]. + * @param name A suggestive name for the [Patch] or [MethodFingerprint]. */ @Target(AnnotationTarget.CLASS) @Retention(AnnotationRetention.RUNTIME) @@ -15,8 +15,8 @@ annotation class Name( ) /** - * Annotation to describe a [Patch] or [MethodSignature]. - * @param description A description for the [Patch] or [MethodSignature]. + * Annotation to describe a [Patch] or [MethodFingerprint]. + * @param description A description for the [Patch] or [MethodFingerprint]. */ @Target(AnnotationTarget.CLASS) @Retention(AnnotationRetention.RUNTIME) @@ -27,8 +27,8 @@ annotation class Description( /** - * Annotation to version a [Patch] or [MethodSignature]. - * @param version The version of a [Patch] or [MethodSignature]. + * Annotation to version a [Patch] or [MethodFingerprint]. + * @param version The version of a [Patch] or [MethodFingerprint]. */ @Target(AnnotationTarget.CLASS) @Retention(AnnotationRetention.RUNTIME) diff --git a/src/main/kotlin/app/revanced/patcher/data/Data.kt b/src/main/kotlin/app/revanced/patcher/data/Data.kt new file mode 100644 index 00000000..aab90762 --- /dev/null +++ b/src/main/kotlin/app/revanced/patcher/data/Data.kt @@ -0,0 +1,9 @@ +package app.revanced.patcher.data + +import app.revanced.patcher.data.impl.BytecodeData +import app.revanced.patcher.data.impl.ResourceData + +/** + * Constraint interface for [BytecodeData] and [ResourceData] + */ +interface Data \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patcher/data/base/Data.kt b/src/main/kotlin/app/revanced/patcher/data/base/Data.kt deleted file mode 100644 index 95351bb0..00000000 --- a/src/main/kotlin/app/revanced/patcher/data/base/Data.kt +++ /dev/null @@ -1,9 +0,0 @@ -package app.revanced.patcher.data.base - -import app.revanced.patcher.data.implementation.BytecodeData -import app.revanced.patcher.data.implementation.ResourceData - -/** - * Constraint interface for [BytecodeData] and [ResourceData] - */ -interface Data \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patcher/data/implementation/BytecodeData.kt b/src/main/kotlin/app/revanced/patcher/data/impl/BytecodeData.kt similarity index 95% rename from src/main/kotlin/app/revanced/patcher/data/implementation/BytecodeData.kt rename to src/main/kotlin/app/revanced/patcher/data/impl/BytecodeData.kt index 6e8e7e18..467951c3 100644 --- a/src/main/kotlin/app/revanced/patcher/data/implementation/BytecodeData.kt +++ b/src/main/kotlin/app/revanced/patcher/data/impl/BytecodeData.kt @@ -1,6 +1,6 @@ -package app.revanced.patcher.data.implementation +package app.revanced.patcher.data.impl -import app.revanced.patcher.data.base.Data +import app.revanced.patcher.data.Data import app.revanced.patcher.util.ProxyBackedClassList import app.revanced.patcher.util.method.MethodWalker import org.jf.dexlib2.iface.ClassDef diff --git a/src/main/kotlin/app/revanced/patcher/data/implementation/ResourceData.kt b/src/main/kotlin/app/revanced/patcher/data/impl/ResourceData.kt similarity index 92% rename from src/main/kotlin/app/revanced/patcher/data/implementation/ResourceData.kt rename to src/main/kotlin/app/revanced/patcher/data/impl/ResourceData.kt index 82ff4758..26fe7bfe 100644 --- a/src/main/kotlin/app/revanced/patcher/data/implementation/ResourceData.kt +++ b/src/main/kotlin/app/revanced/patcher/data/impl/ResourceData.kt @@ -1,10 +1,9 @@ -package app.revanced.patcher.data.implementation +package app.revanced.patcher.data.impl -import app.revanced.patcher.data.base.Data +import app.revanced.patcher.data.Data import org.w3c.dom.Document import java.io.Closeable import java.io.File -import javax.xml.XMLConstants import javax.xml.parsers.DocumentBuilderFactory import javax.xml.transform.TransformerFactory import javax.xml.transform.dom.DOMSource diff --git a/src/main/kotlin/app/revanced/patcher/extensions/AnnotationExtensions.kt b/src/main/kotlin/app/revanced/patcher/extensions/AnnotationExtensions.kt index abad2b91..8963b017 100644 --- a/src/main/kotlin/app/revanced/patcher/extensions/AnnotationExtensions.kt +++ b/src/main/kotlin/app/revanced/patcher/extensions/AnnotationExtensions.kt @@ -4,11 +4,9 @@ import app.revanced.patcher.annotation.Compatibility import app.revanced.patcher.annotation.Description import app.revanced.patcher.annotation.Name import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.base.Data -import app.revanced.patcher.patch.base.Patch -import app.revanced.patcher.signature.implementation.method.MethodSignature -import app.revanced.patcher.signature.implementation.method.annotation.FuzzyPatternScanMethod -import app.revanced.patcher.signature.implementation.method.annotation.MatchingMethod +import app.revanced.patcher.data.Data +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import app.revanced.patcher.patch.Patch import kotlin.reflect.KClass /** @@ -47,13 +45,13 @@ object PatchExtensions { val Class>.compatiblePackages get() = recursiveAnnotation(Compatibility::class)?.compatiblePackages } -object MethodSignatureExtensions { - val MethodSignature.name: String +object MethodFingerprintExtensions { + val MethodFingerprint.name: String get() = javaClass.recursiveAnnotation(Name::class)?.name ?: this.javaClass.simpleName - val MethodSignature.version get() = javaClass.recursiveAnnotation(Version::class)?.version ?: "0.0.1" - val MethodSignature.description get() = javaClass.recursiveAnnotation(Description::class)?.description - val MethodSignature.compatiblePackages get() = javaClass.recursiveAnnotation(Compatibility::class)?.compatiblePackages - val MethodSignature.matchingMethod get() = javaClass.recursiveAnnotation(MatchingMethod::class) - val MethodSignature.fuzzyPatternScanMethod get() = javaClass.recursiveAnnotation(FuzzyPatternScanMethod::class) - val MethodSignature.fuzzyThreshold get() = fuzzyPatternScanMethod?.threshold ?: 0 + val MethodFingerprint.version get() = javaClass.recursiveAnnotation(Version::class)?.version ?: "0.0.1" + val MethodFingerprint.description get() = javaClass.recursiveAnnotation(Description::class)?.description + val MethodFingerprint.compatiblePackages get() = javaClass.recursiveAnnotation(Compatibility::class)?.compatiblePackages + val MethodFingerprint.matchingMethod get() = javaClass.recursiveAnnotation(app.revanced.patcher.fingerprint.method.annotation.MatchingMethod::class) + val MethodFingerprint.fuzzyPatternScanMethod get() = javaClass.recursiveAnnotation(app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod::class) + val MethodFingerprint.fuzzyScanThreshold get() = fuzzyPatternScanMethod?.threshold ?: 0 } \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patcher/extensions/Extensions.kt b/src/main/kotlin/app/revanced/patcher/extensions/Extensions.kt index 1efba354..50384e81 100644 --- a/src/main/kotlin/app/revanced/patcher/extensions/Extensions.kt +++ b/src/main/kotlin/app/revanced/patcher/extensions/Extensions.kt @@ -77,6 +77,13 @@ internal fun Method.clone( ) } +/** + * Add a smali instruction to the method. + * @param instruction The smali instruction to add. + */ +fun MutableMethod.addInstruction(instruction: String) = + this.implementation!!.addInstruction(instruction.toInstruction(this)) + /** * Add a smali instruction to the method. * @param index The index to insert the instruction at. @@ -152,3 +159,20 @@ internal val nullOutputStream: OutputStream = object : OutputStream() { override fun write(b: Int) {} } + +/** + * Should be used to parse a list of parameters represented by their first letter, + * or in the case of arrays prefixed with an unspecified amount of '[' character. + */ +internal fun String.parseParameters(): List { + val parameters = mutableListOf() + var parameter = "" + for (char in this.toCharArray()) { + parameter += char + if (char == '[') continue + + parameters.add(parameter) + parameter = "" + } + return parameters +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patcher/fingerprint/Fingerprint.kt b/src/main/kotlin/app/revanced/patcher/fingerprint/Fingerprint.kt new file mode 100644 index 00000000..d6881140 --- /dev/null +++ b/src/main/kotlin/app/revanced/patcher/fingerprint/Fingerprint.kt @@ -0,0 +1,9 @@ +package app.revanced.patcher.fingerprint + +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint + +/** + * A ReVanced fingerprint. + * Can be a [MethodFingerprint]. + */ +interface Fingerprint \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patcher/signature/implementation/method/annotation/MethodSignatureMetadata.kt b/src/main/kotlin/app/revanced/patcher/fingerprint/method/annotation/MethodFingerprintMetadata.kt similarity index 61% rename from src/main/kotlin/app/revanced/patcher/signature/implementation/method/annotation/MethodSignatureMetadata.kt rename to src/main/kotlin/app/revanced/patcher/fingerprint/method/annotation/MethodFingerprintMetadata.kt index f9451a14..15048ff6 100644 --- a/src/main/kotlin/app/revanced/patcher/signature/implementation/method/annotation/MethodSignatureMetadata.kt +++ b/src/main/kotlin/app/revanced/patcher/fingerprint/method/annotation/MethodFingerprintMetadata.kt @@ -1,11 +1,11 @@ -package app.revanced.patcher.signature.implementation.method.annotation +package app.revanced.patcher.fingerprint.method.annotation -import app.revanced.patcher.signature.implementation.method.MethodSignature +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint /** - * Annotations for a method which matches to a [MethodSignature]. + * Annotations for a method which matches to a [MethodFingerprint]. * @param definingClass The defining class name of the method. - * @param name A suggestive name for the method which the [MethodSignature] was created for. + * @param name A suggestive name for the method which the [MethodFingerprint] was created for. */ @Target(AnnotationTarget.CLASS) @Retention(AnnotationRetention.RUNTIME) @@ -15,7 +15,7 @@ annotation class MatchingMethod( ) /** - * Annotations to scan a pattern [MethodSignature] with fuzzy algorithm. + * Annotations to scan a pattern [MethodFingerprint] with fuzzy algorithm. * @param threshold if [threshold] or more of the opcodes do not match, skip. */ @Target(AnnotationTarget.CLASS) @@ -25,7 +25,7 @@ annotation class FuzzyPatternScanMethod( ) /** - * Annotations to scan a pattern [MethodSignature] directly. + * Annotations to scan a pattern [MethodFingerprint] directly. */ @Target(AnnotationTarget.CLASS) @Retention(AnnotationRetention.RUNTIME) diff --git a/src/main/kotlin/app/revanced/patcher/fingerprint/method/impl/MethodFingerprint.kt b/src/main/kotlin/app/revanced/patcher/fingerprint/method/impl/MethodFingerprint.kt new file mode 100644 index 00000000..7a376acc --- /dev/null +++ b/src/main/kotlin/app/revanced/patcher/fingerprint/method/impl/MethodFingerprint.kt @@ -0,0 +1,99 @@ +package app.revanced.patcher.fingerprint.method.impl + +import app.revanced.patcher.data.impl.BytecodeData +import app.revanced.patcher.data.impl.MethodNotFoundException +import app.revanced.patcher.data.impl.proxy +import app.revanced.patcher.extensions.MethodFingerprintExtensions.name +import app.revanced.patcher.extensions.softCompareTo +import app.revanced.patcher.fingerprint.Fingerprint +import app.revanced.patcher.fingerprint.method.utils.MethodFingerprintUtils +import app.revanced.patcher.util.proxy.ClassProxy +import org.jf.dexlib2.Opcode +import org.jf.dexlib2.iface.ClassDef +import org.jf.dexlib2.iface.Method + +/** + * Represents the [MethodFingerprint] for a method. + * @param returnType The return type of the method. + * @param access The access flags of the method. + * @param parameters The parameters of the method. + * @param opcodes The list of opcodes of the method. + * @param strings A list of strings which a method contains. + * @param customFingerprint A custom condition for this fingerprint. + * A `null` opcode is equals to an unknown opcode. + */ +abstract class MethodFingerprint( + internal val returnType: String?, + internal val access: Int?, + internal val parameters: Iterable?, + internal val opcodes: Iterable?, + internal val strings: Iterable? = null, + internal val customFingerprint: ((methodDef: Method) -> Boolean)? = null +) : Fingerprint { + /** + * The result of the [MethodFingerprint] the [Method]. + * @throws MethodNotFoundException If the resolution of the [Method] has not happened. + */ + var result: MethodFingerprintResult? = null + get() = field ?: throw MethodNotFoundException("${this.name} has not been resolved yet.") +} + +/** + * Represents the result of a [MethodFingerprintUtils]. + * @param method The matching method. + * @param classDef The [ClassDef] that contains the matching [method]. + * @param patternScanResult Opcodes pattern scan result. + * @param data The [BytecodeData] this [MethodFingerprintResult] is attached to, to create proxies. + */ +data class MethodFingerprintResult( + val method: Method, + val classDef: ClassDef, + val patternScanResult: PatternScanResult?, + val data: BytecodeData +) { + /** + * Returns a mutable clone of [classDef] + * + * Please note, this method allocates a [ClassProxy]. + * Use [classDef] where possible. + */ + val mutableClass by lazy { data.proxy(classDef).resolve() } + + /** + * Returns a mutable clone of [method] + * + * Please note, this method allocates a [ClassProxy]. + * Use [method] where possible. + */ + val mutableMethod by lazy { + mutableClass.methods.first { + it.softCompareTo(this.method) + } + } +} + +/** + * The result of a pattern scan. + * @param startIndex The start index of the instructions where to which this pattern matches. + * @param endIndex The end index of the instructions where to which this pattern matches. + * @param warnings A list of warnings considering this [PatternScanResult]. + */ +data class PatternScanResult( + val startIndex: Int, + val endIndex: Int, + var warnings: List? = null +) { + /** + * Represents warnings of the pattern scan. + * @param correctOpcode The opcode the instruction list has. + * @param wrongOpcode The opcode the pattern list of the signature currently has. + * @param instructionIndex The index of the opcode relative to the instruction list. + * @param patternIndex The index of the opcode relative to the pattern list from the signature. + */ + data class Warning( + val correctOpcode: Opcode, + val wrongOpcode: Opcode, + val instructionIndex: Int, + val patternIndex: Int, + ) +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patcher/fingerprint/method/utils/MethodFingerprintUtils.kt b/src/main/kotlin/app/revanced/patcher/fingerprint/method/utils/MethodFingerprintUtils.kt new file mode 100644 index 00000000..ddd78f67 --- /dev/null +++ b/src/main/kotlin/app/revanced/patcher/fingerprint/method/utils/MethodFingerprintUtils.kt @@ -0,0 +1,158 @@ +package app.revanced.patcher.fingerprint.method.utils + +import app.revanced.patcher.data.impl.BytecodeData +import app.revanced.patcher.extensions.MethodFingerprintExtensions.fuzzyPatternScanMethod +import app.revanced.patcher.extensions.MethodFingerprintExtensions.fuzzyScanThreshold +import app.revanced.patcher.extensions.parametersEqual +import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprintResult +import app.revanced.patcher.fingerprint.method.impl.PatternScanResult +import org.jf.dexlib2.Opcode +import org.jf.dexlib2.iface.ClassDef +import org.jf.dexlib2.iface.Method +import org.jf.dexlib2.iface.instruction.Instruction +import org.jf.dexlib2.iface.instruction.ReferenceInstruction +import org.jf.dexlib2.iface.reference.StringReference + +/** + * Utility class for [MethodFingerprint] + */ +object MethodFingerprintUtils { + /** + * Resolve a list of [MethodFingerprint] against a list of [ClassDef]. + * @param context The classes on which to resolve the [MethodFingerprint]. + * @param forData The [BytecodeData] to host proxies. + * @return True if the resolution was successful, false otherwise. + */ + fun Iterable.resolve(forData: BytecodeData, context: Iterable) { + for (fingerprint in this) // For each fingerprint + classes@ for (classDef in context) // search through all classes for the fingerprint + if (fingerprint.resolve(forData, classDef)) + break@classes // if the resolution succeeded, continue with the next fingerprint + } + + /** + * Resolve a [MethodFingerprint] against a [ClassDef]. + * @param context The class on which to resolve the [MethodFingerprint]. + * @param forData The [BytecodeData] to host proxies. + * @return True if the resolution was successful, false otherwise. + */ + fun MethodFingerprint.resolve(forData: BytecodeData, context: ClassDef): Boolean { + for (method in context.methods) + if (this.resolve(forData, method, context)) + return true + return false + } + + /** + * Resolve a [MethodFingerprint] against a [Method]. + * @param context The context on which to resolve the [MethodFingerprint]. + * @param classDef The class of the matching [Method]. + * @param forData The [BytecodeData] to host proxies. + * @return True if the resolution was successful, false otherwise. + */ + fun MethodFingerprint.resolve(forData: BytecodeData, context: Method, classDef: ClassDef): Boolean { + val methodFingerprint = this + + if (methodFingerprint.returnType != null && !context.returnType.startsWith(methodFingerprint.returnType)) + return false + + if (methodFingerprint.access != null && methodFingerprint.access != context.accessFlags) + return false + + + if (methodFingerprint.parameters != null && !parametersEqual( + methodFingerprint.parameters, // TODO: parseParameters() + context.parameterTypes + ) + ) return false + + if (methodFingerprint.customFingerprint != null && methodFingerprint.customFingerprint!!(context)) + return false + + if (methodFingerprint.strings != null) { + val implementation = context.implementation ?: return false + + val stringsList = methodFingerprint.strings.toMutableList() + + implementation.instructions.forEach { instruction -> + if (instruction.opcode.ordinal != Opcode.CONST_STRING.ordinal) return@forEach + + val string = ((instruction as ReferenceInstruction).reference as StringReference).string + val index = stringsList.indexOfFirst { it == string } + if (index != -1) stringsList.removeAt(index) + } + + if (stringsList.isNotEmpty()) return false + } + + val patternScanResult = if (methodFingerprint.opcodes != null) { + context.implementation?.instructions ?: return false + + context.patternScan(methodFingerprint) ?: return false + } else null + + methodFingerprint.result = MethodFingerprintResult(context, classDef, patternScanResult, forData) + + return true + } + + private fun Method.patternScan( + fingerprint: MethodFingerprint + ): PatternScanResult? { + val instructions = this.implementation!!.instructions + val fingerprintFuzzyPatternScanThreshold = fingerprint.fuzzyScanThreshold + + val pattern = fingerprint.opcodes!! + val instructionLength = instructions.count() + val patternLength = pattern.count() + + for (index in 0 until instructionLength) { + var patternIndex = 0 + var threshold = fingerprintFuzzyPatternScanThreshold + + while (index + patternIndex < instructionLength) { + val originalOpcode = instructions.elementAt(index + patternIndex).opcode + val patternOpcode = pattern.elementAt(patternIndex) + + if (patternOpcode != null && patternOpcode.ordinal != originalOpcode.ordinal) { + // reaching maximum threshold (0) means, + // the pattern does not match to the current instructions + if (threshold-- == 0) break + } + + if (patternIndex < patternLength - 1) { + // if the entire pattern has not been scanned yet + // continue the scan + patternIndex++ + continue + } + // the pattern is valid, generate warnings if fuzzyPatternScanMethod is FuzzyPatternScanMethod + val result = PatternScanResult(index, index + patternIndex) + if (fingerprint.fuzzyPatternScanMethod !is FuzzyPatternScanMethod) return result + result.warnings = result.createWarnings(pattern, instructions) + + return result + } + } + + return null + } +} + +private fun PatternScanResult.createWarnings( + pattern: Iterable, instructions: Iterable +) = buildList { + for ((patternIndex, instructionIndex) in (this@createWarnings.startIndex until this@createWarnings.endIndex).withIndex()) { + val originalOpcode = instructions.elementAt(instructionIndex).opcode + val patternOpcode = pattern.elementAt(patternIndex) + + if (patternOpcode == null || patternOpcode.ordinal == originalOpcode.ordinal) continue + + this.add(PatternScanResult.Warning(originalOpcode, patternOpcode, instructionIndex, patternIndex)) + } +} + +private operator fun ClassDef.component1() = this +private operator fun ClassDef.component2() = this.methods \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patcher/patch/Patch.kt b/src/main/kotlin/app/revanced/patcher/patch/Patch.kt new file mode 100644 index 00000000..3edf855f --- /dev/null +++ b/src/main/kotlin/app/revanced/patcher/patch/Patch.kt @@ -0,0 +1,18 @@ +package app.revanced.patcher.patch + +import app.revanced.patcher.data.Data +import app.revanced.patcher.patch.impl.BytecodePatch +import app.revanced.patcher.patch.impl.ResourcePatch + + +/** + * A ReVanced patch. + * Can either be a [ResourcePatch] or a [BytecodePatch]. + */ +abstract class Patch { + + /** + * The main function of the [Patch] which the patcher will call. + */ + abstract fun execute(data: @UnsafeVariance T): PatchResult +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patcher/patch/implementation/misc/PatchResult.kt b/src/main/kotlin/app/revanced/patcher/patch/PatchResult.kt similarity index 88% rename from src/main/kotlin/app/revanced/patcher/patch/implementation/misc/PatchResult.kt rename to src/main/kotlin/app/revanced/patcher/patch/PatchResult.kt index 9d6e37ab..b1771705 100644 --- a/src/main/kotlin/app/revanced/patcher/patch/implementation/misc/PatchResult.kt +++ b/src/main/kotlin/app/revanced/patcher/patch/PatchResult.kt @@ -1,4 +1,4 @@ -package app.revanced.patcher.patch.implementation.misc +package app.revanced.patcher.patch interface PatchResult { fun error(): PatchResultError? { diff --git a/src/main/kotlin/app/revanced/patcher/patch/annotations/PatchAnnotation.kt b/src/main/kotlin/app/revanced/patcher/patch/annotations/PatchAnnotation.kt index 901f6161..ebfe5c8f 100644 --- a/src/main/kotlin/app/revanced/patcher/patch/annotations/PatchAnnotation.kt +++ b/src/main/kotlin/app/revanced/patcher/patch/annotations/PatchAnnotation.kt @@ -1,7 +1,7 @@ package app.revanced.patcher.patch.annotations -import app.revanced.patcher.data.base.Data -import app.revanced.patcher.patch.base.Patch +import app.revanced.patcher.data.Data +import app.revanced.patcher.patch.Patch import kotlin.reflect.KClass /** diff --git a/src/main/kotlin/app/revanced/patcher/patch/base/Patch.kt b/src/main/kotlin/app/revanced/patcher/patch/base/Patch.kt deleted file mode 100644 index 80a26352..00000000 --- a/src/main/kotlin/app/revanced/patcher/patch/base/Patch.kt +++ /dev/null @@ -1,19 +0,0 @@ -package app.revanced.patcher.patch.base - -import app.revanced.patcher.data.base.Data -import app.revanced.patcher.patch.implementation.BytecodePatch -import app.revanced.patcher.patch.implementation.ResourcePatch -import app.revanced.patcher.patch.implementation.misc.PatchResult - - -/** - * A ReVanced patch. - * Can either be a [ResourcePatch] or a [BytecodePatch]. - */ -abstract class Patch { - - /** - * The main function of the [Patch] which the patcher will call. - */ - abstract fun execute(data: @UnsafeVariance T): PatchResult -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patcher/patch/impl/BytecodePatch.kt b/src/main/kotlin/app/revanced/patcher/patch/impl/BytecodePatch.kt new file mode 100644 index 00000000..a5934d23 --- /dev/null +++ b/src/main/kotlin/app/revanced/patcher/patch/impl/BytecodePatch.kt @@ -0,0 +1,13 @@ +package app.revanced.patcher.patch.impl + +import app.revanced.patcher.data.impl.BytecodeData +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import app.revanced.patcher.patch.Patch + +/** + * Bytecode patch for the Patcher. + * @param fingerprints A list of [MethodFingerprint] this patch relies on. + */ +abstract class BytecodePatch( + internal val fingerprints: Iterable +) : Patch() \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patcher/patch/impl/ResourcePatch.kt b/src/main/kotlin/app/revanced/patcher/patch/impl/ResourcePatch.kt new file mode 100644 index 00000000..89df023f --- /dev/null +++ b/src/main/kotlin/app/revanced/patcher/patch/impl/ResourcePatch.kt @@ -0,0 +1,9 @@ +package app.revanced.patcher.patch.impl + +import app.revanced.patcher.data.impl.ResourceData +import app.revanced.patcher.patch.Patch + +/** + * Resource patch for the Patcher. + */ +abstract class ResourcePatch : Patch() \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patcher/patch/implementation/BytecodePatch.kt b/src/main/kotlin/app/revanced/patcher/patch/implementation/BytecodePatch.kt deleted file mode 100644 index a2ff07de..00000000 --- a/src/main/kotlin/app/revanced/patcher/patch/implementation/BytecodePatch.kt +++ /dev/null @@ -1,13 +0,0 @@ -package app.revanced.patcher.patch.implementation - -import app.revanced.patcher.data.implementation.BytecodeData -import app.revanced.patcher.patch.base.Patch -import app.revanced.patcher.signature.implementation.method.MethodSignature - -/** - * Bytecode patch for the Patcher. - * @param signatures A list of [MethodSignature] this patch relies on. - */ -abstract class BytecodePatch( - internal val signatures: Iterable -) : Patch() \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patcher/patch/implementation/ResourcePatch.kt b/src/main/kotlin/app/revanced/patcher/patch/implementation/ResourcePatch.kt deleted file mode 100644 index b8fd606c..00000000 --- a/src/main/kotlin/app/revanced/patcher/patch/implementation/ResourcePatch.kt +++ /dev/null @@ -1,9 +0,0 @@ -package app.revanced.patcher.patch.implementation - -import app.revanced.patcher.data.implementation.ResourceData -import app.revanced.patcher.patch.base.Patch - -/** - * Resource patch for the Patcher. - */ -abstract class ResourcePatch : Patch() \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patcher/signature/base/Signature.kt b/src/main/kotlin/app/revanced/patcher/signature/base/Signature.kt deleted file mode 100644 index 4ad9af62..00000000 --- a/src/main/kotlin/app/revanced/patcher/signature/base/Signature.kt +++ /dev/null @@ -1,9 +0,0 @@ -package app.revanced.patcher.signature.base - -import app.revanced.patcher.signature.implementation.method.MethodSignature - -/** - * A ReVanced signature. - * Can be a [MethodSignature]. - */ -interface Signature \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patcher/signature/implementation/method/MethodSignature.kt b/src/main/kotlin/app/revanced/patcher/signature/implementation/method/MethodSignature.kt deleted file mode 100644 index 49e47f50..00000000 --- a/src/main/kotlin/app/revanced/patcher/signature/implementation/method/MethodSignature.kt +++ /dev/null @@ -1,33 +0,0 @@ -package app.revanced.patcher.signature.implementation.method - -import app.revanced.patcher.data.implementation.MethodNotFoundException -import app.revanced.patcher.extensions.MethodSignatureExtensions.name -import app.revanced.patcher.signature.base.Signature -import app.revanced.patcher.signature.implementation.method.resolver.SignatureResolverResult -import org.jf.dexlib2.Opcode - -/** - * Represents the [MethodSignature] for a method. - * @param returnType The return type of the method. - * @param accessFlags The access flags of the method. - * @param methodParameters The parameters of the method. - * @param opcodes The list of opcodes of the method. - * @param strings A list of strings which a method contains. - * A `null` opcode is equals to an unknown opcode. - */ -abstract class MethodSignature( - internal val returnType: String?, - internal val accessFlags: Int?, - internal val methodParameters: Iterable?, - internal val opcodes: Iterable?, - internal val strings: Iterable? = null -) : Signature { - /** - * The result of the signature - */ - var result: SignatureResolverResult? = null - @Throws(MethodNotFoundException::class) - get() { - return field ?: throw MethodNotFoundException("Could not resolve required signature ${this.name}") - } -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patcher/signature/implementation/method/resolver/MethodSignatureResolver.kt b/src/main/kotlin/app/revanced/patcher/signature/implementation/method/resolver/MethodSignatureResolver.kt deleted file mode 100644 index 5c1f8044..00000000 --- a/src/main/kotlin/app/revanced/patcher/signature/implementation/method/resolver/MethodSignatureResolver.kt +++ /dev/null @@ -1,162 +0,0 @@ -package app.revanced.patcher.signature.implementation.method.resolver - -import app.revanced.patcher.data.PatcherData -import app.revanced.patcher.data.implementation.proxy -import app.revanced.patcher.extensions.MethodSignatureExtensions.fuzzyThreshold -import app.revanced.patcher.extensions.parametersEqual -import app.revanced.patcher.signature.implementation.method.MethodSignature -import org.jf.dexlib2.Opcode -import org.jf.dexlib2.iface.ClassDef -import org.jf.dexlib2.iface.Method -import org.jf.dexlib2.iface.instruction.Instruction -import org.jf.dexlib2.iface.instruction.formats.Instruction21c -import org.jf.dexlib2.iface.reference.StringReference - -internal class MethodSignatureResolver( - private val classes: List, - private val methodSignatures: Iterable -) { - fun resolve(patcherData: PatcherData) { - for (signature in methodSignatures) { - for (classDef in classes) { - for (method in classDef.methods) { - val patternScanData = compareSignatureToMethod(signature, method) ?: continue - - // create class proxy, in case a patch needs mutability - val classProxy = patcherData.bytecodeData.proxy(classDef) - signature.result = SignatureResolverResult( - classProxy, - patternScanData, - method, - ) - } - } - } - } - - // These functions do not require the constructor values, so they can be static. - companion object { - fun resolveFromProxy( - classProxy: app.revanced.patcher.util.proxy.ClassProxy, - signature: MethodSignature - ): SignatureResolverResult? { - for (method in classProxy.immutableClass.methods) { - val result = compareSignatureToMethod(signature, method) ?: continue - return SignatureResolverResult( - classProxy, - result, - method, - ) - } - return null - } - - private fun compareSignatureToMethod( - signature: MethodSignature, - method: Method - ): PatternScanResult? { - signature.returnType?.let { - if (!method.returnType.startsWith(signature.returnType)) { - return null - } - } - - signature.accessFlags?.let { - if (signature.accessFlags != method.accessFlags) { - return null - } - } - - signature.methodParameters?.let { - if (!parametersEqual(signature.methodParameters, method.parameterTypes)) { - return null - } - } - - signature.strings?.let { strings -> - method.implementation ?: return null - - val stringsList = strings.toMutableList() - - for (instruction in method.implementation!!.instructions) { - if (instruction.opcode != Opcode.CONST_STRING) continue - - val string = ((instruction as Instruction21c).reference as StringReference).string - val i = stringsList.indexOfFirst { it == string } - if (i != -1) stringsList.removeAt(i) - } - - if (stringsList.isNotEmpty()) return null - } - - return if (signature.opcodes == null) { - PatternScanResult(0, 0) - } else { - method.implementation?.instructions?.let { - compareOpcodes(signature, it) - } - } - } - - private fun compareOpcodes( - signature: MethodSignature, - instructions: Iterable - ): PatternScanResult? { - val count = instructions.count() - val pattern = signature.opcodes!! - val size = pattern.count() - - val threshold = signature.fuzzyThreshold - - for (instructionIndex in 0 until count) { - var patternIndex = 0 - var currentThreshold = threshold - while (instructionIndex + patternIndex < count) { - val originalOpcode = instructions.elementAt(instructionIndex + patternIndex).opcode - val patternOpcode = pattern.elementAt(patternIndex) - if ( - patternOpcode != null && // unknown opcode - originalOpcode != patternOpcode && - currentThreshold-- == 0 - ) break - if (++patternIndex < size) continue - patternIndex-- // fix pattern offset - - val result = PatternScanResult(instructionIndex, instructionIndex + patternIndex) - - result.warnings = generateWarnings(signature, instructions, result) - - return result - } - } - - return null - } - - private fun generateWarnings( - signature: MethodSignature, - instructions: Iterable, - scanResult: PatternScanResult, - ) = buildList { - val pattern = signature.opcodes!! - for ((patternIndex, instructionIndex) in (scanResult.startIndex until scanResult.endIndex).withIndex()) { - val correctOpcode = instructions.elementAt(instructionIndex).opcode - val patternOpcode = pattern.elementAt(patternIndex) - if ( - patternOpcode != null && // unknown opcode - correctOpcode != patternOpcode - ) { - this.add( - PatternScanResult.Warning( - correctOpcode, patternOpcode, - instructionIndex, patternIndex, - ) - ) - } - } - } - } -} - -private operator fun ClassDef.component1() = this -private operator fun ClassDef.component2() = this.methods \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patcher/signature/implementation/method/resolver/MethodSignatureResolverResult.kt b/src/main/kotlin/app/revanced/patcher/signature/implementation/method/resolver/MethodSignatureResolverResult.kt deleted file mode 100644 index 0465417f..00000000 --- a/src/main/kotlin/app/revanced/patcher/signature/implementation/method/resolver/MethodSignatureResolverResult.kt +++ /dev/null @@ -1,75 +0,0 @@ -package app.revanced.patcher.signature.implementation.method.resolver - -import app.revanced.patcher.extensions.softCompareTo -import app.revanced.patcher.signature.implementation.method.MethodSignature -import app.revanced.patcher.util.proxy.ClassProxy -import org.jf.dexlib2.Opcode -import org.jf.dexlib2.iface.Method - -/** - * Represents the result of a [MethodSignatureResolver]. - * @param definingClassProxy The [ClassProxy] that the matching method was found in. - * @param resolvedMethod The actual matching method. - * @param scanResult Opcodes pattern scan result. - */ -data class SignatureResolverResult( - val definingClassProxy: ClassProxy, - val scanResult: PatternScanResult, - private val resolvedMethod: Method, -) { - /** - * Returns the **mutable** method by the [resolvedMethod] from the [definingClassProxy]. - * - * Please note, this method allocates a [ClassProxy]. - * Use [immutableMethod] where possible. - */ - val method - get() = definingClassProxy.resolve().methods.first { - it.softCompareTo(resolvedMethod) - } - - /** - * Returns the **immutable** method by the [resolvedMethod] from the [definingClassProxy]. - * - * If you need to modify the method, use [method] instead. - */ - @Suppress("MemberVisibilityCanBePrivate") - val immutableMethod: Method - get() = definingClassProxy.immutableClass.methods.first { - it.softCompareTo(resolvedMethod) - } - - fun findParentMethod(signature: MethodSignature): SignatureResolverResult? { - return MethodSignatureResolver.resolveFromProxy(definingClassProxy, signature) - } -} - -data class PatternScanResult( - val startIndex: Int, - val endIndex: Int -) { - /** - * A list of warnings the resolver found. - * - * This list will be allocated when the signature has been found. - * Meaning, if the signature was not found, - * or the signature was not yet resolved, - * the list will be null. - */ - var warnings: List? = null - - /** - * Represents a resolver warning. - * @param correctOpcode The opcode the instruction list has. - * @param wrongOpcode The opcode the pattern list of the signature currently has. - * @param instructionIndex The index of the opcode relative to the instruction list. - * @param patternIndex The index of the opcode relative to the pattern list from the signature. - */ - data class Warning( - val correctOpcode: Opcode, - val wrongOpcode: Opcode, - val instructionIndex: Int, - val patternIndex: Int, - ) -} - diff --git a/src/main/kotlin/app/revanced/patcher/util/method/MethodWalker.kt b/src/main/kotlin/app/revanced/patcher/util/method/MethodWalker.kt index 0b1c10e9..103841a2 100644 --- a/src/main/kotlin/app/revanced/patcher/util/method/MethodWalker.kt +++ b/src/main/kotlin/app/revanced/patcher/util/method/MethodWalker.kt @@ -1,7 +1,7 @@ package app.revanced.patcher.util.method -import app.revanced.patcher.data.implementation.BytecodeData -import app.revanced.patcher.data.implementation.MethodNotFoundException +import app.revanced.patcher.data.impl.BytecodeData +import app.revanced.patcher.data.impl.MethodNotFoundException import app.revanced.patcher.extensions.softCompareTo import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod import org.jf.dexlib2.Format diff --git a/src/main/kotlin/app/revanced/patcher/util/patch/base/PatchBundle.kt b/src/main/kotlin/app/revanced/patcher/util/patch/base/PatchBundle.kt index befc786f..b3133f80 100644 --- a/src/main/kotlin/app/revanced/patcher/util/patch/base/PatchBundle.kt +++ b/src/main/kotlin/app/revanced/patcher/util/patch/base/PatchBundle.kt @@ -1,7 +1,7 @@ package app.revanced.patcher.util.patch.base -import app.revanced.patcher.data.base.Data -import app.revanced.patcher.patch.base.Patch +import app.revanced.patcher.data.Data +import app.revanced.patcher.patch.Patch import java.io.File /** diff --git a/src/test/kotlin/app/revanced/patcher/usage/bytecode/signatures/ExampleSignature.kt b/src/test/kotlin/app/revanced/patcher/usage/bytecode/fingerprints/ExampleFingerprint.kt similarity index 65% rename from src/test/kotlin/app/revanced/patcher/usage/bytecode/signatures/ExampleSignature.kt rename to src/test/kotlin/app/revanced/patcher/usage/bytecode/fingerprints/ExampleFingerprint.kt index d0983b71..63acbaa0 100644 --- a/src/test/kotlin/app/revanced/patcher/usage/bytecode/signatures/ExampleSignature.kt +++ b/src/test/kotlin/app/revanced/patcher/usage/bytecode/fingerprints/ExampleFingerprint.kt @@ -1,16 +1,16 @@ -package app.revanced.patcher.usage.bytecode.signatures +package app.revanced.patcher.usage.bytecode.fingerprints import app.revanced.patcher.annotation.Name import app.revanced.patcher.annotation.Version import app.revanced.patcher.extensions.or -import app.revanced.patcher.signature.implementation.method.MethodSignature -import app.revanced.patcher.signature.implementation.method.annotation.FuzzyPatternScanMethod -import app.revanced.patcher.signature.implementation.method.annotation.MatchingMethod +import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod +import app.revanced.patcher.fingerprint.method.annotation.MatchingMethod +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import app.revanced.patcher.usage.bytecode.annotation.ExampleBytecodeCompatibility import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.Opcode -@Name("example-signature") +@Name("example-fingerprint") @MatchingMethod( "LexampleClass;", "exampleMehod" @@ -18,7 +18,7 @@ import org.jf.dexlib2.Opcode @FuzzyPatternScanMethod(2) @ExampleBytecodeCompatibility @Version("0.0.1") -object ExampleSignature : MethodSignature( +object ExampleFingerprint : MethodFingerprint( "V", AccessFlags.PUBLIC or AccessFlags.STATIC, listOf("[L"), diff --git a/src/test/kotlin/app/revanced/patcher/usage/bytecode/patch/ExampleBytecodePatch.kt b/src/test/kotlin/app/revanced/patcher/usage/bytecode/patch/ExampleBytecodePatch.kt index f8bd8f25..70ebf89a 100644 --- a/src/test/kotlin/app/revanced/patcher/usage/bytecode/patch/ExampleBytecodePatch.kt +++ b/src/test/kotlin/app/revanced/patcher/usage/bytecode/patch/ExampleBytecodePatch.kt @@ -3,14 +3,14 @@ package app.revanced.patcher.usage.bytecode.patch import app.revanced.patcher.annotation.Description import app.revanced.patcher.annotation.Name import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.implementation.BytecodeData +import app.revanced.patcher.data.impl.BytecodeData import app.revanced.patcher.extensions.addInstructions import app.revanced.patcher.extensions.or +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patcher.patch.implementation.BytecodePatch -import app.revanced.patcher.patch.implementation.misc.PatchResult -import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess -import app.revanced.patcher.usage.bytecode.signatures.ExampleSignature +import app.revanced.patcher.patch.impl.BytecodePatch +import app.revanced.patcher.usage.bytecode.fingerprints.ExampleFingerprint import app.revanced.patcher.usage.resource.annotation.ExampleResourceCompatibility import app.revanced.patcher.util.proxy.mutableTypes.MutableField.Companion.toMutable import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable @@ -39,34 +39,35 @@ import org.jf.dexlib2.util.Preconditions class ExampleBytecodePatch : BytecodePatch( listOf( - ExampleSignature + ExampleFingerprint ) ) { // This function will be executed by the patcher. // You can treat it as a constructor override fun execute(data: BytecodeData): PatchResult { - // Get the resolved method for the signature from the resolver cache - val result = ExampleSignature.result!! + // Get the resolved method by its fingerprint from the resolver cache + val result = ExampleFingerprint.result!! // Get the implementation for the resolved method - val implementation = result.method.implementation!! + val method = result.mutableMethod + val implementation = method.implementation!! // Let's modify it, so it prints "Hello, ReVanced! Editing bytecode." // Get the start index of our opcode pattern. // This will be the index of the instruction with the opcode CONST_STRING. - val startIndex = result.scanResult.startIndex + val startIndex = result.patternScanResult!!.startIndex implementation.replaceStringAt(startIndex, "Hello, ReVanced! Editing bytecode.") - // Get the class in which the method matching our signature is defined in. + // Get the class in which the method matching our fingerprint is defined in. val mainClass = data.findClass { - it.type == result.definingClassProxy.immutableClass.type + it.type == result.classDef.type }!!.resolve() // Add a new method returning a string mainClass.methods.add( ImmutableMethod( - result.definingClassProxy.immutableClass.type, + result.classDef.type, "returnHello", null, "Ljava/lang/String;", @@ -126,7 +127,7 @@ class ExampleBytecodePatch : BytecodePatch( move-result-object v1 invoke-virtual { v0, v1 }, Ljava/io/PrintStream;->println(Ljava/lang/String;)V """ - result.method.addInstructions(startIndex + 2, instructions) + method.addInstructions(startIndex + 2, instructions) // Finally, tell the patcher that this patch was a success. // You can also return PatchResultError with a message. diff --git a/src/test/kotlin/app/revanced/patcher/usage/resource/patch/ExampleResourcePatch.kt b/src/test/kotlin/app/revanced/patcher/usage/resource/patch/ExampleResourcePatch.kt index d5b2c425..4a9d5354 100644 --- a/src/test/kotlin/app/revanced/patcher/usage/resource/patch/ExampleResourcePatch.kt +++ b/src/test/kotlin/app/revanced/patcher/usage/resource/patch/ExampleResourcePatch.kt @@ -3,11 +3,11 @@ package app.revanced.patcher.usage.resource.patch import app.revanced.patcher.annotation.Description import app.revanced.patcher.annotation.Name import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.implementation.ResourceData +import app.revanced.patcher.data.impl.ResourceData +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patcher.patch.implementation.ResourcePatch -import app.revanced.patcher.patch.implementation.misc.PatchResult -import app.revanced.patcher.patch.implementation.misc.PatchResultSuccess +import app.revanced.patcher.patch.impl.ResourcePatch import app.revanced.patcher.usage.resource.annotation.ExampleResourceCompatibility import org.w3c.dom.Element