Skip to content

Commit

Permalink
Merge branch 'feat/integrations' into dev
Browse files Browse the repository at this point in the history
  • Loading branch information
crimera committed Mar 2, 2024
2 parents 3d734cc + f511c38 commit 1a9dbf1
Show file tree
Hide file tree
Showing 6 changed files with 228 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package app.revanced.patches.shared.misc.integrations

import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.fingerprint.MethodFingerprint
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchException
import app.revanced.patches.shared.misc.integrations.BaseIntegrationsPatch.IntegrationsFingerprint.IRegisterResolver
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.ClassDef
import com.android.tools.smali.dexlib2.iface.Method

abstract class BaseIntegrationsPatch(
private val hooks: Set<IntegrationsFingerprint>
) : BytecodePatch(hooks) {

@Deprecated(
"Use the constructor without the integrationsDescriptor parameter",
ReplaceWith("AbstractIntegrationsPatch(hooks)")
)
@Suppress("UNUSED_PARAMETER")
constructor(
integrationsDescriptor: String,
hooks: Set<IntegrationsFingerprint>
) : this(hooks)

override fun execute(context: BytecodeContext) {
if (context.findClass(INTEGRATIONS_CLASS_DESCRIPTOR) == null) throw PatchException(
"Integrations have not been merged yet. This patch can not succeed without merging the integrations."
)

hooks.forEach { hook ->
hook.invoke(INTEGRATIONS_CLASS_DESCRIPTOR)
}
}

/**
* [MethodFingerprint] for integrations.
*
* @param contextRegisterResolver A [IRegisterResolver] to get the register.
* @see MethodFingerprint
*/
abstract class IntegrationsFingerprint(
returnType: String? = null,
accessFlags: Int? = null,
parameters: Iterable<String>? = null,
opcodes: Iterable<Opcode?>? = null,
strings: Iterable<String>? = null,
customFingerprint: ((methodDef: Method, classDef: ClassDef) -> Boolean)? = null,
private val contextRegisterResolver: (Method) -> Int = object : IRegisterResolver {}
) : MethodFingerprint(
returnType,
accessFlags,
parameters,
opcodes,
strings,
customFingerprint
) {
fun invoke(integrationsDescriptor: String) {
result?.mutableMethod?.let { method ->
val contextRegister = contextRegisterResolver(method)

method.addInstruction(
0,
"sput-object v$contextRegister, " +
"$integrationsDescriptor->context:Landroid/content/Context;"
)
} ?: throw PatchException("Could not find hook target fingerprint.")
}

interface IRegisterResolver : (Method) -> Int {
override operator fun invoke(method: Method) = method.implementation!!.registerCount - 1
}
}

private companion object {
private const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/shared/Utils;"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package crimera.patches.twitter.misc.integrations

import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patches.shared.misc.integrations.BaseIntegrationsPatch
import crimera.patches.twitter.misc.integrations.fingerprints.InitFingerprint

@Patch(
requiresIntegrations = true
)
object IntegrationsPatch: BaseIntegrationsPatch(
setOf(InitFingerprint)
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package crimera.patches.twitter.misc.integrations.fingerprints

import app.revanced.patches.shared.misc.integrations.BaseIntegrationsPatch.IntegrationsFingerprint

internal object InitFingerprint : IntegrationsFingerprint(
strings = listOf("builderClass"),
customFingerprint = { methodDef, _ ->
methodDef.name == "onCreate"
}
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package crimera.patches.twitter.misc.settings

import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.extensions.InstructionExtensions.getInstructions
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchException
import app.revanced.patcher.patch.annotation.CompatiblePackage
import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patcher.util.smali.ExternalLabel
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction11x
import crimera.patches.twitter.misc.integrations.IntegrationsPatch
import crimera.patches.twitter.misc.settings.fingerprints.SettingsFingerprint

@Patch(
name = "Settings",
description = "Adds settings",
requiresIntegrations = true,
dependencies = [SettingsResourcePatch::class, IntegrationsPatch::class],
compatiblePackages = [CompatiblePackage("com.twitter.android")],
)
@Suppress("unused")
object SettingsPatch : BytecodePatch(
setOf(SettingsFingerprint)
) {
private const val INTEGRATIONS_PACKAGE = "Lapp/revanced/integrations/twitter"
private const val UTILS_DESCRIPTOR = "$INTEGRATIONS_PACKAGE/Utils"
private const val ADD_PREF_DESCRIPTOR = "$UTILS_DESCRIPTOR;->addPref([Ljava/lang/String;Ljava/lang/String;)[Ljava/lang/String;"
private const val START_ACTIVITY_DESCRIPTOR =
"invoke-static {}, $UTILS_DESCRIPTOR;->startActivity()V"

override fun execute(context: BytecodeContext) {
val result = SettingsFingerprint.result
?: throw PatchException("Fingerprint not found")

val initMethod = result.mutableClass.methods.first()

val arrayCreation = initMethod.getInstructions()
.first { it.opcode == Opcode.FILLED_NEW_ARRAY_RANGE }.location.index+1

initMethod.getInstruction<BuilderInstruction11x>(arrayCreation).registerA.also { reg->
initMethod.addInstructions(arrayCreation+1, """
const-string v1, "pref_mod"
invoke-static {v$reg, v1}, $ADD_PREF_DESCRIPTOR
move-result-object v$reg
""")
}

val prefCLickedMethod = result.mutableClass.methods.find { it.returnType == "Z" }!!
val constIndex = prefCLickedMethod.getInstructions().first{ it.opcode == Opcode.CONST_4 }.location.index

prefCLickedMethod.addInstructionsWithLabels(1, """
const-string v1, "pref_mod"
invoke-virtual {p1, v1}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
move-result v2
if-nez v2, :start
goto :cont
:start
$START_ACTIVITY_DESCRIPTOR
const/4 v3, 0x1
return v3
""",
ExternalLabel("cont", prefCLickedMethod.getInstruction(constIndex))
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package crimera.patches.twitter.misc.settings

import app.revanced.patcher.data.ResourceContext
import app.revanced.patcher.patch.PatchException
import app.revanced.patcher.patch.ResourcePatch
import app.revanced.patcher.patch.annotation.CompatiblePackage
import app.revanced.patcher.patch.annotation.Patch
import org.w3c.dom.Element

@Patch(
compatiblePackages = [CompatiblePackage("com.twitter.android")],
)
@Suppress("unused")
object SettingsResourcePatch: ResourcePatch() {
override fun execute(context: ResourceContext) {
val settingsRoot = context["res/xml/settings_root.xml"]
if (!settingsRoot.exists()) throw PatchException("settings_root not found")

context.xmlEditor["res/xml/settings_root.xml"].use { editor ->
val parent = editor.file.getElementsByTagName("PreferenceScreen").item(0) as Element

val prefMod = editor.file.createElement("Preference")
prefMod.setAttribute("android:icon", "@drawable/ic_vector_settings_stroke")
prefMod.setAttribute("android:title", "Mod Settings")
prefMod.setAttribute("android:key", "pref_mod")
prefMod.setAttribute("android:order", "110")

parent.appendChild(prefMod)
}

context.xmlEditor["AndroidManifest.xml"].use {
val applicationNode = it.file.getElementsByTagName("application").item(0)

val modActivity = it.file.createElement("activity").apply {
setAttribute("android:label", "Mod Settings")
setAttribute("android:name", "app.revanced.integrations.twitter.settings.SettingsActivity")
setAttribute("android:excludeFromRecents", "true")
}

applicationNode.appendChild(modActivity)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package crimera.patches.twitter.misc.settings.fingerprints

import app.revanced.patcher.fingerprint.MethodFingerprint

object SettingsFingerprint: MethodFingerprint(
returnType = "V",
strings = listOf(
"pref_proxy"
),
customFingerprint = { it, _ ->
it.name == "<clinit>"
}
)

0 comments on commit 1a9dbf1

Please sign in to comment.