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.
* @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
}

View file

@ -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<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(
signature: Iterable<String>,
original: MutableList<out CharSequence>
@ -89,20 +123,4 @@ internal class SignatureResolver(
}
private operator fun ClassDef.component1() = this
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
}
private operator fun ClassDef.component2() = this.methods

View file

@ -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
)
)