diff --git a/api/revanced-patcher.api b/api/revanced-patcher.api index 2f173eb..5e68eca 100644 --- a/api/revanced-patcher.api +++ b/api/revanced-patcher.api @@ -1,8 +1,29 @@ +public final class app/revanced/patcher/AnyInstruction : app/revanced/patcher/InstructionFilter { + public fun getLocation ()Lapp/revanced/patcher/InstructionLocation; + public fun matches (Lcom/android/tools/smali/dexlib2/iface/Method;Lcom/android/tools/smali/dexlib2/iface/instruction/Instruction;)Z +} + +public final class app/revanced/patcher/CheckCastFilter : app/revanced/patcher/OpcodeFilter { + public final fun getType ()Lkotlin/jvm/functions/Function0; + public fun matches (Lcom/android/tools/smali/dexlib2/iface/Method;Lcom/android/tools/smali/dexlib2/iface/instruction/Instruction;)Z + public final fun setType (Lkotlin/jvm/functions/Function0;)V +} + +public final class app/revanced/patcher/FieldAccessFilter : app/revanced/patcher/OpcodesFilter { + public final fun getDefiningClass ()Lkotlin/jvm/functions/Function0; + public final fun getName ()Lkotlin/jvm/functions/Function0; + public final fun getType ()Lkotlin/jvm/functions/Function0; + public fun matches (Lcom/android/tools/smali/dexlib2/iface/Method;Lcom/android/tools/smali/dexlib2/iface/instruction/Instruction;)Z +} + public final class app/revanced/patcher/Fingerprint { - public final fun getClassDef (Lapp/revanced/patcher/patch/BytecodePatchContext;)Lapp/revanced/patcher/util/proxy/mutableTypes/MutableClass; - public final fun getClassDefOrNull (Lapp/revanced/patcher/patch/BytecodePatchContext;)Lapp/revanced/patcher/util/proxy/mutableTypes/MutableClass; - public final fun getMethod (Lapp/revanced/patcher/patch/BytecodePatchContext;)Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod; - public final fun getMethodOrNull (Lapp/revanced/patcher/patch/BytecodePatchContext;)Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod; + public final fun clearMatch ()V + public final fun getClassDef (Lapp/revanced/patcher/patch/BytecodePatchContext;)Lapp/revanced/patcher/dex/mutable/MutableClassDef; + public final fun getClassDefOrNull (Lapp/revanced/patcher/patch/BytecodePatchContext;)Lapp/revanced/patcher/dex/mutable/MutableClassDef; + public final fun getInstructionMatches (Lapp/revanced/patcher/patch/BytecodePatchContext;)Ljava/util/List; + public final fun getInstructionMatchesOrNull (Lapp/revanced/patcher/patch/BytecodePatchContext;)Ljava/util/List; + public final fun getMethod (Lapp/revanced/patcher/patch/BytecodePatchContext;)Lapp/revanced/patcher/dex/mutable/MutableMethod; + public final fun getMethodOrNull (Lapp/revanced/patcher/patch/BytecodePatchContext;)Lapp/revanced/patcher/dex/mutable/MutableMethod; public final fun getOriginalClassDef (Lapp/revanced/patcher/patch/BytecodePatchContext;)Lcom/android/tools/smali/dexlib2/iface/ClassDef; public final fun getOriginalClassDefOrNull (Lapp/revanced/patcher/patch/BytecodePatchContext;)Lcom/android/tools/smali/dexlib2/iface/ClassDef; public final fun getOriginalMethod (Lapp/revanced/patcher/patch/BytecodePatchContext;)Lcom/android/tools/smali/dexlib2/iface/Method; @@ -11,19 +32,24 @@ public final class app/revanced/patcher/Fingerprint { public final fun getPatternMatchOrNull (Lapp/revanced/patcher/patch/BytecodePatchContext;)Lapp/revanced/patcher/Match$PatternMatch; public final fun getStringMatches (Lapp/revanced/patcher/patch/BytecodePatchContext;)Ljava/util/List; public final fun getStringMatchesOrNull (Lapp/revanced/patcher/patch/BytecodePatchContext;)Ljava/util/List; + public final fun match (Lapp/revanced/patcher/patch/BytecodePatchContext;)Lapp/revanced/patcher/Match; public final fun match (Lapp/revanced/patcher/patch/BytecodePatchContext;Lcom/android/tools/smali/dexlib2/iface/ClassDef;)Lapp/revanced/patcher/Match; public final fun match (Lapp/revanced/patcher/patch/BytecodePatchContext;Lcom/android/tools/smali/dexlib2/iface/Method;)Lapp/revanced/patcher/Match; public final fun match (Lapp/revanced/patcher/patch/BytecodePatchContext;Lcom/android/tools/smali/dexlib2/iface/Method;Lcom/android/tools/smali/dexlib2/iface/ClassDef;)Lapp/revanced/patcher/Match; + public final fun matchOrNull (Lapp/revanced/patcher/patch/BytecodePatchContext;)Lapp/revanced/patcher/Match; public final fun matchOrNull (Lapp/revanced/patcher/patch/BytecodePatchContext;Lcom/android/tools/smali/dexlib2/iface/ClassDef;)Lapp/revanced/patcher/Match; + public final fun matchOrNull (Lapp/revanced/patcher/patch/BytecodePatchContext;Lcom/android/tools/smali/dexlib2/iface/ClassDef;Lcom/android/tools/smali/dexlib2/iface/Method;)Lapp/revanced/patcher/Match; public final fun matchOrNull (Lapp/revanced/patcher/patch/BytecodePatchContext;Lcom/android/tools/smali/dexlib2/iface/Method;)Lapp/revanced/patcher/Match; - public final fun matchOrNull (Lapp/revanced/patcher/patch/BytecodePatchContext;Lcom/android/tools/smali/dexlib2/iface/Method;Lcom/android/tools/smali/dexlib2/iface/ClassDef;)Lapp/revanced/patcher/Match; + public final fun patchException ()Lapp/revanced/patcher/patch/PatchException; } public final class app/revanced/patcher/FingerprintBuilder { public fun ()V public final fun accessFlags (I)V public final fun accessFlags ([Lcom/android/tools/smali/dexlib2/AccessFlags;)V + public final fun build ()Lapp/revanced/patcher/Fingerprint; public final fun custom (Lkotlin/jvm/functions/Function2;)V + public final fun instructions ([Lapp/revanced/patcher/InstructionFilter;)V public final fun opcodes (Ljava/lang/String;)V public final fun opcodes ([Lcom/android/tools/smali/dexlib2/Opcode;)V public final fun parameters ([Ljava/lang/String;)V @@ -32,20 +58,139 @@ public final class app/revanced/patcher/FingerprintBuilder { } public final class app/revanced/patcher/FingerprintKt { - public static final fun fingerprint (ILkotlin/jvm/functions/Function1;)Lapp/revanced/patcher/Fingerprint; - public static synthetic fun fingerprint$default (ILkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lapp/revanced/patcher/Fingerprint; + public static final fun fingerprint (Lkotlin/jvm/functions/Function1;)Lapp/revanced/patcher/Fingerprint; +} + +public final class app/revanced/patcher/IndexedMatcher : app/revanced/patcher/Matcher { + public fun ()V + public final fun after (IILkotlin/jvm/functions/Function1;)Z + public static synthetic fun after$default (Lapp/revanced/patcher/IndexedMatcher;IILkotlin/jvm/functions/Function1;ILjava/lang/Object;)Z + public final fun contains (Ljava/lang/Object;)Z + public fun contains (Lkotlin/jvm/functions/Function1;)Z + public final fun first (Lkotlin/jvm/functions/Function1;)Z + public final fun getIndices ()Ljava/util/List; + public final fun indexOf (Ljava/lang/Object;)I + public fun indexOf (Lkotlin/jvm/functions/Function1;)I + public fun invoke (Ljava/lang/Iterable;)Z + public final fun lastIndexOf (Ljava/lang/Object;)I + public fun lastIndexOf (Lkotlin/jvm/functions/Function1;)I + public final fun remove (I)Lkotlin/jvm/functions/Function1; + public final fun remove (Ljava/lang/Object;)Z + public fun remove (Lkotlin/jvm/functions/Function1;)Z + public fun removeAt (I)Lkotlin/jvm/functions/Function1; +} + +public abstract interface class app/revanced/patcher/InstructionFilter { + public fun getLocation ()Lapp/revanced/patcher/InstructionLocation; + public abstract fun matches (Lcom/android/tools/smali/dexlib2/iface/Method;Lcom/android/tools/smali/dexlib2/iface/instruction/Instruction;)Z +} + +public final class app/revanced/patcher/InstructionFilter$DefaultImpls { + public static fun getLocation (Lapp/revanced/patcher/InstructionFilter;)Lapp/revanced/patcher/InstructionLocation; +} + +public final class app/revanced/patcher/InstructionFilterKt { + public static final fun anyInstruction ([Lapp/revanced/patcher/InstructionFilter;Lapp/revanced/patcher/InstructionLocation;)Lapp/revanced/patcher/AnyInstruction; + public static synthetic fun anyInstruction$default ([Lapp/revanced/patcher/InstructionFilter;Lapp/revanced/patcher/InstructionLocation;ILjava/lang/Object;)Lapp/revanced/patcher/AnyInstruction; + public static final fun checkCast (Ljava/lang/String;Lapp/revanced/patcher/InstructionLocation;)Lapp/revanced/patcher/CheckCastFilter; + public static final fun checkCast (Lkotlin/jvm/functions/Function0;Lapp/revanced/patcher/InstructionLocation;)Lapp/revanced/patcher/CheckCastFilter; + public static synthetic fun checkCast$default (Ljava/lang/String;Lapp/revanced/patcher/InstructionLocation;ILjava/lang/Object;)Lapp/revanced/patcher/CheckCastFilter; + public static synthetic fun checkCast$default (Lkotlin/jvm/functions/Function0;Lapp/revanced/patcher/InstructionLocation;ILjava/lang/Object;)Lapp/revanced/patcher/CheckCastFilter; + public static final fun fieldAccess (Ljava/lang/String;Lcom/android/tools/smali/dexlib2/Opcode;Lapp/revanced/patcher/InstructionLocation;)Lapp/revanced/patcher/FieldAccessFilter; + public static final fun fieldAccess (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/android/tools/smali/dexlib2/Opcode;Lapp/revanced/patcher/InstructionLocation;)Lapp/revanced/patcher/FieldAccessFilter; + public static final fun fieldAccess (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/List;Lapp/revanced/patcher/InstructionLocation;)Lapp/revanced/patcher/FieldAccessFilter; + public static final fun fieldAccess (Ljava/lang/String;Ljava/util/List;Lapp/revanced/patcher/InstructionLocation;)Lapp/revanced/patcher/FieldAccessFilter; + public static final fun fieldAccess (Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function0;Ljava/util/List;Lapp/revanced/patcher/InstructionLocation;)Lapp/revanced/patcher/FieldAccessFilter; + public static synthetic fun fieldAccess$default (Ljava/lang/String;Lcom/android/tools/smali/dexlib2/Opcode;Lapp/revanced/patcher/InstructionLocation;ILjava/lang/Object;)Lapp/revanced/patcher/FieldAccessFilter; + public static synthetic fun fieldAccess$default (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/android/tools/smali/dexlib2/Opcode;Lapp/revanced/patcher/InstructionLocation;ILjava/lang/Object;)Lapp/revanced/patcher/FieldAccessFilter; + public static synthetic fun fieldAccess$default (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/List;Lapp/revanced/patcher/InstructionLocation;ILjava/lang/Object;)Lapp/revanced/patcher/FieldAccessFilter; + public static synthetic fun fieldAccess$default (Ljava/lang/String;Ljava/util/List;Lapp/revanced/patcher/InstructionLocation;ILjava/lang/Object;)Lapp/revanced/patcher/FieldAccessFilter; + public static synthetic fun fieldAccess$default (Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function0;Ljava/util/List;Lapp/revanced/patcher/InstructionLocation;ILjava/lang/Object;)Lapp/revanced/patcher/FieldAccessFilter; + public static final fun literal (DLjava/util/List;Lapp/revanced/patcher/InstructionLocation;)Lapp/revanced/patcher/LiteralFilter; + public static final fun literal (FLjava/util/List;Lapp/revanced/patcher/InstructionLocation;)Lapp/revanced/patcher/LiteralFilter; + public static final fun literal (ILjava/util/List;Lapp/revanced/patcher/InstructionLocation;)Lapp/revanced/patcher/LiteralFilter; + public static final fun literal (JLjava/util/List;Lapp/revanced/patcher/InstructionLocation;)Lapp/revanced/patcher/LiteralFilter; + public static final fun literal (Lkotlin/jvm/functions/Function0;Ljava/util/List;Lapp/revanced/patcher/InstructionLocation;)Lapp/revanced/patcher/LiteralFilter; + public static synthetic fun literal$default (DLjava/util/List;Lapp/revanced/patcher/InstructionLocation;ILjava/lang/Object;)Lapp/revanced/patcher/LiteralFilter; + public static synthetic fun literal$default (FLjava/util/List;Lapp/revanced/patcher/InstructionLocation;ILjava/lang/Object;)Lapp/revanced/patcher/LiteralFilter; + public static synthetic fun literal$default (ILjava/util/List;Lapp/revanced/patcher/InstructionLocation;ILjava/lang/Object;)Lapp/revanced/patcher/LiteralFilter; + public static synthetic fun literal$default (JLjava/util/List;Lapp/revanced/patcher/InstructionLocation;ILjava/lang/Object;)Lapp/revanced/patcher/LiteralFilter; + public static synthetic fun literal$default (Lkotlin/jvm/functions/Function0;Ljava/util/List;Lapp/revanced/patcher/InstructionLocation;ILjava/lang/Object;)Lapp/revanced/patcher/LiteralFilter; + public static final fun methodCall (Ljava/lang/String;Lcom/android/tools/smali/dexlib2/Opcode;Lapp/revanced/patcher/InstructionLocation;)Lapp/revanced/patcher/MethodCallFilter; + public static final fun methodCall (Ljava/lang/String;Ljava/lang/String;Ljava/util/List;Ljava/lang/String;Lcom/android/tools/smali/dexlib2/Opcode;Lapp/revanced/patcher/InstructionLocation;)Lapp/revanced/patcher/MethodCallFilter; + public static final fun methodCall (Ljava/lang/String;Ljava/lang/String;Ljava/util/List;Ljava/lang/String;Ljava/util/List;Lapp/revanced/patcher/InstructionLocation;)Lapp/revanced/patcher/MethodCallFilter; + public static final fun methodCall (Ljava/lang/String;Ljava/util/List;Lapp/revanced/patcher/InstructionLocation;)Lapp/revanced/patcher/MethodCallFilter; + public static final fun methodCall (Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function0;Ljava/util/List;Lapp/revanced/patcher/InstructionLocation;)Lapp/revanced/patcher/MethodCallFilter; + public static synthetic fun methodCall$default (Ljava/lang/String;Lcom/android/tools/smali/dexlib2/Opcode;Lapp/revanced/patcher/InstructionLocation;ILjava/lang/Object;)Lapp/revanced/patcher/MethodCallFilter; + public static synthetic fun methodCall$default (Ljava/lang/String;Ljava/lang/String;Ljava/util/List;Ljava/lang/String;Lcom/android/tools/smali/dexlib2/Opcode;Lapp/revanced/patcher/InstructionLocation;ILjava/lang/Object;)Lapp/revanced/patcher/MethodCallFilter; + public static synthetic fun methodCall$default (Ljava/lang/String;Ljava/lang/String;Ljava/util/List;Ljava/lang/String;Ljava/util/List;Lapp/revanced/patcher/InstructionLocation;ILjava/lang/Object;)Lapp/revanced/patcher/MethodCallFilter; + public static synthetic fun methodCall$default (Ljava/lang/String;Ljava/util/List;Lapp/revanced/patcher/InstructionLocation;ILjava/lang/Object;)Lapp/revanced/patcher/MethodCallFilter; + public static synthetic fun methodCall$default (Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function0;Ljava/util/List;Lapp/revanced/patcher/InstructionLocation;ILjava/lang/Object;)Lapp/revanced/patcher/MethodCallFilter; + public static final fun newInstance (Ljava/lang/String;Lapp/revanced/patcher/InstructionLocation;)Lapp/revanced/patcher/NewInstanceFilter; + public static synthetic fun newInstance$default (Ljava/lang/String;Lapp/revanced/patcher/InstructionLocation;ILjava/lang/Object;)Lapp/revanced/patcher/NewInstanceFilter; + public static final fun newInstancetype (Lkotlin/jvm/functions/Function0;Lapp/revanced/patcher/InstructionLocation;)Lapp/revanced/patcher/NewInstanceFilter; + public static synthetic fun newInstancetype$default (Lkotlin/jvm/functions/Function0;Lapp/revanced/patcher/InstructionLocation;ILjava/lang/Object;)Lapp/revanced/patcher/NewInstanceFilter; + public static final fun opcode (Lcom/android/tools/smali/dexlib2/Opcode;Lapp/revanced/patcher/InstructionLocation;)Lapp/revanced/patcher/OpcodeFilter; + public static synthetic fun opcode$default (Lcom/android/tools/smali/dexlib2/Opcode;Lapp/revanced/patcher/InstructionLocation;ILjava/lang/Object;)Lapp/revanced/patcher/OpcodeFilter; + public static final fun string (Ljava/lang/String;Lapp/revanced/patcher/StringMatchType;Lapp/revanced/patcher/InstructionLocation;)Lapp/revanced/patcher/StringFilter; + public static final fun string (Lkotlin/jvm/functions/Function0;Lapp/revanced/patcher/StringMatchType;Lapp/revanced/patcher/InstructionLocation;)Lapp/revanced/patcher/StringFilter; + public static synthetic fun string$default (Ljava/lang/String;Lapp/revanced/patcher/StringMatchType;Lapp/revanced/patcher/InstructionLocation;ILjava/lang/Object;)Lapp/revanced/patcher/StringFilter; + public static synthetic fun string$default (Lkotlin/jvm/functions/Function0;Lapp/revanced/patcher/StringMatchType;Lapp/revanced/patcher/InstructionLocation;ILjava/lang/Object;)Lapp/revanced/patcher/StringFilter; +} + +public abstract interface class app/revanced/patcher/InstructionLocation { + public abstract fun indexIsValidForMatching (II)Z +} + +public final class app/revanced/patcher/InstructionLocation$MatchAfterAnywhere : app/revanced/patcher/InstructionLocation { + public fun ()V + public fun indexIsValidForMatching (II)Z +} + +public final class app/revanced/patcher/InstructionLocation$MatchAfterImmediately : app/revanced/patcher/InstructionLocation { + public fun ()V + public fun indexIsValidForMatching (II)Z +} + +public final class app/revanced/patcher/InstructionLocation$MatchAfterWithin : app/revanced/patcher/InstructionLocation { + public fun (I)V + public final fun getMatchDistance ()I + public fun indexIsValidForMatching (II)Z + public final fun setMatchDistance (I)V +} + +public final class app/revanced/patcher/InstructionLocation$MatchFirst : app/revanced/patcher/InstructionLocation { + public fun ()V + public fun indexIsValidForMatching (II)Z } public abstract interface annotation class app/revanced/patcher/InternalApi : java/lang/annotation/Annotation { } +public final class app/revanced/patcher/LiteralFilter : app/revanced/patcher/OpcodesFilter { + public final fun getLiteral ()Lkotlin/jvm/functions/Function0; + public fun matches (Lcom/android/tools/smali/dexlib2/iface/Method;Lcom/android/tools/smali/dexlib2/iface/instruction/Instruction;)Z + public final fun setLiteral (Lkotlin/jvm/functions/Function0;)V +} + public final class app/revanced/patcher/Match { - public final fun getClassDef ()Lapp/revanced/patcher/util/proxy/mutableTypes/MutableClass; - public final fun getMethod ()Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod; + public final fun getClassDef ()Lapp/revanced/patcher/dex/mutable/MutableClassDef; + public final fun getContext ()Lapp/revanced/patcher/patch/BytecodePatchContext; + public final fun getInstructionMatches ()Ljava/util/List; + public final fun getInstructionMatchesOrNull ()Ljava/util/List; + public final fun getMethod ()Lapp/revanced/patcher/dex/mutable/MutableMethod; public final fun getOriginalClassDef ()Lcom/android/tools/smali/dexlib2/iface/ClassDef; public final fun getOriginalMethod ()Lcom/android/tools/smali/dexlib2/iface/Method; public final fun getPatternMatch ()Lapp/revanced/patcher/Match$PatternMatch; public final fun getStringMatches ()Ljava/util/List; + public final fun getStringMatchesOrNull ()Ljava/util/List; +} + +public final class app/revanced/patcher/Match$InstructionMatch { + public final fun getFilter ()Lapp/revanced/patcher/InstructionFilter; + public final fun getIndex ()I + public final fun getInstruction ()Lcom/android/tools/smali/dexlib2/iface/instruction/Instruction; + public final fun getInstruction ()Ljava/lang/Object; } public final class app/revanced/patcher/Match$PatternMatch { @@ -58,6 +203,177 @@ public final class app/revanced/patcher/Match$StringMatch { public final fun getString ()Ljava/lang/String; } +public abstract class app/revanced/patcher/Matcher : java/util/List, kotlin/jvm/internal/markers/KMutableList { + public fun ()V + public fun add (ILjava/lang/Object;)V + public fun add (Ljava/lang/Object;)Z + public fun addAll (ILjava/util/Collection;)Z + public fun addAll (Ljava/util/Collection;)Z + public fun clear ()V + public fun contains (Ljava/lang/Object;)Z + public fun containsAll (Ljava/util/Collection;)Z + public fun get (I)Ljava/lang/Object; + public final fun getMatchIndex ()I + public fun getSize ()I + public fun indexOf (Ljava/lang/Object;)I + public abstract fun invoke (Ljava/lang/Iterable;)Z + public fun isEmpty ()Z + public fun iterator ()Ljava/util/Iterator; + public fun lastIndexOf (Ljava/lang/Object;)I + public fun listIterator ()Ljava/util/ListIterator; + public fun listIterator (I)Ljava/util/ListIterator; + public final fun remove (I)Ljava/lang/Object; + public fun remove (Ljava/lang/Object;)Z + public fun removeAll (Ljava/util/Collection;)Z + public fun removeAt (I)Ljava/lang/Object; + public fun retainAll (Ljava/util/Collection;)Z + public fun set (ILjava/lang/Object;)Ljava/lang/Object; + protected final fun setMatchIndex (I)V + public final fun size ()I + public fun subList (II)Ljava/util/List; + public fun toArray ()[Ljava/lang/Object; + public fun toArray ([Ljava/lang/Object;)[Ljava/lang/Object; +} + +public final class app/revanced/patcher/Matcher$MatchContext : java/util/Map, kotlin/jvm/internal/markers/KMutableMap { + public fun clear ()V + public final fun containsKey (Ljava/lang/Object;)Z + public fun containsKey (Ljava/lang/String;)Z + public fun containsValue (Ljava/lang/Object;)Z + public final fun entrySet ()Ljava/util/Set; + public final fun get (Ljava/lang/Object;)Ljava/lang/Object; + public fun get (Ljava/lang/String;)Ljava/lang/Object; + public fun getEntries ()Ljava/util/Set; + public fun getKeys ()Ljava/util/Set; + public fun getSize ()I + public fun getValues ()Ljava/util/Collection; + public fun isEmpty ()Z + public final fun keySet ()Ljava/util/Set; + public synthetic fun put (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; + public fun put (Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object; + public fun putAll (Ljava/util/Map;)V + public final fun remove (Ljava/lang/Object;)Ljava/lang/Object; + public fun remove (Ljava/lang/String;)Ljava/lang/Object; + public final fun size ()I + public final fun values ()Ljava/util/Collection; +} + +public final class app/revanced/patcher/MatchingKt { + public static final fun a (Lapp/revanced/patcher/patch/BytecodePatchContext;)V + public static final fun anyAnnotation (Lcom/android/tools/smali/dexlib2/iface/ClassDef;Lkotlin/jvm/functions/Function1;)Z + public static final fun anyAnnotation (Lcom/android/tools/smali/dexlib2/iface/Method;Lkotlin/jvm/functions/Function1;)Z + public static final fun anyClassDef (Ljava/lang/Iterable;Lkotlin/jvm/functions/Function1;)Z + public static final fun anyDebugItem (Lcom/android/tools/smali/dexlib2/iface/MethodImplementation;Lkotlin/jvm/functions/Function1;)Z + public static final fun anyDirectMethod (Lcom/android/tools/smali/dexlib2/iface/ClassDef;Lkotlin/jvm/functions/Function1;)Z + public static final fun anyField (Lcom/android/tools/smali/dexlib2/iface/ClassDef;Lkotlin/jvm/functions/Function1;)Z + public static final fun anyHiddenApiRestriction (Lcom/android/tools/smali/dexlib2/iface/Method;Lkotlin/jvm/functions/Function1;)Z + public static final fun anyInstanceField (Lcom/android/tools/smali/dexlib2/iface/ClassDef;Lkotlin/jvm/functions/Function1;)Z + public static final fun anyInstruction (Lcom/android/tools/smali/dexlib2/iface/MethodImplementation;Lkotlin/jvm/functions/Function1;)Z + public static final fun anyInstruction (Ljava/lang/Iterable;Lkotlin/jvm/functions/Function1;)Z + public static final fun anyInterface (Lcom/android/tools/smali/dexlib2/iface/ClassDef;Lkotlin/jvm/functions/Function1;)Z + public static final fun anyMethod (Lcom/android/tools/smali/dexlib2/iface/ClassDef;Lkotlin/jvm/functions/Function1;)Z + public static final fun anyParameter (Lcom/android/tools/smali/dexlib2/iface/Method;Lkotlin/jvm/functions/Function1;)Z + public static final fun anyParameterType (Lcom/android/tools/smali/dexlib2/iface/Method;Lkotlin/jvm/functions/Function1;)Z + public static final fun anyStaticField (Lcom/android/tools/smali/dexlib2/iface/ClassDef;Lkotlin/jvm/functions/Function1;)Z + public static final fun anyTryBlock (Lcom/android/tools/smali/dexlib2/iface/MethodImplementation;Lkotlin/jvm/functions/Function1;)Z + public static final fun anyVirtualMethod (Lcom/android/tools/smali/dexlib2/iface/ClassDef;Lkotlin/jvm/functions/Function1;)Z + public static final fun firstClassDef (Lapp/revanced/patcher/patch/BytecodePatchContext;Ljava/lang/String;Lkotlin/jvm/functions/Function2;)Lcom/android/tools/smali/dexlib2/iface/ClassDef; + public static final fun firstClassDef (Lapp/revanced/patcher/patch/BytecodePatchContext;Lkotlin/jvm/functions/Function2;)Lcom/android/tools/smali/dexlib2/iface/ClassDef; + public static synthetic fun firstClassDef$default (Lapp/revanced/patcher/patch/BytecodePatchContext;Ljava/lang/String;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lcom/android/tools/smali/dexlib2/iface/ClassDef; + public static final fun firstClassDefMutable (Lapp/revanced/patcher/patch/BytecodePatchContext;Ljava/lang/String;Lkotlin/jvm/functions/Function2;)Lapp/revanced/patcher/dex/mutable/MutableClassDef; + public static final fun firstClassDefMutable (Lapp/revanced/patcher/patch/BytecodePatchContext;Lkotlin/jvm/functions/Function2;)Lapp/revanced/patcher/dex/mutable/MutableClassDef; + public static synthetic fun firstClassDefMutable$default (Lapp/revanced/patcher/patch/BytecodePatchContext;Ljava/lang/String;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lapp/revanced/patcher/dex/mutable/MutableClassDef; + public static final fun firstClassDefMutableOrNull (Lapp/revanced/patcher/patch/BytecodePatchContext;Ljava/lang/String;Lkotlin/jvm/functions/Function2;)Lapp/revanced/patcher/dex/mutable/MutableClassDef; + public static final fun firstClassDefMutableOrNull (Lapp/revanced/patcher/patch/BytecodePatchContext;Lkotlin/jvm/functions/Function2;)Lapp/revanced/patcher/dex/mutable/MutableClassDef; + public static synthetic fun firstClassDefMutableOrNull$default (Lapp/revanced/patcher/patch/BytecodePatchContext;Ljava/lang/String;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lapp/revanced/patcher/dex/mutable/MutableClassDef; + public static final fun firstClassDefOrNull (Lapp/revanced/patcher/patch/BytecodePatchContext;Ljava/lang/String;Lkotlin/jvm/functions/Function2;)Lcom/android/tools/smali/dexlib2/iface/ClassDef; + public static final fun firstClassDefOrNull (Lapp/revanced/patcher/patch/BytecodePatchContext;Lkotlin/jvm/functions/Function2;)Lcom/android/tools/smali/dexlib2/iface/ClassDef; + public static synthetic fun firstClassDefOrNull$default (Lapp/revanced/patcher/patch/BytecodePatchContext;Ljava/lang/String;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lcom/android/tools/smali/dexlib2/iface/ClassDef; + public static final fun firstMethod (Lapp/revanced/patcher/patch/BytecodePatchContext;Lkotlin/jvm/functions/Function2;)Lcom/android/tools/smali/dexlib2/iface/Method; + public static final fun firstMethod (Lapp/revanced/patcher/patch/BytecodePatchContext;[Ljava/lang/String;Lkotlin/jvm/functions/Function2;)Lcom/android/tools/smali/dexlib2/iface/Method; + public static final fun firstMethod (Ljava/lang/Iterable;Lkotlin/jvm/functions/Function2;)Lcom/android/tools/smali/dexlib2/iface/Method; + public static synthetic fun firstMethod$default (Lapp/revanced/patcher/patch/BytecodePatchContext;[Ljava/lang/String;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lcom/android/tools/smali/dexlib2/iface/Method; + public static final fun firstMethodMutable (Lapp/revanced/patcher/patch/BytecodePatchContext;Ljava/lang/Iterable;Lkotlin/jvm/functions/Function2;)Lapp/revanced/patcher/dex/mutable/MutableMethod; + public static final fun firstMethodMutable (Lapp/revanced/patcher/patch/BytecodePatchContext;Lkotlin/jvm/functions/Function2;)Lapp/revanced/patcher/dex/mutable/MutableMethod; + public static final fun firstMethodMutable (Lapp/revanced/patcher/patch/BytecodePatchContext;[Ljava/lang/String;Lkotlin/jvm/functions/Function2;)Lapp/revanced/patcher/dex/mutable/MutableMethod; + public static synthetic fun firstMethodMutable$default (Lapp/revanced/patcher/patch/BytecodePatchContext;[Ljava/lang/String;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lapp/revanced/patcher/dex/mutable/MutableMethod; + public static final fun firstMethodMutableOrNull (Lapp/revanced/patcher/patch/BytecodePatchContext;Ljava/lang/Iterable;Lkotlin/jvm/functions/Function2;)Lapp/revanced/patcher/dex/mutable/MutableMethod; + public static final fun firstMethodMutableOrNull (Lapp/revanced/patcher/patch/BytecodePatchContext;Lkotlin/jvm/functions/Function2;)Lapp/revanced/patcher/dex/mutable/MutableMethod; + public static final fun firstMethodMutableOrNull (Lapp/revanced/patcher/patch/BytecodePatchContext;[Ljava/lang/String;Lkotlin/jvm/functions/Function2;)Lapp/revanced/patcher/dex/mutable/MutableMethod; + public static synthetic fun firstMethodMutableOrNull$default (Lapp/revanced/patcher/patch/BytecodePatchContext;[Ljava/lang/String;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lapp/revanced/patcher/dex/mutable/MutableMethod; + public static final fun firstMethodOrNull (Lapp/revanced/patcher/patch/BytecodePatchContext;Lkotlin/jvm/functions/Function2;)Lcom/android/tools/smali/dexlib2/iface/Method; + public static final fun firstMethodOrNull (Lapp/revanced/patcher/patch/BytecodePatchContext;[Ljava/lang/String;Lkotlin/jvm/functions/Function2;)Lcom/android/tools/smali/dexlib2/iface/Method; + public static final fun firstMethodOrNull (Ljava/lang/Iterable;Lkotlin/jvm/functions/Function2;)Lcom/android/tools/smali/dexlib2/iface/Method; + public static synthetic fun firstMethodOrNull$default (Lapp/revanced/patcher/patch/BytecodePatchContext;[Ljava/lang/String;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lcom/android/tools/smali/dexlib2/iface/Method; + public static final fun gettingFirstClassDef (Ljava/lang/String;Lkotlin/jvm/functions/Function2;)Lkotlin/properties/ReadOnlyProperty; + public static final fun gettingFirstClassDef (Lkotlin/jvm/functions/Function2;)Lkotlin/properties/ReadOnlyProperty; + public static synthetic fun gettingFirstClassDef$default (Ljava/lang/String;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lkotlin/properties/ReadOnlyProperty; + public static final fun gettingFirstClassDefMutable (Ljava/lang/String;Lkotlin/jvm/functions/Function2;)Lkotlin/properties/ReadOnlyProperty; + public static final fun gettingFirstClassDefMutable (Lkotlin/jvm/functions/Function2;)Lkotlin/properties/ReadOnlyProperty; + public static synthetic fun gettingFirstClassDefMutable$default (Ljava/lang/String;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lkotlin/properties/ReadOnlyProperty; + public static final fun gettingFirstClassDefMutableOrNull (Ljava/lang/String;Lkotlin/jvm/functions/Function2;)Lkotlin/properties/ReadOnlyProperty; + public static final fun gettingFirstClassDefMutableOrNull (Lkotlin/jvm/functions/Function2;)Lkotlin/properties/ReadOnlyProperty; + public static synthetic fun gettingFirstClassDefMutableOrNull$default (Ljava/lang/String;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lkotlin/properties/ReadOnlyProperty; + public static final fun gettingFirstClassDefOrNull (Ljava/lang/String;Lkotlin/jvm/functions/Function2;)Lkotlin/properties/ReadOnlyProperty; + public static final fun gettingFirstClassDefOrNull (Lkotlin/jvm/functions/Function2;)Lkotlin/properties/ReadOnlyProperty; + public static synthetic fun gettingFirstClassDefOrNull$default (Ljava/lang/String;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lkotlin/properties/ReadOnlyProperty; + public static final fun gettingFirstMethod (Lkotlin/jvm/functions/Function2;)Lkotlin/properties/ReadOnlyProperty; + public static final fun gettingFirstMethod ([Ljava/lang/String;Lkotlin/jvm/functions/Function2;)Lkotlin/properties/ReadOnlyProperty; + public static synthetic fun gettingFirstMethod$default ([Ljava/lang/String;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lkotlin/properties/ReadOnlyProperty; + public static final fun gettingFirstMethodMutable (Lkotlin/jvm/functions/Function2;)Lkotlin/properties/ReadOnlyProperty; + public static final fun gettingFirstMethodMutable ([Ljava/lang/String;Lkotlin/jvm/functions/Function2;)Lkotlin/properties/ReadOnlyProperty; + public static synthetic fun gettingFirstMethodMutable$default ([Ljava/lang/String;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lkotlin/properties/ReadOnlyProperty; + public static final fun gettingFirstMethodMutableOrNull (Lkotlin/jvm/functions/Function2;)Lkotlin/properties/ReadOnlyProperty; + public static final fun gettingFirstMethodMutableOrNull ([Ljava/lang/String;Lkotlin/jvm/functions/Function2;)Lkotlin/properties/ReadOnlyProperty; + public static synthetic fun gettingFirstMethodMutableOrNull$default ([Ljava/lang/String;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lkotlin/properties/ReadOnlyProperty; + public static final fun gettingFirstMethodOrNull (Lkotlin/jvm/functions/Function2;)Lkotlin/properties/ReadOnlyProperty; + public static final fun gettingFirstMethodOrNull ([Ljava/lang/String;Lkotlin/jvm/functions/Function2;)Lkotlin/properties/ReadOnlyProperty; + public static synthetic fun gettingFirstMethodOrNull$default ([Ljava/lang/String;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lkotlin/properties/ReadOnlyProperty; + public static final fun implementation (Lcom/android/tools/smali/dexlib2/iface/Method;Lkotlin/jvm/functions/Function1;)Z + public static final fun indexedMatcher ()Lapp/revanced/patcher/IndexedMatcher; + public static final fun indexedMatcher (Lkotlin/jvm/functions/Function1;)Lapp/revanced/patcher/IndexedMatcher; + public static final fun invoke (Lapp/revanced/patcher/Matcher$MatchContext;Lapp/revanced/patcher/IndexedMatcher;Ljava/lang/Iterable;Ljava/lang/String;Lkotlin/jvm/functions/Function1;)Z + public static final fun matchIndexed (Lapp/revanced/patcher/Matcher$MatchContext;Ljava/lang/Iterable;Ljava/lang/String;Lkotlin/jvm/functions/Function1;)Z + public static final fun matchIndexed (Ljava/lang/Iterable;Lkotlin/jvm/functions/Function1;)Z + public static final fun matchers (Lapp/revanced/patcher/patch/BytecodePatchContext;)V +} + +public final class app/revanced/patcher/MethodCallFilter : app/revanced/patcher/OpcodesFilter { + public static final field Companion Lapp/revanced/patcher/MethodCallFilter$Companion; + public final fun getDefiningClass ()Lkotlin/jvm/functions/Function0; + public final fun getName ()Lkotlin/jvm/functions/Function0; + public final fun getParameters ()Lkotlin/jvm/functions/Function0; + public final fun getReturnType ()Lkotlin/jvm/functions/Function0; + public fun matches (Lcom/android/tools/smali/dexlib2/iface/Method;Lcom/android/tools/smali/dexlib2/iface/instruction/Instruction;)Z +} + +public final class app/revanced/patcher/MethodCallFilter$Companion { +} + +public final class app/revanced/patcher/NewInstanceFilter : app/revanced/patcher/OpcodesFilter { + public final fun getType ()Lkotlin/jvm/functions/Function0; + public fun matches (Lcom/android/tools/smali/dexlib2/iface/Method;Lcom/android/tools/smali/dexlib2/iface/instruction/Instruction;)Z + public final fun setType (Lkotlin/jvm/functions/Function0;)V +} + +public class app/revanced/patcher/OpcodeFilter : app/revanced/patcher/InstructionFilter { + public fun (Lcom/android/tools/smali/dexlib2/Opcode;Lapp/revanced/patcher/InstructionLocation;)V + public fun getLocation ()Lapp/revanced/patcher/InstructionLocation; + public final fun getOpcode ()Lcom/android/tools/smali/dexlib2/Opcode; + public fun matches (Lcom/android/tools/smali/dexlib2/iface/Method;Lcom/android/tools/smali/dexlib2/iface/instruction/Instruction;)Z +} + +public class app/revanced/patcher/OpcodesFilter : app/revanced/patcher/InstructionFilter { + public static final field Companion Lapp/revanced/patcher/OpcodesFilter$Companion; + protected fun (Ljava/util/List;Lapp/revanced/patcher/InstructionLocation;)V + public fun getLocation ()Lapp/revanced/patcher/InstructionLocation; + public final fun getOpcodes ()Ljava/util/EnumSet; + public fun matches (Lcom/android/tools/smali/dexlib2/iface/Method;Lcom/android/tools/smali/dexlib2/iface/instruction/Instruction;)Z +} + +public final class app/revanced/patcher/OpcodesFilter$Companion { +} + public final class app/revanced/patcher/PackageMetadata { public final fun getPackageName ()Ljava/lang/String; public final fun getPackageVersion ()Ljava/lang/String; @@ -101,49 +417,414 @@ public final class app/revanced/patcher/PatcherResult$PatchedResources { public final fun getResourcesApk ()Ljava/io/File; } -public final class app/revanced/patcher/extensions/ExtensionsKt { - public static final fun newLabel (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;I)Lcom/android/tools/smali/dexlib2/builder/Label; +public final class app/revanced/patcher/StringFilter : app/revanced/patcher/OpcodesFilter { + public final fun getMatchType ()Lapp/revanced/patcher/StringMatchType; + public final fun getString ()Lkotlin/jvm/functions/Function0; + public fun matches (Lcom/android/tools/smali/dexlib2/iface/Method;Lcom/android/tools/smali/dexlib2/iface/instruction/Instruction;)Z + public final fun setMatchType (Lapp/revanced/patcher/StringMatchType;)V + public final fun setString (Lkotlin/jvm/functions/Function0;)V } -public final class app/revanced/patcher/extensions/InstructionExtensions { - public static final field INSTANCE Lapp/revanced/patcher/extensions/InstructionExtensions; - public final fun addInstruction (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;ILcom/android/tools/smali/dexlib2/builder/BuilderInstruction;)V - public final fun addInstruction (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;ILjava/lang/String;)V - public final fun addInstruction (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;Lcom/android/tools/smali/dexlib2/builder/BuilderInstruction;)V - public final fun addInstruction (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;Ljava/lang/String;)V - public final fun addInstructions (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;ILjava/lang/String;)V - public final fun addInstructions (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;ILjava/util/List;)V - public final fun addInstructions (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;Ljava/lang/String;)V - public final fun addInstructions (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;Ljava/util/List;)V - public final fun addInstructions (Lcom/android/tools/smali/dexlib2/builder/MutableMethodImplementation;ILjava/util/List;)V - public final fun addInstructions (Lcom/android/tools/smali/dexlib2/builder/MutableMethodImplementation;Ljava/util/List;)V - public final fun addInstructionsWithLabels (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;ILjava/lang/String;[Lapp/revanced/patcher/util/smali/ExternalLabel;)V - public final fun getInstruction (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;I)Lcom/android/tools/smali/dexlib2/builder/BuilderInstruction; - public final fun getInstruction (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;I)Ljava/lang/Object; - public final fun getInstruction (Lcom/android/tools/smali/dexlib2/builder/MutableMethodImplementation;I)Lcom/android/tools/smali/dexlib2/builder/BuilderInstruction; - public final fun getInstruction (Lcom/android/tools/smali/dexlib2/builder/MutableMethodImplementation;I)Ljava/lang/Object; - public final fun getInstruction (Lcom/android/tools/smali/dexlib2/iface/Method;I)Lcom/android/tools/smali/dexlib2/iface/instruction/Instruction; - public final fun getInstruction (Lcom/android/tools/smali/dexlib2/iface/Method;I)Ljava/lang/Object; - public final fun getInstruction (Lcom/android/tools/smali/dexlib2/iface/MethodImplementation;I)Lcom/android/tools/smali/dexlib2/iface/instruction/Instruction; - public final fun getInstruction (Lcom/android/tools/smali/dexlib2/iface/MethodImplementation;I)Ljava/lang/Object; - public final fun getInstructionOrNull (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;I)Lcom/android/tools/smali/dexlib2/builder/BuilderInstruction; - public final fun getInstructionOrNull (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;I)Ljava/lang/Object; - public final fun getInstructionOrNull (Lcom/android/tools/smali/dexlib2/iface/Method;I)Lcom/android/tools/smali/dexlib2/iface/instruction/Instruction; - public final fun getInstructionOrNull (Lcom/android/tools/smali/dexlib2/iface/Method;I)Ljava/lang/Object; - public final fun getInstructions (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;)Ljava/util/List; - public final fun getInstructions (Lcom/android/tools/smali/dexlib2/iface/Method;)Ljava/lang/Iterable; - public final fun getInstructionsOrNull (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;)Ljava/util/List; - public final fun getInstructionsOrNull (Lcom/android/tools/smali/dexlib2/iface/Method;)Ljava/lang/Iterable; - public final fun removeInstruction (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;I)V - public final fun removeInstructions (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;I)V - public final fun removeInstructions (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;II)V - public final fun removeInstructions (Lcom/android/tools/smali/dexlib2/builder/MutableMethodImplementation;I)V - public final fun removeInstructions (Lcom/android/tools/smali/dexlib2/builder/MutableMethodImplementation;II)V - public final fun replaceInstruction (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;ILcom/android/tools/smali/dexlib2/builder/BuilderInstruction;)V - public final fun replaceInstruction (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;ILjava/lang/String;)V - public final fun replaceInstructions (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;ILjava/lang/String;)V - public final fun replaceInstructions (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;ILjava/util/List;)V - public final fun replaceInstructions (Lcom/android/tools/smali/dexlib2/builder/MutableMethodImplementation;ILjava/util/List;)V +public final class app/revanced/patcher/StringMatchType : java/lang/Enum { + public static final field CONTAINS Lapp/revanced/patcher/StringMatchType; + public static final field ENDS_WITH Lapp/revanced/patcher/StringMatchType; + public static final field EQUALS Lapp/revanced/patcher/StringMatchType; + public static final field STARTS_WITH Lapp/revanced/patcher/StringMatchType; + public static fun getEntries ()Lkotlin/enums/EnumEntries; + public static fun valueOf (Ljava/lang/String;)Lapp/revanced/patcher/StringMatchType; + public static fun values ()[Lapp/revanced/patcher/StringMatchType; +} + +public final class app/revanced/patcher/dex/mutable/MutableAnnotation : com/android/tools/smali/dexlib2/base/BaseAnnotation { + public static final field Companion Lapp/revanced/patcher/dex/mutable/MutableAnnotation$Companion; + public fun (Lcom/android/tools/smali/dexlib2/iface/Annotation;)V + public fun getElements ()Ljava/util/Set; + public fun getType ()Ljava/lang/String; + public fun getVisibility ()I +} + +public final class app/revanced/patcher/dex/mutable/MutableAnnotation$Companion { + public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/Annotation;)Lapp/revanced/patcher/dex/mutable/MutableAnnotation; +} + +public final class app/revanced/patcher/dex/mutable/MutableAnnotationElement : com/android/tools/smali/dexlib2/base/BaseAnnotationElement { + public static final field Companion Lapp/revanced/patcher/dex/mutable/MutableAnnotationElement$Companion; + public fun (Lcom/android/tools/smali/dexlib2/iface/AnnotationElement;)V + public fun getName ()Ljava/lang/String; + public fun getValue ()Lcom/android/tools/smali/dexlib2/iface/value/EncodedValue; + public final fun setName (Ljava/lang/String;)V + public final fun setValue (Lapp/revanced/patcher/dex/mutable/encodedValue/MutableEncodedValue;)V +} + +public final class app/revanced/patcher/dex/mutable/MutableAnnotationElement$Companion { + public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/AnnotationElement;)Lapp/revanced/patcher/dex/mutable/MutableAnnotationElement; +} + +public final class app/revanced/patcher/dex/mutable/MutableClassDef : com/android/tools/smali/dexlib2/base/reference/BaseTypeReference, com/android/tools/smali/dexlib2/iface/ClassDef { + public static final field Companion Lapp/revanced/patcher/dex/mutable/MutableClassDef$Companion; + public fun (Lcom/android/tools/smali/dexlib2/iface/ClassDef;)V + public final fun charAt (I)C + public fun get (I)C + public fun getAccessFlags ()I + public fun getAnnotations ()Ljava/util/Set; + public synthetic fun getDirectMethods ()Ljava/lang/Iterable; + public fun getDirectMethods ()Ljava/util/Set; + public synthetic fun getFields ()Ljava/lang/Iterable; + public fun getFields ()Ljava/util/Set; + public synthetic fun getInstanceFields ()Ljava/lang/Iterable; + public fun getInstanceFields ()Ljava/util/Set; + public fun getInterfaces ()Ljava/util/List; + public fun getLength ()I + public synthetic fun getMethods ()Ljava/lang/Iterable; + public fun getMethods ()Ljava/util/Set; + public fun getSourceFile ()Ljava/lang/String; + public synthetic fun getStaticFields ()Ljava/lang/Iterable; + public fun getStaticFields ()Ljava/util/Set; + public fun getSuperclass ()Ljava/lang/String; + public fun getType ()Ljava/lang/String; + public synthetic fun getVirtualMethods ()Ljava/lang/Iterable; + public fun getVirtualMethods ()Ljava/util/Set; + public final fun length ()I + public final fun setAccessFlags (I)V + public final fun setSourceFile (Ljava/lang/String;)V + public final fun setSuperClass (Ljava/lang/String;)V + public final fun setType (Ljava/lang/String;)V +} + +public final class app/revanced/patcher/dex/mutable/MutableClassDef$Companion { + public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/ClassDef;)Lapp/revanced/patcher/dex/mutable/MutableClassDef; +} + +public final class app/revanced/patcher/dex/mutable/MutableField : com/android/tools/smali/dexlib2/base/reference/BaseFieldReference, com/android/tools/smali/dexlib2/iface/Field { + public static final field Companion Lapp/revanced/patcher/dex/mutable/MutableField$Companion; + public fun (Lcom/android/tools/smali/dexlib2/iface/Field;)V + public fun getAccessFlags ()I + public fun getAnnotations ()Ljava/util/Set; + public fun getDefiningClass ()Ljava/lang/String; + public fun getHiddenApiRestrictions ()Ljava/util/Set; + public fun getInitialValue ()Lapp/revanced/patcher/dex/mutable/encodedValue/MutableEncodedValue; + public synthetic fun getInitialValue ()Lcom/android/tools/smali/dexlib2/iface/value/EncodedValue; + public fun getName ()Ljava/lang/String; + public fun getType ()Ljava/lang/String; + public final fun setAccessFlags (I)V + public final fun setDefiningClass (Ljava/lang/String;)V + public final fun setInitialValue (Lapp/revanced/patcher/dex/mutable/encodedValue/MutableEncodedValue;)V + public final fun setName (Ljava/lang/String;)V + public final fun setType (Ljava/lang/String;)V +} + +public final class app/revanced/patcher/dex/mutable/MutableField$Companion { + public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/Field;)Lapp/revanced/patcher/dex/mutable/MutableField; +} + +public final class app/revanced/patcher/dex/mutable/MutableMethod : com/android/tools/smali/dexlib2/base/reference/BaseMethodReference, com/android/tools/smali/dexlib2/iface/Method { + public static final field Companion Lapp/revanced/patcher/dex/mutable/MutableMethod$Companion; + public fun (Lcom/android/tools/smali/dexlib2/iface/Method;)V + public fun getAccessFlags ()I + public fun getAnnotations ()Ljava/util/Set; + public fun getDefiningClass ()Ljava/lang/String; + public fun getHiddenApiRestrictions ()Ljava/util/Set; + public fun getImplementation ()Lcom/android/tools/smali/dexlib2/builder/MutableMethodImplementation; + public synthetic fun getImplementation ()Lcom/android/tools/smali/dexlib2/iface/MethodImplementation; + public fun getName ()Ljava/lang/String; + public fun getParameterTypes ()Ljava/util/List; + public fun getParameters ()Ljava/util/List; + public fun getReturnType ()Ljava/lang/String; + public final fun setAccessFlags (I)V + public final fun setDefiningClass (Ljava/lang/String;)V + public final fun setName (Ljava/lang/String;)V + public final fun setReturnType (Ljava/lang/String;)V +} + +public final class app/revanced/patcher/dex/mutable/MutableMethod$Companion { + public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/Method;)Lapp/revanced/patcher/dex/mutable/MutableMethod; +} + +public final class app/revanced/patcher/dex/mutable/MutableMethodParameter : com/android/tools/smali/dexlib2/base/BaseMethodParameter, com/android/tools/smali/dexlib2/iface/MethodParameter { + public static final field Companion Lapp/revanced/patcher/dex/mutable/MutableMethodParameter$Companion; + public fun (Lcom/android/tools/smali/dexlib2/iface/MethodParameter;)V + public final fun charAt (I)C + public fun get (I)C + public fun getAnnotations ()Ljava/util/Set; + public fun getLength ()I + public fun getName ()Ljava/lang/String; + public fun getSignature ()Ljava/lang/String; + public fun getType ()Ljava/lang/String; + public final fun length ()I +} + +public final class app/revanced/patcher/dex/mutable/MutableMethodParameter$Companion { + public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/MethodParameter;)Lapp/revanced/patcher/dex/mutable/MutableMethodParameter; +} + +public final class app/revanced/patcher/dex/mutable/encodedValue/MutableAnnotationEncodedValue : com/android/tools/smali/dexlib2/base/value/BaseAnnotationEncodedValue, app/revanced/patcher/dex/mutable/encodedValue/MutableEncodedValue { + public static final field Companion Lapp/revanced/patcher/dex/mutable/encodedValue/MutableAnnotationEncodedValue$Companion; + public fun (Lcom/android/tools/smali/dexlib2/iface/value/AnnotationEncodedValue;)V + public fun getElements ()Ljava/util/Set; + public fun getType ()Ljava/lang/String; + public final fun setType (Ljava/lang/String;)V +} + +public final class app/revanced/patcher/dex/mutable/encodedValue/MutableAnnotationEncodedValue$Companion { + public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/AnnotationEncodedValue;)Lapp/revanced/patcher/dex/mutable/encodedValue/MutableAnnotationEncodedValue; +} + +public final class app/revanced/patcher/dex/mutable/encodedValue/MutableArrayEncodedValue : com/android/tools/smali/dexlib2/base/value/BaseArrayEncodedValue, app/revanced/patcher/dex/mutable/encodedValue/MutableEncodedValue { + public static final field Companion Lapp/revanced/patcher/dex/mutable/encodedValue/MutableArrayEncodedValue$Companion; + public fun (Lcom/android/tools/smali/dexlib2/iface/value/ArrayEncodedValue;)V + public fun getValue ()Ljava/util/List; +} + +public final class app/revanced/patcher/dex/mutable/encodedValue/MutableArrayEncodedValue$Companion { + public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/ArrayEncodedValue;)Lapp/revanced/patcher/dex/mutable/encodedValue/MutableArrayEncodedValue; +} + +public final class app/revanced/patcher/dex/mutable/encodedValue/MutableBooleanEncodedValue : com/android/tools/smali/dexlib2/base/value/BaseBooleanEncodedValue, app/revanced/patcher/dex/mutable/encodedValue/MutableEncodedValue { + public static final field Companion Lapp/revanced/patcher/dex/mutable/encodedValue/MutableBooleanEncodedValue$Companion; + public fun (Lcom/android/tools/smali/dexlib2/iface/value/BooleanEncodedValue;)V + public fun getValue ()Z + public final fun setValue (Z)V +} + +public final class app/revanced/patcher/dex/mutable/encodedValue/MutableBooleanEncodedValue$Companion { + public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/BooleanEncodedValue;)Lapp/revanced/patcher/dex/mutable/encodedValue/MutableBooleanEncodedValue; +} + +public final class app/revanced/patcher/dex/mutable/encodedValue/MutableByteEncodedValue : com/android/tools/smali/dexlib2/base/value/BaseByteEncodedValue, app/revanced/patcher/dex/mutable/encodedValue/MutableEncodedValue { + public static final field Companion Lapp/revanced/patcher/dex/mutable/encodedValue/MutableByteEncodedValue$Companion; + public fun (Lcom/android/tools/smali/dexlib2/iface/value/ByteEncodedValue;)V + public fun getValue ()B + public final fun setValue (B)V +} + +public final class app/revanced/patcher/dex/mutable/encodedValue/MutableByteEncodedValue$Companion { + public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/ByteEncodedValue;)Lapp/revanced/patcher/dex/mutable/encodedValue/MutableByteEncodedValue; +} + +public final class app/revanced/patcher/dex/mutable/encodedValue/MutableCharEncodedValue : com/android/tools/smali/dexlib2/base/value/BaseCharEncodedValue, app/revanced/patcher/dex/mutable/encodedValue/MutableEncodedValue { + public static final field Companion Lapp/revanced/patcher/dex/mutable/encodedValue/MutableCharEncodedValue$Companion; + public fun (Lcom/android/tools/smali/dexlib2/iface/value/CharEncodedValue;)V + public fun getValue ()C + public final fun setValue (C)V +} + +public final class app/revanced/patcher/dex/mutable/encodedValue/MutableCharEncodedValue$Companion { + public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/CharEncodedValue;)Lapp/revanced/patcher/dex/mutable/encodedValue/MutableCharEncodedValue; +} + +public final class app/revanced/patcher/dex/mutable/encodedValue/MutableDoubleEncodedValue : com/android/tools/smali/dexlib2/base/value/BaseDoubleEncodedValue, app/revanced/patcher/dex/mutable/encodedValue/MutableEncodedValue { + public static final field Companion Lapp/revanced/patcher/dex/mutable/encodedValue/MutableDoubleEncodedValue$Companion; + public fun (Lcom/android/tools/smali/dexlib2/iface/value/DoubleEncodedValue;)V + public fun getValue ()D + public final fun setValue (D)V +} + +public final class app/revanced/patcher/dex/mutable/encodedValue/MutableDoubleEncodedValue$Companion { + public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/DoubleEncodedValue;)Lapp/revanced/patcher/dex/mutable/encodedValue/MutableDoubleEncodedValue; +} + +public abstract interface class app/revanced/patcher/dex/mutable/encodedValue/MutableEncodedValue : com/android/tools/smali/dexlib2/iface/value/EncodedValue { + public static final field Companion Lapp/revanced/patcher/dex/mutable/encodedValue/MutableEncodedValue$Companion; +} + +public final class app/revanced/patcher/dex/mutable/encodedValue/MutableEncodedValue$Companion { + public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/EncodedValue;)Lapp/revanced/patcher/dex/mutable/encodedValue/MutableEncodedValue; +} + +public final class app/revanced/patcher/dex/mutable/encodedValue/MutableEnumEncodedValue : com/android/tools/smali/dexlib2/base/value/BaseEnumEncodedValue, app/revanced/patcher/dex/mutable/encodedValue/MutableEncodedValue { + public static final field Companion Lapp/revanced/patcher/dex/mutable/encodedValue/MutableEnumEncodedValue$Companion; + public fun (Lcom/android/tools/smali/dexlib2/iface/value/EnumEncodedValue;)V + public fun getValue ()Lcom/android/tools/smali/dexlib2/iface/reference/FieldReference; + public final fun setValue (Lcom/android/tools/smali/dexlib2/iface/reference/FieldReference;)V +} + +public final class app/revanced/patcher/dex/mutable/encodedValue/MutableEnumEncodedValue$Companion { + public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/EnumEncodedValue;)Lapp/revanced/patcher/dex/mutable/encodedValue/MutableEnumEncodedValue; +} + +public final class app/revanced/patcher/dex/mutable/encodedValue/MutableFieldEncodedValue : com/android/tools/smali/dexlib2/base/value/BaseFieldEncodedValue, app/revanced/patcher/dex/mutable/encodedValue/MutableEncodedValue { + public static final field Companion Lapp/revanced/patcher/dex/mutable/encodedValue/MutableFieldEncodedValue$Companion; + public fun (Lcom/android/tools/smali/dexlib2/iface/value/FieldEncodedValue;)V + public fun getValue ()Lcom/android/tools/smali/dexlib2/iface/reference/FieldReference; + public fun getValueType ()I + public final fun setValue (Lcom/android/tools/smali/dexlib2/iface/reference/FieldReference;)V +} + +public final class app/revanced/patcher/dex/mutable/encodedValue/MutableFieldEncodedValue$Companion { + public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/FieldEncodedValue;)Lapp/revanced/patcher/dex/mutable/encodedValue/MutableFieldEncodedValue; +} + +public final class app/revanced/patcher/dex/mutable/encodedValue/MutableFloatEncodedValue : com/android/tools/smali/dexlib2/base/value/BaseFloatEncodedValue, app/revanced/patcher/dex/mutable/encodedValue/MutableEncodedValue { + public static final field Companion Lapp/revanced/patcher/dex/mutable/encodedValue/MutableFloatEncodedValue$Companion; + public fun (Lcom/android/tools/smali/dexlib2/iface/value/FloatEncodedValue;)V + public fun getValue ()F + public final fun setValue (F)V +} + +public final class app/revanced/patcher/dex/mutable/encodedValue/MutableFloatEncodedValue$Companion { + public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/FloatEncodedValue;)Lapp/revanced/patcher/dex/mutable/encodedValue/MutableFloatEncodedValue; +} + +public final class app/revanced/patcher/dex/mutable/encodedValue/MutableIntEncodedValue : com/android/tools/smali/dexlib2/base/value/BaseIntEncodedValue, app/revanced/patcher/dex/mutable/encodedValue/MutableEncodedValue { + public static final field Companion Lapp/revanced/patcher/dex/mutable/encodedValue/MutableIntEncodedValue$Companion; + public fun (Lcom/android/tools/smali/dexlib2/iface/value/IntEncodedValue;)V + public fun getValue ()I + public final fun setValue (I)V +} + +public final class app/revanced/patcher/dex/mutable/encodedValue/MutableIntEncodedValue$Companion { + public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/IntEncodedValue;)Lapp/revanced/patcher/dex/mutable/encodedValue/MutableIntEncodedValue; +} + +public final class app/revanced/patcher/dex/mutable/encodedValue/MutableLongEncodedValue : com/android/tools/smali/dexlib2/base/value/BaseLongEncodedValue, app/revanced/patcher/dex/mutable/encodedValue/MutableEncodedValue { + public static final field Companion Lapp/revanced/patcher/dex/mutable/encodedValue/MutableLongEncodedValue$Companion; + public fun (Lcom/android/tools/smali/dexlib2/iface/value/LongEncodedValue;)V + public fun getValue ()J + public final fun setValue (J)V +} + +public final class app/revanced/patcher/dex/mutable/encodedValue/MutableLongEncodedValue$Companion { + public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/LongEncodedValue;)Lapp/revanced/patcher/dex/mutable/encodedValue/MutableLongEncodedValue; +} + +public final class app/revanced/patcher/dex/mutable/encodedValue/MutableMethodEncodedValue : com/android/tools/smali/dexlib2/base/value/BaseMethodEncodedValue, app/revanced/patcher/dex/mutable/encodedValue/MutableEncodedValue { + public static final field Companion Lapp/revanced/patcher/dex/mutable/encodedValue/MutableMethodEncodedValue$Companion; + public fun (Lcom/android/tools/smali/dexlib2/iface/value/MethodEncodedValue;)V + public fun getValue ()Lcom/android/tools/smali/dexlib2/iface/reference/MethodReference; + public final fun setValue (Lcom/android/tools/smali/dexlib2/iface/reference/MethodReference;)V +} + +public final class app/revanced/patcher/dex/mutable/encodedValue/MutableMethodEncodedValue$Companion { + public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/MethodEncodedValue;)Lapp/revanced/patcher/dex/mutable/encodedValue/MutableMethodEncodedValue; +} + +public final class app/revanced/patcher/dex/mutable/encodedValue/MutableMethodHandleEncodedValue : com/android/tools/smali/dexlib2/base/value/BaseMethodHandleEncodedValue, app/revanced/patcher/dex/mutable/encodedValue/MutableEncodedValue { + public static final field Companion Lapp/revanced/patcher/dex/mutable/encodedValue/MutableMethodHandleEncodedValue$Companion; + public fun (Lcom/android/tools/smali/dexlib2/iface/value/MethodHandleEncodedValue;)V + public fun getValue ()Lcom/android/tools/smali/dexlib2/iface/reference/MethodHandleReference; + public final fun setValue (Lcom/android/tools/smali/dexlib2/iface/reference/MethodHandleReference;)V +} + +public final class app/revanced/patcher/dex/mutable/encodedValue/MutableMethodHandleEncodedValue$Companion { + public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/MethodHandleEncodedValue;)Lapp/revanced/patcher/dex/mutable/encodedValue/MutableMethodHandleEncodedValue; +} + +public final class app/revanced/patcher/dex/mutable/encodedValue/MutableMethodTypeEncodedValue : com/android/tools/smali/dexlib2/base/value/BaseMethodTypeEncodedValue, app/revanced/patcher/dex/mutable/encodedValue/MutableEncodedValue { + public static final field Companion Lapp/revanced/patcher/dex/mutable/encodedValue/MutableMethodTypeEncodedValue$Companion; + public fun (Lcom/android/tools/smali/dexlib2/iface/value/MethodTypeEncodedValue;)V + public fun getValue ()Lcom/android/tools/smali/dexlib2/iface/reference/MethodProtoReference; + public final fun setValue (Lcom/android/tools/smali/dexlib2/iface/reference/MethodProtoReference;)V +} + +public final class app/revanced/patcher/dex/mutable/encodedValue/MutableMethodTypeEncodedValue$Companion { + public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/MethodTypeEncodedValue;)Lapp/revanced/patcher/dex/mutable/encodedValue/MutableMethodTypeEncodedValue; +} + +public final class app/revanced/patcher/dex/mutable/encodedValue/MutableNullEncodedValue : com/android/tools/smali/dexlib2/base/value/BaseNullEncodedValue, app/revanced/patcher/dex/mutable/encodedValue/MutableEncodedValue { + public static final field Companion Lapp/revanced/patcher/dex/mutable/encodedValue/MutableNullEncodedValue$Companion; + public fun ()V +} + +public final class app/revanced/patcher/dex/mutable/encodedValue/MutableNullEncodedValue$Companion { + public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/ByteEncodedValue;)Lapp/revanced/patcher/dex/mutable/encodedValue/MutableByteEncodedValue; +} + +public final class app/revanced/patcher/dex/mutable/encodedValue/MutableShortEncodedValue : com/android/tools/smali/dexlib2/base/value/BaseShortEncodedValue, app/revanced/patcher/dex/mutable/encodedValue/MutableEncodedValue { + public static final field Companion Lapp/revanced/patcher/dex/mutable/encodedValue/MutableShortEncodedValue$Companion; + public fun (Lcom/android/tools/smali/dexlib2/iface/value/ShortEncodedValue;)V + public fun getValue ()S + public final fun setValue (S)V +} + +public final class app/revanced/patcher/dex/mutable/encodedValue/MutableShortEncodedValue$Companion { + public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/ShortEncodedValue;)Lapp/revanced/patcher/dex/mutable/encodedValue/MutableShortEncodedValue; +} + +public final class app/revanced/patcher/dex/mutable/encodedValue/MutableStringEncodedValue : com/android/tools/smali/dexlib2/base/value/BaseStringEncodedValue, app/revanced/patcher/dex/mutable/encodedValue/MutableEncodedValue { + public static final field Companion Lapp/revanced/patcher/dex/mutable/encodedValue/MutableStringEncodedValue$Companion; + public fun (Lcom/android/tools/smali/dexlib2/iface/value/StringEncodedValue;)V + public fun getValue ()Ljava/lang/String; + public final fun setValue (Ljava/lang/String;)V +} + +public final class app/revanced/patcher/dex/mutable/encodedValue/MutableStringEncodedValue$Companion { + public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/ByteEncodedValue;)Lapp/revanced/patcher/dex/mutable/encodedValue/MutableByteEncodedValue; +} + +public final class app/revanced/patcher/dex/mutable/encodedValue/MutableTypeEncodedValue : com/android/tools/smali/dexlib2/base/value/BaseTypeEncodedValue, app/revanced/patcher/dex/mutable/encodedValue/MutableEncodedValue { + public static final field Companion Lapp/revanced/patcher/dex/mutable/encodedValue/MutableTypeEncodedValue$Companion; + public fun (Lcom/android/tools/smali/dexlib2/iface/value/TypeEncodedValue;)V + public fun getValue ()Ljava/lang/String; + public final fun setValue (Ljava/lang/String;)V +} + +public final class app/revanced/patcher/dex/mutable/encodedValue/MutableTypeEncodedValue$Companion { + public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/TypeEncodedValue;)Lapp/revanced/patcher/dex/mutable/encodedValue/MutableTypeEncodedValue; +} + +public final class app/revanced/patcher/extensions/ExternalLabel { + public fun (Ljava/lang/String;Lcom/android/tools/smali/dexlib2/iface/instruction/Instruction;)V + public final fun copy (Ljava/lang/String;Lcom/android/tools/smali/dexlib2/iface/instruction/Instruction;)Lapp/revanced/patcher/extensions/ExternalLabel; + public static synthetic fun copy$default (Lapp/revanced/patcher/extensions/ExternalLabel;Ljava/lang/String;Lcom/android/tools/smali/dexlib2/iface/instruction/Instruction;ILjava/lang/Object;)Lapp/revanced/patcher/extensions/ExternalLabel; + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class app/revanced/patcher/extensions/InstructionKt { + public static final fun fieldReference (Lcom/android/tools/smali/dexlib2/iface/instruction/Instruction;Ljava/lang/String;)Z + public static final fun fieldReference (Lcom/android/tools/smali/dexlib2/iface/instruction/Instruction;Lkotlin/jvm/functions/Function1;)Z + public static final fun getFieldReference (Lcom/android/tools/smali/dexlib2/iface/instruction/Instruction;)Lcom/android/tools/smali/dexlib2/iface/reference/FieldReference; + public static final fun getMethodReference (Lcom/android/tools/smali/dexlib2/iface/instruction/Instruction;)Lcom/android/tools/smali/dexlib2/iface/reference/MethodReference; + public static final fun getReference (Lcom/android/tools/smali/dexlib2/iface/instruction/Instruction;)Lcom/android/tools/smali/dexlib2/iface/reference/Reference; + public static final fun getStringReference (Lcom/android/tools/smali/dexlib2/iface/instruction/Instruction;)Lcom/android/tools/smali/dexlib2/iface/reference/StringReference; + public static final fun getTypeReference (Lcom/android/tools/smali/dexlib2/iface/instruction/Instruction;)Lcom/android/tools/smali/dexlib2/iface/reference/TypeReference; + public static final fun getWideLiteral (Lcom/android/tools/smali/dexlib2/iface/instruction/Instruction;)Ljava/lang/Long; + public static final fun methodReference (Lcom/android/tools/smali/dexlib2/iface/instruction/Instruction;Lcom/android/tools/smali/dexlib2/iface/reference/MethodReference;)Z + public static final fun methodReference (Lcom/android/tools/smali/dexlib2/iface/instruction/Instruction;Lkotlin/jvm/functions/Function1;)Z + public static final fun opcode (Lcom/android/tools/smali/dexlib2/iface/instruction/Instruction;Lcom/android/tools/smali/dexlib2/Opcode;)Z + public static final fun reference (Lcom/android/tools/smali/dexlib2/iface/instruction/Instruction;Lkotlin/jvm/functions/Function1;)Z + public static final fun reference2 (Lcom/android/tools/smali/dexlib2/iface/instruction/Instruction;Lkotlin/jvm/functions/Function1;)Z + public static final fun string (Lcom/android/tools/smali/dexlib2/iface/instruction/Instruction;Ljava/lang/String;)Z + public static final fun string (Lcom/android/tools/smali/dexlib2/iface/instruction/Instruction;Lkotlin/jvm/functions/Function1;)Z + public static final fun type (Lcom/android/tools/smali/dexlib2/iface/instruction/Instruction;Ljava/lang/String;)Z + public static final fun type (Lcom/android/tools/smali/dexlib2/iface/instruction/Instruction;Lkotlin/jvm/functions/Function1;)Z + public static final fun wideLiteral (Lcom/android/tools/smali/dexlib2/iface/instruction/Instruction;J)Z +} + +public final class app/revanced/patcher/extensions/MethodKt { + public static final fun accessFlags (Lcom/android/tools/smali/dexlib2/iface/Method;[Lcom/android/tools/smali/dexlib2/AccessFlags;)Z + public static final fun addInstructions (Lapp/revanced/patcher/dex/mutable/MutableMethod;ILjava/lang/String;)V + public static final fun addInstructions (Lapp/revanced/patcher/dex/mutable/MutableMethod;ILjava/util/List;)V + public static final fun addInstructions (Lapp/revanced/patcher/dex/mutable/MutableMethod;Ljava/lang/String;)V + public static final fun addInstructions (Lapp/revanced/patcher/dex/mutable/MutableMethod;Ljava/util/List;)V + public static final fun addInstructions (Lcom/android/tools/smali/dexlib2/builder/MutableMethodImplementation;ILjava/util/List;)V + public static final fun addInstructions (Lcom/android/tools/smali/dexlib2/builder/MutableMethodImplementation;Ljava/util/List;)V + public static final fun addInstructionsWithLabels (Lapp/revanced/patcher/dex/mutable/MutableMethod;ILjava/lang/String;[Lapp/revanced/patcher/extensions/ExternalLabel;)V + public static final fun getInstruction (Lapp/revanced/patcher/dex/mutable/MutableMethod;I)Lcom/android/tools/smali/dexlib2/builder/BuilderInstruction; + public static final fun getInstruction (Lapp/revanced/patcher/dex/mutable/MutableMethod;I)Ljava/lang/Object; + public static final fun getInstruction (Lcom/android/tools/smali/dexlib2/builder/MutableMethodImplementation;I)Lcom/android/tools/smali/dexlib2/builder/BuilderInstruction; + public static final fun getInstruction (Lcom/android/tools/smali/dexlib2/builder/MutableMethodImplementation;I)Ljava/lang/Object; + public static final fun getInstruction (Lcom/android/tools/smali/dexlib2/iface/Method;I)Lcom/android/tools/smali/dexlib2/iface/instruction/Instruction; + public static final fun getInstruction (Lcom/android/tools/smali/dexlib2/iface/Method;I)Ljava/lang/Object; + public static final fun getInstruction (Lcom/android/tools/smali/dexlib2/iface/MethodImplementation;I)Lcom/android/tools/smali/dexlib2/iface/instruction/Instruction; + public static final fun getInstruction (Lcom/android/tools/smali/dexlib2/iface/MethodImplementation;I)Ljava/lang/Object; + public static final fun getInstructionOrNull (Lapp/revanced/patcher/dex/mutable/MutableMethod;I)Lcom/android/tools/smali/dexlib2/builder/BuilderInstruction; + public static final fun getInstructionOrNull (Lapp/revanced/patcher/dex/mutable/MutableMethod;I)Ljava/lang/Object; + public static final fun getInstructionOrNull (Lcom/android/tools/smali/dexlib2/iface/Method;I)Lcom/android/tools/smali/dexlib2/iface/instruction/Instruction; + public static final fun getInstructionOrNull (Lcom/android/tools/smali/dexlib2/iface/Method;I)Ljava/lang/Object; + public static final fun getInstructions (Lapp/revanced/patcher/dex/mutable/MutableMethod;)Ljava/util/List; + public static final fun getInstructions (Lcom/android/tools/smali/dexlib2/iface/Method;)Ljava/lang/Iterable; + public static final fun getInstructionsOrNull (Lapp/revanced/patcher/dex/mutable/MutableMethod;)Ljava/util/List; + public static final fun getInstructionsOrNull (Lcom/android/tools/smali/dexlib2/iface/Method;)Ljava/lang/Iterable; + public static final fun newLabel (Lapp/revanced/patcher/dex/mutable/MutableMethod;I)Lcom/android/tools/smali/dexlib2/builder/Label; + public static final fun removeInstructions (Lapp/revanced/patcher/dex/mutable/MutableMethod;I)V + public static final fun removeInstructions (Lapp/revanced/patcher/dex/mutable/MutableMethod;II)V + public static final fun removeInstructions (Lcom/android/tools/smali/dexlib2/builder/MutableMethodImplementation;I)V + public static final fun removeInstructions (Lcom/android/tools/smali/dexlib2/builder/MutableMethodImplementation;II)V + public static final fun replaceInstructions (Lapp/revanced/patcher/dex/mutable/MutableMethod;ILjava/lang/String;)V + public static final fun replaceInstructions (Lapp/revanced/patcher/dex/mutable/MutableMethod;ILjava/util/List;)V + public static final fun replaceInstructions (Lcom/android/tools/smali/dexlib2/builder/MutableMethodImplementation;ILjava/util/List;)V } public final class app/revanced/patcher/patch/BytecodePatch : app/revanced/patcher/patch/Patch { @@ -159,13 +840,12 @@ public final class app/revanced/patcher/patch/BytecodePatchBuilder : app/revance } public final class app/revanced/patcher/patch/BytecodePatchContext : app/revanced/patcher/patch/PatchContext, java/io/Closeable { - public final fun classBy (Lkotlin/jvm/functions/Function1;)Lapp/revanced/patcher/util/proxy/ClassProxy; public fun close ()V public synthetic fun get ()Ljava/lang/Object; public fun get ()Ljava/util/Set; - public final fun getClasses ()Lapp/revanced/patcher/util/ProxyClassList; + public final fun getClassDefs ()Ljava/util/Set; + public final fun mutable (Lcom/android/tools/smali/dexlib2/iface/ClassDef;)Lapp/revanced/patcher/dex/mutable/MutableClassDef; public final fun navigate (Lcom/android/tools/smali/dexlib2/iface/reference/MethodReference;)Lapp/revanced/patcher/util/MethodNavigator; - public final fun proxy (Lcom/android/tools/smali/dexlib2/iface/ClassDef;)Lapp/revanced/patcher/util/proxy/ClassProxy; } public final class app/revanced/patcher/patch/Option { @@ -341,6 +1021,12 @@ public final class app/revanced/patcher/patch/PatchException : java/lang/Excepti public final class app/revanced/patcher/patch/PatchKt { public static final fun bytecodePatch (Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Lapp/revanced/patcher/patch/BytecodePatch; public static synthetic fun bytecodePatch$default (Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lapp/revanced/patcher/patch/BytecodePatch; + public static final fun gettingBytecodePatch (Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Lkotlin/properties/ReadOnlyProperty; + public static synthetic fun gettingBytecodePatch$default (Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lkotlin/properties/ReadOnlyProperty; + public static final fun gettingRawResourcePatch (Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Lkotlin/properties/ReadOnlyProperty; + public static synthetic fun gettingRawResourcePatch$default (Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lkotlin/properties/ReadOnlyProperty; + public static final fun gettingResourcePatch (Ljava/lang/String;ZLkotlin/jvm/functions/Function1;)Lkotlin/properties/ReadOnlyProperty; + public static synthetic fun gettingResourcePatch$default (Ljava/lang/String;ZLkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lkotlin/properties/ReadOnlyProperty; public static final fun loadPatchesFromDex (Ljava/util/Set;Ljava/io/File;)Lapp/revanced/patcher/patch/PatchLoader$Dex; public static synthetic fun loadPatchesFromDex$default (Ljava/util/Set;Ljava/io/File;ILjava/lang/Object;)Lapp/revanced/patcher/patch/PatchLoader$Dex; public static final fun loadPatchesFromJar (Ljava/util/Set;)Lapp/revanced/patcher/patch/PatchLoader$Jar; @@ -485,405 +1171,16 @@ public final class app/revanced/patcher/util/Document : java/io/Closeable, org/w } public final class app/revanced/patcher/util/MethodNavigator { - public final fun getValue (Ljava/lang/Void;Lkotlin/reflect/KProperty;)Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod; - public final fun original ()Lcom/android/tools/smali/dexlib2/iface/Method; - public final fun stop ()Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod; - public final fun to (ILkotlin/jvm/functions/Function1;)Lapp/revanced/patcher/util/MethodNavigator; - public final fun to ([I)Lapp/revanced/patcher/util/MethodNavigator; - public static synthetic fun to$default (Lapp/revanced/patcher/util/MethodNavigator;ILkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lapp/revanced/patcher/util/MethodNavigator; + public final fun getValue (Lapp/revanced/patcher/patch/BytecodePatchContext;Lkotlin/reflect/KProperty;)Lapp/revanced/patcher/dex/mutable/MutableMethod; + public final fun original (Lapp/revanced/patcher/patch/BytecodePatchContext;)Lcom/android/tools/smali/dexlib2/iface/Method; + public final fun stop (Lapp/revanced/patcher/patch/BytecodePatchContext;)Lapp/revanced/patcher/dex/mutable/MutableMethod; + public final fun to (Lapp/revanced/patcher/patch/BytecodePatchContext;ILkotlin/jvm/functions/Function1;)Lapp/revanced/patcher/util/MethodNavigator; + public final fun to (Lapp/revanced/patcher/patch/BytecodePatchContext;[I)Lapp/revanced/patcher/util/MethodNavigator; + public static synthetic fun to$default (Lapp/revanced/patcher/util/MethodNavigator;Lapp/revanced/patcher/patch/BytecodePatchContext;ILkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lapp/revanced/patcher/util/MethodNavigator; } -public final class app/revanced/patcher/util/ProxyClassList : java/util/List, kotlin/jvm/internal/markers/KMutableList { - public fun add (ILcom/android/tools/smali/dexlib2/iface/ClassDef;)V - public synthetic fun add (ILjava/lang/Object;)V - public fun add (Lcom/android/tools/smali/dexlib2/iface/ClassDef;)Z - public synthetic fun add (Ljava/lang/Object;)Z - public fun addAll (ILjava/util/Collection;)Z - public fun addAll (Ljava/util/Collection;)Z - public fun clear ()V - public fun contains (Lcom/android/tools/smali/dexlib2/iface/ClassDef;)Z - public final fun contains (Ljava/lang/Object;)Z - public fun containsAll (Ljava/util/Collection;)Z - public fun get (I)Lcom/android/tools/smali/dexlib2/iface/ClassDef; - public synthetic fun get (I)Ljava/lang/Object; - public fun getSize ()I - public fun indexOf (Lcom/android/tools/smali/dexlib2/iface/ClassDef;)I - public final fun indexOf (Ljava/lang/Object;)I - public fun isEmpty ()Z - public fun iterator ()Ljava/util/Iterator; - public fun lastIndexOf (Lcom/android/tools/smali/dexlib2/iface/ClassDef;)I - public final fun lastIndexOf (Ljava/lang/Object;)I - public fun listIterator ()Ljava/util/ListIterator; - public fun listIterator (I)Ljava/util/ListIterator; - public final fun remove (I)Lcom/android/tools/smali/dexlib2/iface/ClassDef; - public synthetic fun remove (I)Ljava/lang/Object; - public fun remove (Lcom/android/tools/smali/dexlib2/iface/ClassDef;)Z - public final fun remove (Ljava/lang/Object;)Z - public fun removeAll (Ljava/util/Collection;)Z - public fun removeAt (I)Lcom/android/tools/smali/dexlib2/iface/ClassDef; - public fun retainAll (Ljava/util/Collection;)Z - public fun set (ILcom/android/tools/smali/dexlib2/iface/ClassDef;)Lcom/android/tools/smali/dexlib2/iface/ClassDef; - public synthetic fun set (ILjava/lang/Object;)Ljava/lang/Object; - public final fun size ()I - public fun subList (II)Ljava/util/List; - public fun toArray ()[Ljava/lang/Object; - public fun toArray ([Ljava/lang/Object;)[Ljava/lang/Object; -} - -public final class app/revanced/patcher/util/proxy/ClassProxy { - public final fun getImmutableClass ()Lcom/android/tools/smali/dexlib2/iface/ClassDef; - public final fun getMutableClass ()Lapp/revanced/patcher/util/proxy/mutableTypes/MutableClass; -} - -public final class app/revanced/patcher/util/proxy/mutableTypes/MutableAnnotation : com/android/tools/smali/dexlib2/base/BaseAnnotation { - public static final field Companion Lapp/revanced/patcher/util/proxy/mutableTypes/MutableAnnotation$Companion; - public fun (Lcom/android/tools/smali/dexlib2/iface/Annotation;)V - public fun getElements ()Ljava/util/Set; - public fun getType ()Ljava/lang/String; - public fun getVisibility ()I -} - -public final class app/revanced/patcher/util/proxy/mutableTypes/MutableAnnotation$Companion { - public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/Annotation;)Lapp/revanced/patcher/util/proxy/mutableTypes/MutableAnnotation; -} - -public final class app/revanced/patcher/util/proxy/mutableTypes/MutableAnnotationElement : com/android/tools/smali/dexlib2/base/BaseAnnotationElement { - public static final field Companion Lapp/revanced/patcher/util/proxy/mutableTypes/MutableAnnotationElement$Companion; - public fun (Lcom/android/tools/smali/dexlib2/iface/AnnotationElement;)V - public fun getName ()Ljava/lang/String; - public fun getValue ()Lcom/android/tools/smali/dexlib2/iface/value/EncodedValue; - public final fun setName (Ljava/lang/String;)V - public final fun setValue (Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue;)V -} - -public final class app/revanced/patcher/util/proxy/mutableTypes/MutableAnnotationElement$Companion { - public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/AnnotationElement;)Lapp/revanced/patcher/util/proxy/mutableTypes/MutableAnnotationElement; -} - -public final class app/revanced/patcher/util/proxy/mutableTypes/MutableClass : com/android/tools/smali/dexlib2/base/reference/BaseTypeReference, com/android/tools/smali/dexlib2/iface/ClassDef { - public static final field Companion Lapp/revanced/patcher/util/proxy/mutableTypes/MutableClass$Companion; - public fun (Lcom/android/tools/smali/dexlib2/iface/ClassDef;)V - public final fun charAt (I)C - public fun get (I)C - public fun getAccessFlags ()I - public fun getAnnotations ()Ljava/util/Set; - public synthetic fun getDirectMethods ()Ljava/lang/Iterable; - public fun getDirectMethods ()Ljava/util/Set; - public synthetic fun getFields ()Ljava/lang/Iterable; - public fun getFields ()Ljava/util/Set; - public synthetic fun getInstanceFields ()Ljava/lang/Iterable; - public fun getInstanceFields ()Ljava/util/Set; - public fun getInterfaces ()Ljava/util/List; - public fun getLength ()I - public synthetic fun getMethods ()Ljava/lang/Iterable; - public fun getMethods ()Ljava/util/Set; - public fun getSourceFile ()Ljava/lang/String; - public synthetic fun getStaticFields ()Ljava/lang/Iterable; - public fun getStaticFields ()Ljava/util/Set; - public fun getSuperclass ()Ljava/lang/String; - public fun getType ()Ljava/lang/String; - public synthetic fun getVirtualMethods ()Ljava/lang/Iterable; - public fun getVirtualMethods ()Ljava/util/Set; - public final fun length ()I - public final fun setAccessFlags (I)V - public final fun setSourceFile (Ljava/lang/String;)V - public final fun setSuperClass (Ljava/lang/String;)V - public final fun setType (Ljava/lang/String;)V -} - -public final class app/revanced/patcher/util/proxy/mutableTypes/MutableClass$Companion { - public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/ClassDef;)Lapp/revanced/patcher/util/proxy/mutableTypes/MutableClass; -} - -public final class app/revanced/patcher/util/proxy/mutableTypes/MutableField : com/android/tools/smali/dexlib2/base/reference/BaseFieldReference, com/android/tools/smali/dexlib2/iface/Field { - public static final field Companion Lapp/revanced/patcher/util/proxy/mutableTypes/MutableField$Companion; - public fun (Lcom/android/tools/smali/dexlib2/iface/Field;)V - public fun getAccessFlags ()I - public fun getAnnotations ()Ljava/util/Set; - public fun getDefiningClass ()Ljava/lang/String; - public fun getHiddenApiRestrictions ()Ljava/util/Set; - public fun getInitialValue ()Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue; - public synthetic fun getInitialValue ()Lcom/android/tools/smali/dexlib2/iface/value/EncodedValue; - public fun getName ()Ljava/lang/String; - public fun getType ()Ljava/lang/String; - public final fun setAccessFlags (I)V - public final fun setDefiningClass (Ljava/lang/String;)V - public final fun setInitialValue (Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue;)V - public final fun setName (Ljava/lang/String;)V - public final fun setType (Ljava/lang/String;)V -} - -public final class app/revanced/patcher/util/proxy/mutableTypes/MutableField$Companion { - public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/Field;)Lapp/revanced/patcher/util/proxy/mutableTypes/MutableField; -} - -public final class app/revanced/patcher/util/proxy/mutableTypes/MutableMethod : com/android/tools/smali/dexlib2/base/reference/BaseMethodReference, com/android/tools/smali/dexlib2/iface/Method { - public static final field Companion Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod$Companion; - public fun (Lcom/android/tools/smali/dexlib2/iface/Method;)V - public fun getAccessFlags ()I - public fun getAnnotations ()Ljava/util/Set; - public fun getDefiningClass ()Ljava/lang/String; - public fun getHiddenApiRestrictions ()Ljava/util/Set; - public fun getImplementation ()Lcom/android/tools/smali/dexlib2/builder/MutableMethodImplementation; - public synthetic fun getImplementation ()Lcom/android/tools/smali/dexlib2/iface/MethodImplementation; - public fun getName ()Ljava/lang/String; - public fun getParameterTypes ()Ljava/util/List; - public fun getParameters ()Ljava/util/List; - public fun getReturnType ()Ljava/lang/String; - public final fun setAccessFlags (I)V - public final fun setDefiningClass (Ljava/lang/String;)V - public final fun setName (Ljava/lang/String;)V - public final fun setReturnType (Ljava/lang/String;)V -} - -public final class app/revanced/patcher/util/proxy/mutableTypes/MutableMethod$Companion { - public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/Method;)Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod; -} - -public final class app/revanced/patcher/util/proxy/mutableTypes/MutableMethodParameter : com/android/tools/smali/dexlib2/base/BaseMethodParameter, com/android/tools/smali/dexlib2/iface/MethodParameter { - public static final field Companion Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethodParameter$Companion; - public fun (Lcom/android/tools/smali/dexlib2/iface/MethodParameter;)V - public final fun charAt (I)C - public fun get (I)C - public fun getAnnotations ()Ljava/util/Set; - public fun getLength ()I - public fun getName ()Ljava/lang/String; - public fun getSignature ()Ljava/lang/String; - public fun getType ()Ljava/lang/String; - public final fun length ()I -} - -public final class app/revanced/patcher/util/proxy/mutableTypes/MutableMethodParameter$Companion { - public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/MethodParameter;)Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethodParameter; -} - -public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableAnnotationEncodedValue : com/android/tools/smali/dexlib2/base/value/BaseAnnotationEncodedValue, app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue { - public static final field Companion Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableAnnotationEncodedValue$Companion; - public fun (Lcom/android/tools/smali/dexlib2/iface/value/AnnotationEncodedValue;)V - public fun getElements ()Ljava/util/Set; - public fun getType ()Ljava/lang/String; - public final fun setType (Ljava/lang/String;)V -} - -public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableAnnotationEncodedValue$Companion { - public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/AnnotationEncodedValue;)Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableAnnotationEncodedValue; -} - -public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableArrayEncodedValue : com/android/tools/smali/dexlib2/base/value/BaseArrayEncodedValue, app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue { - public static final field Companion Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableArrayEncodedValue$Companion; - public fun (Lcom/android/tools/smali/dexlib2/iface/value/ArrayEncodedValue;)V - public fun getValue ()Ljava/util/List; -} - -public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableArrayEncodedValue$Companion { - public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/ArrayEncodedValue;)Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableArrayEncodedValue; -} - -public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableBooleanEncodedValue : com/android/tools/smali/dexlib2/base/value/BaseBooleanEncodedValue, app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue { - public static final field Companion Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableBooleanEncodedValue$Companion; - public fun (Lcom/android/tools/smali/dexlib2/iface/value/BooleanEncodedValue;)V - public fun getValue ()Z - public final fun setValue (Z)V -} - -public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableBooleanEncodedValue$Companion { - public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/BooleanEncodedValue;)Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableBooleanEncodedValue; -} - -public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableByteEncodedValue : com/android/tools/smali/dexlib2/base/value/BaseByteEncodedValue, app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue { - public static final field Companion Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableByteEncodedValue$Companion; - public fun (Lcom/android/tools/smali/dexlib2/iface/value/ByteEncodedValue;)V - public fun getValue ()B - public final fun setValue (B)V -} - -public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableByteEncodedValue$Companion { - public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/ByteEncodedValue;)Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableByteEncodedValue; -} - -public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableCharEncodedValue : com/android/tools/smali/dexlib2/base/value/BaseCharEncodedValue, app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue { - public static final field Companion Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableCharEncodedValue$Companion; - public fun (Lcom/android/tools/smali/dexlib2/iface/value/CharEncodedValue;)V - public fun getValue ()C - public final fun setValue (C)V -} - -public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableCharEncodedValue$Companion { - public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/CharEncodedValue;)Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableCharEncodedValue; -} - -public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableDoubleEncodedValue : com/android/tools/smali/dexlib2/base/value/BaseDoubleEncodedValue, app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue { - public static final field Companion Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableDoubleEncodedValue$Companion; - public fun (Lcom/android/tools/smali/dexlib2/iface/value/DoubleEncodedValue;)V - public fun getValue ()D - public final fun setValue (D)V -} - -public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableDoubleEncodedValue$Companion { - public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/DoubleEncodedValue;)Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableDoubleEncodedValue; -} - -public abstract interface class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue : com/android/tools/smali/dexlib2/iface/value/EncodedValue { - public static final field Companion Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue$Companion; -} - -public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue$Companion { - public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/EncodedValue;)Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue; -} - -public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEnumEncodedValue : com/android/tools/smali/dexlib2/base/value/BaseEnumEncodedValue, app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue { - public static final field Companion Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEnumEncodedValue$Companion; - public fun (Lcom/android/tools/smali/dexlib2/iface/value/EnumEncodedValue;)V - public fun getValue ()Lcom/android/tools/smali/dexlib2/iface/reference/FieldReference; - public final fun setValue (Lcom/android/tools/smali/dexlib2/iface/reference/FieldReference;)V -} - -public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEnumEncodedValue$Companion { - public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/EnumEncodedValue;)Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEnumEncodedValue; -} - -public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableFieldEncodedValue : com/android/tools/smali/dexlib2/base/value/BaseFieldEncodedValue, app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue { - public static final field Companion Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableFieldEncodedValue$Companion; - public fun (Lcom/android/tools/smali/dexlib2/iface/value/FieldEncodedValue;)V - public fun getValue ()Lcom/android/tools/smali/dexlib2/iface/reference/FieldReference; - public fun getValueType ()I - public final fun setValue (Lcom/android/tools/smali/dexlib2/iface/reference/FieldReference;)V -} - -public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableFieldEncodedValue$Companion { - public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/FieldEncodedValue;)Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableFieldEncodedValue; -} - -public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableFloatEncodedValue : com/android/tools/smali/dexlib2/base/value/BaseFloatEncodedValue, app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue { - public static final field Companion Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableFloatEncodedValue$Companion; - public fun (Lcom/android/tools/smali/dexlib2/iface/value/FloatEncodedValue;)V - public fun getValue ()F - public final fun setValue (F)V -} - -public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableFloatEncodedValue$Companion { - public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/FloatEncodedValue;)Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableFloatEncodedValue; -} - -public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableIntEncodedValue : com/android/tools/smali/dexlib2/base/value/BaseIntEncodedValue, app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue { - public static final field Companion Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableIntEncodedValue$Companion; - public fun (Lcom/android/tools/smali/dexlib2/iface/value/IntEncodedValue;)V - public fun getValue ()I - public final fun setValue (I)V -} - -public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableIntEncodedValue$Companion { - public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/IntEncodedValue;)Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableIntEncodedValue; -} - -public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableLongEncodedValue : com/android/tools/smali/dexlib2/base/value/BaseLongEncodedValue, app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue { - public static final field Companion Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableLongEncodedValue$Companion; - public fun (Lcom/android/tools/smali/dexlib2/iface/value/LongEncodedValue;)V - public fun getValue ()J - public final fun setValue (J)V -} - -public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableLongEncodedValue$Companion { - public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/LongEncodedValue;)Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableLongEncodedValue; -} - -public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableMethodEncodedValue : com/android/tools/smali/dexlib2/base/value/BaseMethodEncodedValue, app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue { - public static final field Companion Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableMethodEncodedValue$Companion; - public fun (Lcom/android/tools/smali/dexlib2/iface/value/MethodEncodedValue;)V - public fun getValue ()Lcom/android/tools/smali/dexlib2/iface/reference/MethodReference; - public final fun setValue (Lcom/android/tools/smali/dexlib2/iface/reference/MethodReference;)V -} - -public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableMethodEncodedValue$Companion { - public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/MethodEncodedValue;)Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableMethodEncodedValue; -} - -public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableMethodHandleEncodedValue : com/android/tools/smali/dexlib2/base/value/BaseMethodHandleEncodedValue, app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue { - public static final field Companion Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableMethodHandleEncodedValue$Companion; - public fun (Lcom/android/tools/smali/dexlib2/iface/value/MethodHandleEncodedValue;)V - public fun getValue ()Lcom/android/tools/smali/dexlib2/iface/reference/MethodHandleReference; - public final fun setValue (Lcom/android/tools/smali/dexlib2/iface/reference/MethodHandleReference;)V -} - -public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableMethodHandleEncodedValue$Companion { - public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/MethodHandleEncodedValue;)Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableMethodHandleEncodedValue; -} - -public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableMethodTypeEncodedValue : com/android/tools/smali/dexlib2/base/value/BaseMethodTypeEncodedValue, app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue { - public static final field Companion Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableMethodTypeEncodedValue$Companion; - public fun (Lcom/android/tools/smali/dexlib2/iface/value/MethodTypeEncodedValue;)V - public fun getValue ()Lcom/android/tools/smali/dexlib2/iface/reference/MethodProtoReference; - public final fun setValue (Lcom/android/tools/smali/dexlib2/iface/reference/MethodProtoReference;)V -} - -public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableMethodTypeEncodedValue$Companion { - public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/MethodTypeEncodedValue;)Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableMethodTypeEncodedValue; -} - -public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableNullEncodedValue : com/android/tools/smali/dexlib2/base/value/BaseNullEncodedValue, app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue { - public static final field Companion Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableNullEncodedValue$Companion; - public fun ()V -} - -public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableNullEncodedValue$Companion { - public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/ByteEncodedValue;)Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableByteEncodedValue; -} - -public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableShortEncodedValue : com/android/tools/smali/dexlib2/base/value/BaseShortEncodedValue, app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue { - public static final field Companion Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableShortEncodedValue$Companion; - public fun (Lcom/android/tools/smali/dexlib2/iface/value/ShortEncodedValue;)V - public fun getValue ()S - public final fun setValue (S)V -} - -public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableShortEncodedValue$Companion { - public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/ShortEncodedValue;)Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableShortEncodedValue; -} - -public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableStringEncodedValue : com/android/tools/smali/dexlib2/base/value/BaseStringEncodedValue, app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue { - public static final field Companion Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableStringEncodedValue$Companion; - public fun (Lcom/android/tools/smali/dexlib2/iface/value/StringEncodedValue;)V - public fun getValue ()Ljava/lang/String; - public final fun setValue (Ljava/lang/String;)V -} - -public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableStringEncodedValue$Companion { - public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/ByteEncodedValue;)Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableByteEncodedValue; -} - -public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableTypeEncodedValue : com/android/tools/smali/dexlib2/base/value/BaseTypeEncodedValue, app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableEncodedValue { - public static final field Companion Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableTypeEncodedValue$Companion; - public fun (Lcom/android/tools/smali/dexlib2/iface/value/TypeEncodedValue;)V - public fun getValue ()Ljava/lang/String; - public final fun setValue (Ljava/lang/String;)V -} - -public final class app/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableTypeEncodedValue$Companion { - public final fun toMutable (Lcom/android/tools/smali/dexlib2/iface/value/TypeEncodedValue;)Lapp/revanced/patcher/util/proxy/mutableTypes/encodedValue/MutableTypeEncodedValue; -} - -public final class app/revanced/patcher/util/smali/ExternalLabel { - public fun (Ljava/lang/String;Lcom/android/tools/smali/dexlib2/iface/instruction/Instruction;)V - public final fun copy (Ljava/lang/String;Lcom/android/tools/smali/dexlib2/iface/instruction/Instruction;)Lapp/revanced/patcher/util/smali/ExternalLabel; - public static synthetic fun copy$default (Lapp/revanced/patcher/util/smali/ExternalLabel;Ljava/lang/String;Lcom/android/tools/smali/dexlib2/iface/instruction/Instruction;ILjava/lang/Object;)Lapp/revanced/patcher/util/smali/ExternalLabel; - public fun equals (Ljava/lang/Object;)Z - public fun hashCode ()I - public fun toString ()Ljava/lang/String; -} - -public final class app/revanced/patcher/util/smali/InlineSmaliCompiler { - public static final field Companion Lapp/revanced/patcher/util/smali/InlineSmaliCompiler$Companion; - public fun ()V -} - -public final class app/revanced/patcher/util/smali/InlineSmaliCompiler$Companion { - public final fun compile (Ljava/lang/String;Ljava/lang/String;IZ)Ljava/util/List; -} - -public final class app/revanced/patcher/util/smali/InlineSmaliCompilerKt { - public static final fun toInstruction (Ljava/lang/String;Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;)Lcom/android/tools/smali/dexlib2/builder/BuilderInstruction; - public static synthetic fun toInstruction$default (Ljava/lang/String;Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;ILjava/lang/Object;)Lcom/android/tools/smali/dexlib2/builder/BuilderInstruction; - public static final fun toInstructions (Ljava/lang/String;Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;)Ljava/util/List; - public static synthetic fun toInstructions$default (Ljava/lang/String;Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;ILjava/lang/Object;)Ljava/util/List; +public final class app/revanced/patcher/util/SmaliKt { + public static final fun toInstructions (Ljava/lang/String;Lapp/revanced/patcher/dex/mutable/MutableMethod;)Ljava/util/List; + public static synthetic fun toInstructions$default (Ljava/lang/String;Lapp/revanced/patcher/dex/mutable/MutableMethod;ILjava/lang/Object;)Ljava/util/List; } diff --git a/build.gradle.kts b/build.gradle.kts index 08cabdc..b6fc031 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -57,7 +57,7 @@ kotlin { compilerOptions { jvmTarget.set(JvmTarget.JVM_11) - freeCompilerArgs = listOf("-Xcontext-receivers") + freeCompilerArgs = listOf("-Xcontext-parameters") } } diff --git a/gradle.properties b/gradle.properties index 4588c83..4ef4a41 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,3 @@ org.gradle.parallel = true org.gradle.caching = true -version = 21.1.0-dev.5 +version = 22.0.0 diff --git a/src/main/kotlin/app/revanced/patcher/Fingerprint.kt b/src/main/kotlin/app/revanced/patcher/Fingerprint.kt new file mode 100644 index 0000000..a531161 --- /dev/null +++ b/src/main/kotlin/app/revanced/patcher/Fingerprint.kt @@ -0,0 +1,909 @@ +@file:Suppress("unused", "MemberVisibilityCanBePrivate") + +package app.revanced.patcher + +import app.revanced.patcher.InstructionLocation.* +import app.revanced.patcher.Match.PatternMatch +import app.revanced.patcher.Matcher.MatchContext +import app.revanced.patcher.extensions.* +import app.revanced.patcher.extensions.opcode +import app.revanced.patcher.extensions.string +import app.revanced.patcher.patch.BytecodePatchContext +import app.revanced.patcher.patch.PatchException +import com.android.tools.smali.dexlib2.AccessFlags +import com.android.tools.smali.dexlib2.Opcode +import com.android.tools.smali.dexlib2.iface.ClassDef +import com.android.tools.smali.dexlib2.iface.Method +import com.android.tools.smali.dexlib2.iface.instruction.Instruction +import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction +import com.android.tools.smali.dexlib2.iface.reference.StringReference +import com.android.tools.smali.dexlib2.iface.reference.TypeReference +import com.android.tools.smali.dexlib2.util.MethodUtil + +/** + * A fingerprint for a method. A fingerprint is a partial description of a method. + * It is used to uniquely match a method by its characteristics. + * + * An example fingerprint for a public method that takes a single string parameter and returns void: + * ``` + * fingerprint { + * accessFlags(AccessFlags.PUBLIC) + * returns("V") + * parameters("Ljava/lang/String;") + * } + * ``` + * + * @param accessFlags The exact access flags using values of [AccessFlags]. + * @param returnType The return type. Compared using [String.startsWith]. + * @param parameters The parameters. Partial matches allowed and follow the same rules as [returnType]. + * @param filters A list of filters to match, declared in the same order the instructions appear in the method. + * @param strings A list of the strings that appear anywhere in the method. Compared using [String.contains]. + * @param custom A custom condition for this fingerprint. + */ +class Fingerprint internal constructor( + internal val accessFlags: Int?, + internal val returnType: String?, + internal val parameters: List?, + internal val filters: List?, + @Deprecated("Instead use instruction filters") + internal val strings: List?, + internal val custom: ((method: Method, classDef: ClassDef) -> Boolean)?, +) { + @Suppress("ktlint:standard:backing-property-naming") + // Backing field needed for lazy initialization. + private var _matchOrNull: Match? = null + + /** + * Clears the current match, forcing this fingerprint to resolve again. + * This method should only be used if this fingerprint is re-used after it's modified, + * and the prior match indexes are no longer correct. + */ + fun clearMatch() { + _matchOrNull = null + } + + /** + * The match for this [Fingerprint], or `null` if no matches exist. + */ + context(context: BytecodePatchContext) + fun matchOrNull(): Match? { + if (_matchOrNull != null) return _matchOrNull + + val matchStrings = indexedMatcher { + strings?.forEach { add { string { contains(it) } } } + } + + val matchIndices = indexedMatcher() + + val match = context(_: MatchContext) fun Method.(): Boolean { + if (this@Fingerprint.accessFlags != null && this@Fingerprint.accessFlags != accessFlags) + return false + + if (this@Fingerprint.returnType != null && this@Fingerprint.returnType != returnType) + return false + + if (this@Fingerprint.parameters != null && parametersStartsWith( + this@Fingerprint.parameters, + parameters + ) + ) return false + + if (custom != null && !custom.invoke(this, context.lookupMaps.classDefsByType[definingClass]!!)) + return false + + + if (strings != null && !matchStrings(instructionsOrNull ?: return false)) + return false + + fun InstructionFilter.evaluate(instruction: Instruction): Boolean { + return when (this) { + is AnyInstruction -> filters.any { evaluate(instruction) } + is CheckCastFilter -> { + val type = type() + + instruction.opcode(Opcode.CHECK_CAST) && + instruction.reference { endsWith(type) } + } + + is FieldAccessFilter -> { + val reference = instruction.fieldReference ?: return false + + if (name != null && reference.name != name()) return false + + if (type != null && !reference.type.startsWith(type())) return false + + if (definingClass != null) { + val definingClass = definingClass() + + if (!reference.definingClass.endsWith(definingClass)) + // else, the method call is for 'this' class. + if (!(definingClass == "this" && reference.definingClass == method.definingClass)) return false + } + + true + } + + is LiteralFilter -> { + instruction.wideLiteral?.equals(literal()) ?: return false + + opcodes != null && !opcodes.contains(instruction.opcode) + } + + is MethodCallFilter -> { + val reference = instruction.methodReference ?: return false + + if (name != null && reference.name != name()) return false + + if (returnType != null && !reference.returnType.startsWith(returnType())) return false + + if (parameters != null && !parametersStartsWith( + reference.parameterTypes, parameters() + ) + ) return false + + if (definingClass != null) { + val definingClass = definingClass() + + if (!reference.definingClass.endsWith(definingClass)) { + // Check if 'this' defining class is used. + // Would be nice if this also checked all super classes, + // but doing so requires iteratively checking all superclasses + // up to the root class since class defs are mere Strings. + if (!(definingClass == "this" && reference.definingClass == method.definingClass)) { + return false + } // else, the method call is for 'this' class. + } + } + + opcodes != null && !opcodes.contains(instruction.opcode) + } + + is NewInstanceFilter -> { + if (opcodes != null && !opcodes.contains(instruction.opcode)) return false + instruction.reference { endsWith(type) } + } + + is OpcodeFilter -> instruction.opcode(opcode) + is StringFilter -> { + val string = instruction.stringReference?.string ?: return false + + val filterString = string() + when (matchType) { + StringMatchType.EQUALS -> string == filterString + StringMatchType.CONTAINS -> string.contains(filterString) + StringMatchType.STARTS_WITH -> string.startsWith(filterString) + StringMatchType.ENDS_WITH -> string.endsWith(filterString) + } + } + + is OpcodesFilter -> opcodes?.contains(instruction.opcode) == true + else -> throw IllegalStateException("Unknown InstructionFilter type: ${this::class.java}") + } + } + + if (filters != null && !matchIndices(instructionsOrNull ?: return false, "match") { + filters.forEach { filter -> + when (val location = filter.location) { + is MatchAfterImmediately -> after { filter.evaluate(this) } + is MatchAfterAnywhere -> add { filter.evaluate(this) } + is MatchAfterWithin -> after(atLeast = 1, atMost = location.matchDistance) { + filter.evaluate( + this + ) + } + + is MatchFirst -> first { filter.evaluate(this) } + } + } + }) + return false + + return true + } + + val allStrings = buildList { + if (filters != null) addAll( + (filters.filterIsInstance() + filters.filterIsInstance().flatMap { + it.filters.filterIsInstance() + }) + ) + }.map { it.string() } + (strings ?: emptyList()) + + val method = if (allStrings.isNotEmpty()) + context.firstMethodOrNull(strings = allStrings.toTypedArray()) { match() } ?: + // Maybe a better way exists + context(MatchContext()) { + context.lookupMaps.methodsWithString.first { it.match() } + } + else context.firstMethodOrNull { match() } ?: return null + + val instructionMatches = filters?.withIndex()?.map { (i, filter) -> + Match.InstructionMatch(filter, matchIndices.indices[i], method.getInstruction(i)) + } + + val stringMatches = if (strings != null) matchStrings.indices.map { i -> + // TODO: Should we use the methods string or the fingerprints string + Match.StringMatch(method.getInstruction(i).stringReference!!.string, i) + } else null + + return Match( + context, + context.lookupMaps.classDefsByType[method.definingClass]!!, + method, + instructionMatches, + stringMatches, + ) + } + + /** + * Match using a [ClassDef]. + * + * @param classDef The class to match against. + * @return The [Match] if a match was found or if the + * fingerprint is already matched to a method, null otherwise. + */ + context(_: BytecodePatchContext) + fun matchOrNull( + classDef: ClassDef, + ): Match? { + if (_matchOrNull != null) return _matchOrNull + + for (method in classDef.methods) { + val match = matchOrNull(classDef, method) + if (match != null) { + _matchOrNull = match + return match + } + } + + return null + } + + /** + * Match using a [Method]. + * The class is retrieved from the method. + * + * @param method The method to match against. + * @return The [Match] if a match was found or if the fingerprint is previously matched to a method, + * otherwise `null`. + */ + context(context: BytecodePatchContext) + fun matchOrNull( + method: Method, + ): Match? { + if (_matchOrNull != null) return _matchOrNull + + return matchOrNull(context.lookupMaps.classDefsByType[method.definingClass]!!, method) + } + + /** + * Match using a [Method]. + * + * @param method The method to match against. + * @param classDef The class the method is a member of. + * @return The [Match] if a match was found or if the fingerprint is previously matched to a method, + * otherwise `null`. + */ + context(context: BytecodePatchContext) + fun matchOrNull( + classDef: ClassDef, + method: Method, + ): Match? { + if (_matchOrNull != null) return _matchOrNull + + if (returnType != null && !method.returnType.startsWith(returnType)) { + return null + } + + if (accessFlags != null && accessFlags != method.accessFlags) { + return null + } + + // TODO: parseParameters() + if (parameters != null && !parametersStartsWith(method.parameterTypes, parameters)) { + return null + } + + if (custom != null && !custom.invoke(method, classDef)) { + return null + } + + // Legacy string declarations. + val stringMatches: List? = if (strings == null) { + null + } else { + buildList { + val instructions = method.instructionsOrNull ?: return null + + var stringsList: MutableList? = null + + instructions.forEachIndexed { instructionIndex, instruction -> + if ( + instruction.opcode != Opcode.CONST_STRING && + instruction.opcode != Opcode.CONST_STRING_JUMBO + ) { + return@forEachIndexed + } + + val string = ((instruction as ReferenceInstruction).reference as StringReference).string + if (stringsList == null) { + stringsList = strings.toMutableList() + } + val index = stringsList.indexOfFirst(string::contains) + if (index < 0) return@forEachIndexed + + add(Match.StringMatch(string, instructionIndex)) + stringsList.removeAt(index) + } + + if (stringsList == null || stringsList.isNotEmpty()) return null + } + } + + val instructionMatches = if (filters == null) { + null + } else { + val instructions = method.instructionsOrNull?.toList() ?: return null + + fun matchFilters(): List? { + val lastMethodIndex = instructions.lastIndex + var instructionMatches: MutableList? = null + + var firstInstructionIndex = 0 + var lastMatchIndex = -1 + + firstFilterLoop@ while (true) { + // Matched index of the first filter. + var firstFilterIndex = -1 + var subIndex = firstInstructionIndex + + for (filterIndex in filters.indices) { + val filter = filters[filterIndex] + val location = filter.location + var instructionsMatched = false + + while (subIndex <= lastMethodIndex && + location.indexIsValidForMatching( + lastMatchIndex, subIndex + ) + ) { + val instruction = instructions[subIndex] + if (filter.matches(method, instruction)) { + lastMatchIndex = subIndex + + if (filterIndex == 0) { + firstFilterIndex = subIndex + } + if (instructionMatches == null) { + instructionMatches = ArrayList(filters.size) + } + instructionMatches += Match.InstructionMatch(filter, subIndex, instruction) + instructionsMatched = true + subIndex++ + break + } + subIndex++ + } + + if (!instructionsMatched) { + if (filterIndex == 0) { + return null // First filter has no more matches to start from. + } + + // Try again with the first filter, starting from + // the next possible first filter index. + firstInstructionIndex = firstFilterIndex + 1 + instructionMatches?.clear() + continue@firstFilterLoop + } + } + + // All instruction filters matches. + return instructionMatches + } + } + + matchFilters() ?: return null + } + + _matchOrNull = Match( + context, + classDef, + method, + instructionMatches, + stringMatches, + ) + + return _matchOrNull + } + + fun patchException() = PatchException("Failed to match the fingerprint: $this") + + /** + * The match for this [Fingerprint]. + * + * @return The [Match] of this fingerprint. + * @throws PatchException If the [Fingerprint] failed to match. + */ + context(_: BytecodePatchContext) + fun match() = matchOrNull() ?: throw patchException() + + /** + * Match using a [ClassDef]. + * + * @param classDef The class to match against. + * @return The [Match] of this fingerprint. + * @throws PatchException If the fingerprint failed to match. + */ + context(_: BytecodePatchContext) + fun match( + classDef: ClassDef, + ) = matchOrNull(classDef) ?: throw patchException() + + /** + * Match using a [Method]. + * The class is retrieved from the method. + * + * @param method The method to match against. + * @return The [Match] of this fingerprint. + * @throws PatchException If the fingerprint failed to match. + */ + context(_: BytecodePatchContext) + fun match( + method: Method, + ) = matchOrNull(method) ?: throw patchException() + + /** + * Match using a [Method]. + * + * @param method The method to match against. + * @param classDef The class the method is a member of. + * @return The [Match] of this fingerprint. + * @throws PatchException If the fingerprint failed to match. + */ + context(_: BytecodePatchContext) + fun match( + method: Method, + classDef: ClassDef, + ) = matchOrNull(classDef, method) ?: throw patchException() + + /** + * The class the matching method is a member of, or null if this fingerprint did not match. + */ + context(_: BytecodePatchContext) + val originalClassDefOrNull + get() = matchOrNull()?.originalClassDef + + /** + * The matching method, or null of this fingerprint did not match. + */ + context(_: BytecodePatchContext) + val originalMethodOrNull + get() = matchOrNull()?.originalMethod + + /** + * The mutable version of [originalClassDefOrNull]. + * + * Accessing this property allocates a new mutable instance. + * Use [originalClassDefOrNull] if mutable access is not required. + */ + context(_: BytecodePatchContext) + val classDefOrNull + get() = matchOrNull()?.classDef + + /** + * The mutable version of [originalMethodOrNull]. + * + * Accessing this property allocates a new mutable instance. + * Use [originalMethodOrNull] if mutable access is not required. + */ + context(_: BytecodePatchContext) + val methodOrNull + get() = matchOrNull()?.method + + /** + * The match for the opcode pattern, or null if this fingerprint did not match. + */ + context(_: BytecodePatchContext) + @Deprecated("instead use instructionMatchesOrNull") + val patternMatchOrNull: PatternMatch? + get() { + val match = this.matchOrNull() + if (match == null || match.instructionMatchesOrNull == null) { + return null + } + return match.patternMatch + } + + /** + * The match for the instruction filters, or null if this fingerprint did not match. + */ + context(_: BytecodePatchContext) + val instructionMatchesOrNull + get() = matchOrNull()?.instructionMatchesOrNull + + /** + * The matches for the strings, or null if this fingerprint did not match. + * + * This does not give matches for strings declared using [string] instruction filters. + */ + context(_: BytecodePatchContext) + @Deprecated("Instead use string instructions and `instructionMatchesOrNull()`") + val stringMatchesOrNull + get() = matchOrNull()?.stringMatchesOrNull + + /** + * The class the matching method is a member of. + * + * @throws PatchException If the fingerprint has not been matched. + */ + context(_: BytecodePatchContext) + val originalClassDef + get() = match().originalClassDef + + /** + * The matching method. + * + * @throws PatchException If the fingerprint has not been matched. + */ + context(_: BytecodePatchContext) + val originalMethod + get() = match().originalMethod + + /** + * The mutable version of [originalClassDef]. + * + * Accessing this property allocates a new mutable instance. + * Use [originalClassDef] if mutable access is not required. + * + * @throws PatchException If the fingerprint has not been matched. + */ + context(_: BytecodePatchContext) + val classDef + get() = match().classDef + + /** + * The mutable version of [originalMethod]. + * + * Accessing this property allocates a new mutable instance. + * Use [originalMethod] if mutable access is not required. + * + * @throws PatchException If the fingerprint has not been matched. + */ + context(_: BytecodePatchContext) + val method + get() = match().method + + /** + * The match for the opcode pattern. + * + * @throws PatchException If the fingerprint has not been matched. + */ + context(_: BytecodePatchContext) + @Deprecated("Instead use instructionMatch") + val patternMatch + get() = match().patternMatch + + /** + * Instruction filter matches. + * + * @throws PatchException If the fingerprint has not been matched. + */ + context(_: BytecodePatchContext) + val instructionMatches + get() = match().instructionMatches + + /** + * The matches for the strings declared using `strings()`. + * This does not give matches for strings declared using [string] instruction filters. + * + * @throws PatchException If the fingerprint has not been matched. + */ + context(_: BytecodePatchContext) + @Deprecated("Instead use string instructions and `instructionMatches()`") + val stringMatches + get() = match().stringMatches +} + +/** + * A match of a [Fingerprint]. + * + * @param originalClassDef The class the matching method is a member of. + * @param originalMethod The matching method. + * @param _instructionMatches The match for the instruction filters. + * @param _stringMatches The matches for the strings declared using `strings()`. + */ +class Match internal constructor( + val context: BytecodePatchContext, + val originalClassDef: ClassDef, + val originalMethod: Method, + private val _instructionMatches: List?, + private val _stringMatches: List?, +) { + /** + * The mutable version of [originalClassDef]. + * + * Accessing this property allocates a new mutable instance. + * Use [originalClassDef] if mutable access is not required. + */ + val classDef by lazy { + with(context) { + originalClassDef.mutable() + } + } + + /** + * The mutable version of [originalMethod]. + * + * Accessing this property allocates a new mutable instance. + * Use [originalMethod] if mutable access is not required. + */ + val method by lazy { classDef.methods.first { MethodUtil.methodSignaturesMatch(it, originalMethod) } } + + @Deprecated("Instead use instructionMatches", ReplaceWith("instructionMatches")) + val patternMatch by lazy { + if (_instructionMatches == null) throw PatchException("Did not match $this") + @SuppressWarnings("deprecation") + PatternMatch(_instructionMatches.first().index, _instructionMatches.last().index) + } + + val instructionMatches + get() = _instructionMatches ?: throw PatchException("Fingerprint declared no instruction filters") + val instructionMatchesOrNull = _instructionMatches + + @Deprecated("Instead use string instructions and `instructionMatches()`") + val stringMatches + get() = _stringMatches ?: throw PatchException("Fingerprint declared no strings") + + @Deprecated("Instead use string instructions and `instructionMatchesOrNull()`") + val stringMatchesOrNull = _stringMatches + + /** + * A match for an opcode pattern. + * @param startIndex The index of the first opcode of the pattern in the method. + * @param endIndex The index of the last opcode of the pattern in the method. + */ + @Deprecated("Instead use InstructionMatch") + class PatternMatch internal constructor( + val startIndex: Int, + val endIndex: Int, + ) + + /** + * A match for a string. + * + * @param string The string that matched. + * @param index The index of the instruction in the method. + */ + @Deprecated("Instead use string instructions and `InstructionMatch`") + class StringMatch internal constructor(val string: String, val index: Int) + + /** + * A match for a [InstructionFilter]. + * @param filter The filter that matched + * @param index The instruction index it matched with. + * @param instruction The instruction that matched. + */ + class InstructionMatch internal constructor( + val filter: InstructionFilter, + val index: Int, + val instruction: Instruction + ) { + @Suppress("UNCHECKED_CAST") + fun getInstruction(): T = instruction as T + } +} + +/** + * A builder for [Fingerprint]. + * + * @property accessFlags The exact access flags using values of [AccessFlags]. + * @property returnType The return type compared using [String.startsWith]. + * @property parameters The parameters of the method. Partial matches allowed and follow the same rules as [returnType]. + * @property instructionFilters Filters to match the method instructions. + * @property strings A list of the strings compared each using [String.contains]. + * @property customBlock A custom condition for this fingerprint. + * + * @constructor Create a new [FingerprintBuilder]. + */ +class FingerprintBuilder() { + private var accessFlags: Int? = null + private var returnType: String? = null + private var parameters: List? = null + private var instructionFilters: List? = null + private var strings: List? = null + private var customBlock: ((method: Method, classDef: ClassDef) -> Boolean)? = null + + /** + * Set the access flags. + * + * @param accessFlags The exact access flags using values of [AccessFlags]. + */ + fun accessFlags(accessFlags: Int) { + this.accessFlags = accessFlags + } + + /** + * Set the access flags. + * + * @param accessFlags The exact access flags using values of [AccessFlags]. + */ + fun accessFlags(vararg accessFlags: AccessFlags) { + this.accessFlags = accessFlags.fold(0) { acc, it -> acc or it.value } + } + + /** + * Set the return type. + * + * If [accessFlags] includes [AccessFlags.CONSTRUCTOR], then there is no need to + * set a return type set since constructors are always void return type. + * + * @param returnType The return type compared using [String.startsWith]. + */ + fun returns(returnType: String) { + this.returnType = returnType + } + + /** + * Set the parameters. + * + * @param parameters The parameters of the method. + * Partial matches allowed and follow the same rules as [returnType]. + */ + fun parameters(vararg parameters: String) { + this.parameters = parameters.toList() + } + + private fun verifyNoFiltersSet() { + if (this.instructionFilters != null) { + throw PatchException("Instruction filters already set") + } + } + + /** + * A pattern of opcodes, where each opcode must appear immediately after the previous. + * + * To use opcodes with other [InstructionFilter] objects, + * instead use [instructions] with individual opcodes declared using [opcode]. + * + * This method is identical to declaring individual opcode filters + * with [InstructionFilter.location] set to [InstructionLocation.MatchAfterImmediately] + * for all but the first opcode. + * + * Unless absolutely necessary, it is recommended to instead use [instructions] + * with more fine grained filters. + * + * ``` + * opcodes( + * Opcode.INVOKE_VIRTUAL, // First opcode matches anywhere in the method. + * Opcode.MOVE_RESULT_OBJECT, // Must match exactly after INVOKE_VIRTUAL. + * Opcode.IPUT_OBJECT // Must match exactly after MOVE_RESULT_OBJECT. + * ) + * ``` + * is identical to: + * ``` + * instructions( + * opcode(Opcode.INVOKE_VIRTUAL), // First opcode matches anywhere in the method. + * opcode(Opcode.MOVE_RESULT_OBJECT, maxAfter = 0), // Must match exactly after INVOKE_VIRTUAL. + * opcode(Opcode.IPUT_OBJECT, maxAfter = 0) // Must match exactly after MOVE_RESULT_OBJECT. + * ) + * ``` + * + * @param opcodes An opcode pattern of instructions. + * Wildcard or unknown opcodes can be specified by `null`. + */ + fun opcodes(vararg opcodes: Opcode?) { + verifyNoFiltersSet() + if (opcodes.isEmpty()) throw IllegalArgumentException("One or more opcodes is required") + + this.instructionFilters = OpcodesFilter.listOfOpcodes(opcodes.toList()) + } + + /** + * A pattern of opcodes from SMALI formatted text, + * where each opcode must appear immediately after the previous opcode. + * + * Unless absolutely necessary, it is recommended to instead use [instructions]. + * + * @param instructions A list of instructions or opcode names in SMALI format. + * - Wildcard or unknown opcodes can be specified by `null`. + * - Empty lines are ignored. + * - Each instruction must be on a new line. + * - The opcode name is enough, no need to specify the operands. + * + * @throws Exception If an unknown opcode is used. + */ + fun opcodes(instructions: String) { + verifyNoFiltersSet() + if (instructions.isBlank()) throw IllegalArgumentException("No instructions declared (empty string)") + + this.instructionFilters = OpcodesFilter.listOfOpcodes( + instructions.trimIndent().split("\n").filter { + it.isNotBlank() + }.map { + // Remove any operands. + val name = it.split(" ", limit = 1).first().trim() + if (name == "null") return@map null + + opcodesByName[name] ?: throw IllegalArgumentException("Unknown opcode: $name") + } + ) + } + + /** + * A list of instruction filters to match. + */ + fun instructions(vararg instructionFilters: InstructionFilter) { + verifyNoFiltersSet() + if (instructionFilters.isEmpty()) throw IllegalArgumentException("One or more instructions is required") + + this.instructionFilters = instructionFilters.toList() + } + + /** + * Set the strings. + * + * @param strings A list of strings compared each using [String.contains]. + */ + @Deprecated("Instead use `instruction()` filters and `string()` instruction declarations") + fun strings(vararg strings: String) { + this.strings = strings.toList() + } + + /** + * Set a custom condition for this fingerprint. + * + * @param customBlock A custom condition for this fingerprint. + */ + fun custom(customBlock: (method: Method, classDef: ClassDef) -> Boolean) { + this.customBlock = customBlock + } + + fun build(): Fingerprint { + // If access flags include constructor then + // skip the return type check since it's always void. + if (returnType?.equals("V") == true && accessFlags != null + && AccessFlags.CONSTRUCTOR.isSet(accessFlags!!) + ) { + returnType = null + } + + return Fingerprint( + accessFlags, + returnType, + parameters, + instructionFilters, + strings, + customBlock, + ) + } + + + private companion object { + val opcodesByName = Opcode.entries.associateBy { it.name } + } +} + +fun fingerprint( + block: FingerprintBuilder.() -> Unit, +) = FingerprintBuilder().apply(block).build() + +/** + * Matches two lists of parameters, where the first parameter list + * starts with the values of the second list. + */ +internal fun parametersStartsWith( + targetMethodParameters: Iterable, + fingerprintParameters: Iterable, +): Boolean { + if (fingerprintParameters.count() != targetMethodParameters.count()) return false + val fingerprintIterator = fingerprintParameters.iterator() + + targetMethodParameters.forEach { + if (!it.startsWith(fingerprintIterator.next())) return false + } + + return true +} + + diff --git a/src/main/kotlin/app/revanced/patcher/InstructionFilter.kt b/src/main/kotlin/app/revanced/patcher/InstructionFilter.kt new file mode 100644 index 0000000..e4cd79a --- /dev/null +++ b/src/main/kotlin/app/revanced/patcher/InstructionFilter.kt @@ -0,0 +1,983 @@ +@file:Suppress("unused") + +package app.revanced.patcher + +import app.revanced.patcher.FieldAccessFilter.Companion.parseJvmFieldAccess +import app.revanced.patcher.MethodCallFilter.Companion.parseJvmMethodCall +import com.android.tools.smali.dexlib2.Opcode +import com.android.tools.smali.dexlib2.iface.Method +import com.android.tools.smali.dexlib2.iface.instruction.Instruction +import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction +import com.android.tools.smali.dexlib2.iface.instruction.WideLiteralInstruction +import com.android.tools.smali.dexlib2.iface.reference.FieldReference +import com.android.tools.smali.dexlib2.iface.reference.MethodReference +import com.android.tools.smali.dexlib2.iface.reference.StringReference +import com.android.tools.smali.dexlib2.iface.reference.TypeReference +import java.util.* + +/** + * Simple interface to control how much space is allowed between a previous + * [InstructionFilter match and the current [InstructionFilter]. + */ +fun interface InstructionLocation { + /** + * @param previouslyMatchedIndex The previously matched index, or -1 if this is the first filter. + * @param currentIndex The current method index that is about to be checked. + */ + fun indexIsValidForMatching(previouslyMatchedIndex: Int, currentIndex: Int) : Boolean + + /** + * Matching can occur anywhere after the previous instruction filter match index. + * Is the default behavior for all filters. + */ + class MatchAfterAnywhere : InstructionLocation { + override fun indexIsValidForMatching(previouslyMatchedIndex: Int, currentIndex: Int) = true + } + + /** + * Matches the first instruction of a method. + * + * This can only be used for the first filter, and using with any other filter will throw an exception. + */ + class MatchFirst() : InstructionLocation { + override fun indexIsValidForMatching(previouslyMatchedIndex: Int, currentIndex: Int) : Boolean { + if (previouslyMatchedIndex >= 0) { + throw IllegalArgumentException( + "MatchFirst can only be used for the first instruction filter" + ) + } + return true + } + } + + /** + * Instruction index immediately after the previous filter. + * + * Useful for opcodes that must always appear immediately after the last filter such as: + * - [Opcode.MOVE_RESULT] + * - [Opcode.MOVE_RESULT_WIDE] + * - [Opcode.MOVE_RESULT_OBJECT] + * + * This cannot be used for the first filter and will throw an exception. + */ + class MatchAfterImmediately() : InstructionLocation { + override fun indexIsValidForMatching(previouslyMatchedIndex: Int, currentIndex: Int) : Boolean { + if (previouslyMatchedIndex < 0) { + throw IllegalArgumentException( + "MatchAfterImmediately cannot be used for the first instruction filter" + ) + } + return currentIndex - 1 == previouslyMatchedIndex + } + } + + /** + * Instruction index can occur within a range of the previous instruction filter match index. + * used to constrain instruction matching to a region after the previous instruction filter. + * + * This cannot be used for the first filter and will throw an exception. + * + * @param matchDistance The number of unmatched instructions that can exist between the + * current instruction filter and the previously matched instruction filter. + * A value of 0 means the current filter can only match immediately after + * the previously matched instruction (making this functionally identical to + * [MatchAfterImmediately]). A value of 10 means between 0 and 10 unmatched + * instructions can exist between the previously matched instruction and + * the current instruction filter. + */ + class MatchAfterWithin(var matchDistance: Int) : InstructionLocation { + init { + if (matchDistance < 0) { + throw IllegalArgumentException("matchDistance must be non-negative") + } + } + + override fun indexIsValidForMatching(previouslyMatchedIndex: Int, currentIndex: Int) : Boolean { + if (previouslyMatchedIndex < 0) { + throw IllegalArgumentException( + "MatchAfterImmediately cannot be used for the first instruction filter" + ) + } + return currentIndex - previouslyMatchedIndex - 1 <= matchDistance + } + } +} + + +/** + * Matches method [Instruction] objects, similar to how [Fingerprint] matches entire fingerprints. + * + * The most basic filters match only opcodes and nothing more, + * and more precise filters can match: + * - Field references (get/put opcodes) by name/type. + * - Method calls (invoke_* opcodes) by name/parameter/return type. + * - Object instantiation for specific class types. + * - Literal const values. + */ +fun interface InstructionFilter { + + /** + * The [InstructionLocation] associated with this filter. + */ + val location: InstructionLocation + get() = InstructionLocation.MatchAfterAnywhere() + + /** + * If this filter matches the method instruction. + * + * @param enclosingMethod The method of that contains [instruction]. + * @param instruction The instruction to check for a match. + */ + fun matches( + enclosingMethod: Method, + instruction: Instruction + ): Boolean +} + + + +class AnyInstruction internal constructor( + internal val filters: List, + override val location : InstructionLocation +) : InstructionFilter { + + override fun matches( + enclosingMethod: Method, + instruction: Instruction + ) : Boolean { + return filters.any { filter -> + filter.matches(enclosingMethod, instruction) + } + } +} + +/** + * Logical OR operator where the first filter that matches satisfies this filter. + */ +fun anyInstruction( + vararg filters: InstructionFilter, + location : InstructionLocation = InstructionLocation.MatchAfterAnywhere() +) = AnyInstruction(filters.asList(), location) + + + +open class OpcodeFilter( + val opcode: Opcode, + override val location : InstructionLocation +) : InstructionFilter { + + override fun matches( + enclosingMethod: Method, + instruction: Instruction + ): Boolean { + return instruction.opcode == opcode + } +} + +/** + * Single opcode. + */ +fun opcode( + opcode: Opcode, + location: InstructionLocation = InstructionLocation.MatchAfterAnywhere() +) = OpcodeFilter(opcode, location) + + + +/** + * Matches a single instruction from many kinds of opcodes. + * If matching only a single opcode instead use [OpcodeFilter]. + */ +open class OpcodesFilter private constructor( + val opcodes: EnumSet?, + override val location : InstructionLocation +) : InstructionFilter { + + protected constructor( + /** + * Value of `null` will match any opcode. + */ + opcodes: List?, + location : InstructionLocation + ) : this(if (opcodes == null) null else EnumSet.copyOf(opcodes), location) + + override fun matches( + enclosingMethod: Method, + instruction: Instruction + ): Boolean { + if (opcodes == null) { + return true // Match anything. + } + return opcodes.contains(instruction.opcode) + } + + companion object { + /** + * First opcode can match anywhere in a method, but all + * subsequent opcodes must match after the previous opcode. + * + * A value of `null` indicates to match any opcode. + */ + internal fun listOfOpcodes(opcodes: Collection): List { + val list = ArrayList(opcodes.size) + var location: InstructionLocation? = null + + opcodes.forEach { opcode -> + // First opcode can match anywhere. + val opcodeLocation = location ?: InstructionLocation.MatchAfterAnywhere() + + list += if (opcode == null) { + // Null opcode matches anything. + OpcodesFilter( + null as List?, + opcodeLocation + ) + } else { + OpcodeFilter(opcode, opcodeLocation) + } + + if (location == null) { + location = InstructionLocation.MatchAfterImmediately() + } + } + + return list + } + } +} + + + +class LiteralFilter internal constructor( + var literal: () -> Long, + opcodes: List? = null, + location : InstructionLocation +) : OpcodesFilter(opcodes, location) { + + private var literalValue: Long? = null + + override fun matches( + enclosingMethod: Method, + instruction: Instruction + ): Boolean { + if (!super.matches(enclosingMethod, instruction)) { + return false + } + + if (instruction !is WideLiteralInstruction) return false + + if (literalValue == null) { + literalValue = literal() + } + + return instruction.wideLiteral == literalValue + } +} + +/** + * Literal value, such as: + * `const v1, 0x7f080318` + * + * that can be matched using: + * `LiteralFilter(0x7f080318)` + * or + * `LiteralFilter(2131231512)` + */ +fun literal( + literal: () -> Long, + opcodes: List? = null, + location : InstructionLocation = InstructionLocation.MatchAfterAnywhere() +) = LiteralFilter(literal, opcodes, location) + +/** + * Literal value, such as: + * `const v1, 0x7f080318` + * + * that can be matched using: + * `LiteralFilter(0x7f080318)` + * or + * `LiteralFilter(2131231512L)` + */ +fun literal( + literal: Long, + opcodes: List? = null, + location : InstructionLocation = InstructionLocation.MatchAfterAnywhere() +) = LiteralFilter({ literal }, opcodes, location) + +/** + * Integer point literal. + */ +fun literal( + literal: Int, + opcodes: List? = null, + location : InstructionLocation = InstructionLocation.MatchAfterAnywhere() +) = LiteralFilter({ literal.toLong() }, opcodes, location) + +/** + * Double point literal. + */ +fun literal( + literal: Double, + opcodes: List? = null, + location : InstructionLocation = InstructionLocation.MatchAfterAnywhere() +) = LiteralFilter({ literal.toRawBits() }, opcodes, location) + +/** + * Floating point literal. + */ +fun literal( + literal: Float, + opcodes: List? = null, + location : InstructionLocation = InstructionLocation.MatchAfterAnywhere() +) = LiteralFilter({ literal.toRawBits().toLong() }, opcodes, location) + + + +enum class StringMatchType { + EQUALS, + CONTAINS, + STARTS_WITH, + ENDS_WITH +} + +class StringFilter internal constructor( + var string: () -> String, + var matchType: StringMatchType, + location : InstructionLocation +) : OpcodesFilter(listOf(Opcode.CONST_STRING, Opcode.CONST_STRING_JUMBO), location) { + + override fun matches( + enclosingMethod: Method, + instruction: Instruction + ): Boolean { + if (!super.matches(enclosingMethod, instruction)) { + return false + } + + val instructionString = ((instruction as ReferenceInstruction).reference as StringReference).string + val filterString = string() + + return when (matchType) { + StringMatchType.EQUALS -> instructionString == filterString + StringMatchType.CONTAINS -> instructionString.contains(filterString) + StringMatchType.STARTS_WITH -> instructionString.startsWith(filterString) + StringMatchType.ENDS_WITH -> instructionString.endsWith(filterString) + } + } +} + +/** + * Literal String instruction. + */ +fun string( + string: () -> String, + /** + * If [string] is a partial match, where the target string contains this string. + * For more precise matching, consider using [anyInstruction] with multiple exact string declarations. + */ + matchType: StringMatchType = StringMatchType.EQUALS, + location : InstructionLocation = InstructionLocation.MatchAfterAnywhere() +) = StringFilter(string, matchType, location) + +/** + * Literal String instruction. + */ +fun string( + string: String, + /** + * How to compare [string] against the string constant opcode. For more precise matching + * of multiple strings, consider using [anyInstruction] with multiple exact string declarations. + */ + matchType: StringMatchType = StringMatchType.EQUALS, + location : InstructionLocation = InstructionLocation.MatchAfterAnywhere() +) = StringFilter({ string }, matchType, location) + + + +class MethodCallFilter internal constructor( + val definingClass: (() -> String)? = null, + val name: (() -> String)? = null, + val parameters: (() -> List)? = null, + val returnType: (() -> String)? = null, + opcodes: List? = null, + location : InstructionLocation +) : OpcodesFilter(opcodes, location) { + + override fun matches( + enclosingMethod: Method, + instruction: Instruction + ): Boolean { + if (!super.matches(enclosingMethod, instruction)) { + return false + } + + val reference = (instruction as? ReferenceInstruction)?.reference as? MethodReference + if (reference == null) return false + + if (definingClass != null) { + val referenceClass = reference.definingClass + val definingClass = definingClass() + + if (!referenceClass.endsWith(definingClass)) { + // Check if 'this' defining class is used. + // Would be nice if this also checked all super classes, + // but doing so requires iteratively checking all superclasses + // up to the root class since class defs are mere Strings. + if (!(definingClass == "this" && referenceClass == enclosingMethod.definingClass)) { + return false + } // else, the method call is for 'this' class. + } + } + if (name != null && reference.name != name()) { + return false + } + if (returnType != null && !reference.returnType.startsWith(returnType())) { + return false + } + if (parameters != null && !parametersStartsWith(reference.parameterTypes, parameters())) { + return false + } + + return true + } + + companion object { + private val regex = Regex("""^(L[^;]+;)->([^(\s]+)\(([^)]*)\)(\[?L[^;]+;|\[?[BCSIJFDZV])${'$'}""") + + internal fun parseJvmMethodCall( + methodSignature: String, + opcodes: List? = null, + location : InstructionLocation = InstructionLocation.MatchAfterAnywhere() + ): MethodCallFilter { + val matchResult = regex.matchEntire(methodSignature) + ?: throw IllegalArgumentException("Invalid method signature: $methodSignature") + + val classDescriptor = matchResult.groupValues[1] + val methodName = matchResult.groupValues[2] + val paramDescriptorString = matchResult.groupValues[3] + val returnDescriptor = matchResult.groupValues[4] + + val paramDescriptors = parseParameterDescriptors(paramDescriptorString) + + return MethodCallFilter( + { classDescriptor }, + { methodName }, + { paramDescriptors }, + { returnDescriptor }, + opcodes, + location + ) + } + + /** + * Parses a single JVM type descriptor or an array descriptor at the current position. + * For example: Lcom/example/SomeClass; or I or [I or [Lcom/example/SomeClass; + */ + private fun parseSingleType(params: String, startIndex: Int): Pair { + var i = startIndex + + // Skip past array declaration, including multi-dimensional arrays. + val paramsLength = params.length + while (i < paramsLength && params[i] == '[') { + i++ + } + + return if (i < paramsLength && params[i] == 'L') { + // It's an object type starting with 'L', read until ';' + val semicolonPos = params.indexOf(';', i) + if (semicolonPos < 0) { + throw IllegalArgumentException("Malformed object descriptor (missing semicolon): $params") + } + // Substring from startIndex up to and including the semicolon. + val typeDescriptor = params.substring(startIndex, semicolonPos + 1) + typeDescriptor to (semicolonPos + 1) + } else { + // It's either a primitive or we've already consumed the array part + // So just take one character (e.g. 'I', 'Z', 'B', etc.) + val typeDescriptor = params.substring(startIndex, i + 1) + typeDescriptor to (i + 1) + } + } + + /** + * Parses the parameters into a list of JVM type descriptors. + */ + private fun parseParameterDescriptors(paramString: String): List { + val result = mutableListOf() + var currentIndex = 0 + val stringLength = paramString.length + + while (currentIndex < stringLength) { + val (type, nextIndex) = parseSingleType(paramString, currentIndex) + result.add(type) + currentIndex = nextIndex + } + + return result + } + } +} + +/** + * Identifies method calls. + * + * `Null` parameters matches anything. + * + * By default any type of method call matches. + * Specify opcodes if a specific type of method call is desired (such as only static calls). + */ +fun methodCall( + /** + * Defining class of the method call. Matches using endsWith(). + * + * For calls to a method in the same class, use 'this' as the defining class. + * Note: 'this' does not work for methods declared only in a superclass. + */ + definingClass: (() -> String)? = null, + /** + * Method name. Must be exact match of the method name. + */ + name: (() -> String)? = null, + /** + * Parameters of the method call. Each parameter matches + * using startsWith() and semantics are the same as [Fingerprint]. + */ + parameters: (() -> List)? = null, + /** + * Return type. Matches using startsWith() + */ + returnType: (() -> String)? = null, + /** + * Opcode types to match. By default this matches any method call opcode: + * `Opcode.INVOKE_*`. + * + * If this filter must match specific types of method call, then specify the desired opcodes + * such as [Opcode.INVOKE_STATIC], [Opcode.INVOKE_STATIC_RANGE] to match only static calls. + */ + opcodes: List? = null, + /** + * The locations where this filter is allowed to match. + */ + location : InstructionLocation = InstructionLocation.MatchAfterAnywhere() +) = MethodCallFilter( + definingClass, + name, + parameters, + returnType, + opcodes, + location +) + +fun methodCall( + /** + * Defining class of the method call. Matches using endsWith(). + * + * For calls to a method in the same class, use 'this' as the defining class. + * Note: 'this' does not work for methods declared only in a superclass. + */ + definingClass: String? = null, + /** + * Method name. Must be exact match of the method name. + */ + name: String? = null, + /** + * Parameters of the method call. Each parameter matches + * using startsWith() and semantics are the same as [Fingerprint]. + */ + parameters: List? = null, + /** + * Return type. Matches using startsWith() + */ + returnType: String? = null, + /** + * Opcode types to match. By default this matches any method call opcode: + * `Opcode.INVOKE_*`. + * + * If this filter must match specific types of method call, then specify the desired opcodes + * such as [Opcode.INVOKE_STATIC], [Opcode.INVOKE_STATIC_RANGE] to match only static calls. + */ + opcodes: List? = null, + /** + * The locations where this filter is allowed to match. + */ + location : InstructionLocation = InstructionLocation.MatchAfterAnywhere() +) = MethodCallFilter( + if (definingClass != null) { + { definingClass } + } else null, + if (name != null) { + { name } + } else null, + if (parameters != null) { + { parameters } + } else null, + if (returnType != null) { + { returnType } + } else null, + opcodes, + location +) + +fun methodCall( + /** + * Defining class of the method call. Matches using endsWith(). + * + * For calls to a method in the same class, use 'this' as the defining class. + * Note: 'this' does not work for methods declared only in a superclass. + */ + definingClass: String? = null, + /** + * Method name. Must be exact match of the method name. + */ + name: String? = null, + /** + * Parameters of the method call. Each parameter matches + * using startsWith() and semantics are the same as [Fingerprint]. + */ + parameters: List? = null, + /** + * Return type. Matches using startsWith() + */ + returnType: String? = null, + /** + * Opcode types to match. By default this matches any method call opcode: + * `Opcode.INVOKE_*`. + * + * If this filter must match specific types of method call, then specify the desired opcodes + * such as [Opcode.INVOKE_STATIC], [Opcode.INVOKE_STATIC_RANGE] to match only static calls. + */ + opcode: Opcode, + /** + * The locations where this filter is allowed to match. + */ + location : InstructionLocation = InstructionLocation.MatchAfterAnywhere() +) = MethodCallFilter( + if (definingClass != null) { + { definingClass } + } else null, + if (name != null) { + { name } + } else null, + if (parameters != null) { + { parameters } + } else null, + if (returnType != null) { + { returnType } + } else null, + listOf(opcode), + location +) + +/** + * Method call for a copy pasted SMALI style method signature. e.g.: + * `Landroid/view/View;->inflate(Landroid/content/Context;ILandroid/view/ViewGroup;)Landroid/view/View;` + * + * Does not support obfuscated method names or parameter/return types. + */ +fun methodCall( + smali: String, + opcodes: List? = null, + location : InstructionLocation = InstructionLocation.MatchAfterAnywhere() +) = parseJvmMethodCall(smali, opcodes, location) + +/** + * Method call for a copy pasted SMALI style method signature. e.g.: + * `Landroid/view/View;->inflate(Landroid/content/Context;ILandroid/view/ViewGroup;)Landroid/view/View;` + * + * Does not support obfuscated method names or parameter/return types. + */ +fun methodCall( + smali: String, + opcode: Opcode, + location : InstructionLocation = InstructionLocation.MatchAfterAnywhere() +) = parseJvmMethodCall(smali, listOf(opcode), location) + + + +class FieldAccessFilter internal constructor( + val definingClass: (() -> String)? = null, + val name: (() -> String)? = null, + val type: (() -> String)? = null, + opcodes: List? = null, + location : InstructionLocation +) : OpcodesFilter(opcodes, location) { + + override fun matches( + enclosingMethod: Method, + instruction: Instruction + ): Boolean { + if (!super.matches(enclosingMethod, instruction)) { + return false + } + + val reference = (instruction as? ReferenceInstruction)?.reference as? FieldReference + if (reference == null) return false + + if (definingClass != null) { + val referenceClass = reference.definingClass + val definingClass = definingClass() + + if (!referenceClass.endsWith(definingClass)) { + if (!(definingClass == "this" && referenceClass == enclosingMethod.definingClass)) { + return false + } // else, the method call is for 'this' class. + } + } + if (name != null && reference.name != name()) { + return false + } + if (type != null && !reference.type.startsWith(type())) { + return false + } + + return true + } + + internal companion object { + private val regex = Regex("""^(L[^;]+;)->([^:]+):(\[?L[^;]+;|\[?[BCSIJFDZV])${'$'}""") + + internal fun parseJvmFieldAccess( + fieldSignature: String, + opcodes: List? = null, + location : InstructionLocation = InstructionLocation.MatchAfterAnywhere() + ): FieldAccessFilter { + val matchResult = regex.matchEntire(fieldSignature) + ?: throw IllegalArgumentException("Invalid field access smali: $fieldSignature") + + return fieldAccess( + definingClass = matchResult.groupValues[1], + name = matchResult.groupValues[2], + type = matchResult.groupValues[3], + opcodes = opcodes, + location = location + ) + } + } +} + +/** + * Matches a field call, such as: + * `iget-object v0, p0, Lahhh;->g:Landroid/view/View;` + */ +fun fieldAccess( + /** + * Defining class of the field call. Matches using endsWith(). + * + * For calls to a method in the same class, use 'this' as the defining class. + * Note: 'this' does not work for fields found in superclasses. + */ + definingClass: (() -> String)? = null, + /** + * Name of the field. Must be a full match of the field name. + */ + name: (() -> String)? = null, + /** + * Class type of field. Partial matches using startsWith() is allowed. + */ + type: (() -> String)? = null, + /** + * Valid opcodes matches for this instruction. + * By default this matches any kind of field access + * (`Opcode.IGET`, `Opcode.SGET`, `Opcode.IPUT`, `Opcode.SPUT`, etc). + */ + opcodes: List? = null, + /** + * The locations where this filter is allowed to match. + */ + location : InstructionLocation = InstructionLocation.MatchAfterAnywhere() +) = FieldAccessFilter(definingClass, name, type, opcodes, location) + +/** + * Matches a field call, such as: + * `iget-object v0, p0, Lahhh;->g:Landroid/view/View;` + */ +fun fieldAccess( + /** + * Defining class of the field call. Matches using endsWith(). + * + * For calls to a method in the same class, use 'this' as the defining class. + * Note: 'this' does not work for fields found in superclasses. + */ + definingClass: String? = null, + /** + * Name of the field. Must be a full match of the field name. + */ + name: String? = null, + /** + * Class type of field. Partial matches using startsWith() is allowed. + */ + type: String? = null, + /** + * Valid opcodes matches for this instruction. + * By default this matches any kind of field access + * (`Opcode.IGET`, `Opcode.SGET`, `Opcode.IPUT`, `Opcode.SPUT`, etc). + */ + opcodes: List? = null, + /** + * The locations where this filter is allowed to match. + */ + location : InstructionLocation = InstructionLocation.MatchAfterAnywhere() +) = FieldAccessFilter( + if (definingClass != null) { + { definingClass } + } else null, + if (name != null) { + { name } + } else null, + if (type != null) { + { type } + } else null, + opcodes, + location +) + +/** + * Matches a field call, such as: + * `iget-object v0, p0, Lahhh;->g:Landroid/view/View;` + */ +fun fieldAccess( + /** + * Defining class of the field call. Matches using endsWith(). + * + * For calls to a method in the same class, use 'this' as the defining class. + * Note: 'this' does not work for fields found in superclasses. + */ + definingClass: String? = null, + /** + * Name of the field. Must be a full match of the field name. + */ + name: String? = null, + /** + * Class type of field. Partial matches using startsWith() is allowed. + */ + type: String? = null, + opcode: Opcode, + /** + * The locations where this filter is allowed to match. + */ + location : InstructionLocation = InstructionLocation.MatchAfterAnywhere() +) = fieldAccess( + definingClass, + name, + type, + listOf(opcode), + location +) + +/** + * Field access for a copy pasted SMALI style field access call. e.g.: + * `Ljava/lang/Boolean;->TRUE:Ljava/lang/Boolean;` + * + * Does not support obfuscated field names or obfuscated field types. + */ +fun fieldAccess( + smali: String, + opcodes: List? = null, + location : InstructionLocation = InstructionLocation.MatchAfterAnywhere() +) = parseJvmFieldAccess(smali, opcodes, location) + +/** + * Field access for a copy pasted SMALI style field access call. e.g.: + * `Ljava/lang/Boolean;->TRUE:Ljava/lang/Boolean;` + * + * Does not support obfuscated field names or obfuscated field types. + */ +fun fieldAccess( + smali: String, + opcode: Opcode, + location : InstructionLocation = InstructionLocation.MatchAfterAnywhere() +) = parseJvmFieldAccess(smali, listOf(opcode), location) + + + +class NewInstanceFilter internal constructor ( + var type: () -> String, + location : InstructionLocation +) : OpcodesFilter(listOf(Opcode.NEW_INSTANCE, Opcode.NEW_ARRAY), location) { + + override fun matches( + enclosingMethod: Method, + instruction: Instruction + ): Boolean { + if (!super.matches(enclosingMethod, instruction)) { + return false + } + + val reference = (instruction as? ReferenceInstruction)?.reference as? TypeReference + if (reference == null) return false + + return reference.type.endsWith(type()) + } +} + + +/** + * Opcode type [Opcode.NEW_INSTANCE] or [Opcode.NEW_ARRAY] with a non obfuscated class type. + * + * @param type Class type that matches the target instruction using [String.endsWith]. + */ +fun newInstancetype( + type: () -> String, + location : InstructionLocation = InstructionLocation.MatchAfterAnywhere() +) = NewInstanceFilter(type, location) + +/** + * Opcode type [Opcode.NEW_INSTANCE] or [Opcode.NEW_ARRAY] with a non obfuscated class type. + * + * @param type Class type that matches the target instruction using [String.endsWith]. + */ +fun newInstance( + type: String, + location : InstructionLocation = InstructionLocation.MatchAfterAnywhere() +) : NewInstanceFilter { + if (!type.endsWith(";")) { + throw IllegalArgumentException("Class type does not end with a semicolon: $type") + } + return NewInstanceFilter({ type }, location) +} + +class CheckCastFilter internal constructor ( + var type: () -> String, + location : InstructionLocation = InstructionLocation.MatchAfterAnywhere() +) : OpcodeFilter(Opcode.CHECK_CAST, location) { + + override fun matches( + enclosingMethod: Method, + instruction: Instruction + ): Boolean { + if (!super.matches(enclosingMethod, instruction)) { + return false + } + + val reference = (instruction as? ReferenceInstruction)?.reference as? TypeReference + if (reference == null) return false + + return reference.type.endsWith(type()) + } +} + +/** + * Opcode type [Opcode.CHECK_CAST] with a non obfuscated class type. + * + * @param type Class type that matches the target instruction using [String.endsWith]. + */ +fun checkCast( + type: () -> String, + location : InstructionLocation = InstructionLocation.MatchAfterAnywhere() +) = CheckCastFilter(type, location) + +/** + * Opcode type [Opcode.CHECK_CAST] with a non obfuscated class type. + * + * @param type Class type that matches the target instruction using [String.endsWith]. + */ +fun checkCast( + type: String, + location : InstructionLocation = InstructionLocation.MatchAfterAnywhere() +) : CheckCastFilter { + if (!type.endsWith(";")) { + throw IllegalArgumentException("Class type does not end with a semicolon: $type") + } + + return CheckCastFilter({ type }, location) +} diff --git a/src/main/kotlin/app/revanced/patcher/Matching.kt b/src/main/kotlin/app/revanced/patcher/Matching.kt index ef6fac1..02dffb8 100644 --- a/src/main/kotlin/app/revanced/patcher/Matching.kt +++ b/src/main/kotlin/app/revanced/patcher/Matching.kt @@ -4,15 +4,14 @@ package app.revanced.patcher import app.revanced.patcher.Matcher.MatchContext import app.revanced.patcher.dex.mutable.MutableMethod -import app.revanced.patcher.extensions.instructions +import app.revanced.patcher.extensions.* import app.revanced.patcher.patch.BytecodePatchContext +import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.HiddenApiRestriction import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.iface.* import com.android.tools.smali.dexlib2.iface.Annotation import com.android.tools.smali.dexlib2.iface.instruction.Instruction -import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction -import com.android.tools.smali.dexlib2.iface.reference.StringReference import com.android.tools.smali.dexlib2.util.MethodUtil import kotlin.properties.ReadOnlyProperty import kotlin.reflect.KProperty @@ -52,110 +51,104 @@ fun MethodImplementation.anyTryBlock(predicate: TryBlock.( fun MethodImplementation.anyDebugItem(predicate: Any.() -> Boolean) = debugItems.any(predicate) fun Iterable.anyInstruction(predicate: Instruction.() -> Boolean) = any(predicate) +fun BytecodePatchContext.firstClassDefOrNull(predicate: context(MatchContext) ClassDef.() -> Boolean) = + with(MatchContext()) { classDefs.firstOrNull { it.predicate() } } -fun BytecodePatchContext.firstClassDefOrNull(predicate: MatchPredicate) = - with(predicate) { with(MatchContext()) { classDefs.firstOrNull { it.match() } } } - -fun BytecodePatchContext.firstClassDef(predicate: MatchPredicate) = +fun BytecodePatchContext.firstClassDef(predicate: context(MatchContext) ClassDef.() -> Boolean) = requireNotNull(firstClassDefOrNull(predicate)) -fun BytecodePatchContext.firstClassDefMutableOrNull(predicate: MatchPredicate) = +fun BytecodePatchContext.firstClassDefMutableOrNull(predicate: context(MatchContext) ClassDef.() -> Boolean) = firstClassDefOrNull(predicate)?.mutable() -fun BytecodePatchContext.firstClassDefMutable(predicate: MatchPredicate) = +fun BytecodePatchContext.firstClassDefMutable(predicate: context(MatchContext) ClassDef.() -> Boolean) = requireNotNull(firstClassDefMutableOrNull(predicate)) fun BytecodePatchContext.firstClassDefOrNull( - type: String, predicate: (MatchPredicate)? = null + type: String, predicate: (context(MatchContext) ClassDef.() -> Boolean)? = null ) = lookupMaps.classDefsByType[type]?.takeIf { - predicate == null || with(predicate) { with(MatchContext()) { it.match() } } + predicate == null || with(MatchContext()) { it.predicate() } } fun BytecodePatchContext.firstClassDef( - type: String, predicate: (MatchPredicate)? = null + type: String, predicate: (context(MatchContext) ClassDef.() -> Boolean)? = null ) = requireNotNull(firstClassDefOrNull(type, predicate)) fun BytecodePatchContext.firstClassDefMutableOrNull( - type: String, predicate: (MatchPredicate)? = null + type: String, predicate: (context(MatchContext) ClassDef.() -> Boolean)? = null ) = firstClassDefOrNull(type, predicate)?.mutable() fun BytecodePatchContext.firstClassDefMutable( - type: String, predicate: (MatchPredicate)? = null + type: String, predicate: (context(MatchContext) ClassDef.() -> Boolean)? = null ) = requireNotNull(firstClassDefMutableOrNull(type, predicate)) -fun Iterable.firstMethodOrNull(predicate: MatchPredicate) = with(predicate) { +fun Iterable.firstMethodOrNull(predicate: context(MatchContext) Method.() -> Boolean) = with(MatchContext()) { - this@firstMethodOrNull.asSequence().flatMap { it.methods.asSequence() }.firstOrNull { it.match() } + this@firstMethodOrNull.asSequence().flatMap { it.methods.asSequence() }.firstOrNull { it.predicate() } } -} -fun Iterable.firstMethod(predicate: MatchPredicate) = requireNotNull(firstMethodOrNull(predicate)) +fun Iterable.firstMethod(predicate: context(MatchContext) Method.() -> Boolean) = + requireNotNull(firstMethodOrNull(predicate)) -context(BytecodePatchContext) -fun Iterable.firstMethodMutableOrNull(predicate: MatchPredicate): MutableMethod? { - with(predicate) { +context(context: BytecodePatchContext) +fun Iterable.firstMethodMutableOrNull(predicate: context(MatchContext) Method.() -> Boolean): MutableMethod? = + with(context) { with(MatchContext()) { this@firstMethodMutableOrNull.forEach { classDef -> - classDef.methods.firstOrNull { it.match() }?.let { method -> + classDef.methods.firstOrNull { it.predicate() }?.let { method -> return classDef.mutable().methods.first { MethodUtil.methodSignaturesMatch(it, method) } } } + + null } } - return null -} - -context(BytecodePatchContext) -fun Iterable.firstMethodMutable(predicate: MatchPredicate) = +context(_: BytecodePatchContext) +fun Iterable.firstMethodMutable(predicate: context(MatchContext) Method.() -> Boolean) = requireNotNull(firstMethodMutableOrNull(predicate)) -fun BytecodePatchContext.firstMethodOrNull(predicate: MatchPredicate) = +fun BytecodePatchContext.firstMethodOrNull(predicate: context(MatchContext) Method.() -> Boolean) = classDefs.firstMethodOrNull(predicate) -fun BytecodePatchContext.firstMethod(predicate: MatchPredicate) = +fun BytecodePatchContext.firstMethod(predicate: context(MatchContext) Method.() -> Boolean) = requireNotNull(firstMethodOrNull(predicate)) -fun BytecodePatchContext.firstMethodMutableOrNull(predicate: MatchPredicate) = +fun BytecodePatchContext.firstMethodMutableOrNull(predicate: context(MatchContext) Method.() -> Boolean) = classDefs.firstMethodMutableOrNull(predicate) -fun BytecodePatchContext.firstMethodMutable(predicate: MatchPredicate) = +fun BytecodePatchContext.firstMethodMutable(predicate: context(MatchContext) Method.() -> Boolean) = requireNotNull(firstMethodMutableOrNull(predicate)) fun BytecodePatchContext.firstMethodOrNull( vararg strings: String, - predicate: MatchPredicate = MatchPredicate { true }, -) = with(predicate) { - with(MatchContext()) { - strings.mapNotNull { lookupMaps.methodsByStrings[it] }.minByOrNull { it.size }?.firstOrNull { it.match() } - } + predicate: context(MatchContext) Method.() -> Boolean = { true }, +) = with(MatchContext()) { + strings.mapNotNull { lookupMaps.methodsByStrings[it] }.minByOrNull { it.size }?.firstOrNull { it.predicate() } } fun BytecodePatchContext.firstMethod( vararg strings: String, - predicate: MatchPredicate = MatchPredicate { true }, + predicate: context(MatchContext) Method.() -> Boolean = { true }, ) = requireNotNull(firstMethodOrNull(*strings, predicate = predicate)) fun BytecodePatchContext.firstMethodMutableOrNull( vararg strings: String, - predicate: MatchPredicate = MatchPredicate { true }, -) = with(predicate) { - with(MatchContext()) { - strings.mapNotNull { lookupMaps.methodsByStrings[it] }.minByOrNull { it.size }?.let { methods -> - methods.firstOrNull { it.match() }?.let { method -> - firstClassDefMutable(method.definingClass).methods.first { - MethodUtil.methodSignaturesMatch( - method, it - ) - } + predicate: context(MatchContext) Method.() -> Boolean = { true }, +) = with(MatchContext()) { + strings.mapNotNull { lookupMaps.methodsByStrings[it] }.minByOrNull { it.size }?.let { methods -> + methods.firstOrNull { it.predicate() }?.let { method -> + firstClassDefMutable(method.definingClass).methods.first { + MethodUtil.methodSignaturesMatch( + method, it + ) } } } } fun BytecodePatchContext.firstMethodMutable( - vararg strings: String, predicate: MatchPredicate = MatchPredicate { true } + vararg strings: String, predicate: context(MatchContext) Method.() -> Boolean = { true } ) = requireNotNull(firstMethodMutableOrNull(*strings, predicate = predicate)) inline fun ReadOnlyProperty(crossinline block: C.(KProperty<*>) -> T) = @@ -165,67 +158,82 @@ inline fun ReadOnlyProperty(crossinline block: C.(KProperty<*>) - thisRef.block(property) } -fun gettingFirstClassDefOrNull(predicate: MatchPredicate) = +fun gettingFirstClassDefOrNull(predicate: context(MatchContext) ClassDef.() -> Boolean) = ReadOnlyProperty { firstClassDefOrNull(predicate) } -fun gettingFirstClassDef(predicate: MatchPredicate) = requireNotNull(gettingFirstClassDefOrNull(predicate)) +fun gettingFirstClassDef(predicate: context(MatchContext) ClassDef.() -> Boolean) = + requireNotNull(gettingFirstClassDefOrNull(predicate)) -fun gettingFirstClassDefMutableOrNull(predicate: MatchPredicate) = +fun gettingFirstClassDefMutableOrNull(predicate: context(MatchContext) ClassDef.() -> Boolean) = ReadOnlyProperty { firstClassDefMutableOrNull(predicate) } -fun gettingFirstClassDefMutable(predicate: MatchPredicate) = +fun gettingFirstClassDefMutable(predicate: context(MatchContext) ClassDef.() -> Boolean) = requireNotNull(gettingFirstClassDefMutableOrNull(predicate)) fun gettingFirstClassDefOrNull( - type: String, predicate: (MatchPredicate)? = null + type: String, predicate: (context(MatchContext) ClassDef.() -> Boolean)? = null ) = ReadOnlyProperty { firstClassDefOrNull(type, predicate) } fun gettingFirstClassDef( - type: String, predicate: (MatchPredicate)? = null + type: String, predicate: (context(MatchContext) ClassDef.() -> Boolean)? = null ) = requireNotNull(gettingFirstClassDefOrNull(type, predicate)) fun gettingFirstClassDefMutableOrNull( - type: String, predicate: (MatchPredicate)? = null + type: String, predicate: (context(MatchContext) ClassDef.() -> Boolean)? = null ) = ReadOnlyProperty { firstClassDefMutableOrNull(type, predicate) } fun gettingFirstClassDefMutable( - type: String, predicate: (MatchPredicate)? = null + type: String, predicate: (context(MatchContext) ClassDef.() -> Boolean)? = null ) = requireNotNull(gettingFirstClassDefMutableOrNull(type, predicate)) -fun gettingFirstMethodOrNull(predicate: MatchPredicate) = +fun gettingFirstMethodOrNull(predicate: context(MatchContext) Method.() -> Boolean) = ReadOnlyProperty { firstMethodOrNull(predicate) } -fun gettingFirstMethod(predicate: MatchPredicate) = requireNotNull(gettingFirstMethodOrNull(predicate)) +fun gettingFirstMethod(predicate: context(MatchContext) Method.() -> Boolean) = + requireNotNull(gettingFirstMethodOrNull(predicate)) -fun gettingFirstMethodMutableOrNull(predicate: MatchPredicate) = +fun gettingFirstMethodMutableOrNull(predicate: context(MatchContext) Method.() -> Boolean) = ReadOnlyProperty { firstMethodMutableOrNull(predicate) } -fun gettingFirstMethodMutable(predicate: MatchPredicate) = +fun gettingFirstMethodMutable(predicate: context(MatchContext) Method.() -> Boolean) = requireNotNull(gettingFirstMethodMutableOrNull(predicate)) fun gettingFirstMethodOrNull( vararg strings: String, - predicate: MatchPredicate = MatchPredicate { true }, + predicate: context(MatchContext) Method.() -> Boolean = { true }, ) = ReadOnlyProperty { firstMethodOrNull(*strings, predicate = predicate) } fun gettingFirstMethod( vararg strings: String, - predicate: MatchPredicate = MatchPredicate { true }, + predicate: context(MatchContext) Method.() -> Boolean = { true }, ) = requireNotNull(gettingFirstMethodOrNull(*strings, predicate = predicate)) fun gettingFirstMethodMutableOrNull( vararg strings: String, - predicate: MatchPredicate = MatchPredicate { true }, + predicate: context(MatchContext) Method.() -> Boolean = { true }, ) = ReadOnlyProperty { firstMethodMutableOrNull(*strings, predicate = predicate) } fun gettingFirstMethodMutable( vararg strings: String, - predicate: MatchPredicate = MatchPredicate { true }, + predicate: context(MatchContext) Method.() -> Boolean = { true }, ) = requireNotNull(gettingFirstMethodMutableOrNull(*strings, predicate = predicate)) -fun interface MatchPredicate { - context(MatchContext) fun T.match(): Boolean -} +fun indexedMatcher() = IndexedMatcher() + +// Add lambda to emit instructions if matched (or matched arg) +fun indexedMatcher(build: IndexedMatcher.() -> Unit) = + IndexedMatcher().apply(build) + +fun Iterable.matchIndexed(build: IndexedMatcher.() -> Unit) = + indexedMatcher(build)(this) + +context(_: MatchContext) +operator fun IndexedMatcher.invoke(iterable: Iterable, key: String, builder: IndexedMatcher.() -> Unit) = + remember(key) { IndexedMatcher().apply(builder) }(iterable) + +context(_: MatchContext) +fun Iterable.matchIndexed(key: String, build: IndexedMatcher.() -> Unit) = + indexedMatcher()(this, key, build) abstract class Matcher : MutableList by mutableListOf() { var matchIndex = -1 @@ -234,101 +242,12 @@ abstract class Matcher : MutableList by mutableListOf() { abstract operator fun invoke(haystack: Iterable): Boolean class MatchContext internal constructor() : MutableMap by mutableMapOf() { - inline fun remember(key: String, defaultValue: () -> V) = - get(key) as? V ?: defaultValue().also { put(key, it) } } } -fun slidingWindowMatcher(build: SlidingWindowMatcher.() -> Unit) = - SlidingWindowMatcher().apply(build) - -context(MatchContext) -fun Iterable.matchSlidingWindow(key: String, build: SlidingWindowMatcher.() -> Unit) = - remember(key) { slidingWindowMatcher(build) }(this) - -fun Iterable.matchSlidingWindow(build: SlidingWindowMatcher.() -> Unit) = - slidingWindowMatcher(build)(this) - -class SlidingWindowMatcher() : Matcher Boolean>() { - override operator fun invoke(haystack: Iterable): Boolean { - val haystackCount = haystack.count() - val needleSize = size - if (needleSize == 0) return false - - for (i in 0..(haystackCount - needleSize)) { - var matched = true - for (j in 0 until needleSize) { - if (!this[j].invoke(haystack.elementAt(i + j))) { - matched = false - break - } - } - if (matched) { - matchIndex = i - return true - } - } - - matchIndex = -1 - return false - } -} - -fun findStringsMatcher(build: MutableList.() -> Unit) = - FindStringsMatcher().apply(build) - -class FindStringsMatcher() : Matcher() { - private val _matchedStrings = mutableListOf>() - val matchedStrings: List> = _matchedStrings - - override fun invoke(haystack: Iterable): Boolean { - _matchedStrings.clear() - val remaining = indices.toMutableList() - - haystack.forEachIndexed { hayIndex, instruction -> - val string = ((instruction as? ReferenceInstruction)?.reference as? StringReference)?.string - ?: return@forEachIndexed - - val index = remaining.firstOrNull { this[it] in string } ?: return@forEachIndexed - - _matchedStrings += this[index] to hayIndex - remaining -= index - } - - return remaining.isEmpty() - } -} - -fun BytecodePatchContext.a() { - val match = indexedMatcher { - first { opcode == Opcode.OR_INT_2ADDR } - after { opcode == Opcode.RETURN_VOID } - after(atLeast = 2, atMost = 5) { opcode == Opcode.MOVE_RESULT_OBJECT } - opcode(Opcode.RETURN_VOID) - } - - val myMethod = firstMethod { - implementation { match(instructions) } - } - - match._indices // Mapped in same order as defined -} - -fun IndexedMatcher.opcode(opcode: Opcode) { - after { this.opcode == opcode } -} - -context(MatchContext) -fun Method.instructions(key: String, build: IndexedMatcher.() -> Unit) = - instructions.matchIndexed("instructions", build) - - -fun indexedMatcher(build: IndexedMatcher.() -> Unit) = - IndexedMatcher().apply(build) - -context(MatchContext) -fun Iterable.matchIndexed(key: String, build: IndexedMatcher.() -> Unit) = - remember>(key) { indexedMatcher(build) }(this) +context(context: MatchContext) +inline fun remember(key: String, defaultValue: () -> V) = + context[key] as? V ?: defaultValue().also { context[key] = it } class IndexedMatcher() : Matcher Boolean>() { private val _indices: MutableList = mutableListOf() @@ -395,3 +314,62 @@ class IndexedMatcher() : Matcher Boolean>() { if (distance in atLeast..atMost) predicate() else false } } + +fun BytecodePatchContext.matchers() { + val customMatcher = object : Matcher Boolean>() { + override fun invoke(haystack: Iterable) = true + }.apply { add { true } } + + // Probably gonna make this ctor internal. + IndexedMatcher().apply { add { true } } + // Since there is a function for it. + val m = indexedMatcher() + m.apply { add { true } } + + // You can directly use the extension function to match. + listOf().matchIndexed { add { true } } + + // Inside a match context extension functions are cacheable: + firstMethod { instructions.matchIndexed("key") { add { true } } } + + // Or create a matcher outside a context and use it in a MatchContext as follows: + val match = indexedMatcher() + firstMethod { match(instructions, "anotherKey") { first { opcode(Opcode.RETURN_VOID) } } } + match.indices // so that you can access the matched indices later. +} + +fun BytecodePatchContext.a() { + val matcher = indexedMatcher() + + firstMethodMutableOrNull("string to find in lookupmap") { + returnType == "L" && matcher(instructions, "key") { + first { + // The first instruction is a field reference to a field in the class of the method being matched. + // We cache the field name using remember to avoid redundant lookups. + fieldReference!!.name == remember("fieldName") { + firstClassDef(definingClass).fields.first().name + } + } + after { fieldReference("fieldName") } + after { + opcode(Opcode.NEW_INSTANCE) && methodReference { toString() == "Lcom/example/MyClass;" } + } + // Followed by 2 to 4 string instructions starting with "test". + after(atLeast = 1, atMost = 2) { string { startsWith("test") } } + } && parameterTypes.matchIndexed("params") { + // Fully dynamic environment to customize depending on your needs. + operator fun String.plus(other: String) { + after { this == this@plus } + after { this == other } + } + + "L" + "I" + "Z" // Matches parameter types "L", "I", "Z" in order. + } + } + + firstMethodMutable { + accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) && instructions.matchIndexed("anotherKey") { + first { opcode(Opcode.RETURN_VOID) } + } + } +} diff --git a/src/main/kotlin/app/revanced/patcher/dex/mutable/MutableAnnotationElement.kt b/src/main/kotlin/app/revanced/patcher/dex/mutable/MutableAnnotationElement.kt index db8f941..08cbb4b 100644 --- a/src/main/kotlin/app/revanced/patcher/dex/mutable/MutableAnnotationElement.kt +++ b/src/main/kotlin/app/revanced/patcher/dex/mutable/MutableAnnotationElement.kt @@ -1,7 +1,5 @@ package app.revanced.patcher.dex.mutable -import app.revanced.patcher.dex.mutable.encodedValue.MutableEncodedValue -import app.revanced.patcher.dex.mutable.encodedValue.MutableEncodedValue.Companion.toMutable import app.revanced.patcher.dex.mutable.encodedValue.MutableEncodedValue import app.revanced.patcher.dex.mutable.encodedValue.MutableEncodedValue.Companion.toMutable import com.android.tools.smali.dexlib2.base.BaseAnnotationElement diff --git a/src/main/kotlin/app/revanced/patcher/extensions/Instruction.kt b/src/main/kotlin/app/revanced/patcher/extensions/Instruction.kt index ecd8db2..46dcc30 100644 --- a/src/main/kotlin/app/revanced/patcher/extensions/Instruction.kt +++ b/src/main/kotlin/app/revanced/patcher/extensions/Instruction.kt @@ -1,9 +1,12 @@ package app.revanced.patcher.extensions +import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.iface.instruction.DualReferenceInstruction import com.android.tools.smali.dexlib2.iface.instruction.Instruction import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction -import com.android.tools.smali.dexlib2.iface.reference.Reference +import com.android.tools.smali.dexlib2.iface.instruction.WideLiteralInstruction +import com.android.tools.smali.dexlib2.iface.reference.* +import com.android.tools.smali.dexlib2.util.MethodUtil @Suppress("UNCHECKED_CAST") fun Instruction.reference(predicate: T.() -> Boolean) = @@ -12,3 +15,52 @@ fun Instruction.reference(predicate: T.() -> Boolean) = @Suppress("UNCHECKED_CAST") fun Instruction.reference2(predicate: T.() -> Boolean) = ((this as? DualReferenceInstruction)?.reference2 as? T)?.predicate() ?: false + +fun Instruction.methodReference(predicate: MethodReference.() -> Boolean) = + reference(predicate) + +fun Instruction.methodReference(methodReference: MethodReference) = + methodReference { MethodUtil.methodSignaturesMatch(methodReference, this) } + +fun Instruction.fieldReference(predicate: FieldReference.() -> Boolean) = + reference(predicate) + +fun Instruction.fieldReference(fieldName: String) = + fieldReference { name == fieldName } + +fun Instruction.type(predicate: String.() -> Boolean) = + reference { type.predicate() } + +fun Instruction.type(type: String) = + type { this == type } + +fun Instruction.string(predicate: String.() -> Boolean) = + reference { string.predicate() } + +fun Instruction.string(string: String) = + string { this == string } + +fun Instruction.opcode(opcode: Opcode) = this.opcode == opcode + +fun Instruction.wideLiteral(wideLiteral: Long) = (this as? WideLiteralInstruction)?.wideLiteral == wideLiteral + +private inline fun Instruction.reference(): T? = + (this as? ReferenceInstruction)?.reference as? T + +val Instruction.reference: Reference? + get() = reference() + +val Instruction.methodReference get() = + reference() + +val Instruction.fieldReference get() = + reference() + +val Instruction.typeReference get() = + reference() + +val Instruction.stringReference get() = + reference() + +val Instruction.wideLiteral get() = + (this as? WideLiteralInstruction)?.wideLiteral diff --git a/src/main/kotlin/app/revanced/patcher/extensions/Method.kt b/src/main/kotlin/app/revanced/patcher/extensions/Method.kt index 0076664..6149e90 100644 --- a/src/main/kotlin/app/revanced/patcher/extensions/Method.kt +++ b/src/main/kotlin/app/revanced/patcher/extensions/Method.kt @@ -1,23 +1,19 @@ package app.revanced.patcher.extensions import app.revanced.patcher.dex.mutable.MutableMethod -import app.revanced.patcher.util.smali.ExternalLabel -import app.revanced.patcher.util.smali.toInstructions +import app.revanced.patcher.util.toInstructions +import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.builder.BuilderInstruction import com.android.tools.smali.dexlib2.builder.BuilderOffsetInstruction import com.android.tools.smali.dexlib2.builder.Label import com.android.tools.smali.dexlib2.builder.MutableMethodImplementation -import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction10t -import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction20t -import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction21t -import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction22t -import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction30t -import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction31t +import com.android.tools.smali.dexlib2.builder.instruction.* import com.android.tools.smali.dexlib2.iface.Method import com.android.tools.smali.dexlib2.iface.MethodImplementation import com.android.tools.smali.dexlib2.iface.instruction.Instruction -import kotlin.collections.forEach -import kotlin.collections.indexOf + +fun Method.accessFlags(vararg flags: AccessFlags) = + accessFlags.and(flags.map { it.ordinal }.reduce { acc, i -> acc or i }) != 0 /** * Add instructions to a method at the given index. @@ -382,3 +378,10 @@ val MutableMethod.instructions: MutableList get() = instruct * @return The label. */ fun MutableMethod.newLabel(index: Int) = implementation!!.newLabelForIndex(index) + +/** + * A class that represents a label for an instruction. + * @param name The label name. + * @param instruction The instruction that this label is for. + */ +data class ExternalLabel(internal val name: String, internal val instruction: Instruction) diff --git a/src/main/kotlin/app/revanced/patcher/util/MethodNavigator.kt b/src/main/kotlin/app/revanced/patcher/util/MethodNavigator.kt index 5c18432..ab4117d 100644 --- a/src/main/kotlin/app/revanced/patcher/util/MethodNavigator.kt +++ b/src/main/kotlin/app/revanced/patcher/util/MethodNavigator.kt @@ -2,9 +2,9 @@ package app.revanced.patcher.util -import app.revanced.patcher.patch.BytecodePatchContext import app.revanced.patcher.dex.mutable.MutableMethod import app.revanced.patcher.extensions.instructionsOrNull +import app.revanced.patcher.patch.BytecodePatchContext import com.android.tools.smali.dexlib2.iface.ClassDef import com.android.tools.smali.dexlib2.iface.Method import com.android.tools.smali.dexlib2.iface.instruction.Instruction @@ -23,12 +23,12 @@ import kotlin.reflect.KProperty * @throws NavigateException If the method does not have an implementation. * @throws NavigateException If the instruction at the specified index is not a method reference. */ -context(BytecodePatchContext) class MethodNavigator internal constructor( private var startMethod: MethodReference, ) { private var lastNavigatedMethodReference = startMethod + context(_: BytecodePatchContext) private val lastNavigatedMethodInstructions get() = with(original()) { instructionsOrNull ?: throw NavigateException("Method $this does not have an implementation.") @@ -41,6 +41,7 @@ class MethodNavigator internal constructor( * * @return This [MethodNavigator]. */ + context(_: BytecodePatchContext) fun to(vararg index: Int): MethodNavigator { index.forEach { lastNavigatedMethodReference = lastNavigatedMethodInstructions.getMethodReferenceAt(it) @@ -55,6 +56,7 @@ class MethodNavigator internal constructor( * @param index The index of the method to navigate to. * @param predicate The predicate to match. */ + context(_: BytecodePatchContext) fun to(index: Int = 0, predicate: (Instruction) -> Boolean): MethodNavigator { lastNavigatedMethodReference = lastNavigatedMethodInstructions.asSequence() .filter(predicate).asIterable().getMethodReferenceAt(index) @@ -79,22 +81,27 @@ class MethodNavigator internal constructor( * * @return The last navigated method mutably. */ - fun stop() = classDefs.find(matchesCurrentMethodReferenceDefiningClass)!!.mutable().firstMethodBySignature - as MutableMethod + context(context: BytecodePatchContext) + fun stop() = with(context) { + classDefs.find(matchesCurrentMethodReferenceDefiningClass)!!.mutable().firstMethodBySignature + as MutableMethod + } /** * Get the last navigated method mutably. * * @return The last navigated method mutably. */ - operator fun getValue(nothing: Nothing?, property: KProperty<*>) = stop() + operator fun getValue(context: BytecodePatchContext?, property: KProperty<*>) = + context(requireNotNull(context)) { stop() } /** * Get the last navigated method immutably. * * @return The last navigated method immutably. */ - fun original(): Method = classDefs.first(matchesCurrentMethodReferenceDefiningClass).firstMethodBySignature + context(context: BytecodePatchContext) + fun original(): Method = context.classDefs.first(matchesCurrentMethodReferenceDefiningClass).firstMethodBySignature /** * Predicate to match the class defining the current method reference. diff --git a/src/main/kotlin/app/revanced/patcher/util/Smali.kt b/src/main/kotlin/app/revanced/patcher/util/Smali.kt new file mode 100644 index 0000000..2d1d2fa --- /dev/null +++ b/src/main/kotlin/app/revanced/patcher/util/Smali.kt @@ -0,0 +1,66 @@ +package app.revanced.patcher.util + +import app.revanced.patcher.dex.mutable.MutableMethod +import app.revanced.patcher.extensions.instructions +import com.android.tools.smali.dexlib2.AccessFlags +import com.android.tools.smali.dexlib2.Opcodes +import com.android.tools.smali.dexlib2.builder.BuilderInstruction +import com.android.tools.smali.dexlib2.writer.builder.DexBuilder +import com.android.tools.smali.smali.smaliFlexLexer +import com.android.tools.smali.smali.smaliParser +import com.android.tools.smali.smali.smaliTreeWalker +import org.antlr.runtime.CommonTokenStream +import org.antlr.runtime.TokenSource +import org.antlr.runtime.tree.CommonTreeNodeStream +import java.io.StringReader + +private const val CLASS_HEADER = ".class LInlineCompiler;\n.super Ljava/lang/Object;\n" +private const val STATIC_HEADER = "$CLASS_HEADER.method public static dummyMethod(" +private const val HEADER = "$CLASS_HEADER.method public dummyMethod(" + +private val dexBuilder = DexBuilder(Opcodes.getDefault()) +private val sb by lazy { StringBuilder(512) } + +/** + * Compile lines of Smali code to a list of instructions. + * + * Note: Adding compiled instructions to an existing method with + * offset instructions WITHOUT specifying a parent method will not work. + * @param templateMethod The method to compile the instructions against. + * @returns A list of instructions. + */ +fun String.toInstructions(templateMethod: MutableMethod? = null): List { + val parameters = templateMethod?.parameterTypes?.joinToString("") { it } ?: "" + val registers = templateMethod?.implementation?.registerCount ?: 1 // TODO: Should this be 0? + val isStatic = templateMethod?.let { AccessFlags.STATIC.isSet(it.accessFlags) } ?: true + + sb.setLength(0) // reset + + if (isStatic) sb.append(STATIC_HEADER) else sb.append(HEADER) + sb.append(parameters).append(")V\n") + sb.append(" .registers ").append(registers).append("\n") + sb.append(trimIndent()).append("\n") + sb.append(".end method") + + val reader = StringReader(sb.toString()) + val lexer = smaliFlexLexer(reader, 15) + val tokens = CommonTokenStream(lexer as TokenSource) + val parser = smaliParser(tokens) + val fileTree = parser.smali_file() + + if (lexer.numberOfSyntaxErrors > 0 || parser.numberOfSyntaxErrors > 0) { + throw IllegalStateException( + "Lexer errors: ${lexer.numberOfSyntaxErrors}, Parser errors: ${parser.numberOfSyntaxErrors}" + ) + } + + val treeStream = CommonTreeNodeStream(fileTree.tree).apply { + tokenStream = tokens + } + + val walker = smaliTreeWalker(treeStream) + walker.setDexBuilder(dexBuilder) + + val classDef = walker.smali_file() + return classDef.methods.first().instructions.map { it as BuilderInstruction } +} diff --git a/src/main/kotlin/app/revanced/patcher/util/smali/ExternalLabel.kt b/src/main/kotlin/app/revanced/patcher/util/smali/ExternalLabel.kt deleted file mode 100644 index e336de6..0000000 --- a/src/main/kotlin/app/revanced/patcher/util/smali/ExternalLabel.kt +++ /dev/null @@ -1,10 +0,0 @@ -package app.revanced.patcher.util.smali - -import com.android.tools.smali.dexlib2.iface.instruction.Instruction - -/** - * A class that represents a label for an instruction. - * @param name The label name. - * @param instruction The instruction that this label is for. - */ -data class ExternalLabel(internal val name: String, internal val instruction: Instruction) diff --git a/src/main/kotlin/app/revanced/patcher/util/smali/InlineSmaliCompiler.kt b/src/main/kotlin/app/revanced/patcher/util/smali/InlineSmaliCompiler.kt deleted file mode 100644 index 7e85e6b..0000000 --- a/src/main/kotlin/app/revanced/patcher/util/smali/InlineSmaliCompiler.kt +++ /dev/null @@ -1,95 +0,0 @@ -package app.revanced.patcher.util.smali - -import app.revanced.patcher.dex.mutable.MutableMethod -import app.revanced.patcher.extensions.instructions -import com.android.tools.smali.dexlib2.AccessFlags -import com.android.tools.smali.dexlib2.Opcodes -import com.android.tools.smali.dexlib2.builder.BuilderInstruction -import com.android.tools.smali.dexlib2.writer.builder.DexBuilder -import com.android.tools.smali.smali.LexerErrorInterface -import com.android.tools.smali.smali.smaliFlexLexer -import com.android.tools.smali.smali.smaliParser -import com.android.tools.smali.smali.smaliTreeWalker -import org.antlr.runtime.CommonTokenStream -import org.antlr.runtime.TokenSource -import org.antlr.runtime.tree.CommonTreeNodeStream -import java.io.InputStreamReader -import java.util.* - -private const val METHOD_TEMPLATE = """ - .class LInlineCompiler; - .super Ljava/lang/Object; - .method %s dummyMethod(%s)V - .registers %d - %s - .end method -""" - -class InlineSmaliCompiler { - companion object { - /** - * Compiles a string of Smali code to a list of instructions. - * Special registers (such as p0, p1) will only work correctly - * if the parameters and registers of the method are passed. - */ - fun compile( - instructions: String, - parameters: String, - registers: Int, - forStaticMethod: Boolean, - ): List { - val input = - METHOD_TEMPLATE.format( - Locale.ENGLISH, - if (forStaticMethod) { - "static" - } else { - "" - }, - parameters, - registers, - instructions, - ) - val reader = InputStreamReader(input.byteInputStream(), Charsets.UTF_8) - val lexer: LexerErrorInterface = smaliFlexLexer(reader, 15) - val tokens = CommonTokenStream(lexer as TokenSource) - val parser = smaliParser(tokens) - val result = parser.smali_file() - if (parser.numberOfSyntaxErrors > 0 || lexer.numberOfSyntaxErrors > 0) { - throw IllegalStateException( - "Encountered ${parser.numberOfSyntaxErrors} parser syntax errors and ${lexer.numberOfSyntaxErrors} lexer syntax errors!", - ) - } - val treeStream = CommonTreeNodeStream(result.tree) - treeStream.tokenStream = tokens - val dexGen = smaliTreeWalker(treeStream) - dexGen.setDexBuilder(DexBuilder(Opcodes.getDefault())) - val classDef = dexGen.smali_file() - return classDef.methods.first().instructions.map { it as BuilderInstruction } - } - } -} - -/** - * Compile lines of Smali code to a list of instructions. - * - * Note: Adding compiled instructions to an existing method with - * offset instructions WITHOUT specifying a parent method will not work. - * @param method The method to compile the instructions against. - * @returns A list of instructions. - */ -fun String.toInstructions(method: MutableMethod? = null): List { - return InlineSmaliCompiler.compile( - this, - method?.parameters?.joinToString("") { it } ?: "", - method?.implementation?.registerCount ?: 1, - method?.let { AccessFlags.STATIC.isSet(it.accessFlags) } ?: true, - ) -} - -/** - * Compile a line of Smali code to an instruction. - * @param templateMethod The method to compile the instructions against. - * @return The instruction. - */ -fun String.toInstruction(templateMethod: MutableMethod? = null) = this.toInstructions(templateMethod).first() diff --git a/src/test/kotlin/app/revanced/patcher/util/smali/InlineSmaliCompilerTest.kt b/src/test/kotlin/app/revanced/patcher/util/smali/InlineSmaliCompilerTest.kt index d5740ae..c4d3f3e 100644 --- a/src/test/kotlin/app/revanced/patcher/util/smali/InlineSmaliCompilerTest.kt +++ b/src/test/kotlin/app/revanced/patcher/util/smali/InlineSmaliCompilerTest.kt @@ -1,10 +1,8 @@ package app.revanced.patcher.util.smali import app.revanced.patcher.dex.mutable.MutableMethod.Companion.toMutable -import app.revanced.patcher.extensions.addInstructions -import app.revanced.patcher.extensions.addInstructionsWithLabels -import app.revanced.patcher.extensions.getInstruction -import app.revanced.patcher.extensions.newLabel +import app.revanced.patcher.extensions.* +import app.revanced.patcher.util.toInstructions import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.builder.BuilderInstruction @@ -22,7 +20,7 @@ internal object InlineSmaliCompilerTest { @Test fun `outputs valid instruction`() { val want = BuilderInstruction21c(Opcode.CONST_STRING, 0, ImmutableStringReference("Test")) as BuilderInstruction - val have = "const-string v0, \"Test\"".toInstruction() + val have = "const-string v0, \"Test\"".toInstructions().first() assertInstructionsEqual(want, have) }