【免费下载链接】playport
Playport runs Windows games, 64-bit and now 32-bit, on a stock, non-jailbroken iPhone. Install a game from your library onto the phone, pick up a controller and press Play. The game runs on the phone's own CPU and GPU: no PC, no cloud, no stream.
Playport 是一款让 Windows 游戏(64 位与 32 位)原生运行在普通 iPhone 上的工具:无需电脑、云端或串流,游戏直接跑在手机自己的 CPU 和 GPU 上。而在它的设计里,安全边界是核心关键词之一——Playport 的宿主 Steam 会话(你在手机上登录的那个 Steam 账号)与游戏内会话(Guest 中 Windows 客户端的会话)被刻意设计成两个彼此隔离的世界:宿主的任何 Steam 凭据默认都永远不会进入游戏。
为什么隔离是Playport安全设计的难题
先理解一个前提:Playport 里"宿主"和"游戏"并不是两堵墙隔开的两个世界。
按照 ARCHITECTURE.md 的描述,宿主 App、运行时(Wine + FEX 翻译器)和每一个 Guest 二进制文件运行在同一个进程里,共享同一个地址空间、同一个容器、同一组 Keychain 权限。这意味着进程内不存在传统的"边界",任何 Guest 侧代码理论上都能读到进程内存里的任何东西。
正是这个现实,逼出了 0004: Steam session boundary 这条最硬的设计决策:
- 宿主的 native Steam 客户端(app/SteamClient/)与 Guest 里运行的任何 Steam 客户端,是两个互不相通的会话;
- 没有任何宿主 Steam 秘密会被传进 Guest:refresh token、access token、QR 登录素材、机器/会话绑定、CDN token、depot key,都不行;
- 堵住的通道也是全的:prefix 文件、环境变量、注册表、命令行参数、IPC、共享内存,乃至 wine_host 的 C ABI 接口——这个 ABI 里根本没有"携带凭据"的参数。
一句话概括:Guest 客户端要玩,请自己登录;拿宿主账号的钥匙去开门,这条路从设计上就不存在。
宿主一侧如何守住秘密:5条基线
0004 不只说"不传",还把"宿主自己怎么防漏"写成了可检查的规则:
| 防线 | 做法 |
|---|---|
| 存储位置 | 宿主秘密只存 Keychain:generic-password 条目、ThisDeviceOnly、不可同步;App 容器里一个字节都没有 |
| 内存形态 | 秘密以Secret<T>持有,打印出来是<redacted> |
| 日志脱敏 | 每行日志都过一遍 scrubber,过滤 JWT、QR URL、query string、bearer 值和主目录路径 |
| 启动模式 | 传递 Steam 命令的启动方式不在环境里放任何秘密,设备驱动会逐条检查日志转录 |
| 登出 | 向 Steam 撤销 token,删除 Keychain 条目和缓存账号数据,游戏与存档保留 |
同时还有一个"休眠规则":游戏运行期间,宿主的 Steam 会话不做任何 Steam 工作——CM(Game Coordinator)连接在运行时启动前就关闭,唯一的例外见下一节。
三条受控通道:哪些"凭据"可以进游戏
绝对隔离会让在线游戏没法登录自家服务器。所以 Playport 为"游戏应该从商店拿到什么"开了三条受控例外,每一条都有独立的决策记录,并必须回答同一个五问:针对哪个秘密、唯一通道是什么、Guest 侧存储量是否实测、登出是否清除所有副本、撤销是否让 Guest 拿到的也失效。
1)加密 App Ticket:一条会自己消失的 ini 行
见 0017: An encrypted app ticket enters the guest。
- 点击 Play 后,宿主为即将启动的那一款游戏向 Steam 申请一张加密 App Ticket,写入游戏配置
steam_settings/configs.user.ini的ticket=<base64>一行;游戏退出(或下次启动、下次 App 启动、登出时)该行即被删除。 - 这张票用发行商的密钥加密,Playport 自己都读不懂;游戏把它发给自家服务器,用于在线账号、跨平台登录与防盗版校验。
- 小偷最多能做到的,是拿这张票冒充"你玩这一款游戏",直到服务器不再接受它;拿不到 Steam 账号本身。
- 真机实测(证据):玩完两轮后搜索整个容器,除 ini 那一行外没有任何文件留下 ticket 的痕迹。
2)游戏运行中的"活着的"Steam 会话:只发 ticket,别的都拒绝
见 0062: A live Steam session during play,这是 0004 休眠规则的唯一口子。
游戏运行期间,宿主保持登录的 CM 连接只为一件事:像 Steam 客户端那样替游戏制作两类票据——auth session ticket(GetAuthSessionTicket)和 web API ticket(GetAuthTicketForWebApi)。除此之外,安装、PICS、资料、云存档、登录等一切 Steam 调用在游戏运行期间全部拒绝。
跨进 Guest 的只有:票据的字节、一个句柄和一个状态。不是 token,不是 SteamID,也不是别款游戏的票据。
这条通道的工程细节很能说明"最小化"的思路:
- 唯一通道:一张 Wine unix call table playport_steam_unix_call_funcs(协议定义见 steam_ticket_protocol.h),由 steam_ticket_provider 挂在 ABI 上,Steam API 模拟器(gbe 补丁 0006)通过它请求。数据块定长、无指针、逐个校验 magic 与 size。
- 配额由宿主定死:仅限被启动的那款 App;最多 8 张存活票据;每张间隔至少 2 秒、同时 4 张;Steam 自身的 token 供给上限再兜一层底。
- 收尾:
CancelAuthTicket可单独取消;一局结束时(1 秒内)发送空票据列表和空ClientGamesPlayed;崩溃或进程被杀,socket 随进程一起消亡。 - 日志只记句柄、类型和大小,永不记录票据字节、token、identity 或 SteamID。
对照 0004 的五问,0062 逐条作答:威胁模型✅、单一通道✅、Guest 侧存储实测✅(票据只活在游戏内存,容器里搜不到票据头)、登出清副本✅(宿主只在内存持有票据,游戏结束后进程重启)、撤销同样作废 Guest 的✅(取消、局终、会话终止都会结束票据)。
3)GOG 与 Epic 游戏的同构例外
Steam 之外,Playport 为其他商店开了结构相同、范围同样收紧的例外:
- GOG(0063):宿主在游戏运行期间扮演"本地 Galaxy 服务",监听
127.0.0.1:9977,只签发限定在该游戏 client ID 范围内的 refresh token;成就、统计、排行榜由宿主代答。跨界的秘密仅此一项,游戏结束监听即停。 - Epic(0059):宿主在 Play 后换取一个一次性、5 分钟有效的 exchange code(以及需要时的 ownership token),像 Epic 启动器一样放在游戏命令行旁。任何 Epic token(
eg1)都不进 Guest。
清理与撤销:让秘密"活不过一局"
隔离不只是"少给",还包括"给过的要收回来"。Playport 的清理策略可以总结为四条:
- 行级清除:加密 App Ticket 的 ini 行在游戏退出、下次启动、下次 App 启动、登出时删除;
- 内存即终点:0062 的票据宿主侧只在内存持有,不落盘、不进 Keychain;
- 进程即墓碑:一局游戏结束后 Playport 会重启运行时进程(0029: restart after each game),崩溃或被杀同样让 socket 与内存票据一起消亡;
- 日志即审计:票据的字节、token、SteamID 永不入日志,
Redactor会连日志里残留的ticket=值一起抹掉,pp secrets检查还能拦截提交中"长得像真票据"的行。
残余风险:设计者自己承认了什么
诚实的安全文档不假装没有洞。0004 明确写下:一个敌意的 Guest 二进制可以读到进程能读的一切,包括内存中正在使用的宿主 token。0062 进一步指出,存活的 CM 连接意味着理论上 Guest 里的原生代码可以"驱动"这条已登录连接。
缓解方式不是假装边界存在,而是收窄范围:
- 只运行你拥有的游戏与真正的客户端(正版库 + 商店登录本身就是筛选器);
- 宿主 token 只在"使用中"的短暂窗口里存在于内存;
- 每条例外通道的爆炸半径都被压到最小——一张票只对应一款游戏、一个玩家、有限寿命。
换句话说:Playport 的安全模型不是"把恶客关在门外",而是"门外根本不放值得偷的东西"。
延伸阅读:决策记录与源码路径
Playport 把这类安全决策都沉淀为编号的 decision record(docs/decisions/),新手可以从这几份入手:
| 主题 | 文档 |
|---|---|
| 会话隔离总纲 | 0004-steam-session-boundary.md |
| 加密 App Ticket | 0017-encrypted-app-ticket.md |
| 局中活会话与票据 | 0062-steam-live-session.md |
| GOG Galaxy 登录 | 0063-gog-galaxy-sign-in.md |
| Epic 交换码 | 0059-epic-exchange-code.md |
| 每局之后重启 | 0029-restart-after-each-game.md |
关键源码:票据宿主侧实现 steam_ticket.c、协议 steam_ticket_protocol.h、宿主 ABI 声明 wine_host.h、宿主 Steam 客户端 app/SteamClient/(Kit 位于 app/SteamClient/)。
总结
- Playport 用"一个进程、没有进程内边界"的现实,倒逼出"宿主秘密永不进 Guest"的硬规则,并从 Keychain 存储、日志脱敏到 ABI 设计逐层落实;
- 三条受控例外(加密 App Ticket、局中票据、GOG/Epic 登录)各自有独立威胁模型、单一通道和清理路径,爆炸半径压到"一款游戏、一局游戏";
- 票据类秘密"活不过一局":ini 行会删、内存票据随进程重启消亡、日志只留句柄;
- 残余风险被如实记录,缓解手段是范围控制而非虚构的墙。
【免费下载链接】playport
Playport runs Windows games, 64-bit and now 32-bit, on a stock, non-jailbroken iPhone. Install a game from your library onto the phone, pick up a controller and press Play. The game runs on the phone's own CPU and GPU: no PC, no cloud, no stream.
相关推荐
CorridorKey-Runtime离进程运行时揭秘:崩溃隔离、会话池与共享内存IPC如何保护DaVinci Resolve
CorridorKey Runtime离进程运行时揭秘:崩溃隔离、会话池与共享内存IPC如何保护DaVinci Resolve CorridorKey Runt
完全掌控你的数字记忆:WeChatMsg终极聊天记录管理方案
完全掌控你的数字记忆:WeChatMsg终极聊天记录管理方案 你是否曾经因为手机丢失或更换设备,那些珍贵的微信对话就永远消失不见?那些与家人的温馨交流、与朋友的
Ory Kratos 会话管理揭秘:Continuity 内部机制与 Cookie 安全设计完整指南
Ory Kratos 会话管理揭秘:Continuity 内部机制与 Cookie 安全设计完整指南 🔐 Ory Kratos 是一个用 Go 编写的无头(H
后端认证鉴权
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考