---
title: 逆向工程需要更大的模型吗？ | REA
url: https://rea.tools/zh-CN/blog/reverse-engineering-models/
---

[首页](https://rea.tools/zh-CN/) / [博客](https://rea.tools/zh-CN/blog/) / 模型与逆向工程

随笔

# 逆向工程需要更大的模型吗？

作者 N0zoM1z0 · 2026 年 10 月 13 日

要点

- **模型能力会影响编程助手能提出哪些假设。** 后来的会话解决了此前工作未能解决的问题。
- **熟悉的编译器为专用模型提供了具体的学习对象。** 有些精确匹配依赖细小但可以复用的源码模式。
- **也要给代码仓库里的知识一个公平的对照。** 较小的模型配上良好的检索，可能已经掌握足够的知识推进工作。
- **训练模型选择下一个有价值的实验，同时检验它使用的校验基准。** 反馈是否有用，取决于校验基准究竟检查了什么。
- **结合时间和成本，评估通过验证的重建成果。** 这是我希望从整个编程助手工作流中获得的结果。

## 更强的模型改变了什么

从 2026 年 8 月开始，我一直在探索：如果给编程助手访问程序的能力，以及验证自身工作的手段，它能独立完成多少逆向工作？我的经验主要来自游戏重建，尤其是东方系列。随着我更换模型，代码仓库记录了每次工作还原出的内容。

这些工作很大一部分追求精确重建：用固定版本的历史工具链编译我们维护的源码，检查它能否复现目标函数。当后来的模型解决了早期工作卡住的问题，我们可以从源码变化中看出，是什么促成了这次进展。

### 临时值必须同时存活

TH09 中一个攻击函数的大部分逻辑已经还原，但编译器对临时结果的存储安排仍然与原版不同。剩下的问题在于：这些结果的生命周期应该多长，编译器何时可以复用它们的存储空间？

[GPT-6-Sol 的一次工作记录](https://github.com/N0zoM1z0/th09/commit/de63c0f9121963f3a6b1ab5471c4878625fd3425)表明，尝试几种常见的源码写法后，差异仍未消除。后来，[GPT-6.1-Sol 重新研究这个问题](https://github.com/N0zoM1z0/th09/commit/52929ed7c299f1a5f29cc13964e22510145fd616)，提出了一个有价值的假设：关键可能在于这些临时值的生命周期。

这个函数会产生临时结果，再把它们复制到动画的位置数据中。在 C++ 中，临时结果会一直存在，直到使用它的表达式执行完毕。把实际操作放进同一个表达式，就能让这些结果同时存活，编译器也就不能为它们全部复用同一块存储空间。

其中一个结果仍然与稍后用于碰撞检查的值共享存储。给那个值单独的生命周期后，最后一处重叠也消失了。经过几次有针对性的实验，**一次干净的重新构建确认，整个函数都已匹配**。

我感兴趣的是，发现与验证如何共同推进工作。生命周期的假设给编程助手指明了新方向；编译器的反馈又帮助它逐步调整源码，直到找到匹配的写法。

### 换一种控制流结构

TH09 的另一个函数说明了，新方向为什么重要。这次的难点是多个分支如何共享末尾的操作。[GPT-6.1-Sol 之前的工作](https://github.com/N0zoM1z0/th09/commit/f8d12d72aaf02212ee1b585a8f3f86d7ed000269)已经让函数的一些部分匹配，但分支汇合的方式仍与原版不同。

[GPT-6-Astra 改写了外围的控制流图](https://github.com/N0zoM1z0/th09/commit/da33a646221198ceb7f3df2b96e2ca0e9b2f705f)，让主要路径汇入共同的最终更新与返回。在这种源码结构下，编译器合并分支的方式与原版一致。整个函数实现了匹配，[另一次独立的重新构建也确认了这一结果](https://github.com/N0zoM1z0/th09/commit/5f825b28a862f8e1a6d4aea2f78a42f04c09a1c0)。

**换一种表达方式，打开了更有价值的搜索空间。** 这两个例子让我认真看待通用模型的能力：编程助手可能花很长时间尝试局部变化，才找到一种更好的整体写法。

不过，后来的工作也继承了之前的源码和失败记录。这些积累本身就是优势的一部分。历史记录让我们可以检查发现及其验证过程；要区分模型能力和继承经验各自带来的帮助，还需要对照实验。

这正是我觉得有趣的地方。有些进展来自新的表达方式，剩下的大量工作则是在熟悉的编译器上试验不同写法。其中有多少需要广泛的推理能力？又有多少可以通过反复接触这个编译器和这些代码来学会？

## 为什么专用模型可能做得很好？

东方系列给了我们一个具体的理由，去期待经验积累能发挥作用。大量游戏代码出自同一个作者 ZUN，因此，把反复出现的编程习惯作为初始假设是合理的。代码仓库也提供了实际例子：相似的循环和辅助函数组织方式，曾为其他游戏的重建提供假设。

把编译器也考虑进去，这些源码模式就更加具体了。在固定版本和选项下，源码的小变化可能稳定地产生不同的机器码。其中一些规律藏得很深。

以 TH095 为例，**连局部变量的名字，都可能改变 VC7.1 为它安排的存储位置**。只移动声明并不能解决布局问题，但先前重建的一个背景函数揭示了会影响编译器选择的命名模式。这为[重建 `Supervisor::LoadDat`](https://github.com/N0zoM1z0/th095/commit/26bb64bdb093a13f73abd0ee8ae7ce199ee4658f)提供了更有希望的假设。

把这个模式用于表示文件大小的变量，不增加额外存储就得到了所需布局。随后，整个函数实现了匹配。

这类细节非常具体，通用模型第一次接触时未必知道。而针对这个编译器训练的专用模型，可以接触许多类似案例，学会哪些源码变化值得优先尝试。

当我们已经理解函数行为，只剩最后的匹配差异时，这个机会尤其明显。此时的问题是：这个编译器会把哪一种普通写法编译成眼前的指令？专用训练可能让模型更高效地提出这些写法，而最终由目标程序决定哪些假设成立。

但这些模式必须保留适用的上下文。TH08 使用的 Visual C++ 版本早于 TH095 和 TH09。TH04 用的是另一种 DOS 时代的编译器，其[玩家逻辑重建](https://github.com/N0zoM1z0/th04/commit/6dce0a79d5b931f0e2a08475b90e0c33d2321b98)需要不同的假设，既涉及源码写法，也涉及编译后的代码如何链接成可执行文件。同一作者为我们提供了先验，具体目标则告诉我们它是否适用。区分这些情况，也是专用模型需要学会的事。

## 这些经验应该存在哪里？

在决定通过训练让模型学会这些模式之前，我会先看看代码仓库里已有的知识。在[上一篇文章](https://rea.tools/zh-CN/blog/touhou-reconstruction/)中，我写过：仓库正在成为项目的工作记忆。这里保存着对编译器的认识，也保存着相关源码和失败实验，让这些经验有据可查。

检索这些记录后，编程助手可以从已知结果出发，看看我们是如何得到它的，也可以避开在相同条件下已经失败的方案。模型的参数没有改变，工作的起点却提高了。

重建 TH09 的敌人生成函数时，[GPT-6-Luna-max 的一次工作](https://github.com/N0zoM1z0/th09/commit/1eb843383941d00065622a9e353146c4bb96979e)从 TH08 对应的源码中找到了假设。之前的写法提示了循环该如何组织，以及内部失败该如何处理。TH09 自身的证据补上了游戏特有的细节，干净的重新构建确认了整个函数的匹配。

**“模型不知道这个编译器特性”和“模型不会利用它”，是两个不同的问题。** 检索可能解决前者，但把知识变成有价值的候选源码，仍然需要能力。如果候选方案失败了，模型还得判断这次结果对下一次尝试意味着什么。知道相关模式，只是这个过程的起点。

所以，在任何对照实验中，我都会加入一个具备良好检索能力的小型通用模型。给它相同的经验库，才能看清训练究竟增加了什么：更好的候选方案、更好的反馈后决策，还是两者都有？

## 学习选择下一个有价值的实验

反馈之后如何决策，是我最想研究的部分。在编程助手驱动的重建中，模型提出解释，再用程序来验证。即使候选方案失败了，结果也可能缩小剩余的可能性，提示下一步更值得尝试什么。

再看前面的临时结果例子。最终源码展示了成功的写法，但得到它的过程包含更多信息。下面的每次实验，都帮助我们确定了还有什么需要改变。

| 实验 | 结果告诉了我们什么 |
| --- | --- |
| 尝试另一种复制结果的方式 | 复制代码改变了，但函数仍有差异。 |
| 直接使用返回值 | 复制方式与原版一致，但临时存储布局仍有差异。 |
| 让临时结果同时保持有效 | 它们得到了各自的存储空间，但其中一个仍与稍后用于碰撞检查的值重叠。 |
| 让碰撞检查的值拥有独立存储 | 一次干净的重建确认了完全匹配。 |

上面攻击函数重建中精选的几个实验，按它们带给我们的启发分类。

保存这个过程的训练记录，比单独保存最终源码能教会模型更多东西。它把每个改动、观察到的结果和下一步决策联系起来。无效的尝试也值得保留：后来的编程助手可以据此知道，在这个上下文中，哪些假设已经检验过。

**我希望模型学会如何利用反馈。** 结果没有变化，可能意味着该重新考虑这个改动；差异发生变化，则可能指向另一个原因。当局部修改不再提供有效信息时，编程助手应该可以重新考虑源码的整体表达，或者回头检查证据。

学会这些选择，需要自主性。有时，更有价值的下一步是检查另一个调用者，而不是再修改一次源码并编译。如果强制按照固定顺序改写，就会剥夺这种选择，也失去一部分我们希望模型学会的行为。

## 为什么逆向工程值得用来探索强化学习

范围明确的重建任务，为研究这些选择提供了一个实际环境。目标和编译器版本固定之后，许多源码实验都能快速给出可重复的反馈。编程助手可以编译候选源码、检查差异，再根据观察选择下一步。

强化学习可以利用这些反馈，训练模型的决策过程。候选源码通过明确定义的检查，就给出了一个具体成果；而尝试的过程，让我们可以看到实现它花了多少功夫。

已有研究支持这个方向。[LLM4Decompile](https://aclanthology.org/2024.emnlp-main.203/)研究专门用于反编译的模型。[AutoDecompiler](https://arxiv.org/html/2606.16162v1)利用编译和执行反馈，训练多轮改进能力。这些研究关注的是功能还原。对于我们的工作，我会以它们为起点，研究一个相关任务：找到能复现历史编译器输出的源码。

不过，要得到这样一个定义明确的任务，有时得先确定函数负责哪些资源，或者设计新的方法观察程序运行时的行为。在 TH08 中，[一次碰撞差异最终追溯到原版处理浮点计算的方式](https://github.com/N0zoM1z0/th08/commit/af9cb1d3e839b15a78b47ac1701506083cc82847)。编程助手必须先弄清楚该测量什么，才能验证有价值的修正。

这提示了能力全面的模型的另一个作用：先把问题变得可验证。验证手段建立起来后，我们才可以研究，学出来的搜索策略能走多远。

## 当校验基准出错时

一旦用某项检查来训练模型，它的覆盖范围就会成为学习环境的一部分。我把这种参考标准或校验基准称为 oracle。即使它能给出可重复的答案，我们也必须知道，这个答案覆盖了什么。

TH08 展示了检查范围之外可能藏着多少问题。一些重建函数使用了错误的浮点常量，却仍然通过了精确比较。比较器会先调整重定位地址，再检查指令；但只有明确登记过的常量，才会进一步检查地址指向的值。其他常量引用，即使值没被检查，也可能通过。

为了补上这个漏洞，[一次更全面的审计](https://github.com/N0zoM1z0/th08/commit/a393f400786e4cc6cbb1000af0dad3276da12c78)在已经通过检查的函数中找到了错误常量。有一个计算中，重建源码加的是 `1.0f`，而原版加的是 `32.0f`。

**如果用旧检查的结果作为奖励，模型可能学会生成错误的重建源码。** 我们没有用这个校验基准训练 RL 模型；实际观察到的是检查本身的漏洞。但如果把它用作奖励，同一个盲点也会进入学习环境。

功能测试也可能存在类似盲点。[针对 LLM 反编译器的差分模糊测试研究](https://arxiv.org/html/2609.05370v1)发现，在已有测试之外，程序行为仍可能不同。因此，理解“测试通过”时，必须看它实际覆盖了哪些情况；理解“指令匹配”时，也必须看它检查了哪些字节和数据。

在把任何一种检查用作奖励之前，我都会用刻意构造的错误来测试它。我还会把最终验收机制放在候选源码可修改的范围之外，让模型通过正确重建来满足检查。否则，直接复制目标程序的字节数组，也可能骗过简单的评分，却没有还原出有用的源码。

**改进模型和改进它的校验基准，属于同一个研究问题。** 模型越擅长优化我们给它的反馈，我们就越需要理解反馈本身。

## 值得做的对照实验

具备这些检查之后，我会从一组固定的 VC7.1 任务开始比较。先为强通用模型和小型通用模型建立基线，再给小模型加入仓库知识，观察检索带来的变化。接着比较监督训练的专用模型，以及在此基础上进行 RL 训练的版本，看看训练增加了什么。

为了让比较有意义，每个模型都应获得相同的目标证据和工具。专门比较训练效果时，还要固定基础模型和可用知识。重复实验有助于区分可靠的搜索策略与偶然成功的候选方案。

我还会区分两种起点：从指令开始重建函数，以及在已有源码中消除最后几处差异。专用模型可能很擅长后者，而通用模型承担了到达这个阶段的大部分工作。分别评估，才能看清这种分工。

两类任务都需要真正未见过的测试案例。东方系列的相关游戏会共享引擎代码，只留出某个游戏，仍可能让几乎相同的函数进入训练集。我会改为按相关源码家族留出测试集，并把它们通过验证的答案同时排除在训练数据和检索库之外。

在这些案例上，要统计的是完整、独立验证过的匹配成果。给每个模型相同的候选数量或编译次数预算，可以比较搜索质量。记录总耗时和总成本，包括编译，才能知道这种质量是否转化成了高效的工作流。训练成本也要单独计算。

两种角度都重要。一个便宜的提议，如果导致大量无效编译，整个工作流仍可能很贵。反过来，较慢的模型如果更早找到有价值的实验，也可能更划算。对照实验应当反映这些成本。

只统计通过验收的结果，也能帮助我们合理看待中间进展。TH09 的一个[录像保存候选方案](https://github.com/N0zoM1z0/th09/commit/ab72fd77728293fc0beacfc656ca701b0e266016)看起来很有希望，因为编译后函数的大小符合预期，但完整比较仍发现大量差异。编译器改变指令排列，也可能让候选源码看起来更接近，却没有解决根本问题。这些诊断可以指导下一步，但若要奖励“变得更接近”，我会先对照完整验收检查，确认这种奖励有效。

我想看这些结果呈现出什么规律。如果专用模型在熟悉的编译器上表现很好，换了工具链后，这种优势还在吗？当双方都拥有良好的检索能力时，训练还能增加多少价值？这些答案能帮助我们决定，每类模型最适合用在哪里。

## 这意味着怎样的编程助手？

如果不同模型在不同阶段各有所长，一种有价值的安排可能是：让能力全面的编程助手可以调用专用模型。当任务变成一种熟悉的编译器搜索时，它可以请专用模型提出候选方案。如果结果开始说不通，通用编程助手可以回头检查目标证据，或者调查测量本身。

在这样的安排中，专用模型成为编程助手可以随着调查推进自行选择的工具。编程助手仍保留改变方向的自由，正是这种自由让前面那些突破成为可能。

这自然延续了上一篇文章中谈到的工业化转变。能够开展更多实验，会改变我们组织工作的方式，也让我们有理由追问：哪些决策需要全面的判断，哪些可以通过反复积累某项具体技艺来改善？

目前，最强的通用模型解决了我过去没能解决的问题，因此在我的工作流中占据了一席之地。正是这些成功，让我想更仔细地研究过程：有多少依赖模型能力的广度？又有多少可以交给专门学习这类重建的模型？

**这些代码仓库让我们有机会验证这个问题。** 我想利用这些记录建立对照实验，看看我们能学到什么。

证据与模型归属

[详细证据记录](https://github.com/morluto/rea/blob/main/website/evidence/reverse-engineering-models.md)包含历史比较结果与实验背景。

这些例子来自链接提交中记录的历史函数级比较。整款游戏的运行时检查属于另一个里程碑。相关源码与匹配记录核查于 2026 年 10 月 13 日。

TH09 中的标签 `gpt-dots` 对应 GPT-6-Astra。`gpt-web` 会随当时使用的模型变化，因此仅凭这个标签无法确定某次运行的具体模型。其他引用提交中的明确模型名，提供了对应的归属记录；这些历史记录并没有统一的单次运行成本或投入统计。

- **TH09 临时值生命周期：**[早期上下文检查](https://github.com/N0zoM1z0/th09/commit/de63c0f9121963f3a6b1ab5471c4878625fd3425)与[完整的干净重建](https://github.com/N0zoM1z0/th09/commit/52929ed7c299f1a5f29cc13964e22510145fd616)。
- **TH09 Front 回调：**[未匹配的诊断区域](https://github.com/N0zoM1z0/th09/commit/f8d12d72aaf02212ee1b585a8f3f86d7ed000269)、[Astra 提出的新控制流图](https://github.com/N0zoM1z0/th09/commit/da33a646221198ceb7f3df2b96e2ca0e9b2f705f)与[通过验收的重新编译检查](https://github.com/N0zoM1z0/th09/commit/5f825b28a862f8e1a6d4aea2f78a42f04c09a1c0)。
- **编译器知识：**[TH095 标识符分桶规律的复用](https://github.com/N0zoM1z0/th095/commit/26bb64bdb093a13f73abd0ee8ae7ce199ee4658f)、[TH04 玩家源码与链接顺序](https://github.com/N0zoM1z0/th04/commit/6dce0a79d5b931f0e2a08475b90e0c33d2321b98)、[Luna 完成的 TH09 敌人生成函数匹配](https://github.com/N0zoM1z0/th09/commit/1eb843383941d00065622a9e353146c4bb96979e)。
- **检查与诊断：**[TH08 浮点常量审计](https://github.com/N0zoM1z0/th08/commit/a393f400786e4cc6cbb1000af0dad3276da12c78)、[TH08 数值问题调查](https://github.com/N0zoM1z0/th08/commit/af9cb1d3e839b15a78b47ac1701506083cc82847)、[TH09 录像保存重建](https://github.com/N0zoM1z0/th09/commit/ab72fd77728293fc0beacfc656ca701b0e266016)。

文中提出的专用模型与 RL 对照，属于未来实验。项目历史为这些想法提供了依据；本文尚未评估经过训练的专用模型。
