不越狱,iPhone 为什么也能安装任意 IPA?聊聊 iLoader、SideStore 和 LiveContainer 的原理

不越狱,iPhone 为什么也能安装任意 IPA?聊聊 iLoader、SideStore 和 LiveContainer 的原理

最近折腾 iOS 侧载,接触到了三个挺有意思的东西:

iLoader、SideStore 和 LiveContainer。

第一次看到这套方案时,我有几个疑问:

  • iPhone 不是只能安装 App Store 里的 App 吗?
  • 为什么登录一个 Apple ID,就能安装自己下载的 IPA?
  • 免费 Apple ID 签名为什么只有 7 天?
  • SideStore 为什么能让手机自己续签?
  • LiveContainer 更离谱:为什么只安装一个 App,却可以在里面运行很多 IPA?
  • 所谓 JIT-Less 又是在解决什么问题?

把整个链路研究一遍之后会发现,这套方案其实没有"破解 iOS"。

恰恰相反:

它是在尽可能利用 Apple 原本提供给开发者的能力,在 iOS 的代码签名体系里寻找操作空间。

本文就从开发者的角度,把这套东西拆开看看。


一、先从一个问题开始:iPhone 为什么不能随便安装 IPA?

Android 开发者对此可能尤其有感。

Android 上拿到一个 APK:

复制代码
APK
 ↓
允许安装未知来源应用
 ↓
安装
 ↓
运行

但 iOS 完全不是这个逻辑。

拿到一个 IPA 文件,并不意味着你就能把它安装到 iPhone 上。

因为 iOS 有一套非常严格的 Code Signing(代码签名) 机制。

简单来说,一个 App 想在真实 iPhone 上运行,需要证明两件事:

复制代码
这个 App 是谁签名的?

这个签名是否允许在这台设备运行?

背后涉及:

css 复制代码
Certificate
Provisioning Profile
Entitlements
App ID
Device UDID
Code Signature

因此,一个普通 IPA:

复制代码
xxx.ipa

直接扔给 iPhone:

复制代码
xxx.ipa
   ↓
iPhone
   ↓
❌ 不能运行

不是因为 IPA 格式有什么问题,而是:

iOS 不认可它现在的签名身份。


二、但 Apple 自己留了一扇门:开发者真机调试

如果你做过 iOS 开发,就会发现一个很明显的问题:

既然 iPhone 只能运行 Apple 认可的 App,那开发者自己写的 App 怎么调试?

总不能每改一行代码就提交一次 App Store。

所以 Apple 必须提供:

Development Signing。

正常情况下,我们在 Xcode 里:

复制代码
Apple ID
   ↓
Xcode
   ↓
申请开发证书
   ↓
生成 Provisioning Profile
   ↓
给 App 签名
   ↓
安装到 iPhone

于是:

css 复制代码
自己写的 App
      ↓
Development Certificate
      ↓
Provisioning Profile
      ↓
Code Signing
      ↓
iPhone
      ↓
运行

关键点来了:

这套能力并不要求 App 来自 App Store。

只要符合开发签名要求,一个开发中的 App 本来就应该可以安装到你的 iPhone。

而这正是整个侧载生态的基础。


三、iLoader:本质上是在帮你干 Xcode 的活

理解这一点之后,iLoader 就很好理解了。

很多人第一次使用 iLoader 时会感觉:

输入 Apple ID → 选择 IPA → 插上 iPhone → 居然装进去了。

看起来像是"绕过了 Apple"。

实际上它做的事情更接近:

自动化了一套类似 Xcode 真机开发部署的流程。

大概可以抽象成:

markdown 复制代码
                 Apple
                   ↑
                   │
               Apple ID
                   │
                   ↓
               iLoader
                   │
          ┌────────┴────────┐
          │                 │
   Development Cert    Provisioning
          │                 │
          └────────┬────────┘
                   ↓
                IPA 重签名
                   ↓
                iPhone

这里实际上存在两个独立问题。

问题一:这个 App 能不能运行?

由:

css 复制代码
Apple ID
Certificate
Provisioning Profile
Code Signature

解决。

问题二:App 怎么进入手机?

由:

复制代码
USB
设备配对
Apple Device Services

等设备通信机制解决。

所以使用 iLoader 时经常出现一种情况:

复制代码
Apple ID 登录成功
但找不到设备

这其实一点都不矛盾。

因为:

Apple ID 登录成功 ≠ iPhone 已经和电脑建立设备通信。

一个负责"签名资格",一个负责"设备部署"。


四、为什么免费 Apple ID 只有 7 天?

到这里又会出现一个问题。

App 确实安装成功了。

但是使用免费 Apple ID 做 Personal Team 开发签名,会受到比较严格的限制,其中最明显的就是:

签名有效期很短。

常见情况下就是 7 天。

可以简单理解为:

sql 复制代码
Day 1

IPA
 ↓
开发签名
 ↓
安装
 ↓
正常运行


Day 7+

签名/Provisioning 过期
 ↓
iOS 不再认可
 ↓
App 无法正常启动

所以如果只有 iLoader,你会陷入一个很麻烦的循环:

复制代码
电脑
 ↓
iLoader
 ↓
签名
 ↓
安装

7 天后

电脑
 ↓
iLoader
 ↓
重新签名
 ↓
重新安装

偶尔装一次还行。

长期使用就很烦。

于是 SideStore 出场了。


五、SideStore:把"续签"这件事搬到手机上

SideStore 要解决的问题其实很明确:

能不能第一次借助电脑完成安装,以后让 iPhone 自己完成签名刷新?

整个结构于是变成:

复制代码
第一次:

Mac / PC
   │
iLoader
   │
   ↓
iPhone
   │
   └── SideStore


以后:

iPhone
   │
SideStore
   │
   ↓
Apple Developer Services
   │
   ↓
刷新签名

这就产生了一个非常有意思的"鸡生蛋"问题。

SideStore 自己也是一个 App。

而它自己一开始也没有资格运行。

怎么办?

答案就是:

先借助电脑,把 SideStore 这个"能够帮助管理侧载 App 的工具"安装进去。

之后很多事情就可以在手机端完成。

所以 iLoader 在整套体系里的角色很像:

Bootstrapping Tool ------ 引导工具。

它负责把第一个关键节点送进去。


六、真正有意思的是 LiveContainer

如果故事到 SideStore 结束,其实还不算特别神奇。

真正让我觉得有意思的是:

LiveContainer。

正常情况下,假设我们想安装三个 IPA:

css 复制代码
A.ipa
B.ipa
C.ipa

传统侧载方案是:

css 复制代码
iOS
 │
 ├── App A
 │
 ├── App B
 │
 └── App C

每一个都是独立 App。

意味着:

css 复制代码
A → 独立签名
B → 独立签名
C → 独立签名

于是马上会碰到免费开发者账号的各种限制:

erlang 复制代码
App ID 数量
活跃 App 数量
Provisioning
7 天有效期
...

LiveContainer 换了一个完全不同的思路。

它不是:

帮你安装十个 App。

而是:

安装一个 App,然后让其他 App 在这个 App 里面运行。

结构一下变成了:

css 复制代码
iPhone
 │
 └── LiveContainer.app
       │
       ├── A.ipa
       │
       ├── B.ipa
       │
       ├── C.ipa
       │
       └── D.ipa

从 iOS 的视角来看,真正安装的核心宿主是:

复制代码
LiveContainer.app

而 A/B/C/D 则由 LiveContainer 管理并运行。

这也是名字里:

Container

的含义。


七、LiveContainer 不是虚拟机

这里特别容易产生一个误解。

看到:

复制代码
一个 App 里面运行另一个 App

很多人的第一反应是:

这是不是类似 Android 模拟器?

其实不是。

它并不是:

复制代码
模拟 CPU
 ↓
模拟 iOS
 ↓
运行 App

目标 App 本身仍然是:

css 复制代码
ARM64 Machine Code
       ↓
iPhone ARM CPU
       ↓
iOS Framework

例如目标 App 最终还是会使用:

objectivec 复制代码
UIKit
Foundation
CoreGraphics
Objective-C Runtime

这些真实的系统 Framework。

所以从大的技术方向来看,它更接近:

在一个已经合法签名的宿主环境中,加载和运行另一个 iOS App 的代码。

这也是为什么它的性能和真正的原生执行非常接近。


八、问题来了:iOS 凭什么让你加载另一份代码?

这才是整个 LiveContainer 最有意思的地方。

假设我们天真地写:

markdown 复制代码
LiveContainer
      │
      ↓
解压 xxx.ipa
      │
      ↓
找到 Mach-O
      │
      ↓
加载
      │
      ↓
执行

正常情况下:

没这么简单。

因为 iOS 对 executable code 有严格限制。

这里会碰到:

css 复制代码
Code Signing
AMFI
Entitlements
Sandbox
Executable Pages
Dynamic Loading

等一整套安全机制。

所以:

markdown 复制代码
下载任意 ARM64 Mach-O
        ↓
      mmap
        ↓
       RX
        ↓
      执行

在普通非越狱 iPhone 上并不是想干就能干。

LiveContainer 真正复杂的地方,就是:

如何在 iOS 现有安全模型允许的范围内,让目标 App 的 Mach-O 代码进入一个可执行状态,并适配宿主环境。

这就开始涉及真正偏底层的东西:

css 复制代码
Mach-O
Code Signature
Dynamic Loader
Objective-C Runtime
Entitlements
App Sandbox
Provisioning Profile

如果做过 iOS Runtime 或 Mach-O 相关研究,到这里应该已经开始觉得有意思了。


九、为什么 LiveContainer 还要从 SideStore 导入证书?

我在配置 LiveContainer 时遇到了一个报错:

复制代码
证书未找到,
你是否登录了内置 SideStore?

一开始我以为只是 SideStore 的账号没登录。

但继续研究会发现:

这个 Certificate 本身就是整个 JIT-Less 工作链路的重要组成部分。

关系大致是:

markdown 复制代码
Apple ID
   │
   ↓
SideStore
   │
   ├── Signing Certificate
   │
   └── Provisioning Profile
            │
            ↓
      LiveContainer
            │
            ↓
       处理目标 IPA
            │
            ↓
        JIT-Less

也就是说:

LiveContainer 并不是凭空获得"执行任意代码"的能力。

它依然需要在 Apple 的:

css 复制代码
Code Signing
+
Provisioning

体系下工作。

这也是为什么 SideStore 和 LiveContainer 经常一起出现。


十、JIT 又是什么?

如果接触过模拟器、虚拟机或者 JavaScript Engine,应该对 JIT 不陌生:

Just-In-Time Compilation。

简单理解,就是程序运行过程中动态生成机器码并执行。

例如:

css 复制代码
Runtime
   ↓
生成 Machine Code
   ↓
写入 Memory
   ↓
标记 Executable
   ↓
CPU 执行

但是从安全角度来看,这是一项非常敏感的能力。

因为如果一个普通 App 可以:

diff 复制代码
随便生成代码
+
随便执行代码

iOS 的很多安全边界都会变得困难。

所以普通 iOS App 对 JIT 的使用受到非常严格的限制。

这也是为什么很多 iOS 模拟器、虚拟机、运行时工具都特别关心:

复制代码
JIT

能力。


十一、JIT-Less 的意义

LiveContainer 后来提供了一个很重要的方向:

JIT-Less。

名字已经把目的写出来了:

复制代码
JIT
 ↓
Less

也就是:

尽量不依赖持续的 JIT 能力来运行目标 App。

因此你在 LiveContainer 里会看到:

csharp 复制代码
Import Certificate from SideStore

JIT-Less Mode Diagnose

这些功能并不是几个毫无关联的设置项。

背后其实是一条完整链路:

css 复制代码
SideStore
     │
     ↓
Signing Certificate
     │
     ↓
LiveContainer
     │
     ↓
处理 IPA / Mach-O
     │
     ↓
满足 Code Signing 要求
     │
     ↓
JIT-Less Runtime
     │
     ↓
目标 App

理解这条链路之后,LiveContainer 的很多设置就不再显得莫名其妙了。


十二、把三者放到一起看

现在我们终于可以画出完整架构:

css 复制代码
                     Apple
                       │
              Developer Services
                       ↑
                       │
                   Apple ID
                       │
          ┌────────────┴────────────┐
          │                         │
       iLoader                  SideStore
     电脑端 Bootstrap           手机端签名管理
          │                         │
          │ 第一次部署               │ 刷新签名
          ↓                         ↓
┌──────────────────────────────────────────┐
│                 iPhone                   │
│                                          │
│             LiveContainer                │
│                  │                       │
│       ┌──────────┼──────────┐            │
│       │          │          │            │
│     A.ipa      B.ipa      C.ipa          │
│       │          │          │            │
│       └──────────┼──────────┘            │
│                  ↓                       │
│           Runtime / JIT-Less             │
│                  ↓                       │
│           iOS Frameworks                 │
│                  ↓                       │
│              ARM64 CPU                   │
│                                          │
└──────────────────────────────────────────┘

三者的分工其实非常清晰:

工具 核心作用
iLoader 解决第一次怎么把开发签名 App 安装进 iPhone
SideStore 解决签名过期以及手机端刷新问题
LiveContainer 解决如何用一个宿主承载和运行多个 IPA

如果非要打个比方:

ini 复制代码
iLoader
=
负责把钥匙送进房间的人

SideStore
=
负责定期给钥匙续期的人

LiveContainer
=
拿着这把钥匙,在房间里面又建了一栋公寓的人

十三、这算不算"破解 iOS"?

我觉得这是研究完之后最有意思的一点。

直觉上:

diff 复制代码
非 App Store IPA
+
免费 Apple ID
+
无需越狱
+
一个 App 运行多个 IPA

怎么看都很像"绕过系统"。

但从技术角度看,更准确的描述应该是:

在 Apple 允许的开发签名、Provisioning、代码签名和 Runtime 能力边界内,组合出一套 Apple 原本没有按照这种使用方式设计的系统。

iLoader 没有让 iOS 放弃验证签名。

SideStore 没有让 Provisioning Profile 永久有效。

LiveContainer 也没有让 iOS 完全取消 Code Signing。

恰恰相反:

整个系统从头到尾都在和 Code Signing 打交道。

这也是我觉得这套东西真正有技术价值的地方。

它不是简单地:

复制代码
找到一个漏洞
↓
关掉安全检查
↓
随便运行

而更像:

复制代码
研究系统规则
↓
理解规则边界
↓
组合已有能力
↓
在限制条件下实现原本很难实现的效果

这其实也是很多优秀系统软件非常典型的设计方式。


十四、从移动开发者角度,这里面值得研究什么?

如果只是为了安装 IPA,到这里其实已经够了。

但如果是 Android / Flutter / iOS 开发者,我反而觉得 LiveContainer 本身比"侧载"这件事情更值得研究。

因为继续往源码里面走,会碰到一堆平时业务开发几乎接触不到的东西:

css 复制代码
Mach-O 到底是什么结构?

iOS Code Signature 存在哪里?

Provisioning Profile 到底约束了什么?

Entitlements 是如何参与权限校验的?

dyld 是怎么加载 Framework 的?

Objective-C Runtime 如何处理另一个 App 的 Class?

App Sandbox 的边界在哪里?

为什么有些 IPA 可以运行,有些完全不行?

为什么 Extension / Framework 特别容易出现兼容问题?

为什么 JIT 在 iOS 上如此敏感?

这些问题背后,其实已经不是:

"怎么安装一个 IPA?"

而是:

iOS 到底是怎么决定一段代码有没有资格在 CPU 上运行的?

当问题来到这一层,事情就开始真正有意思了。


最后

最开始折腾这套东西,我只是想:

在 iPhone 上安装一个 IPA。

最后却一路顺着:

css 复制代码
IPA
 ↓
iLoader
 ↓
Apple Developer Signing
 ↓
Certificate
 ↓
Provisioning Profile
 ↓
SideStore
 ↓
LiveContainer
 ↓
JIT / JIT-Less
 ↓
Mach-O
 ↓
Code Signing
 ↓
dyld
 ↓
iOS Runtime

摸到了 iOS 安全体系的边缘。

这也是我觉得研究这类工具很有意思的地方。

很多看起来像"黑科技"的东西,拆开之后往往没有魔法。

只有:

系统提供了什么能力?

系统设置了什么限制?

以及:

有没有人能在这些能力与限制之间,找到一条足够巧妙的路径。

相关推荐
ApacheSeaTunnel2 小时前
用 Apache SeaTunnel 同步 DynamoDB 到 Redis,一个配置文件就够
redis·开源·seatunnel·数据同步·dynamodb
白鲸开源3 小时前
DolphinScheduler 挂了你不知道?Prometheus + Grafana 监控兜底方案,亲测可用
开源·grafana·监控
小小龙学IT3 小时前
ONNX Runtime 开源 AI 推理引擎深度解析:从模型部署到边缘 AI 加速的全栈实战
c++·人工智能·开源
d6760158633 小时前
免费开源的视频剪辑工具-UniCut
ai·开源·视频·剪辑
redfred4 小时前
HandBrake 使用教程:开源视频压缩工具 视频太大压缩 MKV转MP4 批量转码 硬件加速 Windows/macOS/Linux
windows·开源·音视频
字节跳动开源6 小时前
VisActor全新图可视化开源项目:VGraph
前端·设计模式·开源
JoyCong19986 小时前
从iPhone Ultra到ToDesk:折叠大屏时代的效率革命,硬件只是开始
大数据·运维·ios·智能手机·iphone·远程工作·远程操作