From af617af523bfa7df00a232a51364ea9e8ea4d34f Mon Sep 17 00:00:00 2001 From: crimera <44558091+crimera@users.noreply.github.com> Date: Sun, 22 Dec 2024 12:29:18 +0800 Subject: [PATCH] fix: Improve getUsername fingerprint --- .../NativeDownloaderHooksPatch.kt | 94 +++++++++++-------- 1 file changed, 57 insertions(+), 37 deletions(-) diff --git a/src/main/kotlin/crimera/patches/twitter/misc/shareMenu/nativeDownloader/NativeDownloaderHooksPatch.kt b/src/main/kotlin/crimera/patches/twitter/misc/shareMenu/nativeDownloader/NativeDownloaderHooksPatch.kt index 7fe7358a..8f3c9717 100644 --- a/src/main/kotlin/crimera/patches/twitter/misc/shareMenu/nativeDownloader/NativeDownloaderHooksPatch.kt +++ b/src/main/kotlin/crimera/patches/twitter/misc/shareMenu/nativeDownloader/NativeDownloaderHooksPatch.kt @@ -11,12 +11,14 @@ import app.revanced.patcher.patch.annotation.Patch import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction21c +import com.android.tools.smali.dexlib2.dexbacked.instruction.DexBackedInstruction35c +import com.android.tools.smali.dexlib2.iface.reference.Reference internal abstract class NativeDownloaderMethodFingerprint( private val methodName: String, ) : MethodFingerprint(customFingerprint = { methodDef, classDef -> - methodDef.name == methodName && classDef.toString() == "Lapp/revanced/integrations/twitter/patches/NativeDownloader;" - }) + methodDef.name == methodName && classDef.toString() == "Lapp/revanced/integrations/twitter/patches/NativeDownloader;" +}) internal object TweetObjectFingerprint : MethodFingerprint(strings = listOf("https://x.com/%1\$s/status/%2\$d")) @@ -28,19 +30,31 @@ internal object GetTweetUsernameFingerprint : NativeDownloaderMethodFingerprint( internal object GetTweetMediaFingerprint : NativeDownloaderMethodFingerprint("getTweetMedia") +internal object GetUserNameMethodCaller : MethodFingerprint( + returnType = "Z", opcodes = listOf( + Opcode.IGET_OBJECT, + Opcode.IGET_OBJECT, + Opcode.IGET_OBJECT, + Opcode.IGET_OBJECT, + Opcode.INVOKE_STATIC, + Opcode.MOVE_RESULT, + Opcode.RETURN + ) +) + @Patch( compatiblePackages = [CompatiblePackage("com.twitter.android")], ) -class NativeDownloaderHooksPatch : - BytecodePatch( - setOf( - GetTweetClassFingerprint, - GetTweetIdFingerprint, - GetTweetUsernameFingerprint, - GetTweetMediaFingerprint, - TweetObjectFingerprint, - ), - ) { +class NativeDownloaderHooksPatch : BytecodePatch( + setOf( + GetTweetClassFingerprint, + GetTweetIdFingerprint, + GetTweetUsernameFingerprint, + GetTweetMediaFingerprint, + GetUserNameMethodCaller, + TweetObjectFingerprint, + ), +) { private fun MutableMethod.changeFirstString(value: String) { this.getInstructions().firstOrNull { it.opcode == Opcode.CONST_STRING }?.let { instruction -> val register = (instruction as BuilderInstruction21c).registerA @@ -48,37 +62,43 @@ class NativeDownloaderHooksPatch : } ?: throw PatchException("const-string not found for method: ${this.name}") } + private fun Reference.getMethodFromReference(): Char { + val ref = this.toString() + val index = ref.indexOf("->") + return ref[index + 2] + } + override fun execute(context: BytecodeContext) { val getTweetObjectFingerprint = TweetObjectFingerprint.result ?: throw PatchException("bruh") val tweetObjectClass = getTweetObjectFingerprint.classDef val tweetObjectClassName = tweetObjectClass.toString().removePrefix("L").removeSuffix(";") - val getIdMethod = - tweetObjectClass.methods.firstOrNull { mutableMethod -> - mutableMethod.name == "getId" - } ?: throw PatchException("getIdMethod not found") - - val getUsernameMethod = - tweetObjectClass.methods - .filter { mutableMethod -> - mutableMethod.returnType == "Ljava/lang/String;" && mutableMethod.implementation?.registerCount == 2 - }.getOrNull(1) ?: throw PatchException("getUsernameMethod not found") - - val getMediaObjectMethod = - tweetObjectClass.methods.firstOrNull { methodDef -> - methodDef.implementation - ?.instructions - ?.map { it.opcode } - ?.toList() == - listOf( - Opcode.IGET_OBJECT, - Opcode.IGET_OBJECT, - Opcode.IGET_OBJECT, - Opcode.IGET_OBJECT, - Opcode.RETURN_OBJECT, - ) - } ?: throw PatchException("getMediaObject not found") + val getIdMethod = tweetObjectClass.methods.firstOrNull { mutableMethod -> + mutableMethod.name == "getId" + } ?: throw PatchException("getIdMethod not found") + + val getUserNameMethodCaller = + GetUserNameMethodCaller.result ?: throw PatchException("Could not find UserNameMethodCaller fingerprint") + val getUserNameMethodName = getUserNameMethodCaller.method.implementation?.instructions?.firstOrNull { t -> + t.opcode == Opcode.INVOKE_STATIC + }.let { + (it as DexBackedInstruction35c).reference.getMethodFromReference() + } + + val getUsernameMethod = tweetObjectClass.methods.firstOrNull { mutableMethod -> + mutableMethod.name.contains(getUserNameMethodName) && mutableMethod.returnType == "Ljava/lang/String;" + } ?: throw PatchException("getUsernameMethod not found") + + val getMediaObjectMethod = tweetObjectClass.methods.firstOrNull { methodDef -> + methodDef.implementation?.instructions?.map { it.opcode }?.toList() == listOf( + Opcode.IGET_OBJECT, + Opcode.IGET_OBJECT, + Opcode.IGET_OBJECT, + Opcode.IGET_OBJECT, + Opcode.RETURN_OBJECT, + ) + } ?: throw PatchException("getMediaObject not found") GetTweetClassFingerprint.result?.mutableMethod?.changeFirstString(tweetObjectClassName) ?: throw GetTweetClassFingerprint.exception