目标:让 com.fanduel.sportsbook 在 palera1n rootless 越狱 (iOS 16 / arm64) 的 iPhone 上能通过 Frida spawn/attach 且不被越狱检测杀进程。结果:60+ 秒稳定存活;绕过方案共三件组合修复,脚本不到 50 行有效逻辑。对照实验结论:这是 FanDuel 专属 的越狱检测,不是 frida/device 侧故障。通过 IDA MCP(server_health 返回 module: SportsbookWrapper, imagebase: 0x100000000, hexrays_ready: true)直接在 IDA 里查询。命中:结论:AppsFlyer 的 JB 判定不会杀进程,只是把结果塞给归因上报。不是这次的元凶。交叉引用回去:发现的反欺诈栈:GeoComply(地理围栏 + RASP)、Sift Science(行为反欺诈)、Incognia(设备指纹)、PredictsFraudMonitor(自建)。静态字串都不像会直接 abort,而是做数据上报。xrefs 追 _exit 的 3 个 code 调用点全在 Firebase Crashlytics(mach exception server / signal handler)内部 —— 都是崩溃处理走的路径,非主动杀。6 条 match 全部不是 4 字节对齐,都落在 __gcc_except_tab 等数据段的字节序巧合 —— 假阳性。二进制里没有直接绕 libc 的 syscall 调用。用 py_eval 在 IDA 里读 segment,0x102066a00..0x102066bc8,一共 114 个初始化函数指针。逐个检查最前的几个:阶段结论:静态看不到明显的"调 _exit 的 JB 判定"。真正的杀必然在三方 SDK(GeoComply / Incognia / Sift)内部,或者走非常规路径。得上动态。覆盖所有经典 JB 检测面:启动命令:脚本根本没装上,frida-agent 的 IPC 就断了。排查两个嫌疑:写最小脚本 test_min.js:用默认 runtime 跑:脚本能装。所以之前是 v8 的问题。弃用 --runtime=v8。把脚本分成 1→2→...→N 个 section,每段跑完打 ok(...) 标志。下一段是:Spawn-gated 期间主动调 OC 方法触发 AppsFlyer 内部 init 副作用(可能要 dispatch 到主线程,但主线程还冻着),直接死锁/崩溃。修复:永远不在 bypass 阶段"主动调"OC,只"被动 hook"。把 setter 调用换成 hook -[AppsFlyerLib skipAdvancedJailbreakValidation] 的 getter,永远返回 YES:然后继续,下一段 hookGeoComply() 里 Object.keys(ObjC.classes) 全扫(2 万+ 类),太慢,同样把 agent 拖超时。改成 setTimeout(hookGeoComply, 400) 延后到 resume 后再扫。此时 hook 能全部装上:但用 Python 宿主 run.py 跑监控循环,结果:进程在 resume 后立刻死,仍然是 0 秒。且 crash=None 表示是"干净终止"而不是崩溃。假设:既然 hook 全装了 JB 还被杀 → 一定是别的信号。尝试 noexit.js:把 exit / _exit / abort / raise / kill / pthread_kill / __cxa_throw / objc_terminate / ... 一股脑用 Interceptor.replace(p, new NativeCallback(()=>0, 'int', [])) 全 no-op 化。结果:进程还是 0 秒死,而且 [NOEXIT] sym called 一条都没打。当时的错误结论:既然所有 exit 原语都被替换为 no-op 还立刻死,杀进程肯定走的是 mach 级(task_terminate)或者 SIGKILL。这一串证据把我往"外部 SIGKILL / launchd entitlement 拒绝"方向带偏了,写了一大段总结放弃 Frida 路线建议用 Substrate tweak。后来才明白:Interceptor.replace(exit_like, ()=>0) 替换一个 noreturn 函数是错的。exit/abort 被编译器标记 __attribute__((noreturn)),调用点后面不保留合法返回路径(常常编译成 BL abort; UDF #0 或者直接接下一个 basic block 的其他代码)。我们的 no-op "return 0" 让执行 flow 穿透到了垃圾指令,下一步走 SIGILL,看起来就像"立刻死"。所以当时看到的现象是我们的 hook 自己把进程搞死的,跟 RASP 没关系。但我当时没反应过来。用户贴了 terminal 给我:并断言"这里 frida 先执行,是可以绕过检测的"。这句提醒是整个会话的转折点。它意味着:于是回到 Frida 正途。纯粹只装 Process.setExceptionHandler,不装任何 hook。看看纯净状态下啥异常会触发。结果:只有 2 次 abort,地址 0x1f98c7198 是 libc 的 abort 函数入口。之前 noexit 实验里看到的 0x2a0184080 这种 "illegal-instruction" 都不存在于 baseline —— 全部是我们自己 Interceptor.replace 引起的副作用(Frida Gum 的半成品 trampoline)。不用 Interceptor.replace 改写 abort 代码页,而是 Interceptor.attach + onEnter 里 Thread.sleep(永远):重跑:解读:backtrace 指向非常明确的调用链:重点:这一步彻底改写了"这是什么检测"的理解:之前以为是第三方 RASP 直接 exit,实际是通过 Apple 内部机制间接 abort。在第 8 步做 noexit 和前期迭代时还看到过 illegal-instruction at 0x2a01...XXXX,总以为是 RASP 埋的 BRK trap。其实:规律总结:对 exit 家族全换用 attach + Thread.sleep(∞) 后,illegal-instruction 再没出现过。另一个踩坑:我用 isRaspProbe() 路径前缀过滤时把:拦了以后 NSBundle 一走到这两类路径就 bug,又触发 _predicateSecurityAction abort(更隐晦的版本)。修复:定位到 kill 在 +[_NSPredicateUtilities _predicateSecurityAction]。要 hook 它,踩了 4 种
...(已截断)
---
来源: 看雪论坛
原文链接: https://bbs.kanxue.com/thread-290966.htm
[原创][讨论] ai 绕过ios越狱检测
188 浏览
3 回复
tql
需要定制tiktok 越狱检测绕过,能做吗? tg nitianchuhai
大佬的iOS 16 的 Cryptex 系统库路径,是通过什么方式扫描到的?