feat(fingerprint)!: StringsScanResult for MethodFingerprint

BREAKING CHANGE: `MethodFingerprint` now has a field for `MethodFingerprintScanResult`. `MethodFingerprintScanResult` now holds the previous field `MethodFingerprint.patternScanResult`.

Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
This commit is contained in:
oSumAtrIX 2022-09-21 01:09:53 +02:00
parent a2bb4004c7
commit 3813e28ac2
No known key found for this signature in database
GPG Key ID: A9B3094ACDB604B4
2 changed files with 98 additions and 46 deletions

View File

@ -37,34 +37,36 @@ abstract class MethodFingerprint(
* Represents the result of a [MethodFingerprintUtils]. * Represents the result of a [MethodFingerprintUtils].
* @param method The matching method. * @param method The matching method.
* @param classDef The [ClassDef] that contains the matching [method]. * @param classDef The [ClassDef] that contains the matching [method].
* @param patternScanResult Opcodes pattern scan result. * @param scanResult The result of scanning for the [MethodFingerprint].
* @param data The [BytecodeData] this [MethodFingerprintResult] is attached to, to create proxies. * @param data The [BytecodeData] this [MethodFingerprintResult] is attached to, to create proxies.
*/ */
data class MethodFingerprintResult( data class MethodFingerprintResult(
val method: Method, val method: Method,
val classDef: ClassDef, val classDef: ClassDef,
val patternScanResult: PatternScanResult?, val scanResult: MethodFingerprintScanResult,
internal val data: BytecodeData internal 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] * The result of scanning on the [MethodFingerprint].
* * @param patternScanResult The result of the pattern scan.
* Please note, this method allocates a [ClassProxy]. * @param stringsScanResult The result of the string scan.
* Use [method] where possible.
*/ */
val mutableMethod by lazy { data class MethodFingerprintScanResult(
mutableClass.methods.first { val patternScanResult: PatternScanResult?,
it.softCompareTo(this.method) val stringsScanResult: StringsScanResult?
} ) {
} /**
* The result of scanning strings on the [MethodFingerprint].
* @param matches The list of strings that were matched.
*/
data class StringsScanResult(val matches: List<StringMatch>){
/**
* Represents a match for a string at an index.
* @param string The string that was matched.
* @param index The index of the string.
*/
data class StringMatch(val string: String, val index: Int)
} }
/** /**
@ -92,3 +94,25 @@ data class PatternScanResult(
val patternIndex: Int, val patternIndex: Int,
) )
} }
}
/**
* 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)
}
}
}

View File

@ -7,14 +7,12 @@ import app.revanced.patcher.extensions.parametersEqual
import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprintResult 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.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
import org.jf.dexlib2.iface.instruction.ReferenceInstruction import org.jf.dexlib2.iface.instruction.ReferenceInstruction
import org.jf.dexlib2.iface.reference.StringReference import org.jf.dexlib2.iface.reference.StringReference
/** /**
* Utility class for [MethodFingerprint] * Utility class for [MethodFingerprint]
*/ */
@ -73,7 +71,9 @@ object MethodFingerprintUtils {
if (methodFingerprint.customFingerprint != null && !methodFingerprint.customFingerprint!!(context)) if (methodFingerprint.customFingerprint != null && !methodFingerprint.customFingerprint!!(context))
return false return false
val stringsScanResult: StringsScanResult? =
if (methodFingerprint.strings != null) { if (methodFingerprint.strings != null) {
StringsScanResult(buildList {
val implementation = context.implementation ?: return false val implementation = context.implementation ?: return false
val stringsList = methodFingerprint.strings.toMutableList() val stringsList = methodFingerprint.strings.toMutableList()
@ -83,11 +83,20 @@ object MethodFingerprintUtils {
val string = ((instruction as ReferenceInstruction).reference as StringReference).string val string = ((instruction as ReferenceInstruction).reference as StringReference).string
val index = stringsList.indexOfFirst { it == string } val index = stringsList.indexOfFirst { it == string }
if (index != -1) stringsList.removeAt(index) if (index == -1) return@forEach
add(
StringMatch(
string,
index
)
)
stringsList.removeAt(index)
} }
if (stringsList.isNotEmpty()) return false if (stringsList.isNotEmpty()) return false
} })
} else null
val patternScanResult = if (methodFingerprint.opcodes != null) { val patternScanResult = if (methodFingerprint.opcodes != null) {
context.implementation?.instructions ?: return false context.implementation?.instructions ?: return false
@ -95,14 +104,22 @@ object MethodFingerprintUtils {
context.patternScan(methodFingerprint) ?: return false context.patternScan(methodFingerprint) ?: return false
} else null } else null
methodFingerprint.result = MethodFingerprintResult(context, classDef, patternScanResult, forData) methodFingerprint.result = MethodFingerprintResult(
context,
classDef,
MethodFingerprintResult.MethodFingerprintScanResult(
patternScanResult,
stringsScanResult
),
forData
)
return true return true
} }
private fun Method.patternScan( private fun Method.patternScan(
fingerprint: MethodFingerprint fingerprint: MethodFingerprint
): PatternScanResult? { ): MethodFingerprintResult.MethodFingerprintScanResult.PatternScanResult? {
val instructions = this.implementation!!.instructions val instructions = this.implementation!!.instructions
val fingerprintFuzzyPatternScanThreshold = fingerprint.fuzzyScanThreshold val fingerprintFuzzyPatternScanThreshold = fingerprint.fuzzyScanThreshold
@ -131,7 +148,8 @@ object MethodFingerprintUtils {
continue continue
} }
// the pattern is valid, generate warnings if fuzzyPatternScanMethod is FuzzyPatternScanMethod // the pattern is valid, generate warnings if fuzzyPatternScanMethod is FuzzyPatternScanMethod
val result = PatternScanResult(index, index + patternIndex) val result =
MethodFingerprintResult.MethodFingerprintScanResult.PatternScanResult(index, index + patternIndex)
if (fingerprint.fuzzyPatternScanMethod !is FuzzyPatternScanMethod) return result if (fingerprint.fuzzyPatternScanMethod !is FuzzyPatternScanMethod) return result
result.warnings = result.createWarnings(pattern, instructions) result.warnings = result.createWarnings(pattern, instructions)
@ -143,7 +161,10 @@ object MethodFingerprintUtils {
} }
} }
private fun PatternScanResult.createWarnings( private typealias StringsScanResult = MethodFingerprintResult.MethodFingerprintScanResult.StringsScanResult
private typealias StringMatch = MethodFingerprintResult.MethodFingerprintScanResult.StringsScanResult.StringMatch
private fun MethodFingerprintResult.MethodFingerprintScanResult.PatternScanResult.createWarnings(
pattern: Iterable<Opcode?>, instructions: Iterable<Instruction> pattern: Iterable<Opcode?>, instructions: Iterable<Instruction>
) = buildList { ) = buildList {
for ((patternIndex, instructionIndex) in (this@createWarnings.startIndex until this@createWarnings.endIndex).withIndex()) { for ((patternIndex, instructionIndex) in (this@createWarnings.startIndex until this@createWarnings.endIndex).withIndex()) {
@ -152,7 +173,14 @@ private fun PatternScanResult.createWarnings(
if (patternOpcode == null || patternOpcode.ordinal == originalOpcode.ordinal) continue if (patternOpcode == null || patternOpcode.ordinal == originalOpcode.ordinal) continue
this.add(PatternScanResult.Warning(originalOpcode, patternOpcode, instructionIndex, patternIndex)) this.add(
MethodFingerprintResult.MethodFingerprintScanResult.PatternScanResult.Warning(
originalOpcode,
patternOpcode,
instructionIndex,
patternIndex
)
)
} }
} }