feat(kakaotalk): update compatibility to version 25.4.3 and add show deleted messages patch

This commit is contained in:
2025-06-08 02:02:36 +09:00
parent 9cd436a948
commit 5791b0e641
25 changed files with 122 additions and 718 deletions

View File

@ -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 {

View File

@ -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

View File

@ -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(

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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(

View File

@ -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;-><init>(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;-><init>(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;-><init>(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;-><init>(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())
}
}
}

View File

@ -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(),
)
}
}
}

View File

@ -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

View File

@ -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;-><init>()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()
)
}
}

View File

@ -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<BuilderInstruction35c>()
.filter { it.opcode == Opcode.INVOKE_VIRTUAL }
.find {
it.getReference<MethodReference>()?.name == "setDate"
}
val dateIndex = insns.indexOf(dateInst ?: return@execute)
val chatLogRegister = insns
.filterIsInstance<BuilderInstruction21c>()
.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<BuilderInstruction35c>()
.filter { it.opcode == Opcode.INVOKE_VIRTUAL }
.find {
it.getReference<MethodReference>()?.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()
)
}
}

View File

@ -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 == "<init>" }
}

View File

@ -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" }
}

View File

@ -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" }
}

View File

@ -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

View File

@ -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(

View File

@ -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

View File

@ -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 = {

View File

@ -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

View File

@ -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(

View File

@ -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

View File

@ -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

View File

@ -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 ->

View File

@ -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 ->