07 拆解程序

起点:程序是游戏的「黑盒」

其他拆解(玩法/结构/关卡/手感/美术/资源)面对的是可观察的产物——规则、画面、手感都能直接感受。

程序是黑盒:

1
2
你看到的:画面、操作反馈
你摸不到的:内存里的对象、函数调用链、数据流向

拆解程序,就是面对一个只有外部行为的黑盒,恢复它的内部结构。


一、程序拆解的本质是逆向

游戏工程的完整地图里有五类工程:

1
2
3
4
5
软件工程   创造世界(从零写出游戏)
游戏工程 定义世界(规则、数值、平衡)
调试工程 观察世界为什么异常
静态分析 从代码推断世界结构
逆向工程 从已存在的世界反推规则

其中逆向工程就是程序拆解

1
2
正向(写游戏): 设计 → 代码 → 可执行文件
逆向(拆游戏): 可执行文件 → 反汇编/内存 → 结构 → 设计

游戏逆向工程 = 从已经存在的游戏程序里,反推出它的结构、数据、规则。


二、程序拆解的四层递进

游戏分析工程是四层递进(21 步):

1
2
3
4
5
6
7
8
9
10
11
第一层:外部观察
运行游戏,观察行为、画面、输入输出

第二层:接口探测
用工具探测进程、窗口、文件、网络交互

第三层:内存分析
搜索内存、观察数据变化、识别结构体

第四层:代码恢复
反汇编、静态分析,恢复函数与调用关系

每一层回答的问题不同:

1
2
3
4
外部观察   它在做什么
接口探测 它和外界怎么交互
内存分析 它内部的数据是什么样
代码恢复 它内部的处理逻辑是什么

三、程序拆解的核心动作

1. 画软件地图

从整体上先定位:

1
2
3
模块结构(主程序 / 子程序 / 插件)
文件与资源(哪些文件、哪些资源)
入口点(从哪启动、初始化顺序)

2. 记录关系而不是地址

逆向信息保存的核心原则:

1
2
3
记录「访问路径」不记录「偏移」
记录「语义位置」不记录「数字」
记录「关系」不记录「地址」

因为地址会变,关系不变。

3. 功能树

把一个程序的功能拆成树:

1
2
3
4
5
6
7
游戏程序
├── 启动
├── 主循环
├── 渲染
├── 输入处理
├── 逻辑更新
└── 资源加载

再往下每一层继续拆,直到每个功能都能定位到:

1
功能 → 对象 → 数据 → 函数

形成「功能到对象数据函数」的知识网络。

4. 数据视角与功能视角

同一个程序有两种拆法:

1
2
数据视角:内存里有哪些对象、结构体、字段
功能视角:程序对外提供了哪些功能、行为

两者互补:

1
2
数据视角回答「有什么」
功能视角回答「能做什么」

四、识别数据结构的技巧

从内存里识别结构体,有几套反复出现的规律:

1
2
3
4
5
6
难以搜索的数据 → 从对象和引用入手(先找对象再找数据)
成倍增加的数据 → 数组 / 列表(数量 × 单个大小)
倍率字段 → 数量字段与单个大小的组合
连续偏移 → 数组而不是结构体
读中间偏移 → 字节切片与对齐问题
结构体 → 不是每个偏移都是成员(有对齐、有间隔)

核心判断:

1
数据变化 → 快照对比 → 结构体展开

观察数据怎么变,比猜测数据是什么更可靠。


五、程序拆解与游戏的关系

游戏程序比普通程序更难拆,因为:

1
2
3
游戏有主循环      所有逻辑在循环里反复执行
游戏状态变化快 数据结构不断被修改
游戏是实时系统 时序影响行为

所以拆游戏程序要特别关注:

1
2
3
主循环的每一帧做了什么
对象生命周期(创建/销毁/复用)
事件与状态变化(输入 → 状态 → 渲染)

六、与其他线的关系

1
2
3
4
5
拆解结构     结构是设计视角,程序是运行视角
拆解玩法 玩法是规则,程序是规则的实现
拆解美术/资源 程序是加载与使用它们的执行者
逆向工程论 程序拆解是逆向工程论在游戏领域的应用
拆解与组织 程序拆解 = 对运行态黑盒的「组织还原」

程序线是所有拆解里最「硬」的一条——其他拆解靠观察和推理,程序拆解要靠工具、内存、反汇编,是逆向工程论的直接落地。


小结

1
2
3
4
5
6
7
8
9
10
11
12
程序 = 黑盒
拆解程序 = 逆向工程在游戏领域的应用

四层递进:外部观察 → 接口探测 → 内存分析 → 代码恢复

核心动作:
画软件地图(整体定位)
记录关系不记地址(信息保存)
功能树(功能 → 对象 → 数据 → 函数)
数据视角 + 功能视角(有什么 / 能做什么)

识别数据:观察数据变化比猜测结构可靠