From 7a56dca004cd793121a59ea854c77f4c1a01bd6f Mon Sep 17 00:00:00 2001 From: Lucaskyy Date: Wed, 13 Apr 2022 20:17:31 +0200 Subject: [PATCH] feat: add fuzzy resolver fixed docs for MethodSignature & added tests for fuzzy resolver --- .../patcher/signature/MethodSignature.kt | 13 +++-- .../signature/resolver/SignatureResolver.kt | 56 ++++++++++++------- .../app/revanced/patcher/PatcherTest.kt | 4 +- 3 files changed, 47 insertions(+), 26 deletions(-) diff --git a/src/main/kotlin/app/revanced/patcher/signature/MethodSignature.kt b/src/main/kotlin/app/revanced/patcher/signature/MethodSignature.kt index 5704285..f52aae1 100644 --- a/src/main/kotlin/app/revanced/patcher/signature/MethodSignature.kt +++ b/src/main/kotlin/app/revanced/patcher/signature/MethodSignature.kt @@ -46,20 +46,23 @@ data class MethodMetadata( /** * Metadata for the Patcher, this contains things like how the Patcher should interpret this signature. - * @param method The method the Patcher should use to resolve the signature. + * @param method The method the resolver should use to resolve the signature. */ data class PatcherMetadata( - val method: PatcherMethod + val method: ResolverMethod ) -interface PatcherMethod { +/** + * The method the resolver should use to resolve the signature. + */ +interface ResolverMethod { /** * When comparing the signature, if one or more of the opcodes do not match, skip. */ - class Direct : PatcherMethod + class Direct : ResolverMethod /** * When comparing the signature, if [threshold] or more of the opcodes do not match, skip. */ - class Fuzzy(val threshold: Int) : PatcherMethod + class Fuzzy(val threshold: Int) : ResolverMethod } \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patcher/signature/resolver/SignatureResolver.kt b/src/main/kotlin/app/revanced/patcher/signature/resolver/SignatureResolver.kt index bdeeda5..700353f 100644 --- a/src/main/kotlin/app/revanced/patcher/signature/resolver/SignatureResolver.kt +++ b/src/main/kotlin/app/revanced/patcher/signature/resolver/SignatureResolver.kt @@ -3,9 +3,9 @@ package app.revanced.patcher.signature.resolver import app.revanced.patcher.cache.MethodMap import app.revanced.patcher.proxy.ClassProxy import app.revanced.patcher.signature.MethodSignature +import app.revanced.patcher.signature.ResolverMethod import app.revanced.patcher.signature.PatternScanResult import app.revanced.patcher.signature.SignatureResolverResult -import org.jf.dexlib2.Opcode import org.jf.dexlib2.iface.ClassDef import org.jf.dexlib2.iface.Method import org.jf.dexlib2.iface.instruction.Instruction @@ -75,10 +75,44 @@ internal class SignatureResolver( return if (signature.opcodes == null) { PatternScanResult(0, 0) } else { - method.implementation?.instructions?.scanFor(signature.opcodes) + 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() + var threshold = 0 + if (signature.metadata.patcher.method is ResolverMethod.Fuzzy) { + threshold = signature.metadata.patcher.method.threshold + } + + for (instructionIndex in 0 until count) { + var patternIndex = 0 + var currentThreshold = threshold + while (instructionIndex + patternIndex < count) { + println("currentThreshold = $currentThreshold") + if ( + instructions.elementAt( + instructionIndex + patternIndex + ).opcode != pattern.elementAt(patternIndex) + && currentThreshold-- == 0 + ) break + if (++patternIndex < size) continue + + return PatternScanResult(instructionIndex, instructionIndex + patternIndex) + } + } + + return null + } + private fun compareParameterTypes( signature: Iterable, original: MutableList @@ -89,20 +123,4 @@ internal class SignatureResolver( } private operator fun ClassDef.component1() = this -private operator fun ClassDef.component2() = this.methods - -private fun MutableIterable.scanFor(pattern: Iterable): PatternScanResult? { - val count = this.count() - val size = pattern.count() - for (instructionIndex in 0 until count) { - var patternIndex = 0 - while (instructionIndex + patternIndex < count) { - if (this.elementAt(instructionIndex + patternIndex).opcode != pattern.elementAt(patternIndex)) break - if (++patternIndex < size) continue - - return PatternScanResult(instructionIndex, instructionIndex + patternIndex) - } - } - - return null -} \ No newline at end of file +private operator fun ClassDef.component2() = this.methods \ No newline at end of file diff --git a/src/test/kotlin/app/revanced/patcher/PatcherTest.kt b/src/test/kotlin/app/revanced/patcher/PatcherTest.kt index a4d613d..de3fb03 100644 --- a/src/test/kotlin/app/revanced/patcher/PatcherTest.kt +++ b/src/test/kotlin/app/revanced/patcher/PatcherTest.kt @@ -38,7 +38,7 @@ internal class PatcherTest { comment = "Main method of TestClass. Version 1.0.0" ), patcher = PatcherMetadata( - method = PatcherMethod.Fuzzy(2) + method = ResolverMethod.Fuzzy(2) ) ), "V", @@ -46,7 +46,7 @@ internal class PatcherTest { listOf("[L"), listOf( Opcode.CONST_STRING, - Opcode.INVOKE_VIRTUAL, + Opcode.INVOKE_STATIC, // This is intentionally wrong to test the Fuzzy resolver. Opcode.RETURN_VOID ) )