122 lines
5.1 KiB
Kotlin

package patcher
import app.revanced.patcher.Patcher
import app.revanced.patcher.cache.Cache
import app.revanced.patcher.extensions.or
import app.revanced.patcher.patch.Patch
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultError
import app.revanced.patcher.patch.PatchResultSuccess
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
import java.io.File
import kotlin.test.assertContentEquals
import kotlin.test.assertEquals
fun main() {
val signatures = arrayOf(
MethodSignature(
"main-method",
"V",
AccessFlags.STATIC or AccessFlags.PUBLIC,
listOf("[O"),
arrayOf(
Opcode.SGET_OBJECT,
Opcode.CONST_STRING,
Opcode.INVOKE_VIRTUAL,
Opcode.RETURN_VOID
)
)
)
val patcher = Patcher(
File("black.apk"),
File("./"),
signatures
)
patcher.addPatches(
object : Patch("main-method-patch-via-proxy") {
override fun execute(cache: Cache): PatchResult {
val proxy = cache.findClass("XAdRemover")
?: return PatchResultError("Class 'XAdRemover' could not be found")
val xAdRemoverClass = proxy.resolve()
val hideReelMethod = xAdRemoverClass.methods.find {
it.name.contains("HideReel")
}!!
val implementation = hideReelMethod.implementation!!
val readSettingsInstructionCompiled =
"invoke-static { }, Lfi/razerman/youtube/XGlobals;->ReadSettings()V"
.asInstruction() as BuilderInstruction35c
val readSettingsInstructionAssembled = BuilderInstruction35c(
Opcode.INVOKE_STATIC,
0, 0, 0, 0, 0, 0,
ImmutableMethodReference(
"Lfi/razerman/youtube/XGlobals;",
"ReadSettings",
emptyList(),
"V"
)
)
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 compiledRef = readSettingsInstructionCompiled.reference as MethodReference
val assembledRef = readSettingsInstructionAssembled.reference as MethodReference
assertEquals(assembledRef.name, compiledRef.name)
assertEquals(assembledRef.definingClass, compiledRef.definingClass)
assertEquals(assembledRef.returnType, compiledRef.returnType)
assertContentEquals(assembledRef.parameterTypes, compiledRef.parameterTypes)
}
implementation.addInstruction(
21,
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()
}
},
object : Patch("main-method-patch-via-signature") {
override fun execute(cache: Cache): PatchResult {
val mainMethodMap = cache.resolvedMethods["main-method"]
mainMethodMap.definingClassProxy.immutableClass.methods.single { method ->
method.name == mainMethodMap.resolvedMethodName
}
return PatchResultSuccess()
}
}
)
patcher.applyPatches()
patcher.save()
}