LiveContainer 实战指南iOS 应用免安装运行【免费下载链接】LiveContainerRun iOS apps without actually installing them!项目地址: https://gitcode.com/gh_mirrors/li/LiveContaineriPhone 上能跑的应用要么来自 App Store要么是侧载进来的 IPA——这是条铁律。LiveContainer 把它掰开了把任意 IPA 导入这个容器启动器应用就能免安装直接运行同一台设备可以同时跑两个版本的同一款 App各自拥有独立的数据与钥匙串。如果你正在找 iOS 应用容器化多开或多版本共存方案它是目前最主流的选择。最短上手路径从零到跑起来两条路按需选择。路径适合谁成本装成品 IPA只想体验、不想碰编译约 10 分钟源码构建想改签名逻辑、学习原理半天起装成品官方发布页提供两个变体——独立版以及内置 SideStore 的 LiveContainerSideStore 版后者可以脱离电脑刷新应用。通过 AltStore 2.0 或 SideStore 0.6.0 安装即可。系统要求 iOS/iPadOS 15多任务功能需要 16。源码构建git clone https://gitcode.com/gh_mirrors/li/LiveContainer cd LiveContainer # 用 Xcode 打开把 xcconfigs/Global.xcconfig 里 # DEVELOPMENT_TEAM[configDebug] 改成你的团队 ID直接编译这里要先泼一盆冷水README 里明确警告过市面上出现过闭源的第三方魔改构建。你装进去的每个应用的数据包括钥匙串里的账号密码对宿主 App 都是完全可见的所以只认官方构建。一个应用从导入到跑起来底层到底发生了什么这是整个项目最有含金量的部分。完整流程可以切成四拍导入 → 改写 → 加载 → 运行。你如果只关心原理重点看这一节。导入IPA 其实只是个文件包你看到的点右上角加号选一个 IPA列表里就多了一个应用。底层做的LiveContainer 把 IPA 解包到Documents/Applications/应用名在旁边写一份LCAppInfo.plist记录元数据并在Data/Application/UUID下为它开一个独立数据目录。多开的关键也在这里埋下——每个容器会从 128 个键链访问组里随机分一个这 128 个组在 entitlements.xml 里写死、签名时就绑进 App分配逻辑在 LCAppModel.swift。类比导入应用就像开店——先租下门面二进制文件再配一把保险柜数据容器 键链组。门面可以有多家分店保险柜各自独立。改写把可执行文件变成可加载的库你看到的什么都没有但这一步不做后面全白搭。核心代码在 LCMachOUtils.m 的LCPatchExecSlice改动浓缩起来就几行// 把可执行文件字面意义上改造成动态库 header-filetype MH_DYLIB; // MH_EXECUTE - MH_DYLIB header-flags ~MH_PIE; seg-vmaddr 0x100000000 - 0x4000; // __PAGEZERO 段挪位 seg-vmsize 0x4000;三处改动各有原因文件类型 MH_EXECUTE → MH_DYLIBMach-O 头里的证件类型从独立主程序换成动态库。程序本身一行没变只是换了身份——dyld 才愿意把这张镜像 mmap 进一个已经存在的进程。压缩 __PAGEZERO 段每个应用可执行文件开头都有一段保留 4GB 虚拟地址空间的占位段。被加载到别的进程里时这块空间根本给不了不压缩的话 dyld 直接报 out of address space。所以把vmaddr挪到0xFFFFC000、vmsize缩到单页0x4000。好比搬进公寓前先把原住户占的整栋空地退掉。注入 TweakLoader 的加载指令插一条LC_LOAD_DYLIB指向TweakLoader.dylib让 tweak 在加载时就有挂载点。如果 load command 区空间不够代码会把LC_LOAD_DYLINKER的位置回收掉复用——二进制改造里处处是这种见缝插针。签名处理则是双轨的JIT 可用时干脆绕过 codesignJIT-less 模式下随包的 ZSign/zsign 的 Feather 分支魔改版会用和 LiveContainer 相同的证书把所有可执行文件重新签一遍。加载一场伪装成对方的戏你看到的点应用图标它正常启动了而且它在所有自检测里都认为我就是那个 App 本人。整个伪装流程在 LCBootstrap.m 的invokeAppMain里主角换了四套身份文件executable_path。dyld 把主可执行路径缓存在内部 config 结构体里。LiveContainer 临时 hookdyld4::APIs::_NSGetExecutablePath趁函数被调用的瞬间把mainExecutablePath字段改写成目标应用的路径完事再恢复原函数。这里能明显看到版本敏感iOS 15–18.3.2 字段在0x1018.4 挪到了0x20iOS 27 还额外缓存了长度。README 里还留了旧方案的遗骸——用非法指针诱发 SIGSEGV 再做点魔法去覆盖路径现在已经换成了精确改字段。NSBundle.mainBundle。注意它不是走 ObjC swizzle而是直接扫描mainBundle方法实现里的_MergedGlobals静态全局数组、把指针原地替换——因为很多代码路径绕开 ObjC 层。iOS 16、17、27 三套布局各不相同代码里按系统版本分叉。CFBundleGetMainBundle同样处理。HOME/CFFIXED_USER_HOME指向容器目录Caches、Cookies、Documents、SystemData四件套建好。有个细枝末节很说明问题tmp目录用的是符号链接而不是改TMP环境变量——因为有些 App 清缓存时直接删光 tmp 目录改了环境变量的话删完就重建不回来了issue #1040、#1125 的教训。进程名与 argv[0]NSProcessInfo的 arguments、_CFGetProgname一并改掉Swift 侧的_NSSwiftProcessInfo连 swizzle 都给你补上了。真正让二进制跑起来之前还有一道关。真实入口的 trampoline 在 main.c——一个极薄的壳dlopen 自己的 framework 后尾调用进LiveContainerMain。回到invokeAppMainJIT 已启用时先初始化 dyld_bypass_validation.m 里的库验证绕过——hookfcntl在F_ADDFILESIGS_RETURN时把签名覆盖范围撑成整个文件在F_CHECK_LV时直接回答没问题。这套手法源自 xpn 的 Restoring Dyld Memory Loading是能让未签名或者说签名对不上的二进制合法进入内存的关键。然后就是高潮dlopen_nolock(appExecPath, RTLD_LAZY|RTLD_GLOBAL|RTLD_FIRST)。iOS 27 上如果检测到段数不匹配还会走bypass_seg_count_check再执行。dlopen 成功后从LC_MAINload command 里读出entryoff拿到入口点地址直接跳进目标应用的main()——接下来它调用UIApplicationMain像任何原装 App 一样启动。类比整个过程相当于替身上台。目标应用从头到尾不知道真正的它只是 LiveContainer 地址空间里的一张镜像。运行从此它只是个普通 iOS 应用目标应用带着完整 UIKit 生命周期跑起来。NSUserDefaults、SecItem键链、NSFileManager、NSURLSessionConfiguration全被 LiveContainer/Tweaks/ 下的一组 guest hook 重定向到对应容器保证数据落在自己的目录和键链组里。任何一步失败——dlopen 报错、找不到入口、bundle 加载失败——LCBootstrap会把错误串写进 NSUserDefaults回到界面变成一行红字。以后启动应用看到报错那行字就是第一现场。进阶玩法多任务、多开容器与外部 Tweak多任务一个 App 里同时开几个效果长按应用横幅选 Multitask应用在 App 内虚拟窗口里运行可以拖动缩放还能切进系统原生画中画iPad 上可直接用系统级原生窗口模式。开启安装时勾选 Keep App Extensions → 长按横幅点 Multitask → 需要的话在设置里把多任务设为默认启动方式。适合需要边看边聊或固定双开对照的人。⚠️ 注意想给多任务窗口里的应用开 JIT需要支持按 PID 附加的启用器如 StikDebug普通 JIT enabler 对不上号。实现基于 FrontBoardAppLauncher代码在 MultitaskSupport/。多开容器同一应用多把钥匙效果长按应用管理容器每个容器有独立的 Documents/Container 数据目录和独立键链访问组等于一账号一钥匙。开启应用设置里新增容器 → 每个容器登录不同账号。适合多账号用户——同一款社交软件开两个号是最典型场景。注意两点128 个键链组是随机分配理论上会撞组且 README 明说 guest 容器之间不沙箱一个容器能摸到另一个的数据敏感信息要自己划边界。另外远程推送通知在所有容器里都不工作这是架构性限制别反复排查。外部 Tweak给容器应用打插件效果往 Tweaks 目录丢.dylib启动的应用会自动带上它相当于容器内 mini 越狱。开启dylib 放进Documents/Tweaks/→ 启动任意应用即自动挂载二进制里已经注入了 TweakLoader 加载指令加载器本身在 TweakLoader/走 CydiaSubstrate 框架。适合熟悉 Substrate 生态、想给容器应用改 UI 的人。注意32 位应用必须额外在设置里选一个 32 位翻译层且强依赖 JITtweak 之间依赖冲突会直接把宿主应用带崩装之前先单个验证。我踩过的坑JIT was not enabled 启动即报错。一开始以为是自己的 JIT enabler 没附加上折腾半天才确认iOS 26 上这条路基本被堵死必须走 JIT-less 模式。解法LiveContainer 设置里从 SideStore 导入证书Import Certificate from SideStore之后应用会被 ZSign 用同一证书重签不再依赖 JIT。文件选择器打不开、应用请求不了本地通知权限。根因是 guest 应用在系统眼里身份不纯部分权限路径走不通。解法进该应用的专属设置页分别打开 Fix File Picker 和 Fix Local Notifications然后杀掉重开。这两个开关是 per-app 的只对问题应用开。多任务按钮点了没反应、画中画不出现。根因不在 LiveContainer 本身而在装它的时候没勾 Keep App Extensionsappex 根本没带进来。解法重新安装并勾选一次到位。换个容器登录状态就丢了。根因是键链条目绑在访问组上新容器 新随机组凭据天然不跟随。这不是 bug是 128 组随机分配设计的直接后果——记住用哪个容器登的号没有键链迁移这回事。它为什么是这样设计的为什么用 hook 而不用 wrapper因为目标应用必须真心相信自己就是主进程——dyld 缓存的主程序路径、NSBundle.mainBundle、argv[0]、进程名任何一处穿帮都可能被 SDK 版本检测或安全 SDK 抓出来。wrapper 方案改不了 dyld 对主可执行文件的认知只有深入改写内部状态才行。代价是脆每升一个 iOS 大版本结构体偏移mainExecutablePath在 18.4 换了位置、_MergedGlobals布局16/17/27 三套都可能变LCBootstrap.m 里那一大片按版本分叉的代码就是这个代价的账单。为什么 dlopen 而不是 fork/exec因为活着的进程没法替换自己。在已运行的 LiveContainer 进程里跑第二个应用唯一的路就是把对方的二进制搬进同一地址空间。代价也是连锁的地址空间要共享 → 才有 __PAGEZERO 压缩签名对不上 → 才有 fcntl 库验证绕过iOS 27 连段数都要核对 → 才有bypass_seg_count_check。每一个 patch 都是上一个选择的利息。为什么是 128 个键链组不多不少entitlements 在签名时就固化了不能无限申请访问组。128 是够用与申请成本之间的平衡点随机分配让撞组概率足够低实际体验接近隔离。但代价写在 README 的 limitations 里——guest 容器不沙箱、权限全局生效。这其实是整个架构的同一枚硬币正因为不安装才拿到自由也因为不安装数据边界只能做到软隔离。顺带一提这也是 README 专门警告第三方闭源构建的原因——你的应用全部活在宿主的可达范围里。参与项目与延伸项目是 AGPLv3见 LICENSE。想读构建相关看 xcconfigs/ 和 ZSign/想研究窗口机制从 MultitaskSupport/ 入手最顺。如果你的场景是一台手机同时挂着好几个账号或者想不动主屏幕上的正式版、先试试某款应用的老版本不妨从一个单容器场景开始跑起来。【免费下载链接】LiveContainerRun iOS apps without actually installing them!项目地址: https://gitcode.com/gh_mirrors/li/LiveContainer创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
阅读完成 · 觉得有帮助?