gengyunmaster/BallanceMiniInstaller
GitHub: gengyunmaster/BallanceMiniInstaller
该工具将大型 Ballance 游戏/整合包打包成约 20MB 的单文件 Windows 安装程序,通过有损预编码和安装时转码实现极高压缩比。
Stars: 0 | Forks: 0
# Ballance 迷你安装包构建器
将约 900 MB 的 Ballance 游戏/整合包打包成一个**约 20 MB 的单文件 Windows
安装程序** (`BallanceSetup.exe`) —— 只需一条命令,在 Linux 上完全离线运行。
该技术逆向工程自原始的 2005 年 Ballance 安装程序
(15 MB → 130 MB 游戏):**有损预编码 + 安装时转码**,而不是
更好的无损压缩器。本项目使用 2026 年的编解码器(WebP + Vorbis + LZMA2)
重新实现了这一技巧,并将其封装在一个静默、精良的安装程序中。
**目录**:[原始技巧](#the-original-trick-reverse-engineering-the-15-mb-installer) ·
[工作原理](#how-it-works) ·
[快速开始](#quick-start) ·
[安装程序用户体验](#the-installer-ux-what-players-see) ·
[可调参数](#tunables) ·
[自检](#self-check-s8) ·
[CI](#ci--releases) ·
[疑难解答](#troubleshooting--lessons-learned) ·
[第三方声明](#third-party-notices) · [法律声明](#legal-note)
## 原始技巧(逆向工程 15 MB 安装程序)
这个项目源于一个谜题:经典的 `Ballance_1.13_en.exe` 大小为
**15.7 MB**,却安装了 **130 MB** 的游戏 —— 而使用 7-Zip(LZMA,最高设置)
重新压缩安装后的文件,最低也只能达到 **42 MB**。
一个 2005 年的安装程序怎么可能比 LZMA 还要小 3 倍?
### 第 1 层:一个几乎不进行压缩的 Wise 外壳
该 exe 是一个 14 KB 的 PE 存根,外加一个 15.7 MB 的附加数据(熵 ≈ 8 bits/byte)。
字符串分析表明它是 **Wise Installation Wizard**(2000 年代产物)。
对 zlib 数据流的简单扫描发现了 31,770 个候选头信息 —— **全是误报**
(在 15 MB 高熵数据中命中随机数据是意料之中的;教训是:务必通过
实际解压来进行验证)。真实的格式(根据
[REWise](https://codeberg.org/CYBERDEV/REWise) 和
[Archive Team wiki](http://fileformats.archiveteam.org/wiki/Wise_installer_package))
是一个 Wise 头部,紧随其后的是 `[raw-DEFLATE entry][CRC32]` 记录,直到 EOF。
遍历该附加数据可得到 16 个条目,CRC 全部有效:
| # | 偏移量 | 压缩后大小 | 解压后大小 | 内容 |
|---|---|---|---|---|
| 0 | 0x3aa9 | 20,428 | 40,362 | WiseColors.dib (140×144 安装向导图像) |
| 1 | 0x8a79 | 3,445 | 12,606 | WiseScript.bin (安装脚本,对话框字符串) |
| 2–7 | … | ~137 KB | ~504 KB | Wise 引擎 DLL,对话框模板,资源文件 |
| 8–11 | … | ~2.4 KB | ~5 KB | 小型数据块 |
| 12 | 0x2c34c | 61,622 | 153,088 | UNWISE.EXE (卸载程序) |
| **13** | **0x3b406** | **15,430,382** | **15,431,518** | **MAIN.exe** — DEFLATE 比率为 1.00007 |
| 14–15 | … | ~63 KB | ~317 KB | 卸载脚本数据 |
第 13 个条目就是铁证:DEFLATE 对它**毫无作用**(它已经被
压缩过了)。它的 CRC32 `7d872a8c` 与游戏自身的 `INSTALL.LOG` 记录
完全匹配 —— 实现了逐位精确恢复。Wise 包装器(构建于 2010 年)只是一个
交付载体;实际的有效载荷是 **MAIN.exe(构建于 2005-04-07,v4.16.0.0)**。
### 第 2 层:MAIN.exe 是一个 7-Zip SFX
```
Type = 7z, Offset = 79360 ← 79 KB UPX-packed SFX stub
Method = LZMA:24 BCJ, Solid = + ← 16 MB dictionary + x86 filter
358 files: 42,758,769 → 15,346,746 bytes
```
### 第 3 层:有效载荷*并不是*安装后的字节
| 压缩包内容 | 安装后的结果 | 压缩率 |
|---|---|---|
| 62 × `.ogg` (3.35 MB) | 62 × `.wav` (34.3 MB) | 10.3× |
| 62 × `.jpc` JPEG2000 (3.0 MB) | 62 × `.bmp` (~63 MB) | ~21× |
| NMO/DLL/TGA/AVI/etc. (~36 MB) | 相同的文件,字节一致 | — |
压缩包中还包含 `temp/oggdec.exe` ("OggDec 1.0")、`temp/nicej2k.exe`
(一个 JPEG2000 解码器)以及两个批处理脚本(`1.bat`/`2.bat`),它们负责在安装时
解码所有内容,然后删除源文件及其自身。
**证据**:重新解码 OGG 文件可以逐样本还原已安装的 WAV 文件
(0.05% 的样本存在 ±1 LSB 的误差 —— 这仅仅是解码器的舍入误差);已安装的天空 BMP 文件与
`.jpc` 解码结果完全匹配,像素差异为 **零**。
### 答案
无损压缩器受限于你输入的字节的熵。
安装后的 WAV/BMP 字节具有约 42 MB 的熵,因此没有任何无损编解码器能够
达到 15 MB。安装程序根本就没有存储这些字节:它存储的是
**感知编码**的媒体(小 10–21 倍),并在安装时重新生成了 WAV/BMP 文件。
它是通过改变游戏规则获胜的,而不是通过把游戏玩得更好。
*(有趣的脚注:`2.bat` 包含一个拼写错误 —— `del /Q texures\atair.jpc` —— 因此
`Textures/atari.JPC` 在每次安装后都能幸存至今;而且 nicej2k 会
在转换后的每个 BMP 后填充 262,634 字节的未初始化尾部垃圾,导致每次安装中都会多出
约 16 MB 的无效负载。)*
## 工作原理
相同的架构,采用现代编解码器:
```
Build side (Linux, offline) Install side (Windows, offline)
───────────────────────────── ───────────────────────────────
Textures *.bmp BallanceSetup.exe double-clicked
└─ downscale to ≤1024px + WebP q85 ──┐ ├─ 7z SFX stub unpacks payload
Sounds *.wav │ ├─ "Ballance Setup" prompt shows
└─ Vorbis q4 ────────────────────────┼─ 7z │ the real install path
Everything else (NMO/DLL/EXE/AVI/...) │ LZMA2 ├─ run.vbs (hidden) drives install.bat:
└─ stored as-is ─────────────────────┘ solid │ tools\dwebp.exe → BMPs
+ 7zSD.sfx stub ──→ BallanceSetup.exe tools\oggdec.exe → WAVs
└─ desktop shortcut + uninstall entry,
cleanup, silent exit
```
- **WebP 替代了 JPEG2000**(更好的压缩率,`dwebp.exe -bmp` 在安装时
可直接解码为 BMP)
- **保留 Vorbis**(Opus 会强制使用 48 kHz 并改变每个文件的采样
率;Vorbis 保留了原始设置 —— 这与 2005 年打包工具的选择
一致)
- **LZMA2 64 MB 字典 + BCJ2 + 固实压缩** 替代了 LZMA 16 MB
- 带有**尾部垃圾**的 BMP(在原版文件中发现的老式 nicej2k 伪影)
在编码前会被截断为其声明的 `bfSize` —— 否则 ffmpeg 会
尝试将垃圾数据作为额外帧进行解码并导致失败
在一个 877 MB 的整合包上测试的结果:**23.6 MB** 安装包。在一个 130 MB 的原版
整合包上:**18.0 MB**(天空图像在 512px/q85 质量下从 743 MB 缩小到了 0.6 MB;即使是 1024px 的
安装分辨率,也依然是原版 512px 分辨率的 2 倍)。
## 快速开始
```
# 1. 下载 toolchain(官方来源,约 120 MB)
./fetch_tools.sh
# 2. 将您的游戏打包为 .7z(请参阅下方的“Game package requirements”)
# 3. Build(此后完全离线)
./build_installer.sh Ballance.7z BallanceSetup.exe
```
### 游戏整合包要求
`.7z` 文件必须包含游戏根目录(一个包含 `Textures/` 和
`Sounds/` 的目录 —— 自动检测),并带有安装后的游戏应具备的所有内容。
接下来的构建过程会:
- 将每个 `.bmp` → `.webp` 进行转换(将所有超过 `IMG_SCALE` 像素的图像进行缩小),
- 将每个 `.wav` → `.ogg` 进行转换(Vorbis q4),
- 如果存在 `VC_redist.*.exe` 则将其删除,
- 保持其他所有文件字节完全一致,
- 通过重放安装过程并与源文件进行 diff 对比来验证结果
(参见 [自检](#self-check-s8))。
示例(使用原版游戏):将你的 `Ballance/` 文件夹打包为
`Ballance.7z`,然后运行 `./build_installer.sh`(默认设置:输入为 `Ballance.7z`,
输出为 `BallanceSetup.exe`)。
## 安装程序用户体验(玩家所看到的)
1. 双击 → 显示 7z 解压进度,然后弹出一个提示
显示真实的安装路径(`%LOCALAPPDATA%\Programs\Ballance`)的 **“Ballance Setup”**。
点击 OK 进行安装,点击 Cancel 则静默退出。
2. 其他所有操作都是不可见的(没有控制台窗口):文件被复制
(自动创建目录、自动覆盖),纹理被解码为 BMP,声音被解码为 WAV,
并带有逐步的退出代码检查和解码文件数量断言。
3. 安装成功:创建一个 `Ballance` 桌面快捷方式(→ `Bin\Player.exe`,起始位置为 `Bin`),
在“应用和功能”中添加一个带有可用卸载程序的条目(HKCU,无需管理员权限),
临时文件/解码器/脚本将被移除,随后静默退出。
4. 仅在失败时:弹出一个带有错误代码的消息框。
SFX 存根包含一个注入的应用清单(`supportedOS`
Win7–Win11),因此 Windows 程序兼容性助手会保持静默
(参见 `patch_sfx_manifest.py`)。
## 可调参数
位于 `build_installer.sh` 的顶部:
| 变量 | 默认值 | 含义 |
|---|---|---|
| `IMG_SCALE` | `1024` | 像素;更大的图像会被缩小(保持长宽比) |
| `IMG_Q` | `85` | WebP 质量 0–100(`75` ≈ 体积 −15%,视觉上更柔和) |
| `IMG_METHOD` | `6` | cwebp 压缩力度(6 = 最佳压缩率) |
| `QAUDIO` | `4` | Vorbis 质量(`6` ≈ 体积增加 +3 MB,动态余量更大) |
## 自检 (S8)
每次构建都会在 Linux 上重放安装过程,并与源代码树进行 diff 对比:
- 非媒体文件:SHA1 必须匹配
- BMP 文件:尺寸/位深必须与缩小规则匹配
- WAV 文件:采样率/声道数/位深必须匹配;长度差值 ≤ 16 KB(Vorbis
尾部样本对齐是正常现象);能量比在 0.25×–4× 之间(防止
解码失败);打印原始 SNR 供参考
- 任何缺失/多出的文件都会导致构建失败
## CI / Releases
- `.github/workflows/ci.yml` — 在每次 push/PR 时:获取工具链,
生成一个**合成游戏**(`tests/make_synthetic_game.sh`:大/小尺寸
BMP,带垃圾尾部的 BMP,多采样率的 WAV),构建安装程序,并运行
自检。保持流水线免受回归问题影响。
- `.github/workflows/release.yml` — 手动触发 `workflow_dispatch`:为它提供一个
指向你的游戏 `.7z` 的 URL(由你自行托管 —— 绝不包含在此 repo 中)以及一个 tag;它会构建
并发布 `BallanceSetup.exe` + `SHA256.txt` 作为 GitHub Release。
或者在本地构建并运行 `gh release create BallanceSetup.exe SHA256.txt`。
## 疑难解答 / 经验教训
以下所有内容都是在真实机器上经过惨痛教训学到的:
- **`RunProgram="cmd /c install.bat"` 失败**(“系统找不到指定的
文件”) —— 原版 SFX 通过 `CreateProcess` 运行 `RunProgram`,
它无法正确处理带有参数的批处理命令。请使用 `ExecuteFile` +
`ExecuteParameters`(通过 `ShellExecuteEx` 运行)。
- **从桌面快捷方式启动时出现“failed to initialize player”** —— Virtools 加载
组件时依赖于*工作目录*。资源管理器双击会将
CWD 设置为 exe 所在文件夹;快捷方式则使用其“起始位置”字段。它必须是
`...\Bin`,而不是游戏根目录。
- **在 Windows 10/11 上弹出 PCA 窗口**(“此程序可能未正确
安装”) —— 原版 `7zSD.sfx` 没有应用程序清单。
`patch_sfx_manifest.py` 会重建 PE 资源段并注入一个清单
(原有 8 个资源按字节原样保留)。此外,注册一个卸载
条也能满足 PCA 的安装程序启发式判定。
- **在某些 BMP 文件上出现 ffmpeg “Cannot write more than one file with the same name”** ——
原版 Ballance 的 BMP(由 2005 年的 nicej2k 生成)在声明的尺寸之外还
带有约 262 KB 的尾部垃圾;ffmpeg 会尝试将这些垃圾解码为
额外的帧。构建过程会先将其截断至 `bfSize`。
- **杀毒软件**可能会在解压过程中吃掉 `install.bat`/解码器 exe 文件 —— 如果
安装过程在解码步骤失败,请检查隔离日志。
- **无控制台窗口**:`wscript.exe`(GUI 子系统)+ `sh.Run(..., 0, True)`
会完全隐藏运行批处理;错误报告通过退出代码和
vbs 包装器的消息框进行。
## 第三方声明
本项目仅分发**脚本**。在设置阶段,`fetch_tools.sh`
会从官方来源下载以下组件;它们的许可协议适用:
| 组件 | 来源 | 许可证 |
|---|---|---|
| 7-Zip (`7zz`, `7zSD.sfx`) | [7-zip.org](https://www.7-zip.org/) | LGPL |
| libwebp (`cwebp`/`dwebp`) | [WebM project](https://storage.googleapis.com/downloads.webmproject.org/releases/webp/) | BSD |
| ffmpeg | [johnvansickle.com](https://johnvansickle.com/ffmpeg/) | GPL |
| OggDec | [rarewares.org](https://www.rarewares.org/ogg-oggdec.php) | GPL |
| `7zSD.sfx` 清单补丁 | `patch_sfx_manifest.py` (本仓库) | MIT (本项目) |
格式参考:[REWise](https://codeberg.org/CYBERDEV/REWise),
[Archive Team — Wise installer package](http://fileformats.archiveteam.org/wiki/Wise_installer_package)。
## 法律声明
Ballance 是一款商业游戏(Cyparade / Atari,2004 年)。**本仓库
不包含任何游戏文件,而且永远不会。**你必须提供自己合法
获取的副本。对于你如何分享自己构建的安装程序,
作者不持任何立场 —— 那是你自己的责任。请勿将包含游戏的
安装程序附加到本仓库的公共发布中。
## 许可证
MIT(在仓库创建时选择)。本仓库中的脚本
(`build_installer.sh`、`fetch_tools.sh`、`verify_replay.py`、
`patch_sfx_manifest.py`、`tests/`)均基于 MIT 许可协议;第三方组件
仍受其各自的许可协议约束(见上文)。
标签:Cutter, 云资产清单, 安装包制作, 数据压缩, 游戏打包, 逆向工具, 逆向工程, 音视频转码