Skip to content

Commit 319a8a7

Browse files
code documentation
1 parent 2b6e437 commit 319a8a7

File tree

4 files changed

+89
-20
lines changed

4 files changed

+89
-20
lines changed

api/revanced-patcher.api

-2
Original file line numberDiff line numberDiff line change
@@ -178,8 +178,6 @@ public final class app/revanced/patcher/OpcodeFilter$Companion {
178178
}
179179

180180
public class app/revanced/patcher/OpcodesFilter : app/revanced/patcher/InstructionFilter {
181-
public fun <init> (Ljava/util/EnumSet;I)V
182-
public synthetic fun <init> (Ljava/util/EnumSet;IILkotlin/jvm/internal/DefaultConstructorMarker;)V
183181
public fun <init> (Ljava/util/List;I)V
184182
public synthetic fun <init> (Ljava/util/List;IILkotlin/jvm/internal/DefaultConstructorMarker;)V
185183
public final fun getOpcodes ()Ljava/util/EnumSet;

build.gradle.kts

+1
Original file line numberDiff line numberDiff line change
@@ -115,5 +115,6 @@ publishing {
115115

116116
signing {
117117
useGpgCmd()
118+
// NOTE: If doing local dev work then comment out or remove this sign task.
118119
sign(publishing.publications["revanced-patcher-publication"])
119120
}

src/main/kotlin/app/revanced/patcher/Fingerprint.kt

+5-2
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ class Fingerprint internal constructor(
8181
private var _matchOrNull: Match? = null
8282

8383
/**
84-
* The match for this [Fingerprint], or Null if no matches exist.
84+
* The match for this [Fingerprint], or `null` if no matches exist.
8585
*/
8686
fun matchOrNull(): Match? {
8787
if (_matchOrNull != null) return _matchOrNull
@@ -619,7 +619,10 @@ class FingerprintBuilder(val name: String) {
619619
}
620620

621621
/**
622-
* Set the opcodes.
622+
* A pattern of opcodes.
623+
*
624+
* To use opcodes with other [InstructionFilter] objects, instead use
625+
* [instructions] with individual opcodes declared using [OpcodeFilter].
623626
*
624627
* @param opcodes An opcode pattern of instructions.
625628
* Wildcard or unknown opcodes can be specified by `null`.

src/main/kotlin/app/revanced/patcher/InstructionFilter.kt

+83-16
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,24 @@ import com.android.tools.smali.dexlib2.iface.reference.TypeReference
1414
import java.util.EnumSet
1515
import kotlin.collections.forEach
1616

17+
/**
18+
* Matches method [Instruction] objects, similar to how [Fingerprint] matches entire fingerprints.
19+
*
20+
* The most basic filters match only opcodes and nothing more,
21+
* and more precise filters can match:
22+
* - Field references (get/put opcodes) by name/type.
23+
* - Method calls (invoke_* opcodes) by name/parameter/return type.
24+
* - Object instantiation for specific class types.
25+
* - Literal const values.
26+
*
27+
* Variable space is allowed between each filter.
28+
*
29+
* By default [OpcodeFilter] and [OpcodesFilter] use a default [maxInstructionsBefore] of zero,
30+
* meaning the opcode must be immediately after the previous filter.
31+
*
32+
* All other filters use a default [maxInstructionsBefore] of [METHOD_MAX_INSTRUCTIONS] meaning
33+
* they can match anywhere after the previous filter.
34+
*/
1735
abstract class InstructionFilter(
1836
/**
1937
* Maximum number of non matching method instructions that can appear before this filter.
@@ -23,6 +41,12 @@ abstract class InstructionFilter(
2341
val maxInstructionsBefore: Int = METHOD_MAX_INSTRUCTIONS
2442
) {
2543

44+
/**
45+
* If this filter matches the method instruction.
46+
*
47+
* method index can be ignored unless a filter has an unusual reason,
48+
* such as checking for the last index of a method.
49+
*/
2650
abstract fun matches(
2751
method: Method,
2852
instruction: Instruction,
@@ -32,6 +56,7 @@ abstract class InstructionFilter(
3256
companion object {
3357
/**
3458
* Maximum number of instructions allowed in a Java method.
59+
* Indicates to allow a match anywhere after the previous filter.
3560
*/
3661
const val METHOD_MAX_INSTRUCTIONS = 65535
3762
}
@@ -54,6 +79,7 @@ class AnyFilter(
5479
}
5580
}
5681

82+
5783
/**
5884
* Single opcode.
5985
*/
@@ -71,6 +97,12 @@ class OpcodeFilter(
7197
}
7298

7399
companion object {
100+
/**
101+
* First opcode can match anywhere in a method, but all
102+
* subsequent opcodes must match after the previous opcode.
103+
*
104+
* A value of `null` indicates to match any opcode.
105+
*/
74106
fun listOfOpcodes(opcodes: Collection<Opcode?>): List<InstructionFilter> {
75107
var list = ArrayList<InstructionFilter>(opcodes.size)
76108

@@ -91,21 +123,19 @@ class OpcodeFilter(
91123
}
92124
}
93125

126+
94127
/**
95128
* Matches multiple opcodes.
96129
* If using only a single opcode instead use [OpcodeFilter].
97130
*/
98-
open class OpcodesFilter(
99-
/**
100-
* Value of null will match any opcode.
101-
*/
131+
open class OpcodesFilter private constructor(
102132
val opcodes: EnumSet<Opcode>?,
103-
maxInstructionsBefore: Int = METHOD_MAX_INSTRUCTIONS,
133+
maxInstructionsBefore: Int,
104134
) : InstructionFilter(maxInstructionsBefore) {
105135

106136
constructor(
107137
/**
108-
* Value of null will match any opcode.
138+
* Value of `null` will match any opcode.
109139
*/
110140
opcodes: List<Opcode>?,
111141
maxInstructionsBefore: Int = METHOD_MAX_INSTRUCTIONS
@@ -119,18 +149,31 @@ open class OpcodesFilter(
119149
if (opcodes == null) {
120150
return true // Match anything.
121151
}
122-
return opcodes.contains(instruction.opcode) == true
152+
return opcodes.contains(instruction.opcode)
123153
}
124154
}
125155

156+
157+
/**
158+
* Literal value, such as:
159+
* `const v1, 0x7f080318`
160+
*
161+
* that can be matched using:
162+
* `LiteralFilter(0x7f080318)`
163+
* or
164+
* `LiteralFilter(2131231512)`
165+
*
166+
* Use a lambda if the literal is not known at the declaration of this object such as:
167+
* `LiteralFilter({ OtherClass.findLiteralToUse() })`
168+
*/
126169
class LiteralFilter(
127170
var literal: () -> Long,
128171
opcodes: List<Opcode>? = null,
129172
maxInstructionsBefore: Int = METHOD_MAX_INSTRUCTIONS,
130173
) : OpcodesFilter(opcodes, maxInstructionsBefore) {
131174

132175
/**
133-
* Constant long literal.
176+
* Integer/Long literal.
134177
*/
135178
constructor(
136179
literal : Long,
@@ -160,6 +203,19 @@ class LiteralFilter(
160203
}
161204
}
162205

206+
/**
207+
* Filters opcode method calls.
208+
*
209+
* `Null` parameters matches anything.
210+
*
211+
* By default any type of method call matches.
212+
* Specify opcodes if a specific type of method call is desired (such as only static calls).
213+
*
214+
* Fingerprints can be used to find obfuscated class/method names to filter with,
215+
* such as:
216+
* `MethodFilter(definingClass = { fingerprint.originalClassDef.type },
217+
* methodName = { fingerprint.originalMethod.name })`
218+
*/
163219
class MethodFilter (
164220
/**
165221
* Defining class of the method call. Matches using endsWith().
@@ -310,40 +366,42 @@ class MethodFilter (
310366
private val regex = Regex("""^(L[^;]+;)->([^(\s]+)\(([^)]*)\)(.+)$""")
311367

312368
/**
313-
* Returns a filter for a JVM-style method signature. e.g.:
369+
* Returns a filter for a copy pasted JVM-style method signature. e.g.:
314370
* Landroid/view/View;->inflate(Landroid/content/Context;ILandroid/view/ViewGroup;)Landroid/view/View;
371+
*
372+
* Does not support obfuscated method names or parameter/return types.
315373
*/
316374
fun parseJvmMethodCall(
317375
methodSignature: String,
318376
) = parseJvmMethodCall(methodSignature, null, METHOD_MAX_INSTRUCTIONS)
319377

320378
/**
321-
* Returns a filter for a JVM-style method signature. e.g.:
379+
* Returns a filter for a copy pasted JVM-style method signature. e.g.:
322380
* Landroid/view/View;->inflate(Landroid/content/Context;ILandroid/view/ViewGroup;)Landroid/view/View;
323381
*
324-
* Does not support obfuscated method names or parameter/return types
382+
* Does not support obfuscated method names or parameter/return types.
325383
*/
326384
fun parseJvmMethodCall(
327385
methodSignature: String,
328386
maxInstructionsBefore: Int
329387
) = parseJvmMethodCall(methodSignature, null, maxInstructionsBefore)
330388

331389
/**
332-
* Returns a filter for a JVM-style method signature. e.g.:
390+
* Returns a filter for a copy pasted JVM-style method signature. e.g.:
333391
* Landroid/view/View;->inflate(Landroid/content/Context;ILandroid/view/ViewGroup;)Landroid/view/View;
334392
*
335-
* Does not support obfuscated method names or parameter/return types
393+
* Does not support obfuscated method names or parameter/return types.
336394
*/
337395
fun parseJvmMethodCall(
338396
methodSignature: String,
339397
opcodes: List<Opcode>?,
340398
) = parseJvmMethodCall(methodSignature, opcodes, METHOD_MAX_INSTRUCTIONS)
341399

342400
/**
343-
* Returns a filter for a JVM-style method signature. e.g.:
401+
* Returns a filter for a copy pasted JVM-style method signature. e.g.:
344402
* Landroid/view/View;->inflate(Landroid/content/Context;ILandroid/view/ViewGroup;)Landroid/view/View;
345403
*
346-
* Does not support obfuscated method names or parameter/return types
404+
* Does not support obfuscated method names or parameter/return types.
347405
*/
348406
fun parseJvmMethodCall(
349407
methodSignature: String,
@@ -415,14 +473,23 @@ class MethodFilter (
415473
}
416474
}
417475

476+
/**
477+
* Matches a field call, such as:
478+
* `iget-object v0, p0, Lahhh;->g:Landroid/view/View;`
479+
*
480+
* Using filter:
481+
* `FieldFilter(type ="Landroid/view/View;", opcode = Opcode.IGET_OBJECT)`
482+
*
483+
* If the field is a call to the defining class, use `this` as the declaring class:
484+
* `FieldFilter(definingClass = "this", type ="Landroid/view/View;", opcode = Opcode.IGET_OBJECT)`
485+
*/
418486
class FieldFilter(
419487
/**
420488
* Defining class of the field call. Matches using endsWith().
421489
*
422490
* For calls to a method in the same class, use 'this' as the defining class.
423491
* Note: 'this' does not work for fields found in superclasses.
424492
*/
425-
426493
val definingClass: (() -> String)? = null,
427494
/**
428495
* Name of the field. Must be a full match of the field name.

0 commit comments

Comments
 (0)