YorkWestenhaver/isaac-afterbirth-macos-fix

GitHub: YorkWestenhaver/isaac-afterbirth-macos-fix

一个用于修复《以撒的结合》在 Apple Silicon Mac 现代 macOS 上因 Steam DRM 加载器的旧版 dyld 兼容性 bug 而启动崩溃的轻量信号处理垫片。

Stars: 3 | Forks: 0

# 《以撒的结合》 — macOS 启动崩溃修复 **修复了在搭载 Apple Silicon 的现代 macOS(Sequoia / macOS 15)上,于 Rosetta 2 环境下运行的 *The Binding of Isaac: Rebirth / Afterbirth / Afterbirth+* 在启动时瞬间崩溃的问题。** 如果你在点击 **Play** 时游戏立即崩溃(没有弹出窗口,直接退回 Steam 库,或者弹出 segfault 崩溃报告),本方案就能修复它。该方案不会修改任何游戏文件,也没有任何破解行为,仅仅是使用一个由你自行编译构建的小型开源 shim(垫片)。

The Binding of Isaac launching and running on macOS 15 after applying the fix

## 适用情况? - 在 Apple Silicon Mac(M1/M2/M3/M4)上运行的 macOS 15(Sequoia),以及很可能是较新版本的 14(Sonoma)。 - 游戏通过 Rosetta 2 启动(这是一个 x86-64 版本)。 - 点击 **Play** 毫无反应,或者游戏瞬间崩溃。 - 崩溃报告(在 **Console → Crash Reports**,或 `~/Library/Logs/DiagnosticReports/` 中)显示在类似 **`0x00007fff5fc01008`** 的地址处发生了 segfault(`EXC_BAD_ACCESS` / `SIGSEGV`),并且 backtrace 中经常出现 `steamloader.dylib`。 如果符合上述情况,请继续阅读。 ## 环境要求与兼容性 **依赖项(所需的一切):** - **Apple Command Line Tools** — 提供 `clang` 用于编译 shim(大约需要 1 秒)。如果尚未安装,请使用 `xcode-select --install` 进行安装。这是*唯一*的构建依赖。 - **Rosetta 2**(仅限 Apple Silicon)— 游戏是一个 x86-64 应用程序,因此需要通过 Rosetta 运行。如果你的 Mac 以前曾成功启动过该游戏,说明你已经安装了它;如果没有,请使用 `softwareupdate --install-rosetta --agree-to-license` 进行安装。 - **Steam**,安装在其默认位置(`~/Library/Application Support/Steam`)。如果你的安装路径不同,请修改 `isaac_launch_wrapper.sh` 中的其中一个路径(文件内已作标注)。 不需要任何其他库、框架或运行时依赖 — 该 shim 仅使用 macOS 自带的组件(`libSystem`:`dlfcn`、`signal`、`ucontext`)。`ffmpeg` 是可选的,仅供制作演示 GIF 的辅助脚本使用,修复方案本身并不需要它。 **已确认可正常运行的环境:** | 组件 | 已测试的配置 | |---|---| | macOS | 15.7.3 Sequoia (build 24G419) | | Mac | MacBook Pro, Apple M2 Max, 32 GB | | 架构 | Apple Silicon (arm64) 通过 Rosetta 2 运行 | | 工具链 | Apple clang 17.0.0 (Command Line Tools) | | 游戏 | Afterbirth+ v1.06.T1 (Steam appid 250900) | **预期也同样适用于**(根本原因相同,且修复方案不依赖特定版本 — 欢迎反馈测试结果): - 运行 macOS 13 Ventura、14 Sonoma 和 15 Sequoia 的其他 **Apple Silicon** Mac(M1/M2/M3/M4)。 - 运行较新版本 macOS 的 **Intel** Mac,游戏在原生 x86-64 环境下运行(不需要 Rosetta)。无论如何,shim 都是针对 x86-64 构建的,因此理论上同样适用;但目前尚未进行测试。 - 基础版的 **Rebirth** 和 **Afterbirth** 版本,而不仅仅是 Afterbirth+ — 它们共享相同的 Steam DRM 加载器。 修复方案本身不依赖于任何特定的 macOS 版本:它使用稳定的 POSIX 信号处理机制,并匹配旧版 dyld 共享缓存的地址范围,该地址范围在多个 macOS 版本中一直保持不变。 ## 快速安装 需要 Apple 的 Command Line Tools(`xcode-select --install`)以便编译 shim(约 1 秒)。 ``` git clone https://github.com/YorkWestenhaver/isaac-afterbirth-macos-fix.git cd isaac-afterbirth-macos-fix ./install.sh ``` 安装程序最后会打印出一行 **Launch Options** 文本。接着,在 Steam 中: 1. 右键点击 **The Binding of Isaac: Rebirth** → **Properties** 2. **General** 标签页 → **Launch Options** 3. 将安装程序打印的那行内容粘贴进去(如下方区块所示,但会显示成*你的*用户文件夹): "/Users/YOU/Library/Application Support/IsaacDyldShim/isaac_launch_wrapper.sh" %command% 4. 关闭属性窗口并点击 **Play**。🎉 ## 到底哪里出了问题(根本原因) 游戏受 Steam 的 DRM 保护。在启动时,Valve 的 **`steamloader.dylib`** 会运行一个例程(`CGlobalInitter::CrackMainImage`),在内存中解密真正的游戏代码并跳转执行。到目前为止一切正常——这部分依然有效。 随后,解密后的代码会调用 steamloader 自身的一个**古老的 dyld 兼容性 stub**(`_dyld_func_lookup` / `_dyld_lookup_and_bind`),以通过名称查找 dyld 的内部函数——这是 2006 年左右 Mac 软件的惯常做法。 该 stub 是一个经典的*延迟绑定* stub:它会通过一个指针槽跳转,该槽本应在加载时被填入正确的地址。在现代 macOS 上,**该槽位永远不会被填入。** 它仍然保留着构建时的原始占位符,该占位符指向 dyld 共享缓存曾经所在的**旧且固定的、前 ASLR 时代的地址**(`~0x7fff5fc00000`)。如今,该地址空间已被随机化,且**没有映射任何内容**,因此调用跳转到了未映射的内存中,进程在 `0x7fff5fc01008` 处瞬间发生 segfault。 **这是 Valve 极其老旧且无人维护的 DRM 加载器中的一个 bug——并非游戏本身的问题,也不是你的 Mac 出了问题。** 这就是为什么无论你怎么验证游戏文件、重新安装或是调整启动参数都无济于事。 ### 修复方案的工作原理 `isaac_dyld_shim.dylib` 会在游戏启动时被加载进去(在 steamloader 之前)。它注册了一个 `SIGSEGV`/`SIGBUS` 处理程序。当崩溃发生时,处理程序会通过其典型的旧版地址特征识别出该故障,并根据 CPU 寄存器(利用原始的 `_dyld_func_lookup(name, &out)` 调用约定)推断出旧 stub 试图解析的符号,接着使用 `dlsym` 正确解析该符号,将结果写回,然后**恢复执行,仿佛刚才的调用已经成功了一样。** 游戏随后便继续正常的启动流程并顺利运行。 任何*其他*崩溃都会直接传递给系统默认的崩溃处理程序,因此真正的 bug 绝不会被掩盖。 包装脚本还处理了另一个 macOS 特有的棘手问题:`/bin/bash` 是一个受 SIP 保护的系统二进制文件,因此当 macOS 运行 shell 脚本时会**剥离 `DYLD_*` 环境变量**。这会导致 Steam *自身*注入的 `steamloader.dylib` 被意外丢弃。该包装脚本会重新注入 steamloader 和 shim,然后再将控制权交给游戏。(详情请参阅 [`src/isaac_launch_wrapper.sh`](src/isaac_launch_wrapper.sh) 中的注释。) ## 这安全吗?合法吗? 两个问题的答案都是肯定的。 - **没有修改或重新分发任何受版权保护的内容。** 该修复方案仅提供完全原创的代码(采用 MIT 许可证的 shim、一个包装脚本和一个安装程序)。它绝不会触碰游戏文件或 Valve 的二进制文件——它仅仅是*引用*了你机器上已有的文件。 - **这不是 DRM 破解——恰恰相反。** 它*重新完整运行了 Valve 的 DRM 加载器*,并修复了其中的一个失效调用。它没有绕过任何版权保护;DRM 会照常执行。这使得它完全符合反规避规则,也不违反 Steam/GitHub 禁止破解和盗版的策略。 - **它是可逆且完全独立的。** 所有文件都存放在同一个文件夹中(`~/Library/Application Support/IsaacDyldShim/`)。运行 `./uninstall.sh` 即可将其删除;清空 Launch Options 即可完全恢复默认行为。 - **该 shim 由你自己使用可读的源码编译构建**,因此你可以清楚地看到它到底做了什么。 ## 验证修复效果 点击 Play 后,你应该能顺利进入开场动画和主菜单。要确认修复方案是否生效,可以开启调试日志:打开 `~/Library/Application Support/IsaacDyldShim/isaac_launch_wrapper.sh`,在文件顶部附近设置 `ISAAC_SHIM_DEBUG=1`,重新启动游戏,然后查看 `~/Library/Application Support/IsaacDyldShim/game_output.log`。你应该会看到: ``` [isaac-shim] installed, watching for legacy dyld address faults [isaac-shim] caught stale legacy-dyld code fetch at 0x7fff5fc01008 -- emulating _dyld_func_lookup [isaac-shim] lookup "__dyld_lookup_and_bind" -> 0x... [isaac-shim] resuming at return address 0x... (result=found) ``` 这就是崩溃被实时捕获并修复的过程。 ## 故障排除 - **“clang: command not found”** — 请安装 Apple 的 Command Line Tools:`xcode-select --install`,然后重新运行 `./install.sh`。 - **游戏依然瞬间关闭且没有崩溃报告** — 这通常意味着找不到 `steamloader.dylib`。请检查 Steam 是否位于默认位置(`~/Library/Application Support/Steam`)。如果不是,请修改 `isaac_launch_wrapper.sh` 顶部附近的 `STEAMLOADER` 路径。 - **Steam 日志中出现“Failed to spawn process / OS Error 260”** — 你的 Launch Options 设置有误。它必须是带有引号的包装脚本路径,后面紧跟 `%command%`。**不要**使用 Linux 下的 `DYLD_INSERT_LIBRARIES=... %command%` 格式;这在 macOS 上行不通。 - **Steam 更新替换了 `steamloader.dylib`** — 无需进行任何操作;包装脚本是通过路径来定位它的,因此它依然能够正常工作。(如果 Valve 有一天*修复*了这个底层 bug,该 shim 根本就不会被触发——它会变成一个无害的空操作。) - **Steam 的“验证游戏文件完整性”** — 非常安全;该修复不会触碰游戏文件,因此验证完整性不会对其造成任何影响。 ## 卸载 ``` ./uninstall.sh ``` 接着,清空 Steam 中该游戏的 **Launch Options**(Properties → General → Launch Options → 删除那一行内容)。 ## 这对其他游戏有帮助吗? 也许吧。任何受老旧 Steam DRM 包装且在启动时于 `0x7fff5fc0xxxx` 附近地址崩溃的 **Mac** 游戏,很可能都遭遇了 `steamloader.dylib` 中*相同的*旧版 dyld stub 失效 bug。该 shim 并非《以撒的结合》专属——只有包装脚本中的游戏路径和 Launch Options 是针对特定游戏的。如果你在其他游戏上进行了尝试并成功运行,请提交一个 issue,以便其他玩家也能找到这个方案。 ## 制作演示 GIF(面向贡献者) 顶部的 `docs/demo.gif` 是由一段简短的屏幕录制制作而成的: 1. 按下 **⌘⇧5**,选择 **Record Selected Portion**,在游戏窗口上拖拽出一个选区,点击 **Record**。游玩大约 6–10 秒(主菜单 → 开始一局游戏 → 四处移动一下),然后点击菜单栏上的 **停止** 图标。macOS 会将一个 `.mov` 文件保存到你的桌面上。 2. 使用内置的辅助工具进行转换(需要 `ffmpeg` — `brew install ffmpeg`): ./tools/make-gif.sh ~/Desktop/Screen\ Recording.mov docs/demo.gif 请保持文件体积较小(GitHub 最偏好 5 MB 以下的文件):你可以传入更小的宽度/帧率或对片段进行裁剪,例如 `./tools/make-gif.sh input.mov docs/demo.gif 480 12 3 8`(宽度 480px,12 帧率,从第 3 秒开始,时长 8 秒)。 ## 致谢与许可协议 通过对 `steamloader.dylib` 的 DRM 解密路径进行逆向工程,并使用 `lldb` 对崩溃进行实时调试,最终查明并解决了该问题。本项目基于 [MIT 许可协议](LICENSE) 发布。与 Valve 或 Nicalis 没有任何隶属关系,也未获得它们的认可。
标签:Steam, 信号处理, 兼容性修复, 动态链接库, 应用安全, 游戏辅助