Skip to content

Commit

Permalink
feat(fingerprint)!: StringsScanResult for MethodFingerprint
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
oSumAtrIX committed Sep 20, 2022
1 parent a2bb400 commit 3813e28
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 46 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,65 @@ abstract class MethodFingerprint(
* Represents the result of a [MethodFingerprintUtils].
* @param method 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.
*/
data class MethodFingerprintResult(
val method: Method,
val classDef: ClassDef,
val patternScanResult: PatternScanResult?,
val scanResult: MethodFingerprintScanResult,
internal val data: BytecodeData
) {

/**
* The result of scanning on the [MethodFingerprint].
* @param patternScanResult The result of the pattern scan.
* @param stringsScanResult The result of the string scan.
*/
data class MethodFingerprintScanResult(
val patternScanResult: PatternScanResult?,
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)
}

/**
* The result of a pattern scan.
* @param startIndex The start index of the instructions where to which this pattern matches.
* @param endIndex The end index of the instructions where to which this pattern matches.
* @param warnings A list of warnings considering this [PatternScanResult].
*/
data class PatternScanResult(
val startIndex: Int,
val endIndex: Int,
var warnings: List<Warning>? = null
) {
/**
* Represents warnings of the pattern scan.
* @param correctOpcode The opcode the instruction list has.
* @param wrongOpcode The opcode the pattern list of the signature currently has.
* @param instructionIndex The index of the opcode relative to the instruction list.
* @param patternIndex The index of the opcode relative to the pattern list from the signature.
*/
data class Warning(
val correctOpcode: Opcode,
val wrongOpcode: Opcode,
val instructionIndex: Int,
val patternIndex: Int,
)
}
}

/**
* Returns a mutable clone of [classDef]
*
Expand All @@ -65,30 +115,4 @@ data class MethodFingerprintResult(
it.softCompareTo(this.method)
}
}
}

/**
* The result of a pattern scan.
* @param startIndex The start index of the instructions where to which this pattern matches.
* @param endIndex The end index of the instructions where to which this pattern matches.
* @param warnings A list of warnings considering this [PatternScanResult].
*/
data class PatternScanResult(
val startIndex: Int,
val endIndex: Int,
var warnings: List<Warning>? = null
) {
/**
* Represents warnings of the pattern scan.
* @param correctOpcode The opcode the instruction list has.
* @param wrongOpcode The opcode the pattern list of the signature currently has.
* @param instructionIndex The index of the opcode relative to the instruction list.
* @param patternIndex The index of the opcode relative to the pattern list from the signature.
*/
data class Warning(
val correctOpcode: Opcode,
val wrongOpcode: Opcode,
val instructionIndex: Int,
val patternIndex: Int,
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,12 @@ import app.revanced.patcher.extensions.parametersEqual
import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
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.iface.ClassDef
import org.jf.dexlib2.iface.Method
import org.jf.dexlib2.iface.instruction.Instruction
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
import org.jf.dexlib2.iface.reference.StringReference

/**
* Utility class for [MethodFingerprint]
*/
Expand Down Expand Up @@ -73,36 +71,55 @@ object MethodFingerprintUtils {
if (methodFingerprint.customFingerprint != null && !methodFingerprint.customFingerprint!!(context))
return false

if (methodFingerprint.strings != null) {
val implementation = context.implementation ?: return false
val stringsScanResult: StringsScanResult? =
if (methodFingerprint.strings != null) {
StringsScanResult(buildList {
val implementation = context.implementation ?: return false

val stringsList = methodFingerprint.strings.toMutableList()
val stringsList = methodFingerprint.strings.toMutableList()

implementation.instructions.forEach { instruction ->
if (instruction.opcode.ordinal != Opcode.CONST_STRING.ordinal) return@forEach
implementation.instructions.forEach { instruction ->
if (instruction.opcode.ordinal != Opcode.CONST_STRING.ordinal) return@forEach

val string = ((instruction as ReferenceInstruction).reference as StringReference).string
val index = stringsList.indexOfFirst { it == string }
if (index != -1) stringsList.removeAt(index)
}
val string = ((instruction as ReferenceInstruction).reference as StringReference).string
val index = stringsList.indexOfFirst { it == string }
if (index == -1) return@forEach

if (stringsList.isNotEmpty()) return false
}
add(
StringMatch(
string,
index
)
)
stringsList.removeAt(index)
}

if (stringsList.isNotEmpty()) return false
})
} else null

val patternScanResult = if (methodFingerprint.opcodes != null) {
context.implementation?.instructions ?: return false

context.patternScan(methodFingerprint) ?: return false
} else null

methodFingerprint.result = MethodFingerprintResult(context, classDef, patternScanResult, forData)
methodFingerprint.result = MethodFingerprintResult(
context,
classDef,
MethodFingerprintResult.MethodFingerprintScanResult(
patternScanResult,
stringsScanResult
),
forData
)

return true
}

private fun Method.patternScan(
fingerprint: MethodFingerprint
): PatternScanResult? {
): MethodFingerprintResult.MethodFingerprintScanResult.PatternScanResult? {
val instructions = this.implementation!!.instructions
val fingerprintFuzzyPatternScanThreshold = fingerprint.fuzzyScanThreshold

Expand Down Expand Up @@ -131,7 +148,8 @@ object MethodFingerprintUtils {
continue
}
// 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
result.warnings = result.createWarnings(pattern, instructions)

Expand All @@ -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>
) = buildList {
for ((patternIndex, instructionIndex) in (this@createWarnings.startIndex until this@createWarnings.endIndex).withIndex()) {
Expand All @@ -152,7 +173,14 @@ private fun PatternScanResult.createWarnings(

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

Expand Down

0 comments on commit 3813e28

Please sign in to comment.