From 263fb212ad63b89933e58ef0d14be4743b101b66 Mon Sep 17 00:00:00 2001 From: naijun0403 Date: Mon, 26 May 2025 01:03:54 +0900 Subject: [PATCH 01/11] feat(kakaotalk): add patch to change package name in source code (WIP) Because of a unique bug, applying that patch will make the class duplicate, and we don't have time to deal with it now, so we'll deal with it later. --- patches/api/patches.api | 4 ++ .../ChangePackageNameInSourcePatch.kt | 65 +++++++++++++++++++ 2 files changed, 69 insertions(+) create mode 100644 patches/src/main/kotlin/app/revanced/patches/kakaotalk/packagename/ChangePackageNameInSourcePatch.kt diff --git a/patches/api/patches.api b/patches/api/patches.api index ea1df7c74..57f1faea3 100644 --- a/patches/api/patches.api +++ b/patches/api/patches.api @@ -309,6 +309,10 @@ public final class app/revanced/patches/kakaotalk/misc/RemoveShopTabPatchKt { public static final fun getRemoveShopTabPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } +public final class app/revanced/patches/kakaotalk/packagename/ChangePackageNameInSourcePatchKt { + public static final fun getChangePackageNameInSourcePatch ()Lapp/revanced/patcher/patch/BytecodePatch; +} + public final class app/revanced/patches/kakaotalk/send/AllowReplyToFeedPatchKt { public static final fun getAllowReplyToFeedPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } diff --git a/patches/src/main/kotlin/app/revanced/patches/kakaotalk/packagename/ChangePackageNameInSourcePatch.kt b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/packagename/ChangePackageNameInSourcePatch.kt new file mode 100644 index 000000000..13b9e5b17 --- /dev/null +++ b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/packagename/ChangePackageNameInSourcePatch.kt @@ -0,0 +1,65 @@ +package app.revanced.patches.kakaotalk.packagename + +import app.revanced.patcher.extensions.InstructionExtensions.instructions +import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction +import app.revanced.patcher.patch.bytecodePatch +import app.revanced.util.findMutableMethodOf +import app.revanced.util.getReference +import com.android.tools.smali.dexlib2.Opcode +import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction21c +import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction21c +import com.android.tools.smali.dexlib2.iface.reference.StringReference +import com.android.tools.smali.dexlib2.immutable.reference.ImmutableStringReference + +val changePackageNameInSourcePatch = bytecodePatch( + name = "Change package name in source", + description = "Changes the package name in the source code of KakaoTalk.", + use = false, +) { +// dependsOn(changePackageNamePatch) + + execute { +// val newPackageName = if (packageNameOption.value == packageNameOption.default) { +// "com.kakao.talk.revanced" +// } else { +// packageNameOption.value!! +// } + val newPackageName = "com.kakao.talk.revanced" + + val newStringReference = ImmutableStringReference(newPackageName) + + classes.forEach { classDef -> + classDef.methods.forEach { method -> + val insns = method.implementation?.instructions ?: return@forEach + + for ((i, insn) in insns.withIndex()) { + if (insn is Instruction21c && + insn.opcode == Opcode.CONST_STRING && + insn.getReference()!!.string == "com.kakao.talk") { + + val mutableMethod = proxy(classDef).mutableClass.findMutableMethodOf(method) + + mutableMethod.instructions + .filterIsInstance() + .filter { it.opcode == Opcode.CONST_STRING && + it.getReference()!!.string == "com.kakao.talk" } + .forEach { + val idx = mutableMethod.instructions.indexOf(it) + + println("Replacing package name in method $mutableMethod at index $idx") + + mutableMethod.replaceInstruction( + idx, + BuilderInstruction21c( + Opcode.CONST_STRING, + it.registerA, + ImmutableStringReference(newPackageName) + ) + ) + } + } + } + } + } + } +} \ No newline at end of file From 555099bef8b1a75abc40ac369cd5e1b2a62a374f Mon Sep 17 00:00:00 2001 From: naijun0403 Date: Mon, 26 May 2025 02:03:26 +0900 Subject: [PATCH 02/11] feat(kakaotalk): add patch to include real deleted and hidden flags in chat log This is the first commit to make deleted, hidden messages visible. --- patches/api/patches.api | 4 ++ .../AddRealDeletedOrHiddenFlagPatch.kt | 47 +++++++++++++++++++ .../fingerprints/ChatLogFingerprint.kt | 14 ++++++ 3 files changed, 65 insertions(+) create mode 100644 patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/AddRealDeletedOrHiddenFlagPatch.kt create mode 100644 patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/fingerprints/ChatLogFingerprint.kt diff --git a/patches/api/patches.api b/patches/api/patches.api index 57f1faea3..f35624a96 100644 --- a/patches/api/patches.api +++ b/patches/api/patches.api @@ -272,6 +272,10 @@ public final class app/revanced/patches/kakaotalk/changemodel/ChangeModelPatchKt public static final fun getChangeModelPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } +public final class app/revanced/patches/kakaotalk/chatlog/AddRealDeletedOrHiddenFlagPatchKt { + public static final fun getAddRealDeletedOrHiddenFlagPatch ()Lapp/revanced/patcher/patch/BytecodePatch; +} + public final class app/revanced/patches/kakaotalk/chatlog/Remove99ClampPatchKt { public static final fun getRemove99ClampPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } diff --git a/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/AddRealDeletedOrHiddenFlagPatch.kt b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/AddRealDeletedOrHiddenFlagPatch.kt new file mode 100644 index 000000000..02ee64dbf --- /dev/null +++ b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/AddRealDeletedOrHiddenFlagPatch.kt @@ -0,0 +1,47 @@ +package app.revanced.patches.kakaotalk.chatlog + +import app.revanced.patcher.patch.bytecodePatch +import app.revanced.patcher.util.proxy.mutableTypes.MutableField.Companion.toMutable +import app.revanced.patches.kakaotalk.chatlog.fingerprints.chatLogFingerprint +import com.android.tools.smali.dexlib2.AccessFlags +import com.android.tools.smali.dexlib2.immutable.ImmutableField +import com.android.tools.smali.dexlib2.immutable.value.ImmutableBooleanEncodedValue + +val addRealDeletedOrHiddenFlagPatch = bytecodePatch( + name = "Add real deleted or hidden flag", + description = "Add real deleted or hidden flag to chat log", +) { + compatibleWith("com.kakao.talk"("25.4.2")) + + execute { + val chatLogClass = proxy(classes.first { + it.type == chatLogFingerprint.method.definingClass + }).mutableClass + + chatLogClass.apply { + fields.add( + ImmutableField( + type, + "isRealDeleted", + "Z", + AccessFlags.PUBLIC.value, + ImmutableBooleanEncodedValue.FALSE_VALUE, + null, + null + ).toMutable(), + ) + + fields.add( + ImmutableField( + type, + "isHidden", + "Z", + AccessFlags.PUBLIC.value, + ImmutableBooleanEncodedValue.FALSE_VALUE, + null, + null + ).toMutable(), + ) + } + } +} \ No newline at end of file diff --git a/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/fingerprints/ChatLogFingerprint.kt b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/fingerprints/ChatLogFingerprint.kt new file mode 100644 index 000000000..8cbcba33b --- /dev/null +++ b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/fingerprints/ChatLogFingerprint.kt @@ -0,0 +1,14 @@ +package app.revanced.patches.kakaotalk.chatlog.fingerprints + +import app.revanced.patcher.fingerprint +import com.android.tools.smali.dexlib2.AccessFlags + +internal val chatLogFingerprint = fingerprint { + accessFlags(AccessFlags.PUBLIC) + returns("Ljava/lang/String;") + parameters() + strings( + "[class:", + "] ChatLog [id=", + ) +} \ No newline at end of file From 8dbd5765e79485502b4669619d13f2fdd87d2930 Mon Sep 17 00:00:00 2001 From: naijun0403 Date: Mon, 26 May 2025 02:35:09 +0900 Subject: [PATCH 03/11] feat(kakaotalk): add patches to handle deleted and hidden messages in chat logs This is the second commit to make deleted, hidden messages visible. --- patches/api/patches.api | 8 + .../chatlog/AddDeletedOrHiddenLayoutPatch.kt | 174 ++++++++++++++++++ .../chatlog/ShowDeletedMessagePatch.kt | 16 ++ .../fingerprints/ChatInfoViewFingerprint.kt | 2 + .../ChatLogsManagerFingerprint.kt | 20 ++ 5 files changed, 220 insertions(+) create mode 100644 patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/AddDeletedOrHiddenLayoutPatch.kt create mode 100644 patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/ShowDeletedMessagePatch.kt create mode 100644 patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/fingerprints/ChatInfoViewFingerprint.kt create mode 100644 patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/fingerprints/ChatLogsManagerFingerprint.kt diff --git a/patches/api/patches.api b/patches/api/patches.api index f35624a96..326e3f9e8 100644 --- a/patches/api/patches.api +++ b/patches/api/patches.api @@ -272,6 +272,10 @@ public final class app/revanced/patches/kakaotalk/changemodel/ChangeModelPatchKt public static final fun getChangeModelPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } +public final class app/revanced/patches/kakaotalk/chatlog/AddDeletedOrHiddenLayoutPatchKt { + public static final fun getAddDeletedOrHiddenLayoutPatch ()Lapp/revanced/patcher/patch/BytecodePatch; +} + public final class app/revanced/patches/kakaotalk/chatlog/AddRealDeletedOrHiddenFlagPatchKt { public static final fun getAddRealDeletedOrHiddenFlagPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } @@ -280,6 +284,10 @@ public final class app/revanced/patches/kakaotalk/chatlog/Remove99ClampPatchKt { public static final fun getRemove99ClampPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } +public final class app/revanced/patches/kakaotalk/chatlog/ShowDeletedMessagePatchKt { + public static final fun getShowDeletedMessagePatch ()Lapp/revanced/patcher/patch/BytecodePatch; +} + public final class app/revanced/patches/kakaotalk/chatroom/Remove300PlusLimitPatchKt { public static final fun getRemove300PlusLimitBaseChatRoomPatch ()Lapp/revanced/patcher/patch/BytecodePatch; public static final fun getRemove300PlusLimitOpenChatRoomPatch ()Lapp/revanced/patcher/patch/BytecodePatch; diff --git a/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/AddDeletedOrHiddenLayoutPatch.kt b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/AddDeletedOrHiddenLayoutPatch.kt new file mode 100644 index 000000000..c9ccee135 --- /dev/null +++ b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/AddDeletedOrHiddenLayoutPatch.kt @@ -0,0 +1,174 @@ +package app.revanced.patches.kakaotalk.chatlog + +import app.revanced.patcher.patch.bytecodePatch +import app.revanced.patcher.util.proxy.mutableTypes.MutableField.Companion.toMutable +import com.android.tools.smali.dexlib2.AccessFlags +import com.android.tools.smali.dexlib2.immutable.ImmutableField +import com.android.tools.smali.dexlib2.immutable.value.ImmutableBooleanEncodedValue + +val addDeletedOrHiddenLayoutPatch = bytecodePatch( + name = "Add deleted or hidden layout", + description = "Adds a layout for deleted or hidden messages in chat logs", +) { + compatibleWith("com.kakao.talk"("25.4.2")) + + execute { + val chatInfoViewClass = proxy(classes.first { + it.type == "Lcom/kakao/talk/widget/chatlog/ChatInfoView;" + }).mutableClass + val makeLayoutMethod = chatInfoViewClass.methods.firstOrNull { + it.name == "makeLayout" + } ?: error("makeLayout method not found in ChatInfoView class") + + println("ChatInfoView class: $chatInfoViewClass") + println("makeLayout method: $makeLayoutMethod") + + chatInfoViewClass.apply { + fields.add( + ImmutableField( + type, + "isDeleted", + "Z", + AccessFlags.PUBLIC.value, + ImmutableBooleanEncodedValue.FALSE_VALUE, + null, + null + ).toMutable(), + ) + + fields.add( + ImmutableField( + type, + "deletedLayout", + "Landroid/text/Layout;", + AccessFlags.PUBLIC.value, + null, + null, + null + ).toMutable() + ) + + fields.add( + ImmutableField( + type, + "deletedPaint", + "Landroid/text/TextPaint;", + AccessFlags.PUBLIC.value, + null, + null, + null + ).toMutable() + ) + + fields.add( + ImmutableField( + type, + "deletedRect", + "Landroid/graphics/Rect;", + AccessFlags.PUBLIC.value, + null, + null, + null + ).toMutable() + ) + + fields.add( + ImmutableField( + type, + "deletedTextColor", + "I", + AccessFlags.PUBLIC.value, + null, + null, + null + ).toMutable() + ) + + fields.add( + ImmutableField( + type, + "deletedTextSize", + "I", + AccessFlags.PUBLIC.value, + null, + null, + null + ).toMutable() + ) + + fields.add( + ImmutableField( + type, + "isHidden", + "Z", + AccessFlags.PUBLIC.value, + ImmutableBooleanEncodedValue.FALSE_VALUE, + null, + null + ).toMutable(), + ) + + fields.add( + ImmutableField( + type, + "hiddenLayout", + "Landroid/text/Layout;", + AccessFlags.PUBLIC.value, + null, + null, + null + ).toMutable() + ) + + fields.add( + ImmutableField( + type, + "hiddenPaint", + "Landroid/text/TextPaint;", + AccessFlags.PUBLIC.value, + null, + null, + null + ).toMutable() + ) + + fields.add( + ImmutableField( + type, + "hiddenRect", + "Landroid/graphics/Rect;", + AccessFlags.PUBLIC.value, + null, + null, + null + ).toMutable() + ) + + fields.add( + ImmutableField( + type, + "hiddenTextColor", + "I", + AccessFlags.PUBLIC.value, + null, + null, + null + ).toMutable() + ) + + fields.add( + ImmutableField( + type, + "hiddenTextSize", + "I", + AccessFlags.PUBLIC.value, + null, + null, + null + ).toMutable() + ) + + // TODO: Add logic to initialize these fields in the makeLayout method + } + } +} \ No newline at end of file diff --git a/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/ShowDeletedMessagePatch.kt b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/ShowDeletedMessagePatch.kt new file mode 100644 index 000000000..aa3a1b70f --- /dev/null +++ b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/ShowDeletedMessagePatch.kt @@ -0,0 +1,16 @@ +package app.revanced.patches.kakaotalk.chatlog + +import app.revanced.patcher.patch.bytecodePatch + +val showDeletedMessagePatch = bytecodePatch( + name = "Show deleted message", + description = "Shows deleted messages in chat logs", +) { + compatibleWith("com.kakao.talk"("25.4.2")) + + dependsOn(addRealDeletedOrHiddenFlagPatch) + + execute { + // TODO: Implement the patch to show deleted messages + } +} \ No newline at end of file diff --git a/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/fingerprints/ChatInfoViewFingerprint.kt b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/fingerprints/ChatInfoViewFingerprint.kt new file mode 100644 index 000000000..5b3d5209c --- /dev/null +++ b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/fingerprints/ChatInfoViewFingerprint.kt @@ -0,0 +1,2 @@ +package app.revanced.patches.kakaotalk.chatlog.fingerprints + diff --git a/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/fingerprints/ChatLogsManagerFingerprint.kt b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/fingerprints/ChatLogsManagerFingerprint.kt new file mode 100644 index 000000000..d7f6f4d9a --- /dev/null +++ b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/fingerprints/ChatLogsManagerFingerprint.kt @@ -0,0 +1,20 @@ +package app.revanced.patches.kakaotalk.chatlog.fingerprints + +import app.revanced.patcher.fingerprint +import com.android.tools.smali.dexlib2.AccessFlags + +internal val replaceToFeedFingerprint = fingerprint { + accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC) + returns("V") + strings( + "feedType", + "{}", + "safeBot", + "getString(...)", + "hidden", + "byHost", + "previous_message", + "previous_enc", + "enc : %s, %s", + ) +} \ No newline at end of file From 1e91a5cb5243ba62dd41d60b5e1f6b8bca338eaa Mon Sep 17 00:00:00 2001 From: naijun0403 Date: Mon, 26 May 2025 03:00:11 +0900 Subject: [PATCH 04/11] feat(kakaotalk): implement layout handling for deleted messages in chat log This is the third commit to make deleted, hidden messages visible. --- .../chatlog/AddDeletedOrHiddenLayoutPatch.kt | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/AddDeletedOrHiddenLayoutPatch.kt b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/AddDeletedOrHiddenLayoutPatch.kt index c9ccee135..09adaad8f 100644 --- a/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/AddDeletedOrHiddenLayoutPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/AddDeletedOrHiddenLayoutPatch.kt @@ -1,7 +1,11 @@ package app.revanced.patches.kakaotalk.chatlog +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.patch.bytecodePatch import app.revanced.patcher.util.proxy.mutableTypes.MutableField.Companion.toMutable +import app.revanced.patcher.util.smali.ExternalLabel import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.immutable.ImmutableField import com.android.tools.smali.dexlib2.immutable.value.ImmutableBooleanEncodedValue @@ -169,6 +173,48 @@ val addDeletedOrHiddenLayoutPatch = bytecodePatch( ) // TODO: Add logic to initialize these fields in the makeLayout method + + makeLayoutMethod.addInstructionsWithLabels( + 0, + """ + iget-boolean v0, p0, Lcom/kakao/talk/widget/chatlog/ChatInfoView;->isDeleted:Z + if-eqz v0, :not_deleted + const-string v0, "[Deleted]" + iget-object v1, p0, Lcom/kakao/talk/widget/chatlog/ChatInfoView;->deletedPaint:Landroid/text/TextPaint; + invoke-static {v0, v1}, Landroid/text/BoringLayout;->isBoring(Ljava/lang/CharSequence;Landroid/text/TextPaint;)Landroid/text/BoringLayout${'$'}Metrics; + move-result-object v8 + + if-nez v8, :boring_deleted + new-instance v1, Landroid/text/StaticLayout; + iget-object v4, p0, Lcom/kakao/talk/widget/chatlog/ChatInfoView;->deletedPaint:Landroid/text/TextPaint; + invoke-virtual { v4, v0 }, Landroid/graphics/Paint;->measureText(Ljava/lang/String;)F + move-result v2 + float-to-int v5, v2 + sget-object v6, Landroid/text/Layout${'$'}Alignment;->ALIGN_NORMAL:Landroid/text/Layout${'$'}Alignment; + const/4 v9, 0x1 + const/high16 v7, 0x3f800000 # 1.0f + const/4 v8, 0x0 + move-object v2, v1 + move-object v3, v0 + invoke-direct/range {v2 .. v9}, Landroid/text/StaticLayout;->(Ljava/lang/CharSequence;Landroid/text/TextPaint;ILandroid/text/Layout${'$'}Alignment;FFZ)V + goto :set_deleted_layout + :boring_deleted + iget-object v3, p0, Lcom/kakao/talk/widget/chatlog/ChatInfoView;->deletedPaint:Landroid/text/TextPaint; + invoke-virtual {v3, v0}, Landroid/graphics/Paint;->measureText(Ljava/lang/String;)F + move-result v1 + float-to-int v4, v1 + sget-object v5, Landroid/text/Layout${'$'}Alignment;->ALIGN_NORMAL:Landroid/text/Layout${'$'}Alignment; + const/4 v9, 0x0 + const/high16 v6, 0x3f800000 # 1.0f + const/4 v7, 0x0 + move-object v2, v0 + invoke-static/range {v2 .. v9}, Landroid/text/BoringLayout;->make(Ljava/lang/CharSequence;Landroid/text/TextPaint;ILandroid/text/Layout${'$'}Alignment;FFLandroid/text/BoringLayout${'$'}Metrics;Z)Landroid/text/BoringLayout; + move-result-object v1 + :set_deleted_layout + iput-object v1, p0, Lcom/kakao/talk/widget/chatlog/ChatInfoView;->deletedLayout:Landroid/text/Layout; + """.trimIndent(), + ExternalLabel("not_deleted", makeLayoutMethod.getInstruction(0)) + ) } } } \ No newline at end of file From 11bf82640d2a6f39f10e5bef944ea20564a97fd1 Mon Sep 17 00:00:00 2001 From: naijun0403 Date: Wed, 28 May 2025 01:29:08 +0900 Subject: [PATCH 05/11] feat(kakaotalk): add layout handling for deleted and hidden messages in chat log This is the fourth commit to make deleted, hidden messages visible. --- .../chatlog/AddDeletedOrHiddenLayoutPatch.kt | 200 ++++++++++++++---- 1 file changed, 160 insertions(+), 40 deletions(-) diff --git a/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/AddDeletedOrHiddenLayoutPatch.kt b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/AddDeletedOrHiddenLayoutPatch.kt index 09adaad8f..dacf9f578 100644 --- a/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/AddDeletedOrHiddenLayoutPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/AddDeletedOrHiddenLayoutPatch.kt @@ -3,10 +3,15 @@ package app.revanced.patches.kakaotalk.chatlog 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.instructions import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.util.proxy.mutableTypes.MutableField.Companion.toMutable import app.revanced.patcher.util.smali.ExternalLabel +import app.revanced.util.getReference import com.android.tools.smali.dexlib2.AccessFlags +import com.android.tools.smali.dexlib2.Opcode +import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction35c +import com.android.tools.smali.dexlib2.iface.reference.FieldReference import com.android.tools.smali.dexlib2.immutable.ImmutableField import com.android.tools.smali.dexlib2.immutable.value.ImmutableBooleanEncodedValue @@ -23,6 +28,9 @@ val addDeletedOrHiddenLayoutPatch = bytecodePatch( val makeLayoutMethod = chatInfoViewClass.methods.firstOrNull { it.name == "makeLayout" } ?: error("makeLayout method not found in ChatInfoView class") + val onDrawMethod = chatInfoViewClass.methods.firstOrNull { + it.name == "onDraw" + } ?: error("onDraw method not found in ChatInfoView class") println("ChatInfoView class: $chatInfoViewClass") println("makeLayout method: $makeLayoutMethod") @@ -172,48 +180,160 @@ val addDeletedOrHiddenLayoutPatch = bytecodePatch( ).toMutable() ) - // TODO: Add logic to initialize these fields in the makeLayout method + val cls = chatInfoViewClass.type - makeLayoutMethod.addInstructionsWithLabels( + val deletedMakeLayoutBlock = """ + iget-boolean v0, p0, $cls->isDeleted:Z + if-eqz v0, :skip_deleted + const-string v0, "[Deleted]" + iget-object v1, p0, $cls->deletedPaint:Landroid/text/TextPaint; + invoke-static {v0, v1}, Landroid/text/BoringLayout;->isBoring(Ljava/lang/CharSequence;Landroid/text/TextPaint;)Landroid/text/BoringLayout${'$'}Metrics; + move-result-object v8 + if-nez v8, :boring_deleted + new-instance v1, Landroid/text/StaticLayout; + iget-object v4, p0, $cls->deletedPaint:Landroid/text/TextPaint; + invoke-virtual {v4, v0}, Landroid/graphics/Paint;->measureText(Ljava/lang/String;)F + move-result v2 + float-to-int v5, v2 + sget-object v6, Landroid/text/Layout${'$'}Alignment;->ALIGN_NORMAL:Landroid/text/Layout${'$'}Alignment; + const/4 v9, 0x1 + const/high16 v7, 0x3f800000 # 1.0f + const/4 v8, 0x0 + move-object v2, v1 + move-object v3, v0 + invoke-direct/range {v2 .. v9}, Landroid/text/StaticLayout;->(Ljava/lang/CharSequence;Landroid/text/TextPaint;ILandroid/text/Layout${'$'}Alignment;FFZ)V + goto :set_deleted + :boring_deleted + iget-object v3, p0, $cls->deletedPaint:Landroid/text/TextPaint; + invoke-virtual {v3, v0}, Landroid/graphics/Paint;->measureText(Ljava/lang/String;)F + move-result v1 + float-to-int v4, v1 + sget-object v5, Landroid/text/Layout${'$'}Alignment;->ALIGN_NORMAL:Landroid/text/Layout${'$'}Alignment; + const/4 v9, 0x0 + const/high16 v6, 0x3f800000 # 1.0f + const/4 v7, 0x0 + move-object v2, v0 + invoke-static/range {v2 .. v9}, Landroid/text/BoringLayout;->make(Ljava/lang/CharSequence;Landroid/text/TextPaint;ILandroid/text/Layout${'$'}Alignment;FFLandroid/text/BoringLayout${'$'}Metrics;Z)Landroid/text/BoringLayout; + move-result-object v1 + :set_deleted + iput-object v1, p0, $cls->deletedLayout:Landroid/text/Layout; + :skip_deleted + """.trimIndent() + + val hiddenMakeLayoutBlock = """ + iget-boolean v0, p0, $cls->isHidden:Z + if-eqz v0, :skip_hidden + const-string v0, "[Hidden]" + iget-object v1, p0, $cls->hiddenPaint:Landroid/text/TextPaint; + invoke-static {v0, v1}, Landroid/text/BoringLayout;->isBoring(Ljava/lang/CharSequence;Landroid/text/TextPaint;)Landroid/text/BoringLayout${'$'}Metrics; + move-result-object v8 + if-nez v8, :boring_hidden + new-instance v1, Landroid/text/StaticLayout; + iget-object v4, p0, $cls->hiddenPaint:Landroid/text/TextPaint; + invoke-virtual {v4, v0}, Landroid/graphics/Paint;->measureText(Ljava/lang/String;)F + move-result v2 + float-to-int v5, v2 + sget-object v6, Landroid/text/Layout${'$'}Alignment;->ALIGN_NORMAL:Landroid/text/Layout${'$'}Alignment; + const/4 v9, 0x1 + const/high16 v7, 0x3f800000 # 1.0f + const/4 v8, 0x0 + move-object v2, v1 + move-object v3, v0 + invoke-direct/range {v2 .. v9}, Landroid/text/StaticLayout;->(Ljava/lang/CharSequence;Landroid/text/TextPaint;ILandroid/text/Layout${'$'}Alignment;FFZ)V + goto :set_hidden + :boring_hidden + iget-object v3, p0, $cls->hiddenPaint:Landroid/text/TextPaint; + invoke-virtual {v3, v0}, Landroid/graphics/Paint;->measureText(Ljava/lang/String;)F + move-result v1 + float-to-int v4, v1 + sget-object v5, Landroid/text/Layout${'$'}Alignment;->ALIGN_NORMAL:Landroid/text/Layout${'$'}Alignment; + const/4 v9, 0x0 + const/high16 v6, 0x3f800000 # 1.0f + const/4 v7, 0x0 + move-object v2, v0 + invoke-static/range {v2 .. v9}, Landroid/text/BoringLayout;->make(Ljava/lang/CharSequence;Landroid/text/TextPaint;ILandroid/text/Layout${'$'}Alignment;FFLandroid/text/BoringLayout${'$'}Metrics;Z)Landroid/text/BoringLayout; + move-result-object v1 + :set_hidden + iput-object v1, p0, $cls->hiddenLayout:Landroid/text/Layout; + :skip_hidden + """.trimIndent() + + makeLayoutMethod.addInstructions( 0, - """ - iget-boolean v0, p0, Lcom/kakao/talk/widget/chatlog/ChatInfoView;->isDeleted:Z - if-eqz v0, :not_deleted - const-string v0, "[Deleted]" - iget-object v1, p0, Lcom/kakao/talk/widget/chatlog/ChatInfoView;->deletedPaint:Landroid/text/TextPaint; - invoke-static {v0, v1}, Landroid/text/BoringLayout;->isBoring(Ljava/lang/CharSequence;Landroid/text/TextPaint;)Landroid/text/BoringLayout${'$'}Metrics; - move-result-object v8 - - if-nez v8, :boring_deleted - new-instance v1, Landroid/text/StaticLayout; - iget-object v4, p0, Lcom/kakao/talk/widget/chatlog/ChatInfoView;->deletedPaint:Landroid/text/TextPaint; - invoke-virtual { v4, v0 }, Landroid/graphics/Paint;->measureText(Ljava/lang/String;)F - move-result v2 - float-to-int v5, v2 - sget-object v6, Landroid/text/Layout${'$'}Alignment;->ALIGN_NORMAL:Landroid/text/Layout${'$'}Alignment; - const/4 v9, 0x1 - const/high16 v7, 0x3f800000 # 1.0f - const/4 v8, 0x0 - move-object v2, v1 - move-object v3, v0 - invoke-direct/range {v2 .. v9}, Landroid/text/StaticLayout;->(Ljava/lang/CharSequence;Landroid/text/TextPaint;ILandroid/text/Layout${'$'}Alignment;FFZ)V - goto :set_deleted_layout - :boring_deleted - iget-object v3, p0, Lcom/kakao/talk/widget/chatlog/ChatInfoView;->deletedPaint:Landroid/text/TextPaint; - invoke-virtual {v3, v0}, Landroid/graphics/Paint;->measureText(Ljava/lang/String;)F - move-result v1 - float-to-int v4, v1 - sget-object v5, Landroid/text/Layout${'$'}Alignment;->ALIGN_NORMAL:Landroid/text/Layout${'$'}Alignment; - const/4 v9, 0x0 - const/high16 v6, 0x3f800000 # 1.0f - const/4 v7, 0x0 - move-object v2, v0 - invoke-static/range {v2 .. v9}, Landroid/text/BoringLayout;->make(Ljava/lang/CharSequence;Landroid/text/TextPaint;ILandroid/text/Layout${'$'}Alignment;FFLandroid/text/BoringLayout${'$'}Metrics;Z)Landroid/text/BoringLayout; - move-result-object v1 - :set_deleted_layout - iput-object v1, p0, Lcom/kakao/talk/widget/chatlog/ChatInfoView;->deletedLayout:Landroid/text/Layout; - """.trimIndent(), - ExternalLabel("not_deleted", makeLayoutMethod.getInstruction(0)) + deletedMakeLayoutBlock + "\n\n" + hiddenMakeLayoutBlock, + ) + + val superIndex = onDrawMethod.instructions.indexOfFirst { + it.opcode == Opcode.INVOKE_SUPER + } + + val deletedOnDrawBlock = """ + iget-object v0, p0, $cls->deletedLayout:Landroid/text/Layout; + if-eqz v0, :skip_deleted_draw + iget-boolean v0, p0, $cls->isDeleted:Z + if-eqz v0, :skip_deleted_draw + invoke-virtual {p1}, Landroid/graphics/Canvas;->save()I + iget-object v0, p0, $cls->deletedRect:Landroid/graphics/Rect; + invoke-virtual {p1, v0}, Landroid/graphics/Canvas;->clipRect(Landroid/graphics/Rect;)Z + iget-object v0, p0, $cls->deletedRect:Landroid/graphics/Rect; + iget v0, v0, Landroid/graphics/Rect;->left:I + int-to-float v0, v0 + iget-object v1, p0, $cls->deletedRect:Landroid/graphics/Rect; + iget v1, v1, Landroid/graphics/Rect;->top:I + int-to-float v1, v1 + invoke-virtual {p1, v0, v1}, Landroid/graphics/Canvas;->translate(FF)V + iget-object v0, p0, $cls->deletedLayout:Landroid/text/Layout; + .line 1 + if-eqz v0, :fuck + .line 2 + invoke-virtual {v0, p1}, Landroid/text/Layout;->draw(Landroid/graphics/Canvas;)V + .line 3 + :fuck + invoke-virtual {p1}, Landroid/graphics/Canvas;->restore()V + """.trimIndent() + + val hiddenOnDrawBlock = """ + iget-object v0, p0, $cls->hiddenLayout:Landroid/text/Layout; + if-eqz v0, :skip_hidden_draw + iget-boolean v0, p0, $cls->isHidden:Z + if-eqz v0, :skip_hidden_draw + invoke-virtual {p1}, Landroid/graphics/Canvas;->save()I + iget-object v0, p0, $cls->hiddenRect:Landroid/graphics/Rect; + invoke-virtual {p1, v0}, Landroid/graphics/Canvas;->clipRect(Landroid/graphics/Rect;)Z + iget-object v0, p0, $cls->hiddenRect:Landroid/graphics/Rect; + iget v0, v0, Landroid/graphics/Rect;->left:I + int-to-float v0, v0 + iget-object v1, p0, $cls->hiddenRect:Landroid/graphics/Rect; + iget v1, v1, Landroid/graphics/Rect;->top:I + int-to-float v1, v1 + invoke-virtual {p1, v0, v1}, Landroid/graphics/Canvas;->translate(FF)V + iget-object v0, p0, $cls->hiddenLayout:Landroid/text/Layout; + .line 4 + if-eqz v0, :nullCheck_2 + .line 5 + invoke-virtual {v0, p1}, Landroid/text/Layout;->draw(Landroid/graphics/Canvas;)V + .line 6 + :nullCheck_2 + invoke-virtual {p1}, Landroid/graphics/Canvas;->restore()V + """.trimIndent() + + val instructionFollowingBothBlocks = onDrawMethod.getInstruction(superIndex + 1) + + val skipHiddenLabel = ExternalLabel("skip_hidden_draw", instructionFollowingBothBlocks) + + onDrawMethod.addInstructionsWithLabels( + superIndex + 1, + hiddenOnDrawBlock, + skipHiddenLabel + ) + + val firstInstructionOfHiddenBlock = onDrawMethod.getInstruction(superIndex + 1) + val skipDeletedLabel = ExternalLabel("skip_deleted_draw", firstInstructionOfHiddenBlock) + + onDrawMethod.addInstructionsWithLabels( + superIndex + 1, + deletedOnDrawBlock, + skipDeletedLabel ) } } From d4e127ccf2e27a0b203600a3d74c1372b0d096b2 Mon Sep 17 00:00:00 2001 From: naijun0403 Date: Wed, 28 May 2025 02:17:06 +0900 Subject: [PATCH 06/11] feat(kakaotalk): add methods to handle deleted and hidden message layouts in ChatInfoView This is the fifth commit to make deleted, hidden messages visible. --- .../chatlog/AddDeletedOrHiddenLayoutPatch.kt | 104 +++++++++++++++++- .../fingerprints/ChatInfoViewFingerprint.kt | 12 ++ 2 files changed, 113 insertions(+), 3 deletions(-) diff --git a/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/AddDeletedOrHiddenLayoutPatch.kt b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/AddDeletedOrHiddenLayoutPatch.kt index dacf9f578..a0188cd56 100644 --- a/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/AddDeletedOrHiddenLayoutPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/AddDeletedOrHiddenLayoutPatch.kt @@ -6,14 +6,18 @@ import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.extensions.InstructionExtensions.instructions import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.util.proxy.mutableTypes.MutableField.Companion.toMutable +import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable import app.revanced.patcher.util.smali.ExternalLabel -import app.revanced.util.getReference +import app.revanced.patches.kakaotalk.chatlog.fingerprints.chatInfoViewConstructorFingerprint import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode -import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction35c -import com.android.tools.smali.dexlib2.iface.reference.FieldReference +import com.android.tools.smali.dexlib2.builder.MutableMethodImplementation import com.android.tools.smali.dexlib2.immutable.ImmutableField +import com.android.tools.smali.dexlib2.immutable.ImmutableMethod +import com.android.tools.smali.dexlib2.immutable.ImmutableMethodImplementation +import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter import com.android.tools.smali.dexlib2.immutable.value.ImmutableBooleanEncodedValue +import com.google.common.collect.ImmutableList val addDeletedOrHiddenLayoutPatch = bytecodePatch( name = "Add deleted or hidden layout", @@ -31,9 +35,12 @@ val addDeletedOrHiddenLayoutPatch = bytecodePatch( val onDrawMethod = chatInfoViewClass.methods.firstOrNull { it.name == "onDraw" } ?: error("onDraw method not found in ChatInfoView class") + val constructor = chatInfoViewConstructorFingerprint.method println("ChatInfoView class: $chatInfoViewClass") println("makeLayout method: $makeLayoutMethod") + println("onDraw method: $onDrawMethod") + println("constructor: $constructor") chatInfoViewClass.apply { fields.add( @@ -180,6 +187,64 @@ val addDeletedOrHiddenLayoutPatch = bytecodePatch( ).toMutable() ) + methods.add( + ImmutableMethod( + type, + "setDeleted", + ImmutableList.of( + ImmutableMethodParameter( + "Z", + null, + null + ) + ), + "V", + AccessFlags.PUBLIC.value or AccessFlags.FINAL.value, + null, + null, + MutableMethodImplementation(2) + ).toMutable().apply { + addInstructions( + 0, + """ + iput-boolean p1, p0, Lcom/kakao/talk/widget/chatlog/ChatInfoView;->isDeleted:Z + invoke-virtual {p0}, Landroid/view/View;->requestLayout()V + invoke-virtual {p0}, Landroid/view/View;->invalidate()V + return-void + """.trimIndent() + ) + }, + ) + + methods.add( + ImmutableMethod( + type, + "setHidden", + ImmutableList.of( + ImmutableMethodParameter( + "Z", + null, + null + ) + ), + "V", + AccessFlags.PUBLIC.value or AccessFlags.FINAL.value, + null, + null, + MutableMethodImplementation(2) + ).toMutable().apply { + addInstructions( + 0, + """ + iput-boolean p1, p0, Lcom/kakao/talk/widget/chatlog/ChatInfoView;->isHidden:Z + invoke-virtual {p0}, Landroid/view/View;->requestLayout()V + invoke-virtual {p0}, Landroid/view/View;->invalidate()V + return-void + """.trimIndent() + ) + }, + ) + val cls = chatInfoViewClass.type val deletedMakeLayoutBlock = """ @@ -335,6 +400,39 @@ val addDeletedOrHiddenLayoutPatch = bytecodePatch( deletedOnDrawBlock, skipDeletedLabel ) + + val indices = constructor.instructions + .withIndex() + .filter { it.value.opcode == Opcode.MOVE_RESULT_OBJECT } + .map { it.index } + + val secondIndex = indices.getOrNull(1) ?: error("Second MOVE_RESULT_OBJECT instruction not found in constructor") + + constructor.addInstructions( + secondIndex + 1, + """ + const/4 v0, 0x1 + + new-instance p3, Landroid/text/TextPaint; + invoke-direct {p3, v0}, Landroid/text/TextPaint;->(I)V + iget v1, p0, $cls->deletedTextSize:I + int-to-float v1, v1 + invoke-virtual {p3, v1}, Landroid/graphics/Paint;->setTextSize(F)V + iget v1, p0, $cls->deletedTextColor:I + invoke-virtual {p3, v1}, Landroid/graphics/Paint;->setColor(I)V + invoke-virtual {p3, p2}, Landroid/graphics/Paint;->setTypeface(Landroid/graphics/Typeface;)Landroid/graphics/Typeface; + iput-object p3, p0, $cls->deletedPaint:Landroid/text/TextPaint; + + new-instance p3, Landroid/text/TextPaint; + invoke-direct {p3, v0}, Landroid/text/TextPaint;->(I)V + iget v1, p0, $cls->hiddenTextSize:I + int-to-float v1, v1 + invoke-virtual {p3, v1}, Landroid/graphics/Paint;->setTextSize(F)V + iget v1, p0, $cls->hiddenTextColor:I + invoke-virtual {p3, v1}, Landroid/graphics/Paint;->setColor(I)V + invoke-virtual {p3, p2}, Landroid/graphics/Paint;->setTypeface(Landroid/graphics/Typeface;)Landroid/graphics/Typeface; + iput-object p3, p0, $cls->hiddenPaint:Landroid/text/TextPaint; + """.trimIndent()) } } } \ No newline at end of file diff --git a/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/fingerprints/ChatInfoViewFingerprint.kt b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/fingerprints/ChatInfoViewFingerprint.kt index 5b3d5209c..cf2736240 100644 --- a/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/fingerprints/ChatInfoViewFingerprint.kt +++ b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/fingerprints/ChatInfoViewFingerprint.kt @@ -1,2 +1,14 @@ package app.revanced.patches.kakaotalk.chatlog.fingerprints +import app.revanced.patcher.fingerprint +import com.android.tools.smali.dexlib2.AccessFlags + +internal val chatInfoViewConstructorFingerprint = fingerprint { + accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) + returns("V") + parameters("Landroid/content/Context;", "Landroid/util/AttributeSet;", "I") + strings( + "context" + ) + custom { method, classDef -> classDef.type == "Lcom/kakao/talk/widget/chatlog/ChatInfoView;" && method.name == "" } +} \ No newline at end of file From 39ef7f16bcf9cbdb66b615dba01c07e804364e8d Mon Sep 17 00:00:00 2001 From: naijun0403 Date: Wed, 28 May 2025 02:29:58 +0900 Subject: [PATCH 07/11] feat(kakaotalk): add fingerprint for creating ChatLogViewHolder from real data This is the 6th commit to make deleted, hidden messages visible. --- .../ChatLogViewHolderFingerprint.kt | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/fingerprints/ChatLogViewHolderFingerprint.kt diff --git a/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/fingerprints/ChatLogViewHolderFingerprint.kt b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/fingerprints/ChatLogViewHolderFingerprint.kt new file mode 100644 index 000000000..5f9f3d3df --- /dev/null +++ b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/fingerprints/ChatLogViewHolderFingerprint.kt @@ -0,0 +1,24 @@ +package app.revanced.patches.kakaotalk.chatlog.fingerprints + +import app.revanced.patcher.fingerprint +import com.android.tools.smali.dexlib2.AccessFlags +import com.android.tools.smali.dexlib2.Opcode + +internal val createChatLogViewHolderFromRealFingerprint = fingerprint { + accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) + returns("V") + parameters() + opcodes( + Opcode.MOVE_OBJECT_FROM16, + Opcode.IGET_OBJECT, + Opcode.CONST_4, + Opcode.SGET_OBJECT, + Opcode.IGET_OBJECT, + Opcode.IGET_OBJECT, + Opcode.CONST_16, + Opcode.IGET_OBJECT, + Opcode.CONST_4, + Opcode.CONST_4, + ) + custom { method, classDef -> classDef.sourceFile == "ChatLogViewHolder.kt" } +} \ No newline at end of file From 21b69efddf146c5bc7ac885bd46ca80dd942e44b Mon Sep 17 00:00:00 2001 From: naijun0403 Date: Wed, 28 May 2025 02:58:16 +0900 Subject: [PATCH 08/11] feat(kakaotalk): rename and update patch to handle deleted and hidden messages in chat logs This is the 7th commit to make deleted, hidden messages visible. --- patches/api/patches.api | 4 +- .../chatlog/ShowDeletedMessagePatch.kt | 16 ------ .../ShowDeletedOrHiddenMessagePatch.kt | 51 +++++++++++++++++++ 3 files changed, 53 insertions(+), 18 deletions(-) delete mode 100644 patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/ShowDeletedMessagePatch.kt create mode 100644 patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/ShowDeletedOrHiddenMessagePatch.kt diff --git a/patches/api/patches.api b/patches/api/patches.api index 326e3f9e8..3dfaa8a8e 100644 --- a/patches/api/patches.api +++ b/patches/api/patches.api @@ -284,8 +284,8 @@ public final class app/revanced/patches/kakaotalk/chatlog/Remove99ClampPatchKt { public static final fun getRemove99ClampPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } -public final class app/revanced/patches/kakaotalk/chatlog/ShowDeletedMessagePatchKt { - public static final fun getShowDeletedMessagePatch ()Lapp/revanced/patcher/patch/BytecodePatch; +public final class app/revanced/patches/kakaotalk/chatlog/ShowDeletedOrHiddenMessagePatchKt { + public static final fun getShowDeletedOrHiddenMessagePatch ()Lapp/revanced/patcher/patch/BytecodePatch; } public final class app/revanced/patches/kakaotalk/chatroom/Remove300PlusLimitPatchKt { diff --git a/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/ShowDeletedMessagePatch.kt b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/ShowDeletedMessagePatch.kt deleted file mode 100644 index aa3a1b70f..000000000 --- a/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/ShowDeletedMessagePatch.kt +++ /dev/null @@ -1,16 +0,0 @@ -package app.revanced.patches.kakaotalk.chatlog - -import app.revanced.patcher.patch.bytecodePatch - -val showDeletedMessagePatch = bytecodePatch( - name = "Show deleted message", - description = "Shows deleted messages in chat logs", -) { - compatibleWith("com.kakao.talk"("25.4.2")) - - dependsOn(addRealDeletedOrHiddenFlagPatch) - - execute { - // TODO: Implement the patch to show deleted messages - } -} \ No newline at end of file diff --git a/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/ShowDeletedOrHiddenMessagePatch.kt b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/ShowDeletedOrHiddenMessagePatch.kt new file mode 100644 index 000000000..ee3a2c038 --- /dev/null +++ b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/ShowDeletedOrHiddenMessagePatch.kt @@ -0,0 +1,51 @@ +package app.revanced.patches.kakaotalk.chatlog + +import app.revanced.patcher.extensions.InstructionExtensions.addInstructions +import app.revanced.patcher.extensions.InstructionExtensions.instructions +import app.revanced.patcher.patch.bytecodePatch +import app.revanced.patches.kakaotalk.chatlog.fingerprints.createChatLogViewHolderFromRealFingerprint +import app.revanced.util.getReference +import com.android.tools.smali.dexlib2.Opcode +import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction35c +import com.android.tools.smali.dexlib2.iface.reference.MethodReference + +val showDeletedOrHiddenMessagePatch = bytecodePatch( + name = "Show deleted or hidden message", + description = "Shows deleted & hidden messages in chat logs", +) { + compatibleWith("com.kakao.talk"("25.4.2")) + + dependsOn(addRealDeletedOrHiddenFlagPatch) + + execute { + val method = createChatLogViewHolderFromRealFingerprint.method + val insns = method.instructions + + val modifyInst = insns + .filterIsInstance() + .filter { it.opcode == Opcode.INVOKE_VIRTUAL } + .find { + it.getReference()?.name == "setModify" + } + val modifyIndex = insns.indexOf(modifyInst ?: return@execute) + + println("Modify index: $modifyIndex") + + method.addInstructions( + modifyIndex, + """ + const/4 v12, 0x0 + if-eqz v14, :skip_get_deleted_flag + iget-boolean v12, v14, LXo/c;->isRealDeleted:Z + :skip_get_deleted_flag + invoke-virtual {v4, v12}, Lcom/kakao/talk/widget/chatlog/ChatInfoView;->setDeleted(Z)V + + const/4 v12, 0x0 + if-eqz v14, :skip_get_hidden_flag + iget-boolean v12, v14, LXo/c;->isHidden:Z + :skip_get_hidden_flag + invoke-virtual {v4, v12}, Lcom/kakao/talk/widget/chatlog/ChatInfoView;->setHidden(Z)V + """.trimIndent() + ) + } +} \ No newline at end of file From 38987cfb466af3590b77ebf9e13f9df7e03ab4f6 Mon Sep 17 00:00:00 2001 From: naijun0403 Date: Wed, 28 May 2025 15:09:45 +0900 Subject: [PATCH 09/11] feat(kakaotalk): update ShowDeletedOrHiddenMessagePatch to handle date and chat log checks Something's wrong, chatLog is fetched twice, performance degradation expected, fix needed --- .../ShowDeletedOrHiddenMessagePatch.kt | 54 +++++++++++++------ 1 file changed, 37 insertions(+), 17 deletions(-) diff --git a/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/ShowDeletedOrHiddenMessagePatch.kt b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/ShowDeletedOrHiddenMessagePatch.kt index ee3a2c038..96292d2a5 100644 --- a/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/ShowDeletedOrHiddenMessagePatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/ShowDeletedOrHiddenMessagePatch.kt @@ -1,11 +1,13 @@ package app.revanced.patches.kakaotalk.chatlog -import app.revanced.patcher.extensions.InstructionExtensions.addInstructions +import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels import app.revanced.patcher.extensions.InstructionExtensions.instructions import app.revanced.patcher.patch.bytecodePatch +import app.revanced.patches.kakaotalk.chatlog.fingerprints.chatLogFingerprint import app.revanced.patches.kakaotalk.chatlog.fingerprints.createChatLogViewHolderFromRealFingerprint import app.revanced.util.getReference import com.android.tools.smali.dexlib2.Opcode +import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction21c import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction35c import com.android.tools.smali.dexlib2.iface.reference.MethodReference @@ -21,31 +23,49 @@ val showDeletedOrHiddenMessagePatch = bytecodePatch( val method = createChatLogViewHolderFromRealFingerprint.method val insns = method.instructions - val modifyInst = insns + val chatLogClass = chatLogFingerprint.classDef + + println("ChatLog class: ${chatLogClass.type}") + + val dateInst = insns .filterIsInstance() .filter { it.opcode == Opcode.INVOKE_VIRTUAL } .find { - it.getReference()?.name == "setModify" + it.getReference()?.name == "setDate" } - val modifyIndex = insns.indexOf(modifyInst ?: return@execute) + val dateIndex = insns.indexOf(dateInst ?: return@execute) - println("Modify index: $modifyIndex") + val chatLogRegister = insns + .filterIsInstance() + .filter { it.opcode == Opcode.CHECK_CAST } + .find { + it.reference == chatLogClass + }?.registerA ?: error("ChatLog class ${chatLogClass.type} not found") - method.addInstructions( - modifyIndex, + println(chatLogRegister) + + println("Date index: $dateIndex") + + method.addInstructionsWithLabels( + dateIndex + 1, """ + invoke-virtual/range {p0 .. p0}, LOe/f2;->u0()LKe/S; + move-result-object v12 + instance-of v13, v12, ${chatLogClass.type} + if-eqz v13, :is_not_chat_log + check-cast v12, ${chatLogClass.type} + goto :fuck + :is_not_chat_log const/4 v12, 0x0 - if-eqz v14, :skip_get_deleted_flag - iget-boolean v12, v14, LXo/c;->isRealDeleted:Z - :skip_get_deleted_flag - invoke-virtual {v4, v12}, Lcom/kakao/talk/widget/chatlog/ChatInfoView;->setDeleted(Z)V + :fuck + nop - const/4 v12, 0x0 - if-eqz v14, :skip_get_hidden_flag - iget-boolean v12, v14, LXo/c;->isHidden:Z - :skip_get_hidden_flag - invoke-virtual {v4, v12}, Lcom/kakao/talk/widget/chatlog/ChatInfoView;->setHidden(Z)V - """.trimIndent() + iget-boolean v10, v12, ${chatLogClass.type}->isRealDeleted:Z + invoke-virtual {v4, v10}, Lcom/kakao/talk/widget/chatlog/ChatInfoView;->setDeleted(Z)V + + iget-boolean v10, v12, ${chatLogClass.type}->isHidden:Z + invoke-virtual {v4, v10}, Lcom/kakao/talk/widget/chatlog/ChatInfoView;->setHidden(Z)V + """.trimIndent(), ) } } \ No newline at end of file From 9cd436a948bb808f3739ccc673b4b4c67b34662f Mon Sep 17 00:00:00 2001 From: naijun0403 Date: Wed, 28 May 2025 18:19:52 +0900 Subject: [PATCH 10/11] feat(kakaotalk): add methods to set text colors for deleted and hidden messages --- .../chatlog/AddDeletedOrHiddenLayoutPatch.kt | 66 +++++++++++++++++++ .../ShowDeletedOrHiddenMessagePatch.kt | 56 ++++++++++++---- 2 files changed, 109 insertions(+), 13 deletions(-) diff --git a/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/AddDeletedOrHiddenLayoutPatch.kt b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/AddDeletedOrHiddenLayoutPatch.kt index a0188cd56..755e29b8f 100644 --- a/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/AddDeletedOrHiddenLayoutPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/AddDeletedOrHiddenLayoutPatch.kt @@ -245,6 +245,72 @@ val addDeletedOrHiddenLayoutPatch = bytecodePatch( }, ) + methods.add( + ImmutableMethod( + type, + "setDeletedTextColor", + ImmutableList.of( + ImmutableMethodParameter( + "I", + null, + null + ) + ), + "V", + AccessFlags.PUBLIC.value or AccessFlags.FINAL.value, + null, + null, + MutableMethodImplementation(2) + ).toMutable().apply { + addInstructions( + 0, + """ + iput p1, p0, Lcom/kakao/talk/widget/chatlog/ChatInfoView;->deletedTextColor:I + iget-object v0, p0, Lcom/kakao/talk/widget/chatlog/ChatInfoView;->deletedPaint:Landroid/text/TextPaint; + if-nez v0, :cond_0 + goto :goto_0 + :cond_0 + invoke-virtual {v0, p1}, Landroid/graphics/Paint;->setColor(I)V + :goto_0 + return-void + """.trimIndent() + ) + }, + ) + + methods.add( + ImmutableMethod( + type, + "setHiddenTextColor", + ImmutableList.of( + ImmutableMethodParameter( + "I", + null, + null + ) + ), + "V", + AccessFlags.PUBLIC.value or AccessFlags.FINAL.value, + null, + null, + MutableMethodImplementation(2) + ).toMutable().apply { + addInstructions( + 0, + """ + iput p1, p0, Lcom/kakao/talk/widget/chatlog/ChatInfoView;->hiddenTextColor:I + iget-object v0, p0, Lcom/kakao/talk/widget/chatlog/ChatInfoView;->hiddenPaint:Landroid/text/TextPaint; + if-nez v0, :cond_0 + goto :goto_0 + :cond_0 + invoke-virtual {v0, p1}, Landroid/graphics/Paint;->setColor(I)V + :goto_0 + return-void + """.trimIndent() + ) + }, + ) + val cls = chatInfoViewClass.type val deletedMakeLayoutBlock = """ diff --git a/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/ShowDeletedOrHiddenMessagePatch.kt b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/ShowDeletedOrHiddenMessagePatch.kt index 96292d2a5..8787c1677 100644 --- a/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/ShowDeletedOrHiddenMessagePatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/ShowDeletedOrHiddenMessagePatch.kt @@ -1,5 +1,6 @@ package app.revanced.patches.kakaotalk.chatlog +import app.revanced.patcher.extensions.InstructionExtensions.addInstructions import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels import app.revanced.patcher.extensions.InstructionExtensions.instructions import app.revanced.patcher.patch.bytecodePatch @@ -11,6 +12,7 @@ import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction21c import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction35c import com.android.tools.smali.dexlib2.iface.reference.MethodReference +// TODO: 레지스터 관련 패치해야함, 자동으로 찾게 val showDeletedOrHiddenMessagePatch = bytecodePatch( name = "Show deleted or hidden message", description = "Shows deleted & hidden messages in chat logs", @@ -50,22 +52,50 @@ val showDeletedOrHiddenMessagePatch = bytecodePatch( dateIndex + 1, """ invoke-virtual/range {p0 .. p0}, LOe/f2;->u0()LKe/S; - move-result-object v12 - instance-of v13, v12, ${chatLogClass.type} - if-eqz v13, :is_not_chat_log - check-cast v12, ${chatLogClass.type} - goto :fuck + move-result-object v14 + instance-of v15, v14, ${chatLogClass.type} + if-eqz v15, :is_not_chat_log + check-cast v14, ${chatLogClass.type} + goto :set_flags :is_not_chat_log - const/4 v12, 0x0 - :fuck + const/4 v14, 0x0 + :set_flags + if-eqz v14, :skip_deleted_check + iget-boolean v15, v14, ${chatLogClass.type}->isRealDeleted:Z + invoke-virtual {v4, v15}, Lcom/kakao/talk/widget/chatlog/ChatInfoView;->setDeleted(Z)V + goto :check_hidden + :skip_deleted_check + const/4 v15, 0x0 + invoke-virtual {v4, v15}, Lcom/kakao/talk/widget/chatlog/ChatInfoView;->setDeleted(Z)V + :check_hidden + if-eqz v14, :skip_hidden_check + iget-boolean v15, v14, ${chatLogClass.type}->isHidden:Z + invoke-virtual {v4, v15}, Lcom/kakao/talk/widget/chatlog/ChatInfoView;->setHidden(Z)V + goto :end_patch + :skip_hidden_check + const/4 v15, 0x0 + invoke-virtual {v4, v15}, Lcom/kakao/talk/widget/chatlog/ChatInfoView;->setHidden(Z)V + :end_patch nop - - iget-boolean v10, v12, ${chatLogClass.type}->isRealDeleted:Z - invoke-virtual {v4, v10}, Lcom/kakao/talk/widget/chatlog/ChatInfoView;->setDeleted(Z)V - - iget-boolean v10, v12, ${chatLogClass.type}->isHidden:Z - invoke-virtual {v4, v10}, Lcom/kakao/talk/widget/chatlog/ChatInfoView;->setHidden(Z)V """.trimIndent(), ) + + val setModifyTextColorInst = insns + .filterIsInstance() + .filter { it.opcode == Opcode.INVOKE_VIRTUAL } + .find { + it.getReference()?.name == "setModifyTextColor" + } ?: error("setModifyTextColor method not found") + val setModifyTextColorInstIndex = insns.indexOf(setModifyTextColorInst) + + println("setModifyTextColorInstIndex: $setModifyTextColorInstIndex") + + method.addInstructions( + setModifyTextColorInstIndex + 1, + """ + invoke-virtual {v4, v6}, Lcom/kakao/talk/widget/chatlog/ChatInfoView;->setDeletedTextColor(I)V + invoke-virtual {v4, v6}, Lcom/kakao/talk/widget/chatlog/ChatInfoView;->setHiddenTextColor(I)V + """.trimIndent() + ) } } \ No newline at end of file From 5791b0e641f9b1883c6500ffa368fdcd9cac26ac Mon Sep 17 00:00:00 2001 From: naijun0403 Date: Sun, 8 Jun 2025 02:02:36 +0900 Subject: [PATCH 11/11] feat(kakaotalk): update compatibility to version 25.4.3 and add show deleted messages patch --- patches/api/patches.api | 12 +- .../kakaotalk/ads/RemoveBizBoardPatch.kt | 2 +- .../kakaotalk/ads/RemoveFocusAdPatch.kt | 2 +- .../kakaotalk/ads/RemoveMoreTabAdPatch.kt | 2 +- .../kakaotalk/ads/RemoveNativeAdPatch.kt | 2 +- .../ads/RemoveOlkChatRoomListAdPatch.kt | 2 +- .../kakaotalk/changemodel/ChangeModelPatch.kt | 2 +- .../chatlog/AddDeletedOrHiddenLayoutPatch.kt | 504 ------------------ .../AddRealDeletedOrHiddenFlagPatch.kt | 47 -- .../kakaotalk/chatlog/Remove99ClampPatch.kt | 2 +- .../chatlog/ShowDeletedMessagePatch.kt | 64 +++ .../ShowDeletedOrHiddenMessagePatch.kt | 101 ---- .../fingerprints/ChatInfoViewFingerprint.kt | 14 - .../fingerprints/ChatLogFingerprint.kt | 38 ++ .../ChatLogViewHolderFingerprint.kt | 24 - .../chatroom/Remove300PlusLimitPatch.kt | 4 +- .../emoticon/ForceEnableEmoticonPlusPatch.kt | 2 +- .../patches/kakaotalk/ghost/GhostModePatch.kt | 2 +- .../integrity/BypassMoatCheckPatch.kt | 2 +- .../integrity/BypassRequestChecksumsPatch.kt | 2 +- .../integrity/VerifyingSignaturePatch.kt | 2 +- .../misc/ForceEnableDebugModePatch.kt | 2 +- .../kakaotalk/misc/RemoveShopTabPatch.kt | 2 +- .../kakaotalk/send/AllowReplyToFeedPatch.kt | 2 +- .../kakaotalk/versioninfo/VersionInfoPatch.kt | 2 +- 25 files changed, 122 insertions(+), 718 deletions(-) delete mode 100644 patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/AddDeletedOrHiddenLayoutPatch.kt delete mode 100644 patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/AddRealDeletedOrHiddenFlagPatch.kt create mode 100644 patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/ShowDeletedMessagePatch.kt delete mode 100644 patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/ShowDeletedOrHiddenMessagePatch.kt delete mode 100644 patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/fingerprints/ChatInfoViewFingerprint.kt delete mode 100644 patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/fingerprints/ChatLogViewHolderFingerprint.kt diff --git a/patches/api/patches.api b/patches/api/patches.api index 3dfaa8a8e..a42224881 100644 --- a/patches/api/patches.api +++ b/patches/api/patches.api @@ -272,20 +272,12 @@ public final class app/revanced/patches/kakaotalk/changemodel/ChangeModelPatchKt public static final fun getChangeModelPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } -public final class app/revanced/patches/kakaotalk/chatlog/AddDeletedOrHiddenLayoutPatchKt { - public static final fun getAddDeletedOrHiddenLayoutPatch ()Lapp/revanced/patcher/patch/BytecodePatch; -} - -public final class app/revanced/patches/kakaotalk/chatlog/AddRealDeletedOrHiddenFlagPatchKt { - public static final fun getAddRealDeletedOrHiddenFlagPatch ()Lapp/revanced/patcher/patch/BytecodePatch; -} - public final class app/revanced/patches/kakaotalk/chatlog/Remove99ClampPatchKt { public static final fun getRemove99ClampPatch ()Lapp/revanced/patcher/patch/BytecodePatch; } -public final class app/revanced/patches/kakaotalk/chatlog/ShowDeletedOrHiddenMessagePatchKt { - public static final fun getShowDeletedOrHiddenMessagePatch ()Lapp/revanced/patcher/patch/BytecodePatch; +public final class app/revanced/patches/kakaotalk/chatlog/ShowDeletedMessagePatchKt { + public static final fun getShowDeletedMessagePatch ()Lapp/revanced/patcher/patch/BytecodePatch; } public final class app/revanced/patches/kakaotalk/chatroom/Remove300PlusLimitPatchKt { diff --git a/patches/src/main/kotlin/app/revanced/patches/kakaotalk/ads/RemoveBizBoardPatch.kt b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/ads/RemoveBizBoardPatch.kt index 4274d9a41..309dde906 100644 --- a/patches/src/main/kotlin/app/revanced/patches/kakaotalk/ads/RemoveBizBoardPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/ads/RemoveBizBoardPatch.kt @@ -9,7 +9,7 @@ val removeBizBoardPatch = bytecodePatch( name = "Remove BizBoard ads", description = "Removes the BizBoard ad by forcing its dimensions to 0x0 and visibility to GONE in onMeasure.", ) { - compatibleWith("com.kakao.talk"("25.4.2")) + compatibleWith("com.kakao.talk"("25.4.3")) execute { val method = measuringBizBoardFingerprint.method diff --git a/patches/src/main/kotlin/app/revanced/patches/kakaotalk/ads/RemoveFocusAdPatch.kt b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/ads/RemoveFocusAdPatch.kt index e92aa892d..8ca1d0359 100644 --- a/patches/src/main/kotlin/app/revanced/patches/kakaotalk/ads/RemoveFocusAdPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/ads/RemoveFocusAdPatch.kt @@ -8,7 +8,7 @@ val removeFocusAdPatch = bytecodePatch( name = "Remove focus ad", description = "Removes the focus ad from the app.", ) { - compatibleWith("com.kakao.talk"("25.4.2")) + compatibleWith("com.kakao.talk"("25.4.3")) execute { loadFocusAdFingerprint.method.addInstructions( diff --git a/patches/src/main/kotlin/app/revanced/patches/kakaotalk/ads/RemoveMoreTabAdPatch.kt b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/ads/RemoveMoreTabAdPatch.kt index fd03e92fd..4f91f13ca 100644 --- a/patches/src/main/kotlin/app/revanced/patches/kakaotalk/ads/RemoveMoreTabAdPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/ads/RemoveMoreTabAdPatch.kt @@ -14,7 +14,7 @@ val removeMoreTabAdPatch = bytecodePatch( name = "Remove More tab ad", description = "Removes the ad from the More tab.", ) { - compatibleWith("com.kakao.talk"("25.4.2")) + compatibleWith("com.kakao.talk"("25.4.3")) execute { val addSectionToMoreTabUIMethod = addSectionToMoreTabUIFingerprint.method diff --git a/patches/src/main/kotlin/app/revanced/patches/kakaotalk/ads/RemoveNativeAdPatch.kt b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/ads/RemoveNativeAdPatch.kt index 34147c0f9..9a3ac7bd1 100644 --- a/patches/src/main/kotlin/app/revanced/patches/kakaotalk/ads/RemoveNativeAdPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/ads/RemoveNativeAdPatch.kt @@ -8,7 +8,7 @@ val removeNativeAdPatch = bytecodePatch( name = "Remove native ad", description = "Removes the native ad from the app.", ) { - compatibleWith("com.kakao.talk"("25.4.2")) + compatibleWith("com.kakao.talk"("25.4.3")) execute { val method = loadNativeAdFingerprint.method diff --git a/patches/src/main/kotlin/app/revanced/patches/kakaotalk/ads/RemoveOlkChatRoomListAdPatch.kt b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/ads/RemoveOlkChatRoomListAdPatch.kt index edcd937a0..93c28e3ef 100644 --- a/patches/src/main/kotlin/app/revanced/patches/kakaotalk/ads/RemoveOlkChatRoomListAdPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/ads/RemoveOlkChatRoomListAdPatch.kt @@ -10,7 +10,7 @@ val removeOlkChatRoomListAdPatch = bytecodePatch( name = "Remove OpenLink chat room list ad", description = "Removes the OpenLink chat room list ad.", ) { - compatibleWith("com.kakao.talk"("25.4.2")) + compatibleWith("com.kakao.talk"("25.4.3")) execute { val findUnit = kotlinUnitInstanceFingerprint.method diff --git a/patches/src/main/kotlin/app/revanced/patches/kakaotalk/changemodel/ChangeModelPatch.kt b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/changemodel/ChangeModelPatch.kt index 75a285eba..3588e8c7a 100644 --- a/patches/src/main/kotlin/app/revanced/patches/kakaotalk/changemodel/ChangeModelPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/changemodel/ChangeModelPatch.kt @@ -14,7 +14,7 @@ val changeModelPatch = bytecodePatch( "model", "SM-X926N" ) - compatibleWith("com.kakao.talk"("25.4.2")) + compatibleWith("com.kakao.talk"("25.4.3")) execute { changeModelFingerprint.method.addInstructions( diff --git a/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/AddDeletedOrHiddenLayoutPatch.kt b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/AddDeletedOrHiddenLayoutPatch.kt deleted file mode 100644 index 755e29b8f..000000000 --- a/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/AddDeletedOrHiddenLayoutPatch.kt +++ /dev/null @@ -1,504 +0,0 @@ -package app.revanced.patches.kakaotalk.chatlog - -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.instructions -import app.revanced.patcher.patch.bytecodePatch -import app.revanced.patcher.util.proxy.mutableTypes.MutableField.Companion.toMutable -import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable -import app.revanced.patcher.util.smali.ExternalLabel -import app.revanced.patches.kakaotalk.chatlog.fingerprints.chatInfoViewConstructorFingerprint -import com.android.tools.smali.dexlib2.AccessFlags -import com.android.tools.smali.dexlib2.Opcode -import com.android.tools.smali.dexlib2.builder.MutableMethodImplementation -import com.android.tools.smali.dexlib2.immutable.ImmutableField -import com.android.tools.smali.dexlib2.immutable.ImmutableMethod -import com.android.tools.smali.dexlib2.immutable.ImmutableMethodImplementation -import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter -import com.android.tools.smali.dexlib2.immutable.value.ImmutableBooleanEncodedValue -import com.google.common.collect.ImmutableList - -val addDeletedOrHiddenLayoutPatch = bytecodePatch( - name = "Add deleted or hidden layout", - description = "Adds a layout for deleted or hidden messages in chat logs", -) { - compatibleWith("com.kakao.talk"("25.4.2")) - - execute { - val chatInfoViewClass = proxy(classes.first { - it.type == "Lcom/kakao/talk/widget/chatlog/ChatInfoView;" - }).mutableClass - val makeLayoutMethod = chatInfoViewClass.methods.firstOrNull { - it.name == "makeLayout" - } ?: error("makeLayout method not found in ChatInfoView class") - val onDrawMethod = chatInfoViewClass.methods.firstOrNull { - it.name == "onDraw" - } ?: error("onDraw method not found in ChatInfoView class") - val constructor = chatInfoViewConstructorFingerprint.method - - println("ChatInfoView class: $chatInfoViewClass") - println("makeLayout method: $makeLayoutMethod") - println("onDraw method: $onDrawMethod") - println("constructor: $constructor") - - chatInfoViewClass.apply { - fields.add( - ImmutableField( - type, - "isDeleted", - "Z", - AccessFlags.PUBLIC.value, - ImmutableBooleanEncodedValue.FALSE_VALUE, - null, - null - ).toMutable(), - ) - - fields.add( - ImmutableField( - type, - "deletedLayout", - "Landroid/text/Layout;", - AccessFlags.PUBLIC.value, - null, - null, - null - ).toMutable() - ) - - fields.add( - ImmutableField( - type, - "deletedPaint", - "Landroid/text/TextPaint;", - AccessFlags.PUBLIC.value, - null, - null, - null - ).toMutable() - ) - - fields.add( - ImmutableField( - type, - "deletedRect", - "Landroid/graphics/Rect;", - AccessFlags.PUBLIC.value, - null, - null, - null - ).toMutable() - ) - - fields.add( - ImmutableField( - type, - "deletedTextColor", - "I", - AccessFlags.PUBLIC.value, - null, - null, - null - ).toMutable() - ) - - fields.add( - ImmutableField( - type, - "deletedTextSize", - "I", - AccessFlags.PUBLIC.value, - null, - null, - null - ).toMutable() - ) - - fields.add( - ImmutableField( - type, - "isHidden", - "Z", - AccessFlags.PUBLIC.value, - ImmutableBooleanEncodedValue.FALSE_VALUE, - null, - null - ).toMutable(), - ) - - fields.add( - ImmutableField( - type, - "hiddenLayout", - "Landroid/text/Layout;", - AccessFlags.PUBLIC.value, - null, - null, - null - ).toMutable() - ) - - fields.add( - ImmutableField( - type, - "hiddenPaint", - "Landroid/text/TextPaint;", - AccessFlags.PUBLIC.value, - null, - null, - null - ).toMutable() - ) - - fields.add( - ImmutableField( - type, - "hiddenRect", - "Landroid/graphics/Rect;", - AccessFlags.PUBLIC.value, - null, - null, - null - ).toMutable() - ) - - fields.add( - ImmutableField( - type, - "hiddenTextColor", - "I", - AccessFlags.PUBLIC.value, - null, - null, - null - ).toMutable() - ) - - fields.add( - ImmutableField( - type, - "hiddenTextSize", - "I", - AccessFlags.PUBLIC.value, - null, - null, - null - ).toMutable() - ) - - methods.add( - ImmutableMethod( - type, - "setDeleted", - ImmutableList.of( - ImmutableMethodParameter( - "Z", - null, - null - ) - ), - "V", - AccessFlags.PUBLIC.value or AccessFlags.FINAL.value, - null, - null, - MutableMethodImplementation(2) - ).toMutable().apply { - addInstructions( - 0, - """ - iput-boolean p1, p0, Lcom/kakao/talk/widget/chatlog/ChatInfoView;->isDeleted:Z - invoke-virtual {p0}, Landroid/view/View;->requestLayout()V - invoke-virtual {p0}, Landroid/view/View;->invalidate()V - return-void - """.trimIndent() - ) - }, - ) - - methods.add( - ImmutableMethod( - type, - "setHidden", - ImmutableList.of( - ImmutableMethodParameter( - "Z", - null, - null - ) - ), - "V", - AccessFlags.PUBLIC.value or AccessFlags.FINAL.value, - null, - null, - MutableMethodImplementation(2) - ).toMutable().apply { - addInstructions( - 0, - """ - iput-boolean p1, p0, Lcom/kakao/talk/widget/chatlog/ChatInfoView;->isHidden:Z - invoke-virtual {p0}, Landroid/view/View;->requestLayout()V - invoke-virtual {p0}, Landroid/view/View;->invalidate()V - return-void - """.trimIndent() - ) - }, - ) - - methods.add( - ImmutableMethod( - type, - "setDeletedTextColor", - ImmutableList.of( - ImmutableMethodParameter( - "I", - null, - null - ) - ), - "V", - AccessFlags.PUBLIC.value or AccessFlags.FINAL.value, - null, - null, - MutableMethodImplementation(2) - ).toMutable().apply { - addInstructions( - 0, - """ - iput p1, p0, Lcom/kakao/talk/widget/chatlog/ChatInfoView;->deletedTextColor:I - iget-object v0, p0, Lcom/kakao/talk/widget/chatlog/ChatInfoView;->deletedPaint:Landroid/text/TextPaint; - if-nez v0, :cond_0 - goto :goto_0 - :cond_0 - invoke-virtual {v0, p1}, Landroid/graphics/Paint;->setColor(I)V - :goto_0 - return-void - """.trimIndent() - ) - }, - ) - - methods.add( - ImmutableMethod( - type, - "setHiddenTextColor", - ImmutableList.of( - ImmutableMethodParameter( - "I", - null, - null - ) - ), - "V", - AccessFlags.PUBLIC.value or AccessFlags.FINAL.value, - null, - null, - MutableMethodImplementation(2) - ).toMutable().apply { - addInstructions( - 0, - """ - iput p1, p0, Lcom/kakao/talk/widget/chatlog/ChatInfoView;->hiddenTextColor:I - iget-object v0, p0, Lcom/kakao/talk/widget/chatlog/ChatInfoView;->hiddenPaint:Landroid/text/TextPaint; - if-nez v0, :cond_0 - goto :goto_0 - :cond_0 - invoke-virtual {v0, p1}, Landroid/graphics/Paint;->setColor(I)V - :goto_0 - return-void - """.trimIndent() - ) - }, - ) - - val cls = chatInfoViewClass.type - - val deletedMakeLayoutBlock = """ - iget-boolean v0, p0, $cls->isDeleted:Z - if-eqz v0, :skip_deleted - const-string v0, "[Deleted]" - iget-object v1, p0, $cls->deletedPaint:Landroid/text/TextPaint; - invoke-static {v0, v1}, Landroid/text/BoringLayout;->isBoring(Ljava/lang/CharSequence;Landroid/text/TextPaint;)Landroid/text/BoringLayout${'$'}Metrics; - move-result-object v8 - if-nez v8, :boring_deleted - new-instance v1, Landroid/text/StaticLayout; - iget-object v4, p0, $cls->deletedPaint:Landroid/text/TextPaint; - invoke-virtual {v4, v0}, Landroid/graphics/Paint;->measureText(Ljava/lang/String;)F - move-result v2 - float-to-int v5, v2 - sget-object v6, Landroid/text/Layout${'$'}Alignment;->ALIGN_NORMAL:Landroid/text/Layout${'$'}Alignment; - const/4 v9, 0x1 - const/high16 v7, 0x3f800000 # 1.0f - const/4 v8, 0x0 - move-object v2, v1 - move-object v3, v0 - invoke-direct/range {v2 .. v9}, Landroid/text/StaticLayout;->(Ljava/lang/CharSequence;Landroid/text/TextPaint;ILandroid/text/Layout${'$'}Alignment;FFZ)V - goto :set_deleted - :boring_deleted - iget-object v3, p0, $cls->deletedPaint:Landroid/text/TextPaint; - invoke-virtual {v3, v0}, Landroid/graphics/Paint;->measureText(Ljava/lang/String;)F - move-result v1 - float-to-int v4, v1 - sget-object v5, Landroid/text/Layout${'$'}Alignment;->ALIGN_NORMAL:Landroid/text/Layout${'$'}Alignment; - const/4 v9, 0x0 - const/high16 v6, 0x3f800000 # 1.0f - const/4 v7, 0x0 - move-object v2, v0 - invoke-static/range {v2 .. v9}, Landroid/text/BoringLayout;->make(Ljava/lang/CharSequence;Landroid/text/TextPaint;ILandroid/text/Layout${'$'}Alignment;FFLandroid/text/BoringLayout${'$'}Metrics;Z)Landroid/text/BoringLayout; - move-result-object v1 - :set_deleted - iput-object v1, p0, $cls->deletedLayout:Landroid/text/Layout; - :skip_deleted - """.trimIndent() - - val hiddenMakeLayoutBlock = """ - iget-boolean v0, p0, $cls->isHidden:Z - if-eqz v0, :skip_hidden - const-string v0, "[Hidden]" - iget-object v1, p0, $cls->hiddenPaint:Landroid/text/TextPaint; - invoke-static {v0, v1}, Landroid/text/BoringLayout;->isBoring(Ljava/lang/CharSequence;Landroid/text/TextPaint;)Landroid/text/BoringLayout${'$'}Metrics; - move-result-object v8 - if-nez v8, :boring_hidden - new-instance v1, Landroid/text/StaticLayout; - iget-object v4, p0, $cls->hiddenPaint:Landroid/text/TextPaint; - invoke-virtual {v4, v0}, Landroid/graphics/Paint;->measureText(Ljava/lang/String;)F - move-result v2 - float-to-int v5, v2 - sget-object v6, Landroid/text/Layout${'$'}Alignment;->ALIGN_NORMAL:Landroid/text/Layout${'$'}Alignment; - const/4 v9, 0x1 - const/high16 v7, 0x3f800000 # 1.0f - const/4 v8, 0x0 - move-object v2, v1 - move-object v3, v0 - invoke-direct/range {v2 .. v9}, Landroid/text/StaticLayout;->(Ljava/lang/CharSequence;Landroid/text/TextPaint;ILandroid/text/Layout${'$'}Alignment;FFZ)V - goto :set_hidden - :boring_hidden - iget-object v3, p0, $cls->hiddenPaint:Landroid/text/TextPaint; - invoke-virtual {v3, v0}, Landroid/graphics/Paint;->measureText(Ljava/lang/String;)F - move-result v1 - float-to-int v4, v1 - sget-object v5, Landroid/text/Layout${'$'}Alignment;->ALIGN_NORMAL:Landroid/text/Layout${'$'}Alignment; - const/4 v9, 0x0 - const/high16 v6, 0x3f800000 # 1.0f - const/4 v7, 0x0 - move-object v2, v0 - invoke-static/range {v2 .. v9}, Landroid/text/BoringLayout;->make(Ljava/lang/CharSequence;Landroid/text/TextPaint;ILandroid/text/Layout${'$'}Alignment;FFLandroid/text/BoringLayout${'$'}Metrics;Z)Landroid/text/BoringLayout; - move-result-object v1 - :set_hidden - iput-object v1, p0, $cls->hiddenLayout:Landroid/text/Layout; - :skip_hidden - """.trimIndent() - - makeLayoutMethod.addInstructions( - 0, - deletedMakeLayoutBlock + "\n\n" + hiddenMakeLayoutBlock, - ) - - val superIndex = onDrawMethod.instructions.indexOfFirst { - it.opcode == Opcode.INVOKE_SUPER - } - - val deletedOnDrawBlock = """ - iget-object v0, p0, $cls->deletedLayout:Landroid/text/Layout; - if-eqz v0, :skip_deleted_draw - iget-boolean v0, p0, $cls->isDeleted:Z - if-eqz v0, :skip_deleted_draw - invoke-virtual {p1}, Landroid/graphics/Canvas;->save()I - iget-object v0, p0, $cls->deletedRect:Landroid/graphics/Rect; - invoke-virtual {p1, v0}, Landroid/graphics/Canvas;->clipRect(Landroid/graphics/Rect;)Z - iget-object v0, p0, $cls->deletedRect:Landroid/graphics/Rect; - iget v0, v0, Landroid/graphics/Rect;->left:I - int-to-float v0, v0 - iget-object v1, p0, $cls->deletedRect:Landroid/graphics/Rect; - iget v1, v1, Landroid/graphics/Rect;->top:I - int-to-float v1, v1 - invoke-virtual {p1, v0, v1}, Landroid/graphics/Canvas;->translate(FF)V - iget-object v0, p0, $cls->deletedLayout:Landroid/text/Layout; - .line 1 - if-eqz v0, :fuck - .line 2 - invoke-virtual {v0, p1}, Landroid/text/Layout;->draw(Landroid/graphics/Canvas;)V - .line 3 - :fuck - invoke-virtual {p1}, Landroid/graphics/Canvas;->restore()V - """.trimIndent() - - val hiddenOnDrawBlock = """ - iget-object v0, p0, $cls->hiddenLayout:Landroid/text/Layout; - if-eqz v0, :skip_hidden_draw - iget-boolean v0, p0, $cls->isHidden:Z - if-eqz v0, :skip_hidden_draw - invoke-virtual {p1}, Landroid/graphics/Canvas;->save()I - iget-object v0, p0, $cls->hiddenRect:Landroid/graphics/Rect; - invoke-virtual {p1, v0}, Landroid/graphics/Canvas;->clipRect(Landroid/graphics/Rect;)Z - iget-object v0, p0, $cls->hiddenRect:Landroid/graphics/Rect; - iget v0, v0, Landroid/graphics/Rect;->left:I - int-to-float v0, v0 - iget-object v1, p0, $cls->hiddenRect:Landroid/graphics/Rect; - iget v1, v1, Landroid/graphics/Rect;->top:I - int-to-float v1, v1 - invoke-virtual {p1, v0, v1}, Landroid/graphics/Canvas;->translate(FF)V - iget-object v0, p0, $cls->hiddenLayout:Landroid/text/Layout; - .line 4 - if-eqz v0, :nullCheck_2 - .line 5 - invoke-virtual {v0, p1}, Landroid/text/Layout;->draw(Landroid/graphics/Canvas;)V - .line 6 - :nullCheck_2 - invoke-virtual {p1}, Landroid/graphics/Canvas;->restore()V - """.trimIndent() - - val instructionFollowingBothBlocks = onDrawMethod.getInstruction(superIndex + 1) - - val skipHiddenLabel = ExternalLabel("skip_hidden_draw", instructionFollowingBothBlocks) - - onDrawMethod.addInstructionsWithLabels( - superIndex + 1, - hiddenOnDrawBlock, - skipHiddenLabel - ) - - val firstInstructionOfHiddenBlock = onDrawMethod.getInstruction(superIndex + 1) - val skipDeletedLabel = ExternalLabel("skip_deleted_draw", firstInstructionOfHiddenBlock) - - onDrawMethod.addInstructionsWithLabels( - superIndex + 1, - deletedOnDrawBlock, - skipDeletedLabel - ) - - val indices = constructor.instructions - .withIndex() - .filter { it.value.opcode == Opcode.MOVE_RESULT_OBJECT } - .map { it.index } - - val secondIndex = indices.getOrNull(1) ?: error("Second MOVE_RESULT_OBJECT instruction not found in constructor") - - constructor.addInstructions( - secondIndex + 1, - """ - const/4 v0, 0x1 - - new-instance p3, Landroid/text/TextPaint; - invoke-direct {p3, v0}, Landroid/text/TextPaint;->(I)V - iget v1, p0, $cls->deletedTextSize:I - int-to-float v1, v1 - invoke-virtual {p3, v1}, Landroid/graphics/Paint;->setTextSize(F)V - iget v1, p0, $cls->deletedTextColor:I - invoke-virtual {p3, v1}, Landroid/graphics/Paint;->setColor(I)V - invoke-virtual {p3, p2}, Landroid/graphics/Paint;->setTypeface(Landroid/graphics/Typeface;)Landroid/graphics/Typeface; - iput-object p3, p0, $cls->deletedPaint:Landroid/text/TextPaint; - - new-instance p3, Landroid/text/TextPaint; - invoke-direct {p3, v0}, Landroid/text/TextPaint;->(I)V - iget v1, p0, $cls->hiddenTextSize:I - int-to-float v1, v1 - invoke-virtual {p3, v1}, Landroid/graphics/Paint;->setTextSize(F)V - iget v1, p0, $cls->hiddenTextColor:I - invoke-virtual {p3, v1}, Landroid/graphics/Paint;->setColor(I)V - invoke-virtual {p3, p2}, Landroid/graphics/Paint;->setTypeface(Landroid/graphics/Typeface;)Landroid/graphics/Typeface; - iput-object p3, p0, $cls->hiddenPaint:Landroid/text/TextPaint; - """.trimIndent()) - } - } -} \ No newline at end of file diff --git a/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/AddRealDeletedOrHiddenFlagPatch.kt b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/AddRealDeletedOrHiddenFlagPatch.kt deleted file mode 100644 index 02ee64dbf..000000000 --- a/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/AddRealDeletedOrHiddenFlagPatch.kt +++ /dev/null @@ -1,47 +0,0 @@ -package app.revanced.patches.kakaotalk.chatlog - -import app.revanced.patcher.patch.bytecodePatch -import app.revanced.patcher.util.proxy.mutableTypes.MutableField.Companion.toMutable -import app.revanced.patches.kakaotalk.chatlog.fingerprints.chatLogFingerprint -import com.android.tools.smali.dexlib2.AccessFlags -import com.android.tools.smali.dexlib2.immutable.ImmutableField -import com.android.tools.smali.dexlib2.immutable.value.ImmutableBooleanEncodedValue - -val addRealDeletedOrHiddenFlagPatch = bytecodePatch( - name = "Add real deleted or hidden flag", - description = "Add real deleted or hidden flag to chat log", -) { - compatibleWith("com.kakao.talk"("25.4.2")) - - execute { - val chatLogClass = proxy(classes.first { - it.type == chatLogFingerprint.method.definingClass - }).mutableClass - - chatLogClass.apply { - fields.add( - ImmutableField( - type, - "isRealDeleted", - "Z", - AccessFlags.PUBLIC.value, - ImmutableBooleanEncodedValue.FALSE_VALUE, - null, - null - ).toMutable(), - ) - - fields.add( - ImmutableField( - type, - "isHidden", - "Z", - AccessFlags.PUBLIC.value, - ImmutableBooleanEncodedValue.FALSE_VALUE, - null, - null - ).toMutable(), - ) - } - } -} \ No newline at end of file diff --git a/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/Remove99ClampPatch.kt b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/Remove99ClampPatch.kt index 594d2f9fd..8e3c482b0 100644 --- a/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/Remove99ClampPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/Remove99ClampPatch.kt @@ -13,7 +13,7 @@ val remove99ClampPatch = bytecodePatch( name = "Disable 99 unread limit", description = "Skip the 99-cap so unread count shows full value" ) { - compatibleWith("com.kakao.talk"("25.4.2")) + compatibleWith("com.kakao.talk"("25.4.3")) execute { val method = processWatermarkCountFingerprint.method diff --git a/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/ShowDeletedMessagePatch.kt b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/ShowDeletedMessagePatch.kt new file mode 100644 index 000000000..7a4339d21 --- /dev/null +++ b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/ShowDeletedMessagePatch.kt @@ -0,0 +1,64 @@ +package app.revanced.patches.kakaotalk.chatlog + +import app.revanced.patcher.extensions.InstructionExtensions.addInstructions +import app.revanced.patcher.extensions.InstructionExtensions.instructions +import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction +import app.revanced.patcher.patch.bytecodePatch +import app.revanced.patches.kakaotalk.chatlog.fingerprints.chatLogGetTextFingerprint +import app.revanced.patches.kakaotalk.chatlog.fingerprints.chatLogSetTextFingerprint +import app.revanced.patches.kakaotalk.chatlog.fingerprints.replaceToFeedFingerprint +import com.android.tools.smali.dexlib2.Opcode + +val showDeletedMessagePatch = bytecodePatch( + name = "Show deleted messages", + description = "Allows you to see deleted messages in chat logs.", +) { + compatibleWith("com.kakao.talk"("25.4.3")) + + execute { + val method = replaceToFeedFingerprint.method + val insns = method.instructions + + val orInsnsIdx = insns + .indexOfFirst { it.opcode == Opcode.OR_INT_LIT16 } + + if (orInsnsIdx == -1) error("could not find or built message $orInsnsIdx") + + method.addInstructions( + orInsnsIdx + 1, + """ + const/16 p1, 0x1 + """.trimIndent() + ) + + val setTextMethod = chatLogSetTextFingerprint.method.name + val getTextMethod = chatLogGetTextFingerprint.method.name + val chatLogClass = chatLogSetTextFingerprint.method.definingClass + + method.replaceInstruction( + orInsnsIdx + 2, + "nop" + ) + method.addInstructions( + orInsnsIdx + 3, + """ + invoke-virtual {p0}, $chatLogClass->$getTextMethod()Ljava/lang/String; + move-result-object v2 + + const-string v1, "[Deleted] " + + new-instance v3, Ljava/lang/StringBuilder; + invoke-direct {v3}, Ljava/lang/StringBuilder;->()V + invoke-virtual {v3, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder; + invoke-virtual {v3, v2}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder; + invoke-virtual {v3}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String; + move-result-object v1 + + invoke-virtual {p0, v1}, $chatLogClass->$setTextMethod(Ljava/lang/String;)V + + invoke-virtual {p0}, $chatLogClass->getChatRoomId()J + move-result-wide v2 + """.trimIndent() + ) + } +} \ No newline at end of file diff --git a/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/ShowDeletedOrHiddenMessagePatch.kt b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/ShowDeletedOrHiddenMessagePatch.kt deleted file mode 100644 index 8787c1677..000000000 --- a/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/ShowDeletedOrHiddenMessagePatch.kt +++ /dev/null @@ -1,101 +0,0 @@ -package app.revanced.patches.kakaotalk.chatlog - -import app.revanced.patcher.extensions.InstructionExtensions.addInstructions -import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels -import app.revanced.patcher.extensions.InstructionExtensions.instructions -import app.revanced.patcher.patch.bytecodePatch -import app.revanced.patches.kakaotalk.chatlog.fingerprints.chatLogFingerprint -import app.revanced.patches.kakaotalk.chatlog.fingerprints.createChatLogViewHolderFromRealFingerprint -import app.revanced.util.getReference -import com.android.tools.smali.dexlib2.Opcode -import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction21c -import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction35c -import com.android.tools.smali.dexlib2.iface.reference.MethodReference - -// TODO: 레지스터 관련 패치해야함, 자동으로 찾게 -val showDeletedOrHiddenMessagePatch = bytecodePatch( - name = "Show deleted or hidden message", - description = "Shows deleted & hidden messages in chat logs", -) { - compatibleWith("com.kakao.talk"("25.4.2")) - - dependsOn(addRealDeletedOrHiddenFlagPatch) - - execute { - val method = createChatLogViewHolderFromRealFingerprint.method - val insns = method.instructions - - val chatLogClass = chatLogFingerprint.classDef - - println("ChatLog class: ${chatLogClass.type}") - - val dateInst = insns - .filterIsInstance() - .filter { it.opcode == Opcode.INVOKE_VIRTUAL } - .find { - it.getReference()?.name == "setDate" - } - val dateIndex = insns.indexOf(dateInst ?: return@execute) - - val chatLogRegister = insns - .filterIsInstance() - .filter { it.opcode == Opcode.CHECK_CAST } - .find { - it.reference == chatLogClass - }?.registerA ?: error("ChatLog class ${chatLogClass.type} not found") - - println(chatLogRegister) - - println("Date index: $dateIndex") - - method.addInstructionsWithLabels( - dateIndex + 1, - """ - invoke-virtual/range {p0 .. p0}, LOe/f2;->u0()LKe/S; - move-result-object v14 - instance-of v15, v14, ${chatLogClass.type} - if-eqz v15, :is_not_chat_log - check-cast v14, ${chatLogClass.type} - goto :set_flags - :is_not_chat_log - const/4 v14, 0x0 - :set_flags - if-eqz v14, :skip_deleted_check - iget-boolean v15, v14, ${chatLogClass.type}->isRealDeleted:Z - invoke-virtual {v4, v15}, Lcom/kakao/talk/widget/chatlog/ChatInfoView;->setDeleted(Z)V - goto :check_hidden - :skip_deleted_check - const/4 v15, 0x0 - invoke-virtual {v4, v15}, Lcom/kakao/talk/widget/chatlog/ChatInfoView;->setDeleted(Z)V - :check_hidden - if-eqz v14, :skip_hidden_check - iget-boolean v15, v14, ${chatLogClass.type}->isHidden:Z - invoke-virtual {v4, v15}, Lcom/kakao/talk/widget/chatlog/ChatInfoView;->setHidden(Z)V - goto :end_patch - :skip_hidden_check - const/4 v15, 0x0 - invoke-virtual {v4, v15}, Lcom/kakao/talk/widget/chatlog/ChatInfoView;->setHidden(Z)V - :end_patch - nop - """.trimIndent(), - ) - - val setModifyTextColorInst = insns - .filterIsInstance() - .filter { it.opcode == Opcode.INVOKE_VIRTUAL } - .find { - it.getReference()?.name == "setModifyTextColor" - } ?: error("setModifyTextColor method not found") - val setModifyTextColorInstIndex = insns.indexOf(setModifyTextColorInst) - - println("setModifyTextColorInstIndex: $setModifyTextColorInstIndex") - - method.addInstructions( - setModifyTextColorInstIndex + 1, - """ - invoke-virtual {v4, v6}, Lcom/kakao/talk/widget/chatlog/ChatInfoView;->setDeletedTextColor(I)V - invoke-virtual {v4, v6}, Lcom/kakao/talk/widget/chatlog/ChatInfoView;->setHiddenTextColor(I)V - """.trimIndent() - ) - } -} \ No newline at end of file diff --git a/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/fingerprints/ChatInfoViewFingerprint.kt b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/fingerprints/ChatInfoViewFingerprint.kt deleted file mode 100644 index cf2736240..000000000 --- a/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/fingerprints/ChatInfoViewFingerprint.kt +++ /dev/null @@ -1,14 +0,0 @@ -package app.revanced.patches.kakaotalk.chatlog.fingerprints - -import app.revanced.patcher.fingerprint -import com.android.tools.smali.dexlib2.AccessFlags - -internal val chatInfoViewConstructorFingerprint = fingerprint { - accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) - returns("V") - parameters("Landroid/content/Context;", "Landroid/util/AttributeSet;", "I") - strings( - "context" - ) - custom { method, classDef -> classDef.type == "Lcom/kakao/talk/widget/chatlog/ChatInfoView;" && method.name == "" } -} \ No newline at end of file diff --git a/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/fingerprints/ChatLogFingerprint.kt b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/fingerprints/ChatLogFingerprint.kt index 8cbcba33b..e1d5eaaaf 100644 --- a/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/fingerprints/ChatLogFingerprint.kt +++ b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/fingerprints/ChatLogFingerprint.kt @@ -2,6 +2,7 @@ package app.revanced.patches.kakaotalk.chatlog.fingerprints import app.revanced.patcher.fingerprint import com.android.tools.smali.dexlib2.AccessFlags +import com.android.tools.smali.dexlib2.Opcode internal val chatLogFingerprint = fingerprint { accessFlags(AccessFlags.PUBLIC) @@ -11,4 +12,41 @@ internal val chatLogFingerprint = fingerprint { "[class:", "] ChatLog [id=", ) +} + +internal val chatLogSetTextFingerprint = fingerprint { + accessFlags(AccessFlags.PUBLIC) + returns("V") + parameters("Ljava/lang/String;") + opcodes( + Opcode.CONST_4, + Opcode.CONST_STRING, + Opcode.CONST_STRING, + Opcode.IF_EQZ, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT, + Opcode.IF_EQZ, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT, + Opcode.CONST_16, + Opcode.IF_LE, + ) + custom { method, classDef -> classDef.sourceFile == "ChatLog.kt" } +} + +internal val chatLogGetTextFingerprint = fingerprint { + accessFlags(AccessFlags.PUBLIC) + returns("Ljava/lang/String;") + parameters() + opcodes( + Opcode.IGET_BOOLEAN, + Opcode.CONST_STRING, + Opcode.IF_EQZ, + Opcode.GOTO, + Opcode.IGET_OBJECT, + Opcode.IF_NEZ, + Opcode.GOTO, + Opcode.MOVE_OBJECT, + ) + custom { method, classDef -> classDef.sourceFile == "ChatLog.kt" } } \ No newline at end of file diff --git a/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/fingerprints/ChatLogViewHolderFingerprint.kt b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/fingerprints/ChatLogViewHolderFingerprint.kt deleted file mode 100644 index 5f9f3d3df..000000000 --- a/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatlog/fingerprints/ChatLogViewHolderFingerprint.kt +++ /dev/null @@ -1,24 +0,0 @@ -package app.revanced.patches.kakaotalk.chatlog.fingerprints - -import app.revanced.patcher.fingerprint -import com.android.tools.smali.dexlib2.AccessFlags -import com.android.tools.smali.dexlib2.Opcode - -internal val createChatLogViewHolderFromRealFingerprint = fingerprint { - accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) - returns("V") - parameters() - opcodes( - Opcode.MOVE_OBJECT_FROM16, - Opcode.IGET_OBJECT, - Opcode.CONST_4, - Opcode.SGET_OBJECT, - Opcode.IGET_OBJECT, - Opcode.IGET_OBJECT, - Opcode.CONST_16, - Opcode.IGET_OBJECT, - Opcode.CONST_4, - Opcode.CONST_4, - ) - custom { method, classDef -> classDef.sourceFile == "ChatLogViewHolder.kt" } -} \ No newline at end of file diff --git a/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatroom/Remove300PlusLimitPatch.kt b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatroom/Remove300PlusLimitPatch.kt index faf73310d..40ba46651 100644 --- a/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatroom/Remove300PlusLimitPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/chatroom/Remove300PlusLimitPatch.kt @@ -14,7 +14,7 @@ val remove300PlusLimitBaseChatRoomPatch = bytecodePatch( name = "Disable 300+ unread limit (BaseChatRoom)", description = "Always show the real unread count instead of '300+' in base chatroom list" ) { - compatibleWith("com.kakao.talk"("25.4.2")) + compatibleWith("com.kakao.talk"("25.4.3")) execute { val method = limit300PlusBaseChatRoomFingerprint.method @@ -40,7 +40,7 @@ val remove300PlusLimitOpenChatRoomPatch = bytecodePatch( name = "Disable 300+ unread limit (OpenChatRoom)", description = "Always show the real unread count instead of '300+' in open chatroom list" ) { - compatibleWith("com.kakao.talk"("25.4.2")) + compatibleWith("com.kakao.talk"("25.4.3")) execute { val method = limit300PlusOpenChatRoomFingerprint.method diff --git a/patches/src/main/kotlin/app/revanced/patches/kakaotalk/emoticon/ForceEnableEmoticonPlusPatch.kt b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/emoticon/ForceEnableEmoticonPlusPatch.kt index fd19b2f07..703724830 100644 --- a/patches/src/main/kotlin/app/revanced/patches/kakaotalk/emoticon/ForceEnableEmoticonPlusPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/emoticon/ForceEnableEmoticonPlusPatch.kt @@ -9,7 +9,7 @@ val forceEnableEmoticonPlusPatch = bytecodePatch( name = "Force enable emoticon plus feature", description = "Force enable emoticon plus feature (Unpurchased emoticon can be sent once per day)", ) { - compatibleWith("com.kakao.talk"("25.4.2")) + compatibleWith("com.kakao.talk"("25.4.3")) execute { isEnableEmoticonPlusFingerprint.method.addInstructions( diff --git a/patches/src/main/kotlin/app/revanced/patches/kakaotalk/ghost/GhostModePatch.kt b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/ghost/GhostModePatch.kt index 008f65e64..a465ba414 100644 --- a/patches/src/main/kotlin/app/revanced/patches/kakaotalk/ghost/GhostModePatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/ghost/GhostModePatch.kt @@ -10,7 +10,7 @@ val ghostMode = bytecodePatch( name = "Ghost Mode", description = "Don't expose your typing status to the other party.", ) { - compatibleWith("com.kakao.talk"("25.4.2")) + compatibleWith("com.kakao.talk"("25.4.3")) execute { val findUnit = kotlinUnitInstanceFingerprint.method diff --git a/patches/src/main/kotlin/app/revanced/patches/kakaotalk/integrity/BypassMoatCheckPatch.kt b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/integrity/BypassMoatCheckPatch.kt index 9d8c5fa51..062610f48 100644 --- a/patches/src/main/kotlin/app/revanced/patches/kakaotalk/integrity/BypassMoatCheckPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/integrity/BypassMoatCheckPatch.kt @@ -21,7 +21,7 @@ val bypassMoatCheckPatch = bytecodePatch( name = "Bypass Moat check", description = "Bypass Moat check that prevents the app from running.", ) { - compatibleWith("com.kakao.talk"("25.4.2")) + compatibleWith("com.kakao.talk"("25.4.3")) execute { val patch: (Fingerprint) -> Unit = { diff --git a/patches/src/main/kotlin/app/revanced/patches/kakaotalk/integrity/BypassRequestChecksumsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/integrity/BypassRequestChecksumsPatch.kt index 76baf286c..17932893f 100644 --- a/patches/src/main/kotlin/app/revanced/patches/kakaotalk/integrity/BypassRequestChecksumsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/integrity/BypassRequestChecksumsPatch.kt @@ -10,7 +10,7 @@ val bypassRequestChecksumPatch = bytecodePatch( name = "Bypass requestChecksums", description = "Prevents the execution of checksum verification logic by making it return early." ) { - compatibleWith("com.kakao.talk"("25.4.2")) + compatibleWith("com.kakao.talk"("25.4.3")) execute { val findUnit = kotlinUnitInstanceFingerprint.method diff --git a/patches/src/main/kotlin/app/revanced/patches/kakaotalk/integrity/VerifyingSignaturePatch.kt b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/integrity/VerifyingSignaturePatch.kt index 21527ddba..ff7f9b83f 100644 --- a/patches/src/main/kotlin/app/revanced/patches/kakaotalk/integrity/VerifyingSignaturePatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/integrity/VerifyingSignaturePatch.kt @@ -9,7 +9,7 @@ val verifyingSignaturePatch = bytecodePatch( name = "Disable verifying signature", description = "Disables the signature verification check that prevents the app from running.", ) { - compatibleWith("com.kakao.talk"("25.4.2")) + compatibleWith("com.kakao.talk"("25.4.3")) execute { verifyingSignatureFingerprint.method.addInstructions( diff --git a/patches/src/main/kotlin/app/revanced/patches/kakaotalk/misc/ForceEnableDebugModePatch.kt b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/misc/ForceEnableDebugModePatch.kt index d72ba6ed2..26c155e34 100644 --- a/patches/src/main/kotlin/app/revanced/patches/kakaotalk/misc/ForceEnableDebugModePatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/misc/ForceEnableDebugModePatch.kt @@ -11,7 +11,7 @@ val forceEnableDebugModePatch = bytecodePatch( name = "Force enable debug mode", description = "Enables debug mode in the app.", ) { - compatibleWith("com.kakao.talk"("25.4.2")) + compatibleWith("com.kakao.talk"("25.4.3")) execute { val method = configConstructorFingerprint.method diff --git a/patches/src/main/kotlin/app/revanced/patches/kakaotalk/misc/RemoveShopTabPatch.kt b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/misc/RemoveShopTabPatch.kt index 40925b368..480fb961e 100644 --- a/patches/src/main/kotlin/app/revanced/patches/kakaotalk/misc/RemoveShopTabPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/misc/RemoveShopTabPatch.kt @@ -15,7 +15,7 @@ val removeShopTabPatch = bytecodePatch( name = "Remove shop tab", description = "Removes the shop tab from the bottom navigation bar.", ) { - compatibleWith("com.kakao.talk"("25.4.2")) + compatibleWith("com.kakao.talk"("25.4.3")) execute { val method = addNavigationTabFingerprint.method diff --git a/patches/src/main/kotlin/app/revanced/patches/kakaotalk/send/AllowReplyToFeedPatch.kt b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/send/AllowReplyToFeedPatch.kt index 8d6dd3340..ecd88ed5e 100644 --- a/patches/src/main/kotlin/app/revanced/patches/kakaotalk/send/AllowReplyToFeedPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/send/AllowReplyToFeedPatch.kt @@ -15,7 +15,7 @@ val allowReplyToFeedPatch = app.revanced.patcher.patch.bytecodePatch( name = "Allow reply to feed", description = "Allows replying to feed messages", ) { - compatibleWith("com.kakao.talk"("25.4.2")) + compatibleWith("com.kakao.talk"("25.4.3")) execute { val patch: (Fingerprint) -> Unit = { fp -> diff --git a/patches/src/main/kotlin/app/revanced/patches/kakaotalk/versioninfo/VersionInfoPatch.kt b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/versioninfo/VersionInfoPatch.kt index 5cfc80f4d..a24d333ea 100644 --- a/patches/src/main/kotlin/app/revanced/patches/kakaotalk/versioninfo/VersionInfoPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/kakaotalk/versioninfo/VersionInfoPatch.kt @@ -17,7 +17,7 @@ val versionInfoPatch = bytecodePatch( name = "Version info patch", description = "Patches the version info to include '(ReVanced)' in the version string.", ) { - compatibleWith("com.kakao.talk"("25.4.2")) + compatibleWith("com.kakao.talk"("25.4.3")) execute { val runPatch: (Fingerprint, Boolean) -> Unit = { fp, inDetail ->