Files

588 lines
29 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# OnionHEN 架构
OnionHEN 是 PS5 的 All-in-One Homebrew Enabler,提供提权、后台服务、Toolbox UI 和 fPKG/fSELF 支持。
| 维度 | 说明 |
|------|------|
| 目标平台 | PS5(Prospero),目标三元组 `x86_64-sie-ps5` |
| 定位 | 内核 exploit 之后加载的 **payload 套件**:提权、服务、Toolbox UI、fPKG/fSELF 支持等 |
| 许可证 | GPLv3 |
| 构建 | CMake + Ninja + `PS5_PAYLOAD_SDK`(clang) |
**运行时前置条件:** 必须先有 **外部 elfldr(端口 9021)** 完成首跳。bootstrapper 启动后会拉起 OnionHEN 自己的私有 **9020** `onion_elfldr.elf`。用户 Payload 只能走 9020,并且必须取得加载器返回的精确 PID;失败时不做进程快照、不自动重试、也不回退 9021。9021 仅作为首次引导和 9020 恢复通道。
---
## 1. 总体架构
### 1.1 加载链路
```
[WebKit / IPV6 等 Kernel Exploit]
│
▼
OnionHEN.elf (unpacker)
│ LZMA 解压内嵌 bootstrapper
│ 经 9021 送出 bootstrapper.elf
▼
bootstrapper.elf
│ 1. 提权 (elfldr_raise_privileges)
│ 2. remount /system、/system_ex
│ 3. unmount /update(阻止系统更新)
│ 4. 经 9021 启动内嵌 onion_elfldr.elf(监听 9020)
│ 5. 将内嵌 ELF 字节经 9020 顺序启动:util → kstuff → daemon
│ 6. 扫描并启动 /data/OnionHEN/plugins/ 下带 descriptor 的 .elf
▼
┌───────────────┬────────────────┬──────────────────┐
│ util.elf │ kstuff.elf │ daemon.elf │
│ 工具服务守护 │ fself / fpkg │ 核心守护进程 │
│ Cheats │ 内核补丁 │ ShellUI 注入 │
└───────┬───────┴───────┬────────┴────────┬─────────┘
│ │ │
│ │ ▼
│ │ inject shellui.elf
│ │ → SceShellUI (Toolbox)
│ │ │
│ └─────────────────┼── 共用 ptrace / ShellUI
▼ ▼
Unix IPC ShellUI monitor bar
```
**启动顺序串行:** util → kstuff → daemon。
- util 先提供网络/IPC 等服务
- kstuff 需先完成 ShellUI 补丁
- daemon 启动插件管理器,发现并管理 `/data/OnionHEN/plugins/` 中的外部插件
- daemon 再注入 Toolbox
若并行 ptrace 同一进程,容易导致 Toolbox 超时或崩溃。
### 1.2 构建嵌入关系
```
shellui.elf ───────┐
util.elf ──────────┼──► 嵌入 daemon.elf ──┐
onion_elfldr.elf ──┘ │
util.elf ─────────────┼──► 嵌入 bootstrapper.elf
kstuff.elf ───────────┤ │
onion_elfldr.elf ─────┘ ▼ LZMA
bootstrapper.elf.lzma
│
▼ 嵌入
OnionHEN.elf (最终用户 payload)
```
构建阶段(`scripts/build.sh`):
1. CMake configure
2. 内部库 + `shellui`
3. sync vendor(kstuff)
4. `daemon` + `util`
5. `bootstrapper`(再 lzma 压缩)
6. `unpacker` → `OnionHEN.elf`
> 用户 Payload 使用裸 `.elf` 文件,存放在 `/data/OnionHEN/payloads/`
> 或 USB 的 `.../payloads/` 目录。插件也是标准 `.elf`,但必须包含
> `.onion_plugin` descriptor,并存放在 `/data/OnionHEN/plugins/`。
产物落在仓库根目录 `build/bin/`(静态库 `build/lib/`;CMake 树 `build/`)。
### 1.3 仓库布局
```
OnionHEN/
├── assets/ # 图标等
├── docs/ # 技术文档(含本文)
├── scripts/ # 构建与主机侧工具
├── source/ # CMake 主工程
│ ├── bootstrapper/ # 启动器
│ ├── daemon/ # 核心守护
│ ├── util/ # 工具守护(金手指、IPC 等)
│ ├── shellui/ # Toolbox
│ ├── unpacker/ # 最终 OnionHEN.elf
│ ├── libhijacker/ libNineS/ libNidResolver/
│ ├── libonion_* # 共享:ipc/settings/proc/platform/ready/detour/payload/elfldr
│ ├── common/ # 项目共享的底层实现
│ ├── include/ # 公共头文件
│ └── platform/ps5/stubs/ # PS5 系统库链接 stub
├── third_party/ # 外部源码、预编译依赖与 git submodule
├── tools/ # NID stub 等仓库侧生成工具
└── .cache/ # 下载缓存(如 kstuff.elf,不提交)
```
---
## 2. 模块职责
### 2.1 `unpacker` → `OnionHEN.elf`
- 用户侧最终 payload
- 内嵌 **LZMA 压缩** 的 `bootstrapper.elf`
- 解压后通过 **9021** 发送并执行
- 依赖 7zip-sdk 的 LZMA 解码实现
### 2.2 `bootstrapper` → `bootstrapper.elf`(再压成 `.lzma`)
- 提权、分区 remount、阻止更新
- 以 `.incbin` 嵌入 `onion_elfldr.elf`、`daemon.elf`、`util.elf`、`kstuff.elf` 与图标资源
- 先用外部 9021 启动内置 `onion_elfldr.elf`,再通过 9020 启动 util / daemon / kstuff
- 扫描并自动启动带 `.auto_start` 标记的用户 Payload ELF
- 可选日志端口 **9088**
关键启动策略:
1. 检查 `127.0.0.1:9021` 上的外部 elfldr(首跳必需)
2. 启动内置 `onion_elfldr.elf`,并通过握手确认 `127.0.0.1:9020`
3. 顺序发送内部 ELF 字节:util → kstuff → daemon;9020 是正常路径,9021 仅承担引导/恢复职责
4. 各子 ELF 启动后把主线程名设为稳定进程名(`onion_util.elf` / `kstuff.elf` / `onion_daemon.elf`)
5. 仅在 9020 健康时加载 `/data/OnionHEN/payloads/` 下带 `.auto_start` 的用户 `.elf`;插件由
`libonion_plugin_manager` 扫描 `/data/OnionHEN/plugins/`,校验 `.onion_plugin`
descriptor 后按 `AUTO_START` 启动。已有有效 PID 记录时保持现有实例,否则必须取得精确 PID
可用 Toolbox「启动时自动加载 Kstuff」(默认开启)关闭,或放 `/mnt/usb0/no_kstuff` 跳过 kstuff。
### 2.3 `daemon` → `daemon.elf`(Critical 守护进程)
- 内嵌 `shellui.elf`、`util.elf` 与 `onion_elfldr.elf`
- 经 **libNineS** 将 Toolbox 注入 `SceShellUI`
- 按依赖顺序监视私有 9020 与 util:9020 异常时先通过外部 9021 恢复加载器,再通过 9020 恢复 util
- 9020 在同步加载 Payload 时发布 busy 标记,避免健康检查误杀;超过有界宽限期仍未恢复则按卡死处理
- Unix socket:`/system_tmp/onionhen/ipc/crit_service`
- IPC 前缀 `0x9000000`(`BREW_*`)
- 休息后 Toolbox 恢复:SceSysCore `NOTE_EXEC` 认出新 `NPXS40087`,等 `libSceNpTrophy.sprx` 与 `libSceNpTrophy2.sprx`,再按 `rest_mode.resume_reinject_delay_seconds` 等待后注入(参考 [kstuff-lite](https://github.com/EchoStretch/kstuff-lite))
- Unix IPC 与 TCP **9048** 在 `accept` 失败时关闭并重新 listen(参考 [ps5-payload-manager](https://github.com/itsplk/ps5-payload-manager))
主要能力:
- 重挂载、拷贝/删除目录、stat、chmod
- 启用 Toolbox
- 风扇阈值调整
- 强制杀进程 / 杀守护进程
### 2.4 `util` → `util.elf`(Utility 守护进程)
- 与 critical 分离,承载网络/IO 与较重业务,提高稳定性
- Unix socket:`/system_tmp/onionhen/ipc/util_service`
- IPC 前缀 `0x8000000`(`BREW_UTIL_*`)
| 服务 | 端口 / 入口 | 说明 |
|------|-------------|------|
| Cheats | IPC | flat-file cheat engine(multi-source `TITLE_VERSION[_PROCESS][_SOURCE_ID].ext` + mdbg/kdirect);详见 [util_arch](util_arch/) |
| Toolbox 请求 | IPC | util 崩溃重拉后向 crit 请求 `BREW_ENABLE_TOOLBOX`;休息恢复在 daemon |
`ps5/klog.h` 的 `klog_printf` / `klog_puts` 用于写入内核日志,不提供 TCP 网络服务。
### 2.5 `shellui` → `shellui.elf`(Toolbox UI)
- 注入 `SceShellUI` 的 Mono 层
- 提供 Debug Settings 风格菜单与扩展入口
- 工具箱与子页菜单 XML 均由 `ps5ui::Page` 动态组装(`toolbox_xml.cpp`)
主要菜单能力:
- 内容安装与管理(系统 PkgInstaller UI、附加内容管理)
- Payload 与内核组件(用户 Payload;插件:kstuff 及已安装外部插件)
- 游戏辅助(金手指引擎、OnionHEN 游戏选项)
- 监控与显示(ShellUI 监控条、Title ID)
- 账号激活
- 系统与硬件(风扇、外置 HDD、BD 激活)
- 网络服务(Remote Play 配对)
- 操作偏好(工具箱语言、手柄快捷键)
- 高级调试 / 关于
Remote Play 由 `remote_play.cpp` 负责:通过 `libSceRemoteplay.sprx` 解析
原生 `sceRemoteplay*` API,启用 Remote Play 注册表设置,生成 PIN,并在后台
确认客户端注册。视频串流与客户端传输仍由 PS5 原生 Remote Play 服务处理;
OnionHEN 只负责配对和设备注册。配对信息可从网络页面保存到 USB。
注入路径详见 [shellui-injection.md](shellui-injection.md)。
HomeUI 顶部导航和 Settings Debug Settings 入口按固件 profile 覆盖 2.30–12.70;11.00 起 Settings 走 `debug_settings_old`。
监控条 FPS 由 daemon skip-hook 采样:`libonion_fps` 通过 `/dev/dce` ioctl
和 DMAP 读取游戏加载的 `libSceAgcDriver`,ShellUI 负责显示 FPS、CPU、GPU、
RAM 与 IP。采样实现参考 [PHU Games Tools](https://github.com/ArkSama)(ArkSama)。
### 2.6 内部静态库
| 库 | 作用 |
|----|------|
| **libhijacker** | 进程劫持、kernel R/W、spawner、调试、通知;依赖 NidResolver |
| **libonion_elfldr** | **唯一** ptrace/`pt_*` + inject 侧 `elfldr_load` / `elfldr_payload_args` / 内置 loader 侧 `elfldr_spawn` / `elfldr_read` / `elfldr_raise_privileges`;**authid 不在每条 ptrace 上翻转**(由 inject 入口一次提权) |
| **libNineS** | 进程注入编排(`inject_elf` / stager);**pt/elfldr 实现来自 libonion_elfldr** |
| **libNidResolver** | PS5 模块 NID 解析(SHA1 等) |
| **libonion_ipc** | **客户端**(injectee 双单例)+ **服务端传输环**(`ipc_server`:listen/accept/loop/reply;`accept` 失败重绑参考 ps5-payload-manager);daemon/util/shellui 共用 |
| **libonion_settings** | 统一 `config.ini` schema;各进程以 `onion::Settings g_settings` 为真相源 |
| **libonion_fps** | skip-hook FPS 采样(PHU Tier 1A/1E/1F 公式、100 样本 multi-pass 校准、缓存 DMAP 物理地址、`/dev/dce` / AgcDriver / seqlock 发布);实现来自 [PHU Games Tools](https://github.com/ArkSama) |
| **libonion_sprx** | 标准 SPRX/PRX 加载用例与最小 INI `SprxCatalog`;策略层与 ptrace 运行时解耦,生产适配器通过远程 `pthread_create` 调用 `sceKernelLoadStartModule`,支持幂等检查、超时、返回码、依赖排序和临时内存清理 |
| **libonion_detour** | 共享 Detour + hde64 钩子栈 |
| **libonion_proc** | 共享 proc/ucred(allproc 遍历、dynlib、authid)+ **sysctl 进程查询**(`find_pid` / `onion_find_pid_ex` / `isProcessAlive`);daemon / util / shellui / bootstrapper 共用 |
| **libonion_platform** | 平台叶子:`if_exists` / `touch_file` / `rmtree`、`OnionHEN_log`(可配置 tag/路径;sink 状态是**进程内**的,每个进程必须自己调 `onion_log_configure`,否则只进 klog/stdout;多进程共享同一路径时靠单次 `O_APPEND` 写入 + `<path>.lock` 非阻塞轮转锁保证一致;上限经 `onion::apply_log_settings` 由 `[logging] max_bytes` 驱动)、`onion_notify`;修一处全树受益 |
| **libonion_ready** | 跨进程 ready/runtime 标记(`/system_tmp/onionhen/ready/<name>`)及 wait/timeout 协调 |
| **onion/lnc.h** | 共享 LNC 启动 ABI(`LncAppParam` / `Flag` / 错误码);daemon `launcher.hpp` 仅为 shim |
| **libNineS** | ptrace 注入编排;**proc/ucred → libonion_proc**;**pt/elfldr → libonion_elfldr** |
#### Daemon 模块
| 模块 | 职责 |
|------|------|
| **msg.cpp** | 仅 `IPC_loop` + transport 胶水 |
| **ipc_handle.cpp** | crit 命令表分发 |
| **daemon_inject.cpp** | Toolbox 注入:冷启动/IPC 立即注入;休息恢复参考 kstuff-lite(SysCore EXEC + trophy sprx + 可配置延时) |
| **daemon_settings.cpp** | LoadSettings + mtime 缓存 |
| **daemon_fs.cpp** | remount / chmod / test_sb / reply / fan / ForceKill / pid 查找 |
| **daemon_fps.cpp** | render/skip-hook FPS 线程 + 独立 V-sync 采样线程;原始值无效时由 V-sync 线程兜底;仅 render 线程发布 `/system_tmp/onionhen/fps_sample` |
#### ShellUI 模块
| 模块 | 职责 |
|------|------|
| **ipc.hpp** | 仅 `onion/ipc_client`(**不**拉 HookedFuncs) |
| **shellui_types.hpp** | 枚举 / 插件 / overlay / settings 类型 |
| **hooked_funcs.hpp** | Mono hooks + UI API(include types) |
| **mono_runtime** | Mono 反射 / 属性读写 / 类查找 |
| **toolbox_xml** | `generate_*_xml` / `generate_toolbox_xml` 菜单 XML(`ps5ui::Page`) |
| **settings_ui** | `settings_commit` / SaveSettings 等 UI 侧设置 |
| **shellui_notify / shellui_proc** | UI 用 `notify(const char*)` 与进程/USB 辅助 |
| **hook_onpress + onpress_*** | 页面所有权策略 + 表驱动 OnPress:原生 Settings 页面纯透传,Toolbox 按 root / cheats / payloads / account 等拆域 |
#### Ready / runtime flags 协议
| 标记名 | 发布方 | 等待方 / 用途 |
|--------|--------|----------------|
| `util` | util 在 IPC 线程启动后,内容为自身 PID | bootstrapper、runtime supervisor 与关栈流程识别内置 util 实例 |
| `kstuff` | bootstrapper 在 mprotect 成功后 | daemon 注入 toolbox 前 |
| `daemon` | daemon 在 IPC 线程启动后,内容为自身 PID | bootstrapper 识别内置 daemon 实例 |
| `toolbox` | shellui 注入完成后,内容为自身 PID | daemon 按当前 SceShellUI PID 判断跳过或重注入 |
| `fps_overlay` | 启动时 clear | ABI 占位标记;实时 FPS 状态发布在 `/system_tmp/onionhen/fps_sample` |
| `util_booted` | util 冷启动完成后 | util 崩溃/重拉后向 daemon 请求再注入 Toolbox |
#### IPC 分层(加深后)
```
msg.hpp 协议:路径、magic、命令枚举、IPCMessage
ipc_server.* 传输:Unix listen/accept/recv/send + 线程环 + reply
handleIPC (进程) 业务:crit 与 util 各自命令表
ipc_client.* 注入侧客户端
```
#### 配置分层
```
onion::Settings 持久化 schema(双路径 twin:primary + shellui)
onion::SettingsStore 进程内线程安全真相源(mutex + snapshot/store/update)
g_settings daemon/util:SettingsStore;shellui:Settings(UI 线程)
LoadSettings() 统一 bool 契约:刷新 store;缺文件用默认并成功
mtime 门控 settings_config_newest_mtime — 任一 twin 更新即失效
运行时原子量 util rest-mode / network 标志等
OverlayLayout 仅 shellui:由 overlay.edge + overlay.align 派生;纯函数在 overlay_layout.hpp
```
### 2.8 主机工具(`scripts/`)
| 脚本 | 用途 |
|------|------|
| `build.sh` | 一键构建流水线 |
| `sync_dependencies.sh` | 同步 kstuff 等外部依赖 |
| `send_elf.py` / `send_payload.ps1` | 网络发送 ELF |
| `launch.py` | IPC 控制应用 |
| `shutdown_onion.py` / `kill_daemon.py` | 从 PC 关栈:util → 重启 ShellUI → daemon 退出;**不杀 kstuff**(TCP **9048**) |
| `daemon_log.py` | 守护进程日志 |
| `ps5_cmake.sh` | Prospero CMake 封装 |
| `pack_bootstrapper.sh` | bootstrapper 尺寸记录 + lzma 打包 |
---
## 3. IPC 与通信模型
```
shellui / homebrew
│ Unix domain socket
├─► /system_tmp/onionhen/ipc/crit_service (daemon, 0x9xxxxxxx)
└─► /system_tmp/onionhen/ipc/util_service (util, 0x8xxxxxxx)
homebrew (app jailbreak)
└─► sandbox file …/download0/etahen_jailbreak|onionhen_jailbreak
(SceSysCore 进程事件触发 Running Big App 补扫 + 沙盒 vnode + 白名单 TID)
```
### 3.1 消息格式
定义见 `source/include/msg.hpp`:
```cpp
struct IPCMessage {
int magic = 0xDEADBABE;
enum DaemonCommands cmd;
int error = 0;
char msg[0x1000];
};
```
### 3.2 主要命令族
**Critical(daemon,约 `0x9000000`):**
- `BREW_REMOUNT_FOLDER` / `BREW_STAT_CMD` / `BREW_COPY_*` / `BREW_DELETE_DIR`
- `BREW_CHMOD_DIR` / `BREW_ENABLE_TOOLBOX`
- `BREW_ADJUST_FAN_SPEED`
- `BREW_KILL_DAEMON` / `BREW_FORCE_KILL_PID`
**Util(约 `0x8000000`):**
- `BREW_UTIL_LAUNCH_PAYLOAD`
- `BREW_UTIL_GET_GAME_VER` / `BREW_UTIL_GET_GAME_CHEAT` / `BREW_UTIL_TOGGLE_CHEAT`
- `BREW_UTIL_DOWNLOAD_CHEATS` / `BREW_UTIL_CHEAT_SYNC_STATUS` / `BREW_UTIL_CANCEL_CHEAT_SYNC`(git catalog 同步)
- `BREW_UTIL_SET_SYSTEM_LANG`(daemon 轮询到控制台系统语言变化时经 IPC 推送;util 重新存储 SCE 语言并刷新通知语言)
**ABI 占位命令:**
- `BREW_UTIL_UNUSED_FTP_TOGGLE` / `BREW_UTIL_UNUSED_FTP_STATUS` /
`BREW_UTIL_UNUSED_FTP_RECOVER` 保留旧版已发布数值,不再处理
- `BREW_UTIL_UNUSED_SHADOWMOUNT_TOGGLE` /
`BREW_UTIL_UNUSED_SHADOWMOUNT_STATUS` 保留旧版已发布数值,不再处理
- `BREW_UTIL_UNUSED_DPI_TOGGLE` / `BREW_UTIL_UNUSED_DPI_STATUS`
保留旧版已发布数值,不再处理
| 命令 | 当前行为 |
|------|----------|
| `BREW_UNUSED_ACTIVATE_DUMPER` | 固定占用 `0x9000004` 并返回 unsupported,保持后续命令序号稳定 |
| `BREW_UNUSED_DECRYPT_DIR` / `BREW_UNUSED_TESTKIT_CHECK` | 返回 unsupported |
| `BREW_UTIL_UNUSED_KLOG` / `BREW_UTIL_UNUSED_DPI_TOGGLE` / `BREW_UTIL_UNUSED_DPI_STATUS` | 返回 unsupported |
| `BREW_UTIL_UNUSED_SHELLUI_ON_STANDBY` | 返回 unsupported;休息恢复由 daemon 的 SceSysCore `NOTE_EXEC` 处理 |
| `BREW_UTIL_UNUSED_RELOAD_CHEATS` | 返回 unsupported;金手指按文件签名热重载 |
| `BREW_UTIL_UNUSED_DOWNLOAD_KSTUFF` / `BREW_UTIL_UNUSED_LEGACY_CMD_SERVER` | 返回 unsupported |
| `BREW_UTIL_UNUSED_LEGACY_SERVICE_SCAN` / `BREW_UTIL_UNUSED_LEGACY_SERVICE_TOGGLE` | 返回 unsupported |
| `BREW_UTIL_LAUNCH_ELFLDR` | 返回 unsupported;私有 9020 由 bootstrapper 管理 |
### 3.3 运行时路径
| 路径 | 用途 |
|------|------|
| `/data/OnionHEN/` | 数据根目录 |
| `/data/OnionHEN/config.ini` | 配置 |
| `/data/OnionHEN/OnionHEN.log` | 主日志;daemon、ShellUI、bootstrapper 三个进程共用(各自 tag 区分)。**ShellUI 在 vsh 沙箱内,打开的是同一文件的沙箱视图 `/user/data/OnionHEN/OnionHEN.log`**;`/data` 在沙箱内不可达,写成 `/data/...` 会导致 open 失败、ShellUI 只进 klog 不进文件(`onion_log_configure` 失败时会往 klog 报一条 error)。每条记录一次 `O_APPEND` 写入保证追加原子;轮转由 `<path>.lock` 跨进程串行,锁以非阻塞方式获取,抢不到则跳过本轮轮转。单文件上限由 `config.ini` 的 `[logging] max_bytes` 控制(默认 768 KiB,加 3 份备份共 3 MiB) |
| `/data/OnionHEN/OnionHEN_util_daemon.log` | util 进程独立日志 |
| `/data/OnionHEN/OnionHEN_crash.log` | 崩溃信号与回溯日志;daemon / util / bootstrapper 写入,跨重启追加保留。超过 1 MiB 时下一次配置 sink 会把它移到 `.1`(仅保留一代),避免 `/data` 被无界占满 |
| `/data/OnionHEN/payloads/` | 用户 payload `.elf`(启动时 stage 到同目录) |
| `/data/OnionHEN/plugins/` | OnionHEN plugin `.elf`(含 `.onion_plugin` descriptor) |
| `/system_tmp/onionhen/ipc/*` | Unix IPC socket |
| `/system_tmp/onionhen/ready/<name>` | ready/runtime 标记;`toolbox` 内容为 SceShellUI PID |
| `/system_tmp/onionhen/pid/<key>.PID` | 用户 Payload PID 状态 |
| `/system_tmp/onionhen/app_launched` | ShellUI LaunchApp 返回值 |
| `/system_tmp/onionhen/patch_plugin` | LaunchApp patch gate(外部标记;ShellUI 只读取) |
### 3.4 Itemzflow 兼容状态
- `ITEM00001` 默认位于 `app_jailbreak.exact_title_ids`,避免 Loader 因未进入 jailbreak 流程而等待 30 秒;精确 Title ID 与前缀白名单均可通过 `config.ini` 覆盖。
- Critical IPC 的 `0x9000004` 是稳定 ABI 占位值,后续命令序号与 Itemzflow 客户端一致。
- ItemzCore 连接 `/system_tmp/etaHEN_crit_service`,daemon 监听
`/system_tmp/onionhen/ipc/crit_service`;使用固定前一路径的客户端可能等待最长一分钟。
---
## 4. 功能清单
### 4.1 系统 / HEN 核心
- 提权与分区 remount
- 阻止系统更新(unmount `/update`)
- **kstuff**:fself / fpkg 相关内核能力(kstuff-lite 1.11 覆盖 1.00–13.60)
- App jailbreak(按设置启停;SceSysCore 生命周期事件触发 Running Big App 补扫,再跟沙盒 vnode 与白名单 TID。EXEC 身份未就绪或 NOTE_TRACK 跟丢时短重试,无沙盒常驻扫描)
- 休息后 Toolbox 恢复(kstuff-lite:新 ShellUI PID + trophy sprx,再按 `rest_mode.resume_reinject_delay_seconds` 等待)
- 休息后监听套接字重绑(ps5-payload-manager:IPC / TCP `accept` 失败自愈)
- 双守护进程架构(util 可被 daemon 拉起)
### 4.2 用户界面(Toolbox)
- Debug Settings 风格菜单
- 内容安装与管理、Payload 与内核组件
- 插件(kstuff、FTP 服务器、ShadowMount+)
- 游戏辅助、监控与显示
- 账号激活
- 系统与硬件、操作偏好
- 高级调试、关于与支持
- 金手指(flat 文件 + mdbg/kdirect)
### 4.3 网络服务
- 首跳依赖外部 **9021 elfldr**;它同时是私有 9020 的恢复根。用户 Payload 严格使用内置 **9020 onion_elfldr**,不回退 9021
- **FTP**:由可选的外部 `onionHEN-ftpsrv-plugin` 提供;daemon 负责进程生命周期,插件通过动态 UI 提供启用、端口与重启控制
- **ShadowMount+**:由可选的外部 `onionHEN-shadowmountplus-plugin` 提供;daemon 负责进程生命周期,插件通过动态 UI 提供立即扫描操作
- **DPI v2**:由可选的外部 `onionHEN-dpiv2-plugin` 提供;浏览器负责上传与安装操作,插件动态 UI 提供启停、API/WebUI 端口与重启配置
- **Remote Play**:ShellUI 调用 PS5 原生 Remote Play API 完成 PIN 生成和客户端注册确认
用户 Payload 的所有 `.elf` 文件名都使用相同的 Payload 页面、自动启动扫描和共享
加载器。用户 Payload 仅由 Payload 页的明确停止操作终止;已有有效 PID 记录时,
后续启动和自动启动请求保持现有实例。带 `.onion_plugin` descriptor 的插件则放在
`/data/OnionHEN/plugins/`,由插件管理器独立发现、校验和管理。
### 4.4 扩展
- 自定义插件(使用 [OnionHEN Plugin SDK](https://github.com/OnionBuddies/onionHEN-plugin-sdk))
- `config.ini` 驱动的开关(overlay、快捷键等)
## 5. 依赖组件
### 5.1 构建与运行时(外部)
| 依赖 | 说明 |
|------|------|
| **ps5-payload-sdk** (`PS5_PAYLOAD_SDK`) | Prospero 工具链、`prospero-cmake`、系统头文件 |
| **clang** | 目标 `x86_64-sie-ps5` |
| **elfldr @ 9021** | 首跳必需,不随 OnionHEN 打包 |
| **onion_elfldr @ 9020** | OnionHEN 内置私有运行时 loader;由 bootstrapper 拉起 |
| Kernel exploit | 如 IPV6 等,用于先获得代码执行 |
### 5.2 第三方依赖(`third_party/`)
| 组件 | 上游 | 角色 |
|------|------|------|
| **kstuff-lite** | [EchoStretch/kstuff-lite](https://github.com/EchoStretch/kstuff-lite) | 提供 `kstuff.elf`;休息后 Toolbox 恢复也参考其 ShellUI PID 监视 |
```bash
git submodule update --init --recursive
./scripts/sync_dependencies.sh
```
### 5.3 树内第三方源码
| 库 | 用途 |
|----|------|
| **7zip-sdk (LZMA)** | unpacker 解压 bootstrapper |
| **cJSON** | JSON(通知、IPC 载荷等) |
金手指解析器使用 `third_party/cheat_support/` 内直接编译的 AES、base64、miniz、SHA-256 实现。
### 5.4 预编译静态库
| 库 | 用途 |
|----|------|
| **libkeystone** (`third_party/keystone/`) | ShnExt 汇编 |
C++ runtime 由 `PS5_PAYLOAD_SDK/target/lib` 提供。金手指仓库同步链接 SDK
`target/user/homebrew` 的 libcurl/OpenSSL,嵌入 SDK CA bundle 校验证书,并用
miniz 定向提取 HTTPS ZIP 中的 `cheats/`。用户 Payload 通过
`common/elfldr_remote.c` 使用私有 9020;外部 9021 用于首次引导和恢复 9020。
### 5.5 PS5 系统库 stub(`source/platform/ps5/stubs/*.so`)
当前链接目标:
- `libkernel_sys`
- `SceSystemService` / `SceUserService`
- `SceNetCtl` / `SceNet`
- `SceNotification` / `SceRegMgr`
- `SceSysCore` / `SceAppInstUtil`
- `SceGnmDriver`
运行时解析到主机系统模块。
### 5.6 构建期工具
| 工具 | 用途 |
|------|------|
| **Go stubber**(`tools/stubber/`) | NID stub 生成 |
| **Python3** | 构建辅助脚本(如 `encryptver.py`) |
| **lzma / xz** | bootstrapper 打包 |
### 5.7 SDK 动态 XML UI
动态 UI 分为三个职责边界:
1. SDK 用稳定 C ABI 构造 neutral UI document,并通过 10–15 号插件 IPC 命令
执行分块注册、提交、取消注册和状态更新。
2. `libonion_plugin_ui` 校验 wire document、维护 owner 隔离的 registry,并在
事务提交后发布不可变 snapshot。`ProtocolBroker` 只接收连接会话绑定的
owner,不使用 document 自报的 `plugin_id` 进行路由。
3. `libonion_plugin_session` 为每条连接处理一次 `HELLO`,绑定插件自报的 ID
与 capability;连接存活期间身份不可改变,重复的活跃 ID 会被拒绝,断连时
自动清理该 owner 的 transfer 和 contribution。
4. ShellUI adapter 将 snapshot 中的页面、菜单、分组、标签、按钮、开关、列表
和输入框转换为 Legacy Settings XML;resource/control ID 使用稳定 hash,
页面返回由动态页面栈恢复。
5. daemon 通过独立的 `shellui_plugin_bridge` Unix stream 向 ShellUI 发布完整
snapshot。ShellUI 将动作送回 daemon 校验,daemon 按 registry 中解析出的
owner 入队;插件在原有 `plugin_service` 连接上用 9 号命令轮询事件。
```text
SDK plugin -> HELLO -> connection session -> ProtocolBroker -> Registry snapshot
-> bridge -> ShellUI XML adapter
ShellUI action -> bridge -> ProtocolBroker validation -> owner event queue
-> command 9 -> SDK UI event
```
文档上限为 256 KiB、256 节点、8 层深度;注册采用 ordered chunk 与 FNV-1a
checksum,只有完整 commit 才替换可见 contribution。断连通过 owner 一次性清理
未完成 transfer 和所有 UI contribution。当前 ShellUI profile 对 2.30–12.x
开放,未知固件 fail closed。
这里采用的是适合自制软件生态的协作式身份,不是安全认证:`HELLO` 不校验签名、
ELF、PID 或启动来源,capability 也只是功能协商与 API 门禁,不能防御恶意插件。
它解决的是误用、连接中途换 ID、重复 ID 和断连遗留 UI。daemon 中的
`/system_tmp/onionhen/ipc/plugin_service` 使用独立持久连接 listener,每条
accepted stream 拥有一个 `ConnectionSession`。它处理完整 SDK frame、`HELLO`、
`PING`、9 号非阻塞事件轮询和 10–15 号 UI 命令。跨进程 snapshot 使用独立
`/system_tmp/onionhen/ipc/shellui_plugin_bridge` stream,避免异步消息破坏插件
socket 的 request/response 配对。休眠恢复会关闭旧连接并重新监听,整体关停会
停止 listener 并触发 contribution 与待处理事件清理。日志、通知、配置等其它
Host Service handler 仍属于后续集成。
---
## 6. 架构特点小结
1. **分层嵌入**
用户只下发一个 `OnionHEN.elf`,内部层层解压/拉起全套服务。
2. **双守护进程**
critical(注入/监视)与 util(网络/IO)分离,util 可崩溃恢复。
3. **elfldr 边界清晰**
外部 9021 只负责首跳;运行时使用内置 9020,并通过握手避免误用其它占端口服务。
4. **UI = 进程注入**
Toolbox 不是独立 App,而是 ptrace 注入 ShellUI 的 Mono 代码。
5. **kstuff 来源**
fPKG/fSELF 能力来自 kstuff-lite;可用 `/data/OnionHEN/kstuff.elf` 覆盖。
6. **IPC 协议稳定**
Unix socket;ABI 占位命令保持已发布的命令序号稳定。
7. **动态 UI 与固件隔离**
插件只提交 neutral document;owner registry、ShellUI XML 与固件 profile
分层实现,未知固件不生成动态页面。
---
## 7. 相关文档
| 文档 | 说明 |
|------|------|
| [../README.md](../README.md) | 项目总览、功能列表、配置、加载方式 |
| [shellui-injection.md](shellui-injection.md) | ShellUI 注入路径、安全契约与失败行为 |
| [pkg-writeup.md](pkg-writeup.md) | PS5 PKG 技术说明 |
| [../source/README.md](../source/README.md) | 源码树与构建说明 |
| [../third_party/README.md](../third_party/README.md) | 第三方源码、子模块与运行时依赖 |
---
## 8. 构建速查
```bash
git submodule update --init --recursive
export PS5_PAYLOAD_SDK=/path/to/ps5-payload-sdk
./scripts/build.sh
# 或缺 vendor 时仅编译验证:
# ./scripts/build.sh --stub-missing
```
手动 CMake:
```bash
./scripts/ps5_cmake.sh -S source -B build -G Ninja
cmake --build build
```