ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Madeira在iOS 26 TXM下的JIT内存策略:BreakpointJIT协议完全解析

Madeira在iOS 26 TXM下的JIT内存策略:BreakpointJIT协议完全解析 Madeira在iOS 26 TXM下的JIT内存策略BreakpointJIT协议完全解析【免费下载链接】MadeiraRun x86-64 Windows PC games on jailed iOS via FEX-Emu Wine DXMT项目地址: https://gitcode.com/GitHub_Trending/mad/MadeiraMadeira 是一个把 Windows PC 游戏搬上 iPhone 的开源项目在 iOS 26 上通过 FEX-Emu Wine DXMT 实现完整模拟。而在 TXMTrusted Execution Management可信执行管理强制 W^X 策略的 iOS 26 上如何让 FEX 的即时编译JIT代码合法执行是整条技术链上最关键的一环。本文将完整解析 Madeira 的 JIT 内存策略与基于断点指令Breakpoint的 BRK 通信协议——无需越狱、仅凭调试器附身即可拿到可执行页。一、背景iOS 26 为什么对 JIT 如此苛刻 在老版本的 iOS 上只要调试器附加、CS_DEBUGGED标志被内核点亮应用基本可以随意申请可执行内存。而 iOS 26 引入了 TXM 之后规则收紧为只有经过准备prepare的 RX 页才能执行普通mprotect(PROT_EXEC)直接被拒。这一点在 Madeira 构建 Wine 虚拟内存层的注释里写得很直白TXM 会拒绝 JIT 池之外的PROT_EXEC请求见 virtual_ios.c 中 iOS TXM refuses PROT_EXEC outside the JIT pool 的说明。也就是说执行权限不再是进程自己说的算而要由外部可信方调试器来盖章。这正是 BreakpointJIT 协议诞生的原因。二、BreakpointJIT 协议把 BRK 断点指令变成私有系统调用 ARM64 的BRK指令原本用于触发断点陷阱SIGTRAP。Madeira 把它改造成了与调试器 StikDebug 之间的 RPC 通道核心实现在 JITAllocator.c固定断点号BRK #0xf00d0xf00d 即 food一眼可辨命令寄存器x16传命令号参数寄存器x0传地址x1传长度返回寄存器x0带回结果地址命令表非常精简x16命令作用0Detach通知调试器断开1PrepareRegion请求调试器为指定地址/长度准备可执行RX页3MapPageZero借助调试器特权把数据映射到第 0 页TEB 等特殊用途调试器侧的对应逻辑内嵌在一段 JavaScript 脚本中由 madeira-jit.js 定义它拦截每一次 BRK 停止解析x16/x0/x1执行prepare_memory_region或_M分配等特权操作后恢复执行。协议接口声明见 JITAllocator.h。协议时序以申请一块 RX 页为例应用执行mov x16, #1; brk #0xf00d进程暂停在断点StikDebug 捕获停止事件读出地址与长度调试器用其特权完成 RX 页授权必要时先_M分配调试器把准备好的地址写回x0恢复进程应用从x0拿到可执行地址开始写入并运行代码整个过程对上层 FEX 透明——它只看到给一块地址还我一块能跑的地址。三、双映射内存RW 视图与 RX 视图 TXM 环境下没有 RWX 页于是 Madeira 采用了业界验证过的双映射dual-map方案同一块物理内存映射出两个虚拟地址视图——RW 视图FEX 往这里写生成的 ARM64 机器码RX 视图CPU 从这里取指执行两个视图始终内容一致写 RW 后立即做指令缓存失效sys_icache_invalidate接口见 jit_region_write。注意 iOS 的页大小是16KBJIT_PAGE_SIZE 0x4000见 JITAllocator.c所有对齐都要按这个粒度计算。此外底层通过mach_make_memory_entry_64创建 RWX 最大权限的命名内存条目JITAllocator.c并打上VM_LEDGER_FLAG_NO_FOOTPRINT标记让这块 JIT 池不计入 Jetsam 内存上限——这就是设置页里那个绿色对勾的 Memory。四、两条 JIT 执行路径策略一与策略二 ️由于 TXM 可能在准备时刻才对页内容做授权写入与授权的先后顺序就成了成败关键。jit_test_execute 用一段mov x0, #42; ret返回值 42作为探针自动验证两条路径策略一先写码后授权Write-then-Prepare创建双映射区域先把代码写入 RW 视图再通过 BRK 协议请调试器准备 RX 页假设 TXM 在 prepare 时固化页内容从 RX 视图执行期望得到 42策略二调试器分配 vm_remapMeloNX 方案若策略一陷入 fault 循环返回 -3说明 TXM 拒绝了自映射的 RX 页自动降级到 策略二传x0 NULL请调试器用_M直接分配 RX 页用vm_remap把同一物理页再映射出一份 RW 视图对 RW 视图vm_protect为可读写写码、校验一致性从调试器分配的 RX 视图执行这种可执行页由调试器亲手出生的方式最容易被 TXM 接受也是当前生产池JIT pool的来源。五、无调试器时的 SIGTRAP 兜底 如果用户忘了挂调试器BRK 照样会触发 SIGTRAP。此时绝不能让进程崩溃sigtrap_handler 会接管信号PC 前进 4 字节跳过断点、x0清零——相当于把这次系统调用标记为失败程序优雅降级。但要注意一个细节当调试器真的在监听时这个兜底 handler 必须不安装否则会抢走调试器要处理的 BRK、直接破坏协议。而调试器离开后CS_DEBUGGED仍会残留所以还专门提供了 jit_arm_trap_fallback 来补装安全网避免无人应答的 BRK杀死应用。六、内存池的低地址抢位战 ⚡RX 池由调试器 first-fit 放置位置不可控而主镜像又需要固定落在低地址窗口0x140000000附近 128MB。两者会争夺同一段约 1.4GB 的空洞不同启动下池子大小从 608MB 一路缩水到 448MB 甚至耗尽。解法很巧妙一个优先级极高的 C 构造函数在main之前就把窗口和它上方最大连续空洞用PROT_NONE预留不占物理内存——makeira_early_va_claim。谁先到谁的地址空间就稳了。七、如何开启 Madeira 的 JIT 普通用户只需三步安装 StikDebugJIT 的钥匙在 Madeira 设置里点Enable JIT应用通过stikjit://enable-jit深链打开 StikDebug 并附带内置脚本见 StikJITHelper.enableJIT轮询到CS_DEBUGGED置位后自动申请约 128MB JIT 池并断开调试器最后在设置里确认JIT与Memory均为绿色对勾即显示 Ready to play流程详见 README。小结 机制解决的问题BRK #0xf00d x16 命令字无系统调用权限下的调试器 RPC双映射 RW/RX 视图TXM 下没有 RWX 页策略一 / 策略二自动降级兼容不同授权时机SIGTRAP 兜底 handler忘记挂调试器时不崩溃NO_FOOTPRINT 早期 VA 预留绕开 Jetsam、抢占低地址空间BreakpointJIT 协议的本质是把调试器从开发工具变成了运行时的可信执行协处理器——这也解释了为什么 Madeira 无法上架 App StoreREADME 明确指出 JIT 依赖调试器附加。完整构建细节可参考 docs/BUILDING.md更多架构文档见 docs/ 目录。【免费下载链接】MadeiraRun x86-64 Windows PC games on jailed iOS via FEX-Emu Wine DXMT项目地址: https://gitcode.com/GitHub_Trending/mad/Madeira创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表