1
mirror of https://github.com/revanced/revanced-patcher synced 2024-11-24 05:16:22 +01:00

feat: add fuzzy resolver

fixed docs for MethodSignature & added tests for fuzzy resolver
This commit is contained in:
Lucaskyy 2022-04-13 20:17:31 +02:00 committed by oSumAtrIX
parent 18853f70a4
commit 7a56dca004
No known key found for this signature in database
GPG Key ID: A9B3094ACDB604B4
3 changed files with 47 additions and 26 deletions

View File

@ -46,20 +46,23 @@ data class MethodMetadata(
/** /**
* Metadata for the Patcher, this contains things like how the Patcher should interpret this signature. * 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( 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. * 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. * 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
} }

View File

@ -3,9 +3,9 @@ package app.revanced.patcher.signature.resolver
import app.revanced.patcher.cache.MethodMap import app.revanced.patcher.cache.MethodMap
import app.revanced.patcher.proxy.ClassProxy import app.revanced.patcher.proxy.ClassProxy
import app.revanced.patcher.signature.MethodSignature import app.revanced.patcher.signature.MethodSignature
import app.revanced.patcher.signature.ResolverMethod
import app.revanced.patcher.signature.PatternScanResult import app.revanced.patcher.signature.PatternScanResult
import app.revanced.patcher.signature.SignatureResolverResult import app.revanced.patcher.signature.SignatureResolverResult
import org.jf.dexlib2.Opcode
import org.jf.dexlib2.iface.ClassDef import org.jf.dexlib2.iface.ClassDef
import org.jf.dexlib2.iface.Method import org.jf.dexlib2.iface.Method
import org.jf.dexlib2.iface.instruction.Instruction import org.jf.dexlib2.iface.instruction.Instruction
@ -75,10 +75,44 @@ internal class SignatureResolver(
return if (signature.opcodes == null) { return if (signature.opcodes == null) {
PatternScanResult(0, 0) PatternScanResult(0, 0)
} else { } else {
method.implementation?.instructions?.scanFor(signature.opcodes) method.implementation?.instructions?.let {
compareOpcodes(signature, it)
}
} }
} }
private fun compareOpcodes(
signature: MethodSignature,
instructions: Iterable<Instruction>
): 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( private fun compareParameterTypes(
signature: Iterable<String>, signature: Iterable<String>,
original: MutableList<out CharSequence> original: MutableList<out CharSequence>
@ -89,20 +123,4 @@ internal class SignatureResolver(
} }
private operator fun ClassDef.component1() = this private operator fun ClassDef.component1() = this
private operator fun ClassDef.component2() = this.methods private operator fun ClassDef.component2() = this.methods
private fun MutableIterable<Instruction>.scanFor(pattern: Iterable<Opcode>): 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
}

View File

@ -38,7 +38,7 @@ internal class PatcherTest {
comment = "Main method of TestClass. Version 1.0.0" comment = "Main method of TestClass. Version 1.0.0"
), ),
patcher = PatcherMetadata( patcher = PatcherMetadata(
method = PatcherMethod.Fuzzy(2) method = ResolverMethod.Fuzzy(2)
) )
), ),
"V", "V",
@ -46,7 +46,7 @@ internal class PatcherTest {
listOf("[L"), listOf("[L"),
listOf( listOf(
Opcode.CONST_STRING, Opcode.CONST_STRING,
Opcode.INVOKE_VIRTUAL, Opcode.INVOKE_STATIC, // This is intentionally wrong to test the Fuzzy resolver.
Opcode.RETURN_VOID Opcode.RETURN_VOID
) )
) )