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:
@ -269,6 +269,10 @@ public final class app/revanced/patches/kakaotalk/ghost/GhostModePatchKt {
|
|||||||
public static final fun getGhostMode ()Lapp/revanced/patcher/patch/BytecodePatch;
|
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 final class app/revanced/patches/kakaotalk/integrity/BypassRequestChecksumsPatchKt {
|
||||||
public static final fun getBypassRequestChecksumPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
public static final fun getBypassRequestChecksumPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
@ -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")
|
||||||
|
}
|
Reference in New Issue
Block a user