gbe_fork 实验版(Experimental Build)完全指南:LAN Only 网络封锁、CPY 破解兼容与 DLL 内存加载
gbe_fork 实验版(Experimental Build)完全指南:LAN Only 网络封锁、CPY 破解兼容与 DLL 内存加载
本文围绕 gbe_fork(Goldberg Emulator 分支)仓库中的 实验版构建说明 展开,系统讲解该构建的三大核心能力:拦截游戏所有指向非局域网 IP 的出站连接(LAN Only)、支持 CPY 风格破解补丁在 SteamAPI_Init() 时于内存中修改游戏进程、以及自动加载 steam_settings/load_dlls/ 下的附加 DLL。读完本文,你将掌握实验版的启用原理、IP 白名单规则、配置开关与破解部署流程,并能结合 dll/base.cpp 源码理解其底层实现。
一、实验版构建是什么:一句话定位
Goldberg 模拟器的常规构建已经能离线模拟 Steam 接口,但很多游戏仍会在启动或运行期间主动连接外部的分析(Analytics)等服务。实验版(Experimental Build)在常规构建的基础上,额外把「网络行为管控」直接做进了 DLL 内部:
- LAN Only:阻断游戏发往一切非局域网 IP 的出站连接,但局域网联机(含标准 IP 的 VPN 局域网)不受影响;
- CPY 破解兼容:允许加载以
steam_apiDLL 为载体、在SteamAPI_Init()被调用时对游戏进程做内存补丁的 CPY 风格破解; - 附加 DLL 加载:通过
LoadLibraryW()(Linux 下为dlopen())把steam_settings/load_dlls/目录下的 DLL 自动注入游戏进程。
Mr.Goldberg 原话:这个文件夹里是实验版构建,代码 hook 了几个 Windows socket 函数,用来阻止游戏到非局域网 IP 的连接。这意味着游戏在局域网联机(即使是 VPN 局域网,只要使用 10.x.x.x、192.168.x.x 等标准局域网 IP)时可以无问题工作。它很可能对某些游戏不生效,但对大多数游戏应该有效。
二、为什么要做 LAN Only:防火墙方案太痛苦
Mr.Goldberg 在 README.experimental.md 中解释了动机:
很多游戏似乎都会连接分析服务和其他乱七八糟的东西。在不影响本模拟器局域网功能的前提下,用防火墙阻止游戏与在线 IP 通信是一件非常痛苦的事情。
也就是说:需求是「只封外网、不伤局域网」,但操作系统防火墙通常按进程/端口粗粒度放行,很难精确做到「局域网放行、公网拒绝」。实验版把判定逻辑内联到 socket 调用层,从游戏自身视角看连接请求被直接处理掉了,不需要用户配置任何防火墙规则。
三、底层机制:hook 了哪些网络函数
在 dll/base.cpp 的 DllMain 中,实验版在 DLL_PROCESS_ATTACH 阶段通过微软 Detours 库挂接(hook)以下 Windows socket 函数:
| 被 Hook 的函数 | 作用 | 实验版替换实现的行为 |
|---|---|---|
sendto() |
UDP 数据发送 | 目标 IP 非 LAN 时,直接返回 len(假装发送成功,实际丢弃数据包),见 dll/base.cpp |
connect() |
TCP 连接建立 | 目标 IP 非 LAN 时,设置 WSAECONNREFUSED 并返回 SOCKET_ERROR,见 dll/base.cpp |
WSAConnect() |
带附加数据的 connect | 行为同 connect(),见 dll/base.cpp |
WinHttpConnect()(可选) |
WinHTTP 连接 | 目标 IP 非 LAN 时,把服务器名改写为 127.1.33.7(一个指向本机的虚拟黑洞地址),见 dll/base.cpp |
关键点是 hook 的启用条件:只有当配置项 disable_lan_only 为 0(默认值)时才会执行 DetourAttach 挂接(dll/base.cpp);卸载时在 DLL_PROCESS_DETACH 中对称地 DetourDetach 还原。另外,如果游戏进程里加载了 winhttp.dll,还会一并挂接 WinHttpConnect,把 HTTP(S) 出口也纳入管控。
判定函数:一个 IP 算不算 LAN
is_lan_ip()(dll/base.cpp)先按 AF_INET / AF_INET6 分族处理,再对字节数组做范围判定。IPv6 情况下额外放行了:回环地址(::1)、链路本地(fe80::/10)、全零地址、多播(ff00::/8)、唯一本地地址 ULA(fc00::/7),以及 IPv4-mapped 地址(::ffff:x.x.x.x,此时按 IPv4 规则再判一次)。
白名单扩展机制
除了内置的局域网判定,实验版还提供了 set_whitelist_ips()(dll/base.cpp):外部代码可以向 DLL 注册自定义的「放行 IP 段」(from/to 成对传入,按网络字节序解析,非法区间会被跳过),被注册的区间会优先生效(is_whitelist_ip() 优先于内置规则)。在非 Windows 平台,该函数为空实现(见 dll/base.cpp),说明这套白名单扩展目前只服务于 Windows 实验版。
四、到底哪些 IP 被阻止:完整白名单范围
原文档给出的结论是:除以下范围外,所有 IP 一律阻止:
| 起始 IP | 结束 IP | 说明 |
|---|---|---|
| 10.0.0.0 | 10.255.255.255 | 私有网段 A 类 |
| 127.0.0.0 | 127.255.255.255 | 回环地址 |
| 169.254.0.0 | 169.254.255.255 | 链路本地(APIPA) |
| 172.16.0.0 | 172.31.255.255 | 私有网段 B 类 |
| 192.168.0.0 | 192.168.255.255 | 私有网段 C 类 |
| 224.0.0.0 | 255.255.255.255 | 多播 / 广播 / 未来保留 |
对照 dll/base.cpp 的 is_lan_ipv4() 实际实现,内置判定比文档列出的还要细,额外还包括:
- 100.64.0.0/10(
ip[0]==100 && (ip[1] & 0xC0) == 0x40):运营商级 NAT(CGNAT)地址段; - 192.18.0.0/15 中的 192.18 / 192.19:用于两个独立子网间基准测试的保留段;
- 224.0.0.0/24 起点以上(
ip[0] >= 224):多播(224–239)、保留(240–255)、广播(255.255.255.255); - 0.x.x.x(
ip[0]==0):表示「当前网络」的特殊地址。
注意:169.254.0.0/16 中
is_lan_ipv4对 169.254.0.x 的第三字节做了!= 0判断,即 169.254.0.0 本身不在放行范围内,这是实现上的一个细节差异。
五、如何禁用 LAN Only 功能
如果你的游戏必须访问外网(例如需要在线验证、下载内容),可以关闭此特性。当前仓库的推荐方式与旧版不同:
当前版本(基于 INI 配置):编辑 steam_settings/configs.main.ini,在 [main::connectivity] 段设置:
[main::connectivity]
disable_lan_only=1
0(默认)= 启用 LAN Only 网络封锁(hook OS 网络 API,阻止外部请求);1= 不 hook 网络 API,允许一切外部请求。
该选项的默认值与语义说明写在 configs.main.EXAMPLE.ini 中,并注明「仅 Windows 实验版构建使用」。解析侧由 settings_parser.cpp 的 settings_disable_lan_only() 读取 main::connectivity 段,缺省时返回 false;dll/base.cpp 正是依据该返回值决定是否执行 Detour 挂接。
历史版本(旧文档):在 z_original_repo_files/Readme_experimental.txt 中,禁用方式是「在 steam_api DLL 旁边或 steam_settings 文件夹内创建一个名为 disable_lan_only.txt 的文件」。这个 txt 触发方式在 tools/migrate_gse/main.py(第 245-249 行)中仍有迁移兼容逻辑,会将 main::connectivity 的 disable_lan_only 值同步写回 disable_lan_only.txt,说明新老两种表达在新工具链中是可以互通的。
六、如何使用 CPY 风格破解
CPY 风格破解通常是一个 steam_api.dll / steam_api64.dll,它的补丁逻辑在游戏调用 SteamAPI_Init() 时对进程内存打补丁。实验版通过「重命名 + 自动加载 + 调用转发」三步让这种破解与模拟器共存:
- 把破解文件
steam_api.dll重命名为cracksteam_api.dll(64 位对应steam_api64.dll→cracksteam_api64.dll); - 用实验版构建中的
steamclient(64).dll替换原破解自带的同名文件; - 像平时一样使用模拟器及其全部配置。
提示:别忘了放置
steam_appid.txt;如果原版steam_api较旧,可能还需要steam_interfaces.txt(旧文档 Readme_experimental.txt 中明确提到)。
底层流程在 dll/base.cpp 中实现:
load_crack_dll():在程序目录搜索crack+ DLL 文件名(cracksteam_api.dll/cracksteam_api64.dll,由DETOURS_64BIT宏决定,见 dll/base.cpp),存在则用LoadLibraryW载入;redirect_crackdll():临时 hookGetModuleHandleA,当破解代码以原名steam_api.dll查询模块时,将其重定向到cracksteam_api.dll(dll/base.cpp),保证破解内部逻辑不因模块名变化而失效;crack_SteamAPI_Init()/crack_SteamAPI_RestartAppIfNecessary():模拟器在对应调用点回调破解 DLL 中导出的同名函数,完成内存补丁动作。crack_SteamAPI_RestartAppIfNecessary特意用#pragma optimize("", off)关闭优化,注释说明这是为了避免破坏 Shogun 2 Prophet(RELOADED)破解(dll/base.cpp)。
七、如何加载额外的 DLL
将任何 DLL 文件放入 steam_settings/load_dlls/ 目录,实验版会在初始化阶段自动加载它们:
- Windows:
LoadLibraryW()加载.dll文件; - Linux:
dlopen(path, RTLD_NOW | RTLD_LOCAL)加载.so文件(实验版在 Linux 上同样支持该功能)。
实现见 dll/base.cpp:load_dlls() 枚举 Local_Storage::get_game_settings_path() + "load_dlls" 目录下的文件,过滤出以扩展名(.dll / .so,大小写不敏感)结尾的条目逐个加载,成功则把句柄记入 loaded_libs,失败会打印错误(Windows 打印 GetLastError 错误码,Linux 打印 dlerror 字符串);进程退出时由 unload_dlls() 统一 FreeLibrary / dlclose 卸载。Windows 下该流程挂在 DllMain 的 DLL_PROCESS_ATTACH(dll/base.cpp),Linux 下则通过 __attribute__((constructor)) 构造器触发(dll/base.cpp)。
用途示例:注入汉化补丁、修复补丁或需要常驻游戏进程的辅助 DLL。注意 README.experimental_steamclient.md 特别提醒:某些用于 Steam Client 启动期注入的 DLL 不能放在
load_dlls里,否则会造成严重的帧率下降。
八、构建产物与平台差异
实验版由 premake5.lua 中的 api_experimental 项目产出,输出到 build/<平台>/<动作>/<配置>/experimental/<架构>/ 目录,产物名与常规版一致:Windows 为 steam_api.dll / steam_api64.dll,非 Windows 为 libsteam_api。
- Windows 实验版:定义
EMU_EXPERIMENTAL_BUILD宏(premake5.lua),因此包含上述全部网络 hook 与白名单逻辑; - Linux 实验版:不定义该宏(不 hook 网络函数,
set_whitelist_ips为空实现),但load_dlls功能仍可用;Linux 实验版的主要差异化内容是启用 overlay,见 README.experimental_linux.md,且其官方说明直言「仅对极少数游戏有效」。
打包时,Windows 的 package_win.bat 会把 README.experimental.md 复制进 experimental/ 目录(package_win.bat),Linux 的 package_linux.sh 则复制 README.experimental_linux.md(package_linux.sh),保证发布包内自带说明文档。
九、适用前提与已知限制
结合 Mr.Goldberg 的原话(README.experimental.md)与源码,使用前请明确以下限制:
- 并非所有游戏都适用:hook 的是常见 socket API,个别游戏可能改用其它网络路径(如原始套接字、驱动级网络栈),官方表述是「可能对某些游戏不生效,但对大多数游戏应该有效」;
- 互联网破解服务器不可用:由于所有公网连接被拦截,托管面向互联网玩家的破解服务器、或连接托管在公网 IP 上的破解服务器,都将失败——这是该特性的设计意图;
- LAN 联机正常:标准局域网 IP(10.x.x.x、192.168.x.x 等)以及使用标准局域网网段的 VPN 局域网均可正常联机;
- 关闭方式明确:需要外网访问时,将 configs.main.ini 的
disable_lan_only置 1 即可整体放行,无需删除 DLL。
十、小结
实验版构建把「网络出口管控、破解补丁兼容、附加 DLL 注入」三件事全部收敛进 steam_api DLL 自身:通过 Detours 对 sendto / connect / WSAConnect / WinHttpConnect 的挂接实现 LAN Only 白名单放行,通过 cracksteam_api*.dll 重命名约定与 GetModuleHandleA 重定向实现 CPY 破解协同,通过 steam_settings/load_dlls/ 目录约定实现插件式 DLL 加载。对于需要局域网联机而又讨厌游戏偷偷连公网的场景,它提供了一个比防火墙更精确、零配置的解决方案。相关实现与示例配置均可在本仓库 dll/base.cpp、configs.main.EXAMPLE.ini 与 premake5.lua 中进一步查阅。