Skip to content

Commit

Permalink
feat: add fuzzy resolver
Browse files Browse the repository at this point in the history
fixed docs for MethodSignature & added tests for fuzzy resolver
  • Loading branch information
Sculas authored and oSumAtrIX committed Jun 5, 2022
1 parent 18853f7 commit 7a56dca
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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>
Expand All @@ -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
4 changes: 2 additions & 2 deletions src/test/kotlin/app/revanced/patcher/PatcherTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,15 @@ internal class PatcherTest {
comment = "Main method of TestClass. Version 1.0.0"
),
patcher = PatcherMetadata(
method = PatcherMethod.Fuzzy(2)
method = ResolverMethod.Fuzzy(2)
)
),
"V",
AccessFlags.PUBLIC or AccessFlags.STATIC or AccessFlags.STATIC,
listOf("[L"),
listOf(
Opcode.CONST_STRING,
Opcode.INVOKE_VIRTUAL,
Opcode.INVOKE_STATIC, // This is intentionally wrong to test the Fuzzy resolver.
Opcode.RETURN_VOID
)
)
Expand Down

0 comments on commit 7a56dca

Please sign in to comment.