Merge pull request 'feat: initial kakaotalk patches' (#3) from feat/kakaotalk into main
Reviewed-on: #3
This commit is contained in:
@ -244,6 +244,75 @@ public final class app/revanced/patches/irplus/ad/RemoveAdsPatchKt {
|
||||
public static final fun getRemoveAdsPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/kakaotalk/ads/RemoveBizBoardPatchKt {
|
||||
public static final fun getRemoveBizBoardPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/kakaotalk/ads/RemoveFocusAdPatchKt {
|
||||
public static final fun getRemoveFocusAdPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/kakaotalk/ads/RemoveMoreTabAdPatchKt {
|
||||
public static final fun getRemoveMoreTabAdPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/kakaotalk/ads/RemoveNativeAdPatchKt {
|
||||
public static final fun getRemoveNativeAdPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/kakaotalk/ads/RemoveOlkChatRoomListAdPatchKt {
|
||||
public static final fun getRemoveOlkChatRoomListAdPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||
}
|
||||
|
||||
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/Remove99ClampPatchKt {
|
||||
public static final fun getRemove99ClampPatch ()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;
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/kakaotalk/emoticon/ForceEnableEmoticonPlusPatchKt {
|
||||
public static final fun getForceEnableEmoticonPlusPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/kakaotalk/ghost/GhostModePatchKt {
|
||||
public static final fun getGhostMode ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/kakaotalk/integrity/BypassMoatCheckPatchKt {
|
||||
public static final fun getBypassMoatCheckPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/kakaotalk/integrity/BypassRequestChecksumsPatchKt {
|
||||
public static final fun getBypassRequestChecksumPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/kakaotalk/integrity/VerifyingSignaturePatchKt {
|
||||
public static final fun getVerifyingSignaturePatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/kakaotalk/misc/ForceEnableDebugModePatchKt {
|
||||
public static final fun getForceEnableDebugModePatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||
}
|
||||
|
||||
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/send/AllowReplyToFeedPatchKt {
|
||||
public static final fun getAllowReplyToFeedPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/kakaotalk/versioninfo/VersionInfoPatchKt {
|
||||
public static final fun getVersionInfoPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/lightroom/misc/login/DisableMandatoryLoginPatchKt {
|
||||
public static final fun getDisableMandatoryLoginPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||
}
|
||||
|
@ -0,0 +1,30 @@
|
||||
package app.revanced.patches.kakaotalk.ads
|
||||
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patches.kakaotalk.ads.fingerprints.measuringBizBoardFingerprint
|
||||
|
||||
@Suppress("unused")
|
||||
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"))
|
||||
|
||||
execute {
|
||||
val method = measuringBizBoardFingerprint.method
|
||||
|
||||
method.addInstructions(
|
||||
0,
|
||||
"""
|
||||
const/4 v0, 0x0
|
||||
invoke-virtual {p0, v0, v0}, Landroid/view/View;->setMeasuredDimension(II)V
|
||||
|
||||
const/16 v0, 0x8
|
||||
invoke-virtual {p0, v0}, Landroid/view/View;->setVisibility(I)V
|
||||
|
||||
return-void
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package app.revanced.patches.kakaotalk.ads
|
||||
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patches.kakaotalk.ads.fingerprints.loadFocusAdFingerprint
|
||||
|
||||
val removeFocusAdPatch = bytecodePatch(
|
||||
name = "Remove focus ad",
|
||||
description = "Removes the focus ad from the app.",
|
||||
) {
|
||||
compatibleWith("com.kakao.talk"("25.4.2"))
|
||||
|
||||
execute {
|
||||
loadFocusAdFingerprint.method.addInstructions(
|
||||
0,
|
||||
"""
|
||||
const/4 v0, 0x1
|
||||
return v0
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
package app.revanced.patches.kakaotalk.ads
|
||||
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.instructions
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.removeInstruction
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patches.kakaotalk.ads.fingerprints.adBigUIModelFingerprint
|
||||
import app.revanced.patches.kakaotalk.ads.fingerprints.addSectionToMoreTabUIFingerprint
|
||||
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 removeMoreTabAdPatch = bytecodePatch(
|
||||
name = "Remove More tab ad",
|
||||
description = "Removes the ad from the More tab.",
|
||||
) {
|
||||
compatibleWith("com.kakao.talk"("25.4.2"))
|
||||
|
||||
execute {
|
||||
val addSectionToMoreTabUIMethod = addSectionToMoreTabUIFingerprint.method
|
||||
val addSectionToMoreTabUIInsns = addSectionToMoreTabUIMethod.instructions
|
||||
|
||||
val adBigUIModelClass = adBigUIModelFingerprint.method.definingClass
|
||||
|
||||
val matches = addSectionToMoreTabUIInsns.mapIndexedNotNull { idx, inst ->
|
||||
if (inst is BuilderInstruction35c
|
||||
&& inst.opcode == Opcode.INVOKE_VIRTUAL
|
||||
&& (inst.getReference<MethodReference>()?.name == "add")
|
||||
) {
|
||||
val prev = addSectionToMoreTabUIInsns.getOrNull(idx - 1) as? BuilderInstruction35c
|
||||
val ref = (prev?.getReference<MethodReference>())
|
||||
if (ref?.definingClass == adBigUIModelClass) {
|
||||
Pair(idx - 1, idx)
|
||||
} else null
|
||||
} else null
|
||||
}
|
||||
|
||||
matches
|
||||
.sortedByDescending { it.second }
|
||||
.forEach { (loadIdx, invokeIdx) ->
|
||||
addSectionToMoreTabUIMethod.removeInstruction(invokeIdx)
|
||||
addSectionToMoreTabUIMethod.removeInstruction(loadIdx)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package app.revanced.patches.kakaotalk.ads
|
||||
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patches.kakaotalk.ads.fingerprints.loadNativeAdFingerprint
|
||||
|
||||
val removeNativeAdPatch = bytecodePatch(
|
||||
name = "Remove native ad",
|
||||
description = "Removes the native ad from the app.",
|
||||
) {
|
||||
compatibleWith("com.kakao.talk"("25.4.2"))
|
||||
|
||||
execute {
|
||||
val method = loadNativeAdFingerprint.method
|
||||
|
||||
method.addInstructions(
|
||||
0,
|
||||
"""
|
||||
const/4 v0, 0x1
|
||||
return v0
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package app.revanced.patches.kakaotalk.ads
|
||||
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patches.kakaotalk.ads.fingerprints.addOlkChatRoomListAdFingerprint
|
||||
import app.revanced.patches.kakaotalk.common.fingerprints.kotlinUnitInstanceFingerprint
|
||||
|
||||
@Suppress("unused")
|
||||
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"))
|
||||
|
||||
execute {
|
||||
val findUnit = kotlinUnitInstanceFingerprint.method
|
||||
val unitClass = findUnit.definingClass
|
||||
|
||||
val method = addOlkChatRoomListAdFingerprint.method
|
||||
|
||||
// I tried to find the field name, but it's pretty obvious to me, so I hardcode it.
|
||||
// If it changes, we need to fix it
|
||||
method.addInstructions(
|
||||
0,
|
||||
"""
|
||||
sget-object v0, $unitClass->a:$unitClass
|
||||
return-object v0
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
package app.revanced.patches.kakaotalk.ads.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
internal val measuringBizBoardFingerprint = fingerprint {
|
||||
accessFlags(AccessFlags.PUBLIC)
|
||||
returns("V")
|
||||
parameters("I", "I")
|
||||
opcodes(
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.MOVE_RESULT,
|
||||
Opcode.INT_TO_FLOAT,
|
||||
Opcode.CONST,
|
||||
Opcode.MUL_FLOAT_2ADDR,
|
||||
Opcode.FLOAT_TO_INT,
|
||||
Opcode.IGET,
|
||||
Opcode.IF_LE,
|
||||
Opcode.MOVE,
|
||||
Opcode.CONST_HIGH16,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.MOVE_RESULT,
|
||||
Opcode.INVOKE_SUPER,
|
||||
Opcode.RETURN_VOID
|
||||
)
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package app.revanced.patches.kakaotalk.ads.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
internal val loadFocusAdFingerprint = fingerprint {
|
||||
accessFlags(AccessFlags.PUBLIC)
|
||||
parameters("Lcom/kakao/adfit/ads/focus/FocusAdLoader\$OnAdLoadListener;")
|
||||
returns("Z")
|
||||
strings("listener", " owner is destroyed.", " loading is already started.", "Request Focus AD", " loading is started.", "Focus ad is cached. [id = ")
|
||||
opcodes(
|
||||
Opcode.CONST_STRING,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.SGET_OBJECT,
|
||||
Opcode.CONST_4,
|
||||
Opcode.IF_NE,
|
||||
)
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
package app.revanced.patches.kakaotalk.ads.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
internal val addSectionToMoreTabUIFingerprint = fingerprint {
|
||||
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
|
||||
parameters("Ljava/lang/Object;")
|
||||
returns("Ljava/lang/Object;")
|
||||
strings(
|
||||
"call to \'resume\' before \'invoke\' with coroutine",
|
||||
"null cannot be cast to non-null type com.kakao.talk.moretab.ui.model.KakaoPayUiModel",
|
||||
"null cannot be cast to non-null type com.kakao.talk.moretab.ui.model.WalletUiModel",
|
||||
"null cannot be cast to non-null type com.kakao.talk.moretab.ui.model.WeatherUiModel",
|
||||
"null cannot be cast to non-null type com.kakao.talk.moretab.ui.model.KakaoNowUiModel",
|
||||
"null cannot be cast to non-null type com.kakao.talk.moretab.ui.model.TalkManualUiModel",
|
||||
"null cannot be cast to non-null type com.kakao.talk.moretab.ui.model.ServiceGroupUiModel",
|
||||
"null cannot be cast to non-null type com.kakao.talk.moretab.ui.model.WalletBannerUiModel",
|
||||
"null cannot be cast to non-null type kotlin.Boolean",
|
||||
)
|
||||
opcodes(
|
||||
Opcode.SGET_OBJECT,
|
||||
Opcode.IGET,
|
||||
Opcode.CONST_4,
|
||||
Opcode.IF_EQZ,
|
||||
)
|
||||
}
|
||||
|
||||
internal val adBigUIModelFingerprint = fingerprint {
|
||||
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
|
||||
parameters()
|
||||
returns("Ljava/lang/String;")
|
||||
strings(
|
||||
"AdBig(uiModel=",
|
||||
)
|
||||
opcodes(
|
||||
Opcode.NEW_INSTANCE,
|
||||
Opcode.CONST_STRING,
|
||||
Opcode.INVOKE_DIRECT,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.CONST_STRING,
|
||||
)
|
||||
custom { method, classDef -> method.name == "toString" }
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package app.revanced.patches.kakaotalk.ads.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
internal val loadNativeAdFingerprint = fingerprint {
|
||||
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
|
||||
parameters("I", "Lcom/kakao/adfit/ads/media/NativeAdLoader\$AdLoadListener;")
|
||||
returns("Z")
|
||||
strings(
|
||||
"listener",
|
||||
" owner is destroyed.",
|
||||
" loading is already started.",
|
||||
"Request Native AD",
|
||||
" loading is started.",
|
||||
"Native ad is cached. [id = ",
|
||||
"] [dsp = ",
|
||||
"] [count = ",
|
||||
"Invalid Count: "
|
||||
)
|
||||
opcodes(
|
||||
Opcode.CONST_STRING,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.IF_LEZ,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.SGET_OBJECT,
|
||||
Opcode.CONST_4,
|
||||
Opcode.IF_NE,
|
||||
)
|
||||
custom { method, classDef -> method.name == "load" }
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package app.revanced.patches.kakaotalk.ads.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
internal val addOlkChatRoomListAdFingerprint = fingerprint {
|
||||
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
|
||||
parameters("Ljava/lang/Object;")
|
||||
returns("Ljava/lang/Object;")
|
||||
strings("list", "key_ad_info", "")
|
||||
opcodes(
|
||||
Opcode.MOVE_OBJECT_FROM16,
|
||||
Opcode.SGET_OBJECT,
|
||||
Opcode.INVOKE_STATIC_RANGE,
|
||||
Opcode.SGET_BOOLEAN,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.IGET,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.MOVE_RESULT,
|
||||
Opcode.CONST_STRING,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.IF_EQZ,
|
||||
)
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package app.revanced.patches.kakaotalk.changemodel
|
||||
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patcher.patch.stringOption
|
||||
import app.revanced.patches.kakaotalk.changemodel.fingerprints.changeModelFingerprint
|
||||
|
||||
@Suppress("unused")
|
||||
val changeModelPatch = bytecodePatch(
|
||||
name = "Change model",
|
||||
description = "Changes the device model to supporting subdevice features",
|
||||
) {
|
||||
val changeModelOption = stringOption(
|
||||
"model", "SM-X926N"
|
||||
)
|
||||
|
||||
compatibleWith("com.kakao.talk"("25.4.2"))
|
||||
|
||||
execute {
|
||||
changeModelFingerprint.method.addInstructions(
|
||||
0,
|
||||
"""
|
||||
const-string v0, "${changeModelOption.value}"
|
||||
return-object v0
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package app.revanced.patches.kakaotalk.changemodel.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint
|
||||
|
||||
@Suppress("unused")
|
||||
internal val changeModelFingerprint = fingerprint {
|
||||
strings("MODEL", "\\s", "-", "US", "toUpperCase(...)")
|
||||
custom {
|
||||
_, classDef ->
|
||||
classDef.methods.indexOf(classDef.methods.last()) > 2
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package app.revanced.patches.kakaotalk.chatlog
|
||||
|
||||
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.processWatermarkCountFingerprint
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction10t
|
||||
import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction22t
|
||||
|
||||
@Suppress("unused")
|
||||
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"))
|
||||
|
||||
execute {
|
||||
val method = processWatermarkCountFingerprint.method
|
||||
|
||||
method.instructions
|
||||
.filterIsInstance<BuilderInstruction22t>()
|
||||
.filter { it.opcode == Opcode.IF_LE }
|
||||
.forEach { ifle ->
|
||||
val idx = method.instructions.indexOf(ifle)
|
||||
val goto = BuilderInstruction10t(Opcode.GOTO, ifle.target)
|
||||
method.replaceInstruction(idx, goto)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package app.revanced.patches.kakaotalk.chatlog.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
|
||||
internal val processWatermarkCountFingerprint = fingerprint {
|
||||
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
|
||||
returns("Ljava/lang/Object;")
|
||||
parameters()
|
||||
strings("notiRead", "openlinkSettingShowUnreadCount")
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
package app.revanced.patches.kakaotalk.chatroom
|
||||
|
||||
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.chatroom.fingerprints.limit300PlusBaseChatRoomFingerprint
|
||||
import app.revanced.patches.kakaotalk.chatroom.fingerprints.limit300PlusOpenChatRoomFingerprint
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction10t
|
||||
import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction22t
|
||||
|
||||
@Suppress("unused")
|
||||
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"))
|
||||
|
||||
execute {
|
||||
val method = limit300PlusBaseChatRoomFingerprint.method
|
||||
|
||||
val branches = method.instructions
|
||||
.filterIsInstance<BuilderInstruction22t>()
|
||||
.filter { it.opcode == Opcode.IF_LT }
|
||||
.toList()
|
||||
|
||||
branches.forEach { iflt ->
|
||||
val idx = method.instructions.indexOf(iflt)
|
||||
val gotoInsn = BuilderInstruction10t(
|
||||
Opcode.GOTO,
|
||||
iflt.target
|
||||
)
|
||||
method.replaceInstruction(idx, gotoInsn)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("unused")
|
||||
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"))
|
||||
|
||||
execute {
|
||||
val method = limit300PlusOpenChatRoomFingerprint.method
|
||||
|
||||
method.instructions
|
||||
.filterIsInstance<BuilderInstruction22t>()
|
||||
.filter { it.opcode == Opcode.IF_LT }
|
||||
.toList()
|
||||
.forEach { iflt ->
|
||||
val idx = method.instructions.indexOf(iflt)
|
||||
val gotoInsn = BuilderInstruction10t(Opcode.GOTO, iflt.target)
|
||||
method.replaceInstruction(idx, gotoInsn)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package app.revanced.patches.kakaotalk.chatroom.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
|
||||
@Suppress("unused")
|
||||
internal val limit300PlusBaseChatRoomFingerprint = fingerprint {
|
||||
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
|
||||
returns("V")
|
||||
parameters("Lcom/kakao/talk/widget/ViewBindable;")
|
||||
strings("300+")
|
||||
}
|
||||
|
||||
@Suppress("unused")
|
||||
internal val limit300PlusOpenChatRoomFingerprint = fingerprint {
|
||||
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
|
||||
returns("V")
|
||||
parameters()
|
||||
strings("300+")
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package app.revanced.patches.kakaotalk.common.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
internal val kotlinUnitInstanceFingerprint = fingerprint {
|
||||
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
|
||||
parameters()
|
||||
returns("Ljava/lang/String;")
|
||||
strings("kotlin.Unit")
|
||||
opcodes(
|
||||
Opcode.CONST_STRING,
|
||||
Opcode.RETURN_OBJECT
|
||||
)
|
||||
custom { method, classDef ->
|
||||
method.name == "toString"
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package app.revanced.patches.kakaotalk.emoticon
|
||||
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patches.kakaotalk.emoticon.fingerprints.isEnableEmoticonPlusFingerprint
|
||||
|
||||
@Suppress("unused")
|
||||
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"))
|
||||
|
||||
execute {
|
||||
isEnableEmoticonPlusFingerprint.method.addInstructions(
|
||||
0,
|
||||
"""
|
||||
const/4 v0, 0x1
|
||||
return v0
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package app.revanced.patches.kakaotalk.emoticon.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
internal val isEnableEmoticonPlusFingerprint = fingerprint {
|
||||
accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC)
|
||||
returns("Z")
|
||||
parameters()
|
||||
strings("emoticonPlusMe")
|
||||
opcodes(
|
||||
Opcode.SGET_OBJECT,
|
||||
Opcode.IF_EQZ,
|
||||
Opcode.IGET_BOOLEAN,
|
||||
Opcode.RETURN,
|
||||
Opcode.CONST_STRING,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.CONST_4,
|
||||
Opcode.THROW,
|
||||
)
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package app.revanced.patches.kakaotalk.ghost
|
||||
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patches.kakaotalk.common.fingerprints.kotlinUnitInstanceFingerprint
|
||||
import app.revanced.patches.kakaotalk.ghost.fingerprints.sendCurrentActionFingerprint
|
||||
|
||||
@Suppress("unused")
|
||||
val ghostMode = bytecodePatch(
|
||||
name = "Ghost Mode",
|
||||
description = "Don't expose your typing status to the other party.",
|
||||
) {
|
||||
compatibleWith("com.kakao.talk"("25.4.2"))
|
||||
|
||||
execute {
|
||||
val findUnit = kotlinUnitInstanceFingerprint.method
|
||||
val unitClass = findUnit.definingClass
|
||||
|
||||
val method = sendCurrentActionFingerprint.method
|
||||
|
||||
// I tried to find the field name, but it's pretty obvious to me, so I hardcode it.
|
||||
// If it changes, we need to fix it
|
||||
method.addInstructions(
|
||||
0,
|
||||
"""
|
||||
sget-object v0, $unitClass->a:$unitClass
|
||||
return-object v0
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
package app.revanced.patches.kakaotalk.ghost.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
internal val sendCurrentActionFingerprint = fingerprint {
|
||||
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
|
||||
returns("Ljava/lang/Object;")
|
||||
parameters("Ljava/lang/Object;")
|
||||
strings(
|
||||
"method",
|
||||
"chatId",
|
||||
"type",
|
||||
"linkId"
|
||||
)
|
||||
opcodes(
|
||||
Opcode.SGET_OBJECT,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.SGET_OBJECT,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.MOVE_RESULT,
|
||||
Opcode.IF_EQZ,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.INVOKE_INTERFACE,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.NEW_INSTANCE,
|
||||
Opcode.IGET_WIDE,
|
||||
Opcode.INVOKE_DIRECT,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_WIDE,
|
||||
Opcode.CONST_WIDE_16,
|
||||
Opcode.CMP_LONG,
|
||||
Opcode.IF_GEZ,
|
||||
Opcode.GOTO
|
||||
)
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
package app.revanced.patches.kakaotalk.integrity
|
||||
|
||||
import app.revanced.patcher.Fingerprint
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.instructions
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.removeInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patches.kakaotalk.integrity.fingerprints.moatCheckResultFingerprintOne
|
||||
import app.revanced.patches.kakaotalk.integrity.fingerprints.moatCheckResultFingerprintTwo
|
||||
import app.revanced.patches.kakaotalk.integrity.fingerprints.postprocessMoatCheckFailedFingerprint
|
||||
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.instruction.Instruction
|
||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||
import com.android.tools.smali.dexlib2.immutable.reference.ImmutableFieldReference
|
||||
|
||||
@Suppress("unused")
|
||||
val bypassMoatCheckPatch = bytecodePatch(
|
||||
name = "Bypass Moat check",
|
||||
description = "Bypass Moat check that prevents the app from running.",
|
||||
) {
|
||||
compatibleWith("com.kakao.talk"("25.4.2"))
|
||||
|
||||
execute {
|
||||
val patch: (Fingerprint) -> Unit = {
|
||||
val method = it.method
|
||||
val insns = method.instructions
|
||||
|
||||
insns
|
||||
.filterIsInstance<BuilderInstruction21c>()
|
||||
.filter { inst ->
|
||||
inst.opcode == Opcode.SGET_OBJECT &&
|
||||
inst.reference == ImmutableFieldReference(
|
||||
"Ljava/lang/Boolean;", "FALSE", "Ljava/lang/Boolean;"
|
||||
)
|
||||
}
|
||||
.forEach { inst ->
|
||||
val idx = insns.indexOf(inst)
|
||||
method.replaceInstruction(
|
||||
idx,
|
||||
BuilderInstruction21c(
|
||||
Opcode.SGET_OBJECT,
|
||||
inst.registerA,
|
||||
ImmutableFieldReference(
|
||||
"Ljava/lang/Boolean;", "TRUE", "Ljava/lang/Boolean;"
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
val postprocessMoatCheckFailedMethod = postprocessMoatCheckFailedFingerprint.method
|
||||
|
||||
val toRemove = mutableListOf<Instruction>()
|
||||
insns.forEachIndexed { i, inst ->
|
||||
if (inst is BuilderInstruction35c &&
|
||||
inst.opcode == Opcode.INVOKE_VIRTUAL &&
|
||||
(inst.getReference<MethodReference>()?.name == postprocessMoatCheckFailedMethod.name) &&
|
||||
inst.getReference<MethodReference>()?.definingClass ==
|
||||
"Lcom/kakaopay/shared/security/moat/PaySecurityWorker;"
|
||||
) {
|
||||
for (j in 0..3) {
|
||||
insns.getOrNull(i + j)?.let { toRemove += it }
|
||||
}
|
||||
}
|
||||
}
|
||||
toRemove
|
||||
.distinct()
|
||||
.sortedByDescending { insns.indexOf(it) }
|
||||
.forEach { inst ->
|
||||
method.removeInstruction(insns.indexOf(inst))
|
||||
}
|
||||
}
|
||||
|
||||
patch(moatCheckResultFingerprintOne)
|
||||
patch(moatCheckResultFingerprintTwo)
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package app.revanced.patches.kakaotalk.integrity
|
||||
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patches.kakaotalk.common.fingerprints.kotlinUnitInstanceFingerprint
|
||||
import app.revanced.patches.kakaotalk.integrity.fingerprints.requestChecksumsFingerprint
|
||||
|
||||
@Suppress("unused")
|
||||
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"))
|
||||
|
||||
execute {
|
||||
val findUnit = kotlinUnitInstanceFingerprint.method
|
||||
val unitClass = findUnit.definingClass
|
||||
|
||||
val method = requestChecksumsFingerprint.method
|
||||
|
||||
// I tried to find the field name, but it's pretty obvious to me, so I hardcode it.
|
||||
// If it changes, we need to fix it
|
||||
method.addInstructions(
|
||||
0,
|
||||
"""
|
||||
sget-object v0, $unitClass->a:$unitClass
|
||||
return-object v0
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package app.revanced.patches.kakaotalk.integrity
|
||||
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patches.kakaotalk.integrity.fingerprints.verifyingSignatureFingerprint
|
||||
|
||||
@Suppress("unused")
|
||||
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"))
|
||||
|
||||
execute {
|
||||
verifyingSignatureFingerprint.method.addInstructions(
|
||||
0,
|
||||
"""
|
||||
const/4 v0, 0x1
|
||||
return v0
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
package app.revanced.patches.kakaotalk.integrity.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
internal val moatCheckResultFingerprintOne = fingerprint {
|
||||
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
|
||||
parameters("Ljava/lang/Object;", "Ljava/lang/Object;", "Ljava/lang/Object;")
|
||||
returns("Ljava/lang/Object;")
|
||||
strings("detectResult", "<anonymous parameter 1>", "<anonymous parameter 2>")
|
||||
opcodes(
|
||||
Opcode.CHECK_CAST,
|
||||
Opcode.CHECK_CAST,
|
||||
Opcode.CHECK_CAST,
|
||||
Opcode.CONST_STRING,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.CONST_STRING,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.CONST_STRING,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.SGET_OBJECT,
|
||||
Opcode.SGET_OBJECT,
|
||||
Opcode.CONST_4,
|
||||
Opcode.IF_NE,
|
||||
Opcode.CHECK_CAST,
|
||||
Opcode.INVOKE_INTERFACE,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.INVOKE_INTERFACE,
|
||||
Opcode.MOVE_RESULT,
|
||||
)
|
||||
}
|
||||
|
||||
internal val moatCheckResultFingerprintTwo = fingerprint {
|
||||
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
|
||||
parameters("Ljava/lang/Object;", "Ljava/lang/Object;", "Ljava/lang/Object;")
|
||||
returns("Ljava/lang/Object;")
|
||||
strings("detectResult", "<anonymous parameter 1>", "<anonymous parameter 2>")
|
||||
opcodes(
|
||||
Opcode.CHECK_CAST,
|
||||
Opcode.CHECK_CAST,
|
||||
Opcode.CHECK_CAST,
|
||||
Opcode.CONST_STRING,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.CONST_STRING,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.CONST_STRING,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.CHECK_CAST,
|
||||
Opcode.NEW_INSTANCE,
|
||||
Opcode.INVOKE_DIRECT,
|
||||
Opcode.INVOKE_INTERFACE,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.INVOKE_INTERFACE,
|
||||
Opcode.MOVE_RESULT,
|
||||
Opcode.SGET_OBJECT,
|
||||
Opcode.IF_EQZ,
|
||||
)
|
||||
}
|
||||
|
||||
internal val postprocessMoatCheckFailedFingerprint = fingerprint {
|
||||
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
|
||||
parameters("Lcom/kakaopay/kpsd/moat/sdk/MoatFlag;", "Ljava/lang/String;", "[Ljava/lang/String;")
|
||||
strings("msg_title", "msg_body", "OUTPUT_KEY_FAILURE_TITLE", "OUTPUT_KEY_FAILURE_REASON", "ADS_BLOCK은 result message를 사용해야 합니다.", "let(...)", "OUTPUT_KEY_FAILURE_TYPE", "OUTPUT_KEY_PACKAGE_NAMES")
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package app.revanced.patches.kakaotalk.integrity.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
internal val requestChecksumsFingerprint = fingerprint {
|
||||
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
|
||||
returns("Ljava/lang/Object;")
|
||||
strings(
|
||||
"context"
|
||||
)
|
||||
opcodes(
|
||||
Opcode.CONST_4,
|
||||
Opcode.INSTANCE_OF,
|
||||
Opcode.IF_EQZ,
|
||||
Opcode.MOVE_OBJECT,
|
||||
Opcode.CHECK_CAST,
|
||||
Opcode.IGET,
|
||||
Opcode.CONST_HIGH16,
|
||||
Opcode.AND_INT,
|
||||
Opcode.IF_EQZ,
|
||||
Opcode.SUB_INT_2ADDR,
|
||||
Opcode.IPUT,
|
||||
Opcode.GOTO,
|
||||
Opcode.NEW_INSTANCE,
|
||||
Opcode.INVOKE_DIRECT,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.SGET_OBJECT,
|
||||
Opcode.IGET,
|
||||
Opcode.IF_EQZ,
|
||||
Opcode.IF_NE,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.GOTO,
|
||||
)
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package app.revanced.patches.kakaotalk.integrity.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
|
||||
@Suppress("unused")
|
||||
internal val verifyingSignatureFingerprint = fingerprint {
|
||||
accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC)
|
||||
returns("Z")
|
||||
parameters()
|
||||
strings("getPackageName(...)")
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package app.revanced.patches.kakaotalk.misc
|
||||
|
||||
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.misc.fingerprints.configConstructorFingerprint
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
@Suppress("unused")
|
||||
val forceEnableDebugModePatch = bytecodePatch(
|
||||
name = "Force enable debug mode",
|
||||
description = "Enables debug mode in the app.",
|
||||
) {
|
||||
compatibleWith("com.kakao.talk"("25.4.2"))
|
||||
|
||||
execute {
|
||||
val method = configConstructorFingerprint.method
|
||||
val insns = method.instructions
|
||||
val idxReturn = insns.indexOfFirst { it.opcode == Opcode.RETURN_VOID } // RETURN_VOID
|
||||
|
||||
val clazz = method.definingClass
|
||||
|
||||
method.addInstructions(
|
||||
idxReturn,
|
||||
"""
|
||||
const/4 v0, 0x1
|
||||
sput-boolean v0, $clazz->a:Z
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
package app.revanced.patches.kakaotalk.misc
|
||||
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.instructions
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.removeInstruction
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patches.kakaotalk.misc.fingerprints.addNavigationTabFingerprint
|
||||
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.FieldReference
|
||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||
|
||||
val removeShopTabPatch = bytecodePatch(
|
||||
name = "Remove shop tab",
|
||||
description = "Removes the shop tab from the bottom navigation bar.",
|
||||
) {
|
||||
compatibleWith("com.kakao.talk"("25.4.2"))
|
||||
|
||||
execute {
|
||||
val method = addNavigationTabFingerprint.method
|
||||
val insns = method.instructions
|
||||
|
||||
val matches = insns.mapIndexedNotNull { idx, inst ->
|
||||
if (inst is BuilderInstruction35c
|
||||
&& inst.opcode == Opcode.INVOKE_VIRTUAL
|
||||
&& (inst.getReference<MethodReference>()?.name == "add")
|
||||
) {
|
||||
val prev = insns.getOrNull(idx - 1) as? BuilderInstruction21c
|
||||
val fldName = (prev?.reference as? FieldReference)?.name
|
||||
if (fldName == "SHOPPING_TAB" || fldName == "CALL_TAB") {
|
||||
Pair(idx - 1, idx)
|
||||
} else null
|
||||
} else null
|
||||
}
|
||||
|
||||
matches
|
||||
.sortedByDescending { it.second }
|
||||
.forEach { (loadIdx, invokeIdx) ->
|
||||
method.removeInstruction(invokeIdx)
|
||||
method.removeInstruction(loadIdx)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package app.revanced.patches.kakaotalk.misc.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
internal val configConstructorFingerprint = fingerprint {
|
||||
accessFlags(AccessFlags.STATIC, AccessFlags.CONSTRUCTOR)
|
||||
returns("V")
|
||||
parameters()
|
||||
strings("google", "one", "getBytes(...)")
|
||||
opcodes(
|
||||
Opcode.SGET_OBJECT,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.SGET_OBJECT,
|
||||
Opcode.CONST_4,
|
||||
Opcode.CONST_4,
|
||||
Opcode.IF_EQ,
|
||||
Opcode.MOVE,
|
||||
Opcode.GOTO,
|
||||
)
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package app.revanced.patches.kakaotalk.misc.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
internal val addNavigationTabFingerprint = fingerprint {
|
||||
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
|
||||
returns("V")
|
||||
parameters()
|
||||
strings("webtoon")
|
||||
opcodes(
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.SGET_OBJECT,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.INVOKE_INTERFACE,
|
||||
Opcode.MOVE_RESULT,
|
||||
Opcode.CONST_4,
|
||||
Opcode.IF_EQZ,
|
||||
Opcode.SGET_OBJECT,
|
||||
Opcode.GOTO,
|
||||
)
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
package app.revanced.patches.kakaotalk.send
|
||||
|
||||
import app.revanced.patcher.Fingerprint
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.instructions
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.removeInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
|
||||
import app.revanced.patches.kakaotalk.send.fingerprints.allowSwipeReplyToFeedFingerprint
|
||||
import app.revanced.patches.kakaotalk.send.fingerprints.realActionForReplyFingerprint
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction11n
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction21t
|
||||
|
||||
@Suppress("unused")
|
||||
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"))
|
||||
|
||||
execute {
|
||||
val patch: (Fingerprint) -> Unit = { fp ->
|
||||
val method = fp.method
|
||||
val insns = method.instructions
|
||||
|
||||
val idxIfnez = insns.indexOfFirst { it is Instruction21t && it.opcode == Opcode.IF_NEZ }
|
||||
val idxIfnezTarget = (insns[idxIfnez] as Instruction21t).registerA
|
||||
|
||||
val idxInvoke = insns.subList(0, idxIfnez)
|
||||
.indexOfLast { it.opcode == Opcode.INVOKE_VIRTUAL }
|
||||
|
||||
(idxInvoke until idxIfnez).toList()
|
||||
.sortedDescending()
|
||||
.forEach { method.removeInstruction(it) }
|
||||
|
||||
method.replaceInstruction(
|
||||
idxInvoke,
|
||||
BuilderInstruction11n(
|
||||
Opcode.CONST_4,
|
||||
idxIfnezTarget,
|
||||
0x0,
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
patch(realActionForReplyFingerprint)
|
||||
patch(allowSwipeReplyToFeedFingerprint)
|
||||
}
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
package app.revanced.patches.kakaotalk.send.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
internal val realActionForReplyFingerprint = fingerprint {
|
||||
accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR)
|
||||
returns("V")
|
||||
strings(
|
||||
"chatLog",
|
||||
"chatRoom"
|
||||
)
|
||||
opcodes(
|
||||
Opcode.CONST_STRING,
|
||||
Opcode.CONST_STRING,
|
||||
Opcode.CONST,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.CONST_4,
|
||||
Opcode.INVOKE_DIRECT,
|
||||
Opcode.IPUT_OBJECT,
|
||||
Opcode.IPUT_OBJECT,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.MOVE_RESULT,
|
||||
Opcode.IF_NEZ,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.SGET_OBJECT,
|
||||
Opcode.IF_NE,
|
||||
Opcode.GOTO_16
|
||||
)
|
||||
}
|
||||
|
||||
internal val allowSwipeReplyToFeedFingerprint = fingerprint {
|
||||
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
|
||||
parameters("Landroidx/recyclerview/widget/RecyclerView;", "Landroidx/recyclerview/widget/RecyclerView\$D;")
|
||||
returns("I")
|
||||
strings("recyclerView", "viewHolder")
|
||||
opcodes(
|
||||
Opcode.CONST_STRING,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.CONST_STRING,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.MOVE_RESULT,
|
||||
Opcode.CONST_4,
|
||||
Opcode.CONST_4,
|
||||
)
|
||||
custom { method, classDef -> method.name == "getMovementFlags" }
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
package app.revanced.patches.kakaotalk.versioninfo
|
||||
|
||||
import app.revanced.patcher.Fingerprint
|
||||
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.versioninfo.fingerprints.versionInfoFingerprint
|
||||
import app.revanced.patches.kakaotalk.versioninfo.fingerprints.versionInfoPreviewFingerprint
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction21c
|
||||
import com.android.tools.smali.dexlib2.iface.reference.StringReference
|
||||
import com.android.tools.smali.dexlib2.immutable.reference.ImmutableStringReference
|
||||
import java.time.format.DateTimeFormatter
|
||||
|
||||
@Suppress("unused")
|
||||
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"))
|
||||
|
||||
execute {
|
||||
val runPatch: (Fingerprint, Boolean) -> Unit = { fp, inDetail ->
|
||||
val versionInfo = fp.method.instructions
|
||||
.filterIsInstance<BuilderInstruction21c>()
|
||||
.first { inst ->
|
||||
inst.opcode == Opcode.CONST_STRING
|
||||
}
|
||||
|
||||
val versionString = (versionInfo.reference as StringReference).string
|
||||
|
||||
fp.method
|
||||
.replaceInstruction(
|
||||
versionInfo.location.index,
|
||||
BuilderInstruction21c(
|
||||
Opcode.CONST_STRING,
|
||||
versionInfo.registerA,
|
||||
ImmutableStringReference(
|
||||
if (inDetail) {
|
||||
val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
|
||||
"$versionString (ReVanced)\nBuild at: ${
|
||||
formatter.format(
|
||||
java.time.LocalDateTime.now()
|
||||
)
|
||||
}"
|
||||
} else {
|
||||
"$versionString (ReVanced)"
|
||||
}
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
runPatch(versionInfoFingerprint, true)
|
||||
runPatch(versionInfoPreviewFingerprint, false)
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package app.revanced.patches.kakaotalk.versioninfo.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
internal val versionInfoFingerprint = fingerprint {
|
||||
accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR)
|
||||
returns("V")
|
||||
opcodes(
|
||||
Opcode.INVOKE_DIRECT,
|
||||
Opcode.CONST_STRING,
|
||||
Opcode.IPUT_OBJECT,
|
||||
Opcode.IPUT_BOOLEAN,
|
||||
Opcode.IPUT_OBJECT,
|
||||
Opcode.RETURN_VOID,
|
||||
)
|
||||
}
|
||||
|
||||
internal val versionInfoPreviewFingerprint = fingerprint {
|
||||
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
|
||||
parameters()
|
||||
returns("Ljava/lang/String;")
|
||||
opcodes(
|
||||
Opcode.CONST_STRING,
|
||||
Opcode.SGET_OBJECT,
|
||||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.NEW_INSTANCE,
|
||||
Opcode.CONST_4,
|
||||
Opcode.CONST_4,
|
||||
Opcode.INVOKE_DIRECT,
|
||||
Opcode.SGET_OBJECT,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.CHECK_CAST,
|
||||
)
|
||||
}
|
Reference in New Issue
Block a user