Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(Twitter): Add Change link sharing domain patch #3118

Closed
wants to merge 30 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
08659a5
Make FxTwitter patch
FrozenAlex Oct 9, 2023
6a666c0
Fix replacing logic. Add dynamic source registers
FrozenAlex Oct 9, 2023
8e071a1
Fixes for the patch. Change the patching algo to make the patch more …
FrozenAlex Oct 9, 2023
15cc3c0
Add removal of telemetry from links too (not sure if should be its ow…
FrozenAlex Oct 9, 2023
5b0eec2
Fix comment
FrozenAlex Oct 9, 2023
243bae3
Moved telemetry patch to its own file
FrozenAlex Oct 9, 2023
a34205f
Simplify patch
FrozenAlex Oct 10, 2023
32394be
Update src/main/kotlin/app/revanced/patches/twitter/misc/links/Change…
FrozenAlex Oct 13, 2023
9368538
Update src/main/kotlin/app/revanced/patches/twitter/misc/links/Remove…
FrozenAlex Oct 13, 2023
d67acd4
Simplify stuff
FrozenAlex Nov 28, 2023
788ecff
Fixup comments
FrozenAlex Nov 28, 2023
a69d916
Reduce size of fingerprints
FrozenAlex Nov 28, 2023
4fc5925
Fix semantic stuff
FrozenAlex Nov 28, 2023
200641b
Make the register dynamic
FrozenAlex Nov 28, 2023
e28a346
Merge branch 'dev' into dev
FrozenAlex Nov 28, 2023
97dfa84
Fix building revanced
FrozenAlex Nov 28, 2023
422d702
Merge branch 'dev' into dev-twittrer
oSumAtrIX Dec 1, 2023
3ca6466
refactor: Use better names
oSumAtrIX Dec 1, 2023
45f84de
fix: Make option required
oSumAtrIX Dec 1, 2023
d884f91
style: Punctuate comments
oSumAtrIX Dec 1, 2023
c48b22d
refactor: Simplify code
oSumAtrIX Dec 1, 2023
1197354
Merge branch 'dev' of https://github.com/revanced/revanced-patches in…
FrozenAlex Dec 2, 2023
fbcee66
Merge branch 'dev' of github.com:FrozenAlex/revanced-patches into dev
FrozenAlex Dec 2, 2023
6f313c1
Fix the typo, improve code readability attempt #1
FrozenAlex Dec 2, 2023
6d3409a
Remove for loops, remove useless variables
FrozenAlex Dec 2, 2023
6e084b3
Remove useless comments, mark regions
FrozenAlex Dec 2, 2023
c1ffa29
Rename stuff
FrozenAlex Dec 2, 2023
3084500
Make code even more readable
FrozenAlex Dec 6, 2023
457733c
Remove invalid comment
FrozenAlex Dec 6, 2023
c8c976c
Remove comment
FrozenAlex Dec 6, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

This comment was marked as spam.

Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
package app.revanced.patches.twitter.misc.links

import app.revanced.extensions.exception
import app.revanced.extensions.getReference
import app.revanced.extensions.indexOfFirstInstruction
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.extensions.InstructionExtensions.removeInstructions
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
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.patch.options.PatchOption.PatchExtensions.stringPatchOption
import app.revanced.patches.twitter.misc.links.fingerprints.LinkBuilderFingerprint
import app.revanced.patches.twitter.misc.links.fingerprints.LinkResourceGetterFingerprint
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.builder.BuilderInstruction
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.MethodReference


@Patch(
name = "Change link sharing domain",
description = "Replaces the domain name of Twitter links when sharing them.",
compatiblePackages = [CompatiblePackage("com.twitter.android")]
)
@Suppress("unused")
object ChangeLinkSharingDomainPatch : BytecodePatch(
setOf(LinkBuilderFingerprint, LinkResourceGetterFingerprint)
) {
private var domainName by stringPatchOption(
key = "domainName",
default = "fxtwitter.com",
title = "Domain name",
description = "The domain to use when sharing links.",
required = true
)

override fun execute(context: BytecodeContext) {
val linkBuilderResult = LinkBuilderFingerprint.result ?: throw LinkBuilderFingerprint.exception

// region Copy link button.
val buildShareLinkMethod = linkBuilderResult.mutableMethod.apply {
val stringIndex = linkBuilderResult.scanResult.stringsScanResult!!.matches
.first().index

val targetRegister = getInstruction<OneRegisterInstruction>(stringIndex).registerA
replaceInstruction(
stringIndex,
"const-string v$targetRegister, \"https://$domainName/%1\$s/status/%2\$d\""
)
}


// endregion

// Used in the Share via... dialog.
LinkResourceGetterFingerprint.result?.apply {
// Remove the original call to the method that uses the resources template to build the link.
val originalMethodIndex = mutableMethod.indexOfFirstInstruction {
getReference<MethodReference>()?.definingClass == "Landroid/content/res/Resources;"
}
if (originalMethodIndex == -1) throw PatchException("Could not find originalMethodIndex")

val shareLinkRegister =
mutableMethod.getInstruction<OneRegisterInstruction>(
// Offset to instruction that saves the result of the method call to the register.
originalMethodIndex + 1
).registerA

mutableMethod.apply {
// Remove original method call and instruction to move the result to the shareLinkRegister.
removeInstructions(originalMethodIndex, 2)

// Remove the instruction that uses the shareLinkRegister as an array reference to prevent an error.
// Original smali aput-object v3, v1, v5 (v1 is the shareLinkRegister)
removeInstructions(originalMethodIndex - 2, 1)
}


// region Get the nickname of the user that posted the tweet. This is used to build the link.
val getNicknameIndex = mutableMethod.indexOfFirstInstruction {
getReference<MethodReference>().toString().endsWith("Ljava/lang/String;")
}
if (getNicknameIndex == -1) throw PatchException("Could not find getNicknameIndex")

val sourceNicknameRegister =
this.mutableMethod.getInstruction<OneRegisterInstruction>(
// Offset to instruction that saves the result of the method call to the register.
getNicknameIndex + 1
).registerA

// Instruction with a spare register that can be used to store the user nickname.
val tempInstructionIndex = mutableMethod.indexOfFirstInstruction {
opcode == Opcode.IGET_OBJECT
}
if (tempInstructionIndex == -1) throw PatchException("Could not find tempInstructionIndex")
if (tempInstructionIndex > getNicknameIndex) throw PatchException(
"tempInstructionIndex > getNicknameIndex, this indicates that the instruction was moved."
)

val tempInstruction = mutableMethod.getInstruction<TwoRegisterInstruction>(
tempInstructionIndex
)
val nicknameRegister = tempInstruction.registerA

// Save the user nickname to the register that was used to store "this".
mutableMethod.addInstruction(
// This offset is used to place the instruction after sourceNicknameRegister is filled with data.
getNicknameIndex + 2,
"move-object v${nicknameRegister}, v$sourceNicknameRegister"
)
// endregion


// region Call the patched method and save the result to shareLinkRegister.
val convertTweetIdToLongIndex = mutableMethod.indexOfFirstInstruction {
opcode == Opcode.INVOKE_VIRTUAL &&
getReference<MethodReference>()?.definingClass == "Ljava/lang/Long;"
}
if (convertTweetIdToLongIndex == -1) throw PatchException("Could not find convertTweetIdToLongIndex")

val tweetIdP1 =
mutableMethod.getInstruction<OneRegisterInstruction>(convertTweetIdToLongIndex + 1).registerA
val tweetIdP2 = tweetIdP1 + 1

this.mutableMethod.addInstructions(
// This offset is used to place the instruction after the save of the method result.
convertTweetIdToLongIndex + 2,
"""
invoke-static { v$tweetIdP1, v$tweetIdP2, v$nicknameRegister }, $buildShareLinkMethod
move-result-object v$shareLinkRegister
"""
)

// Restore the borrowed nicknameRegister.
this.mutableMethod.addInstruction(
convertTweetIdToLongIndex + 4,
tempInstruction as BuilderInstruction
)
// endregion
} ?: throw LinkResourceGetterFingerprint.exception
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package app.revanced.patches.twitter.misc.links

import app.revanced.extensions.exception
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.annotation.CompatiblePackage
import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patches.twitter.misc.links.fingerprints.AddTrackingQueryToLinkFingerprint

@Patch(
name = "Remove tracking query parameter",
description = "Remove the tracking query parameter from links.",
compatiblePackages = [CompatiblePackage("com.twitter.android")]
)
@Suppress("unused")
object RemoveTrackingQueryParameterPatch : BytecodePatch(
setOf(AddTrackingQueryToLinkFingerprint)
) {
override fun execute(context: BytecodeContext) {
AddTrackingQueryToLinkFingerprint.result?.mutableMethod?.addInstruction(0, "return-object p0")
?: throw AddTrackingQueryToLinkFingerprint.exception
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package app.revanced.patches.twitter.misc.links.fingerprints

import app.revanced.patcher.fingerprint.MethodFingerprint

object AddTrackingQueryToLinkFingerprint : MethodFingerprint(
strings = listOf("<this>", "shareParam", "sessionToken"),
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package app.revanced.patches.twitter.misc.links.fingerprints

import app.revanced.patcher.fingerprint.MethodFingerprint

// Returns a shareable link string based on a tweet ID and a username.
object LinkBuilderFingerprint : MethodFingerprint(
strings = listOf("/%1\$s/status/%2\$d"),
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package app.revanced.patches.twitter.misc.links.fingerprints

import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode

// Gets Resource string for share link view available by pressing "Share via" button.
object LinkResourceGetterFingerprint : MethodFingerprint(
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
opcodes = listOf(
Opcode.CONST_STRING,
Opcode.INVOKE_STATIC,
Opcode.CONST_4,
Opcode.NEW_ARRAY,
Opcode.IGET_OBJECT,
Opcode.INVOKE_VIRTUAL,
),
parameters = listOf("Landroid/content/res/Resources;"),
strings = listOf("res.getString"),
)