feat(kakaotalk): add bypass moat check patch and associated fingerprints

It's up, but it's not working, need to check further
This commit is contained in:
2025-05-19 20:23:04 +09:00
parent 50b735da19
commit 60a02aa90a
3 changed files with 149 additions and 0 deletions

View File

@ -269,6 +269,10 @@ 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;
}

View File

@ -0,0 +1,80 @@
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.bypassMoatCheckFingerprintOne
import app.revanced.patches.kakaotalk.integrity.fingerprints.bypassMoatCheckFingerprintTwo
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 ->
println("Replacing ${inst.reference} with TRUE")
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(bypassMoatCheckFingerprintOne)
patch(bypassMoatCheckFingerprintTwo)
}
}

View File

@ -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 bypassMoatCheckFingerprintOne = 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 bypassMoatCheckFingerprintTwo = 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")
}