Skip to content

Commit

Permalink
fix: fix classes having multiple method instances
Browse files Browse the repository at this point in the history
  • Loading branch information
oSumAtrIX committed Jun 5, 2022
1 parent d18a3b6 commit 398239d
Show file tree
Hide file tree
Showing 6 changed files with 54 additions and 34 deletions.
10 changes: 5 additions & 5 deletions src/main/kotlin/app/revanced/patcher/Patcher.kt
Expand Up @@ -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())
}

/**
Expand All @@ -39,13 +39,13 @@ class Patcher(
val newDexFile = object : DexFile {
override fun getClasses(): Set<ClassDef> {
// 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 {
Expand Down
2 changes: 1 addition & 1 deletion src/main/kotlin/app/revanced/patcher/cache/Cache.kt
Expand Up @@ -5,7 +5,7 @@ import app.revanced.patcher.signature.SignatureResolverResult
import org.jf.dexlib2.iface.ClassDef

class Cache(
internal val classes: Set<ClassDef>,
internal val classes: MutableSet<ClassDef>,
val resolvedMethods: MethodMap
) {
// TODO: currently we create ClassProxies at multiple places, which is why we could have merge conflicts
Expand Down
Expand Up @@ -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
Expand All @@ -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
Expand Down
Expand Up @@ -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
Expand Down
Expand Up @@ -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
Expand Down
53 changes: 32 additions & 21 deletions src/test/kotlin/patcher/PatcherTest.kt
Expand Up @@ -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
Expand Down Expand Up @@ -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(
Expand All @@ -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()
}
},
Expand Down

0 comments on commit 398239d

Please sign in to comment.