From 12c10d8c64422c4534c23467e367707e3b953f82 Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Tue, 5 Apr 2022 03:52:00 +0200 Subject: [PATCH] fix: fix classes having multiple method instances --- .../kotlin/app/revanced/patcher/Patcher.kt | 10 ++-- .../app/revanced/patcher/cache/Cache.kt | 2 +- .../proxy/mutableTypes/MutableClass.kt | 18 +++++-- .../mutableTypes/MutableMethodParameter.kt | 4 +- .../patcher/smali/InlineSmaliCompiler.kt | 1 - src/test/kotlin/patcher/PatcherTest.kt | 53 +++++++++++-------- 6 files changed, 54 insertions(+), 34 deletions(-) diff --git a/src/main/kotlin/app/revanced/patcher/Patcher.kt b/src/main/kotlin/app/revanced/patcher/Patcher.kt index c1032342..2410741a 100644 --- a/src/main/kotlin/app/revanced/patcher/Patcher.kt +++ b/src/main/kotlin/app/revanced/patcher/Patcher.kt @@ -29,7 +29,7 @@ class Patcher( init { val dexFile = MultiDexIO.readDexFile(true, input, BasicDexFileNamer(), null, null) - cache = Cache(dexFile.classes, SignatureResolver(dexFile.classes, signatures).resolve()) + cache = Cache(dexFile.classes.toMutableSet(), SignatureResolver(dexFile.classes, signatures).resolve()) } /** @@ -39,13 +39,13 @@ class Patcher( val newDexFile = object : DexFile { override fun getClasses(): Set { // this is a slow workaround for now - val classes = cache.classes.toMutableSet() cache.classProxy .filter { it.proxyUsed }.forEach { proxy -> - classes.remove(classes.elementAt(proxy.originalIndex)) - classes.add(proxy.mutatedClass) + cache.classes.remove(cache.classes.elementAt(proxy.originalIndex)) + cache.classes.add(proxy.mutatedClass) } - return classes + + return setOf(cache.classProxy.first().mutatedClass) } override fun getOpcodes(): Opcodes { diff --git a/src/main/kotlin/app/revanced/patcher/cache/Cache.kt b/src/main/kotlin/app/revanced/patcher/cache/Cache.kt index 8b7321f9..4b66fac3 100644 --- a/src/main/kotlin/app/revanced/patcher/cache/Cache.kt +++ b/src/main/kotlin/app/revanced/patcher/cache/Cache.kt @@ -5,7 +5,7 @@ import app.revanced.patcher.signature.SignatureResolverResult import org.jf.dexlib2.iface.ClassDef class Cache( - internal val classes: Set, + internal val classes: MutableSet, val resolvedMethods: MethodMap ) { // TODO: currently we create ClassProxies at multiple places, which is why we could have merge conflicts diff --git a/src/main/kotlin/app/revanced/patcher/proxy/mutableTypes/MutableClass.kt b/src/main/kotlin/app/revanced/patcher/proxy/mutableTypes/MutableClass.kt index 4b4f8070..92cc1e48 100644 --- a/src/main/kotlin/app/revanced/patcher/proxy/mutableTypes/MutableClass.kt +++ b/src/main/kotlin/app/revanced/patcher/proxy/mutableTypes/MutableClass.kt @@ -3,8 +3,10 @@ package app.revanced.patcher.proxy.mutableTypes import app.revanced.patcher.proxy.mutableTypes.MutableAnnotation.Companion.toMutable import app.revanced.patcher.proxy.mutableTypes.MutableField.Companion.toMutable import app.revanced.patcher.proxy.mutableTypes.MutableMethod.Companion.toMutable +import com.google.common.collect.Iterables import org.jf.dexlib2.base.reference.BaseTypeReference import org.jf.dexlib2.iface.ClassDef +import org.jf.dexlib2.util.MethodUtil class MutableClass(classDef: ClassDef) : ClassDef, BaseTypeReference() { // Class @@ -14,17 +16,23 @@ class MutableClass(classDef: ClassDef) : ClassDef, BaseTypeReference() { private var superclass = classDef.superclass private val _interfaces by lazy { classDef.interfaces.toMutableList() } - private val _annotations by lazy { classDef.annotations.map { annotation -> annotation.toMutable() }.toMutableSet() } + private val _annotations by lazy { + classDef.annotations.map { annotation -> annotation.toMutable() }.toMutableSet() + } // Methods private val _methods by lazy { classDef.methods.map { method -> method.toMutable() }.toMutableSet() } - private val _directMethods by lazy { classDef.directMethods.map { directMethod -> directMethod.toMutable() }.toMutableSet() } - private val _virtualMethods by lazy { classDef.virtualMethods.map { virtualMethod -> virtualMethod.toMutable() }.toMutableSet() } + private val _directMethods by lazy { Iterables.filter(_methods, MethodUtil.METHOD_IS_DIRECT).toMutableSet() } + private val _virtualMethods by lazy { Iterables.filter(_methods, MethodUtil.METHOD_IS_VIRTUAL).toMutableSet() } // Fields private val _fields by lazy { classDef.fields.map { field -> field.toMutable() }.toMutableSet() } - private val _staticFields by lazy { classDef.staticFields.map { staticField -> staticField.toMutable() }.toMutableSet() } - private val _instanceFields by lazy { classDef.instanceFields.map { instanceFields -> instanceFields.toMutable() }.toMutableSet() } + private val _staticFields by lazy { + classDef.staticFields.map { staticField -> staticField.toMutable() }.toMutableSet() + } + private val _instanceFields by lazy { + classDef.instanceFields.map { instanceFields -> instanceFields.toMutable() }.toMutableSet() + } fun setType(type: String) { this.type = type diff --git a/src/main/kotlin/app/revanced/patcher/proxy/mutableTypes/MutableMethodParameter.kt b/src/main/kotlin/app/revanced/patcher/proxy/mutableTypes/MutableMethodParameter.kt index d4594d4f..3b5287fe 100644 --- a/src/main/kotlin/app/revanced/patcher/proxy/mutableTypes/MutableMethodParameter.kt +++ b/src/main/kotlin/app/revanced/patcher/proxy/mutableTypes/MutableMethodParameter.kt @@ -9,7 +9,9 @@ class MutableMethodParameter(parameter: MethodParameter) : MethodParameter, Base private var type = parameter.type private var name = parameter.name private var signature = parameter.signature - private val _annotations by lazy { parameter.annotations.map { annotation -> annotation.toMutable() }.toMutableSet() } + private val _annotations by lazy { + parameter.annotations.map { annotation -> annotation.toMutable() }.toMutableSet() + } override fun getType(): String { return type diff --git a/src/main/kotlin/app/revanced/patcher/smali/InlineSmaliCompiler.kt b/src/main/kotlin/app/revanced/patcher/smali/InlineSmaliCompiler.kt index 3496a9e8..d1ced4f4 100644 --- a/src/main/kotlin/app/revanced/patcher/smali/InlineSmaliCompiler.kt +++ b/src/main/kotlin/app/revanced/patcher/smali/InlineSmaliCompiler.kt @@ -5,7 +5,6 @@ import org.antlr.runtime.TokenSource import org.antlr.runtime.tree.CommonTreeNodeStream import org.jf.dexlib2.Opcodes import org.jf.dexlib2.builder.BuilderInstruction -import org.jf.dexlib2.iface.instruction.Instruction import org.jf.dexlib2.writer.builder.DexBuilder import org.jf.smali.LexerErrorInterface import org.jf.smali.smaliFlexLexer diff --git a/src/test/kotlin/patcher/PatcherTest.kt b/src/test/kotlin/patcher/PatcherTest.kt index 1b49beb3..77aab4c5 100644 --- a/src/test/kotlin/patcher/PatcherTest.kt +++ b/src/test/kotlin/patcher/PatcherTest.kt @@ -11,6 +11,7 @@ import app.revanced.patcher.signature.MethodSignature import app.revanced.patcher.smali.asInstruction import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.Opcode +import org.jf.dexlib2.builder.instruction.BuilderInstruction21t import org.jf.dexlib2.builder.instruction.BuilderInstruction35c import org.jf.dexlib2.iface.reference.MethodReference import org.jf.dexlib2.immutable.reference.ImmutableMethodReference @@ -51,12 +52,12 @@ fun main() { it.name.contains("HideReel") }!! - val instructions = hideReelMethod.implementation!! + val implementation = hideReelMethod.implementation!! - val readInsn = + val readSettingsInstructionCompiled = "invoke-static { }, Lfi/razerman/youtube/XGlobals;->ReadSettings()V" .asInstruction() as BuilderInstruction35c - val testInsn = BuilderInstruction35c( + val readSettingsInstructionAssembled = BuilderInstruction35c( Opcode.INVOKE_STATIC, 0, 0, 0, 0, 0, 0, ImmutableMethodReference( @@ -67,30 +68,40 @@ fun main() { ) ) - assertEquals(testInsn.opcode, readInsn.opcode) - assertEquals(testInsn.referenceType, readInsn.referenceType) - assertEquals(testInsn.registerCount, readInsn.registerCount) - assertEquals(testInsn.registerC, readInsn.registerC) - assertEquals(testInsn.registerD, readInsn.registerD) - assertEquals(testInsn.registerE, readInsn.registerE) - assertEquals(testInsn.registerF, readInsn.registerF) - assertEquals(testInsn.registerG, readInsn.registerG) + assertEquals(readSettingsInstructionAssembled.opcode, readSettingsInstructionCompiled.opcode) + assertEquals( + readSettingsInstructionAssembled.referenceType, + readSettingsInstructionCompiled.referenceType + ) + assertEquals( + readSettingsInstructionAssembled.registerCount, + readSettingsInstructionCompiled.registerCount + ) + assertEquals(readSettingsInstructionAssembled.registerC, readSettingsInstructionCompiled.registerC) + assertEquals(readSettingsInstructionAssembled.registerD, readSettingsInstructionCompiled.registerD) + assertEquals(readSettingsInstructionAssembled.registerE, readSettingsInstructionCompiled.registerE) + assertEquals(readSettingsInstructionAssembled.registerF, readSettingsInstructionCompiled.registerF) + assertEquals(readSettingsInstructionAssembled.registerG, readSettingsInstructionCompiled.registerG) run { - val tref = testInsn.reference as MethodReference - val rref = readInsn.reference as MethodReference + val compiledRef = readSettingsInstructionCompiled.reference as MethodReference + val assembledRef = readSettingsInstructionAssembled.reference as MethodReference - assertEquals(tref.name, rref.name) - assertEquals(tref.definingClass, rref.definingClass) - assertEquals(tref.returnType, rref.returnType) - assertContentEquals(tref.parameterTypes, rref.parameterTypes) + assertEquals(assembledRef.name, compiledRef.name) + assertEquals(assembledRef.definingClass, compiledRef.definingClass) + assertEquals(assembledRef.returnType, compiledRef.returnType) + assertContentEquals(assembledRef.parameterTypes, compiledRef.parameterTypes) } - // TODO: figure out control flow - // otherwise the we would still jump over to the original instruction at index 21 instead to our new one - instructions.addInstruction( + implementation.addInstruction( 21, - readInsn + readSettingsInstructionCompiled ) + + // fix labels + // create a new label for the instruction we want to jump to + val newLabel = implementation.newLabelForIndex(21) + // replace all instances of the old label with the new one + implementation.replaceInstruction(4, BuilderInstruction21t(Opcode.IF_NEZ, 0, newLabel)) return PatchResultSuccess() } },