2026年8月发生了什么变化
在这之前,我做过很多手工逆向。我会反复查看一个函数,直到能解释它,再对照程序验证这个解释。想推进项目,就得亲自花更多时间研究下一个函数,脑子里也要记住越来越多的整体关系。
我的逆向工作主要围绕游戏。我希望通过重建弄清游戏的行为,最终做出移植版或 mod。这篇文章来自这些经历。方法可以迁移到其他领域,但每个领域都需要先明确:什么可以用可靠的基准来验证。
2026 年 8 月,我开始认真探索让编程助手做逆向。有了程序本身和常用开发工具,它究竟能走多远?东方游戏重建给了我一个足够完整的项目来寻找答案。
早期的进展让我吃惊。我不再需要为每一步作选择,调查也能持续推进。对比失败后,助手可能转去查看另一个调用方,写一段诊断程序,再根据结果决定下一步。这种自主性改变了我的工作:我可以更多关注项目方向,以及检查是否可靠。
速度先引起了我的注意。随后我开始想:当前项目结束后,什么会留下来?下一个游戏能不能用上我们刚学到的经验?
TH08:接续前人的工作
TH08,也就是《东方永夜抄》,从接续GensokyoClub 的重建工作开始。他们的公开源码提供了扎实的基础,也留下了构建经验和贡献历史。我在后续工作中保留了这些历史。
导入的历史截至 8 月 10 日的公开检查点。我的独立续作从 8 月 13 日开始。到 8 月 19 日,进度台账中已识别的 1,107 个游戏函数都有了源码。
8 月 24 日,我们提交了可玩的 Linux 重建移植版,距离开始续作约十一天。随后做出了 Web 版。8 月 30 日,原生 Linux 64 位版发布。
最打动我的是,这些工作最终变成了大家能运行的程序。为此必须解决单个函数以外的问题。即使两个函数分别看起来都对,也可能各自使用一份本应共享的状态。
这让对照检查成为工作的核心。我把这些基准称为校验基准(oracle)。代码对比可以检查重建函数是否复现原始指令;运行时检查可以确认已走过的路径是否到达预期状态。助手提出解释,再验证它。发现不匹配,就有了具体的调查方向。
常量错了,却仍然“精确匹配”
校验工具也是人写的软件。TH08 让我清楚地看到,多少结论都依赖着它。
9 月,下游 Switch 移植版报告了一个 bug,最后追溯到道具自动收集。重建源码把玩家火力与 0.0 比较,而原版用的是 128.0,即满火力的阈值。
正常火力不会小于零,所以重建版的火力条件几乎总是满足。玩家到了收集线上方,不用满火力也会吸取道具。条件里的其他例外没有问题,但这一个常量就改变了行为。
可这个函数之前已经通过了精确对比。
重新编译后,常量可能出现在不同地址。比较工具会先调整编译后指令中的地址,再和原版比较,以处理这种差异。问题是,它从未检查被引用地址中实际存放的浮点值。
漏洞就在这里:工具可以把重建指令的引用地址调整为原版的 128.0,而源码里写的仍然是 0.0。指令字节匹配了,源码含义却不同。
9 月 2 日的修复纠正了源码,并让比较工具检查被引用常量的实际字节。随后进行的全面审计检查了 1,548 处浮点常量引用,又在五个已通过验收的函数中发现十二处错误引用。
现在工具会检查每一处这样的浮点常量。测试还会故意使用错误值,确保工具能够拒绝它们。我们也重新检查了曾经通过旧版检查的结果。
校验基准本身也需要重建。修复它,就是修复游戏的一部分。
当团队几乎就是一个人加一群编程助手时,这一点尤其重要。我无法逐行检查它们写出的所有代码,很多信心都来自检查结果。共享校验基准中的盲点,可能在我发现之前就影响许多调查。我必须弄清工具到底验证了什么,再用应当失败的案例测试它。
随着项目推进,检查程序进入了代码仓库。源码修改的理由也保存在里面,还有让下一次会话能够接着做的记录。代码仓库正在成为项目的工作记忆。
每完成一批工作,我们既得到了还原的代码,也改善了下一批工作的环境。
两种不同的重建理念
GensokyoClub 的公开 README明确表达了对这种工作的异议。公告说,项目完成前,后续开发将在私下进行。其中有这样一段话:
“这个领域里出现了利用我们成果的投机者(AI 反编译和移植项目),给未来的反编译工作留下了不好的印象……”
公告也提到了维护者承受的心理压力。他们的贡献政策不接受主要由 AI 生成的 PR。他们用业余时间投入了艰难的工作,这些成果让我的续作成为可能。我尊重他们付出的努力。我想讨论的分歧,是重建应当如何推进,以及贡献应当如何评价。
在我熟悉的手工流程中,理解一个函数和重建它,通常由同一个人完成。项目非常依赖这个人的专业能力。很多推理发生在工作过程中,所以对贡献者本人的信任很重要。
已有项目本就会在源码和构建工具中保存知识。对我而言,变化在于:编程助手能利用这些知识,自主推进下一次调查。
在我的续作中,我来确定目标和验收标准,助手有充分的调查自由。它提出的重建方案必须通过相应检查。我希望其他人能够看懂我们为什么选择这个实现,即使大部分工作由助手完成。
这可能是一个艰难的转变。多年的细致工作,可能成为一个推进得更快的续作的基础。这会带来真实的归属与署名问题,也改变维护者在接受贡献前需要了解的事情。
工业化的比喻有助于理解这一点。手工作业的过程往往依赖操作者的技艺。机器改变了这些技艺发挥作用的位置,但仍然需要人设计流程、识别错误产出。不同社区可以选择接受多少这样的变化。
我的选择是公开继续,注明继承的工作并保留其历史。我希望新工作可以被审查。这样,我们才能探索这种方法能走多远,也从沿途的问题中学习。
来源:GensokyoClub 的README 公告(于 2026 年 10 月 10 日核对)及其贡献政策。上面的引文为节选译文。TH08 的贡献署名与来源记录说明了独立续作的起点。
TH095:经验开始产生复利
TH095,也就是《东方文花帖》,让这些经验的价值更容易看清。仓库于 8 月 29 日建立,当时台账中确认的游戏函数数量为零。我们仍需研究游戏本身,但已经更清楚如何开始重建,以及怎样持续推进。
到 9 月 7 日,全部 697 个已识别游戏函数都有了源码。9 月 8 日,其中 696 个通过了精确对比。9 月 9 日,整个程序完成链接。9 月 10 日,Windows i386 重建版被记录为可玩,距离初始化约十二天。
这比第一个项目的速度更让我兴奋。新目标能受益于另一个游戏的工作。经验已经进入工具,也进入了项目的组织方式。
例如,TH08 教会我们尽早关注整个程序。如果几个还原函数依赖同一份状态,分别对比它们仍然会留下一个关键问题:它们能否一起正常工作?这条经验影响了 TH095 的整程序构建方式。
经验只记在我脑子里,我在场时它才有用。变成其他会话能运行的检查后,即使我离开,它仍能帮助项目。下一个助手可以利用检查结果,不用重复当初得出这条经验的调查。
浮点常量的 bug 也属于这份记忆。它说明,检查引用时,还要检查引用背后的数据。把修正保存在代码旁边,可以帮助后续项目避免继承旧工具的盲点。
方法本身成了下一个游戏的起始材料。我们可以把更多精力放在新目标真正不同的地方。
后来加入的人也能受益。他们可以查看某个决定,重新运行检查,再继续工作。不用先重走整个项目的历史,才能理解源码为何这样写。
TH04:换了架构,工作方式仍然适用
TH04,也就是《东方幻想乡》,把这套工作带到了 PC-98 DOS 时代。这次是一个由四个程序协作的 16 位环境。理解硬件行为,需要和 Windows 游戏不同的证据。已有的ReC98 工作同样提供了宝贵的知识与源码材料。
DOS 重建版现在已经能运行。我手工打完了完整的 Normal 路线,看到结局,并检查了存档。目前正在做原生 64 位移植。先得到一个正常工作的 DOS 版,就为移植提供了参照。
架构改变了要调查的问题,也改变了用来验证的编译器和运行时。但助手依然能沿着问题找到结果,再用结果指导下一次实验。
比如从游戏过程切换到结局:哪些状态需要跨越这个边界?哪个程序负责它们?我们可以对照 DOS 原版调查。只要证据和检查可用,助手就能像研究 Windows 游戏一样推进这个问题。
这就是 TH04 对这篇文章的意义。大幅的平台变化,并没有迫使我们重新发明一套工作方式。架构决定了问题,工作流程仍然提供了解决问题的方法。
做 64 位移植时,我们可以把新实现与 DOS 上已经还原的行为对照。重建得到的知识为移植提供了基础。
截至 2026 年 10 月 10 日:DOS 重建与手工测试 · 64 位移植。移植仍在开发中。
从精确还原到可读源码
重建版能运行之后,我还希望别人能读懂它。
对我而言,汇编和原始偏移就像老朋友。我知道,这种“可读”的定义有点特别。多数人更希望直接看懂游戏逻辑,而不用在脑中记住可执行文件的内存布局。
这就需要语义重建。一个还原字段可能仍然只有偏移作为标识。我们追踪游戏如何使用它,直到能解释其作用,再依据证据赋予合适的名称和类型。推理过程和源码一起保存,后来的人就能知道这个解释从何而来。
移植时,语义尤其重要。绝对地址能告诉我数据在旧程序中的位置,却很难帮助 64 位实现决定哪个对象应当持有这份状态。要正确迁移行为,就得还原旧内存访问背后的关系。
我现在采用这样的顺序:
- 先建立精确还原的基线。用当年的编译器编译重建代码,与原始可执行文件对比相关代码和数据。记录尚未解决的差异,让下一阶段有明确的起点。
- 在原平台上构建,并实际游玩。用原架构和编译器把各部分链接为真正的程序,走过重要的游戏路径。这能发现单函数对比漏掉的共享状态或初始化问题。
- 对照两套基准做语义重建。每次处理游戏中一个完整、连贯的部分,明确还原源码的含义。改善代码表达,同时保留精确对比和可玩的原平台构建。
- 再做现代平台移植。把已经确定的行为带入新环境,例如原生 64 位构建。原平台重建版继续作为比较移植行为的参照。
第二阶段的可玩构建,在第三阶段成为第二套校验基准。第一套检查修改后的源码是否仍然复现原版相关代码和数据;第二套检查重建程序是否能构建,并在实际测试的路径上保持正确行为。
它们能发现不同类型的错误。类型修改可能改变生成的指令。状态归属的修改,可能让游戏的两部分各自使用一份状态。保留两套检查,助手就能在继续重构之前,针对具体的失败展开调查。
命名也需要自己的证据。精确对比不能证明某字段一定是“无敌时间”。我们必须从游戏如何写入和使用它来确认。如果含义仍不明确,中性名称比自信的猜测更有利于下一位读者。
这个顺序来自项目中的教训。TH08 在后来的一些原平台审计之前,就已经有了可玩的移植版,一些缺陷因此更难察觉。Factory 目前的工作流程把原平台构建放在前面,让语义重建先有参照,再开始移植。
精确重建提供基准,语义重建让还原的知识可用。移植随后建立在两者之上。
为什么这是工业化的转变
这些项目改变了我投入注意力的地方。助手能自主推进大部分调查之后,改善它们的工作环境,就成了我最值得做的事情之一。一项工具的改进,可以帮助之后所有需要它的函数。
自主性在这里很重要。下一步该怎么做,常常在实验失败后才清楚。助手需要足够的自由,沿着结果探索意料之外的方向。如果每一步都要等我指定,大部分工作仍然绑在我的注意力上。
我预期助手会提出错误假设。关键是我们能否验证它们,并从结果中学习。失败的检查应该帮助它理解错误,再次尝试。我仍要判断:累积的证据是否足以支持某个项目里程碑。
REA 让助手能够使用分析工具。调查某函数的调用方时,它可以直接继续检查那个调用方。重建项目提供编译器和自己的对照检查。助手用它们验证提出的源码,看看解释在哪些地方成立。
TH08 的 bug 说明,检查工具本身也值得认真工程化。相同的比较用于数百个函数时,一个漏洞的影响可能远大于某个实现中的错误。测试检查器,能改善所有后续工作得到的反馈。
工业史中有一个合适的例子:博尔顿和瓦特在1796 年引入蒸汽机示功器,帮助调节阀门。记录式示功器能绘出活塞行程中的压力变化,让人看到机器内部的运行情况。我们的比较工具也有类似作用:改进机器时,能看清它究竟做了什么。
我们正处于这场工业化转变的早期。许多基础设施还不成熟。助手推进工作的速度,可能超过原有检查的承受能力,所以流程也要一起发展。共享工具出现缺陷时,要修好它,并重查受影响的结果。下一个项目才能继承更可靠的工具。
任何一段对话都有实际的长度限制。大型重建完成之前,对话就会结束。代码仓库必须让下一次会话能继续工作,而不丢失上一次决定背后的理由。
Touhou Reconstruction Factory正是为此而建立。它提供一种共用方式,让项目把检查和经验传递下去。一个游戏的工作,可以改善另一个游戏的起点。
这就是工业化比喻对我的意义:经验开始进入别人也能使用的工具。改善工具,就能改变下一个人或下一个助手能完成多少工作。
现在值得尝试的项目
速度的意义在于,它改变了是否开始一个项目的决定。某个游戏也许很值得逆向,却需要我投入远超现实所能承受的精力。很多项目因此一直停留在想法里。
现在,我看到了通过一次次调查持续推进它们的可能。得到能运行的重建版,让移植更可行;还原可读的语义,让别人更容易探索 mod。理解游戏的投入,可以在第一版运行之后继续带来回报。
现在看到一个陌生程序,我会问:怎样的工具访问、反馈和知识积累,能让助手可靠地推进这个项目?
这个问题让我考虑以前会放弃的项目。每个项目都能改善下一个项目的工作方式。我想继续探索,这能带我们走多远。
项目里程碑与来源
这些日期是已记录的项目检查点,于 2026 年 10 月 10 日对照公开 GitHub 历史核实。耗时是提交之间经过的日历时间。“有源码”“通过精确对比”“完成构建”和“得到运行结果”是不同的里程碑。
- TH08:8 月 13 日开始续作、8 月 19 日源码台账、8 月 24 日 Linux 移植、8 月 26 日 Web 版、8 月 30 日 64 位 Linux 发布。
- TH095:8 月 29 日初始台账、9 月 7 日源码台账、9 月 8 日对比结果、9 月 9 日链接、9 月 10 日可玩构建记录。
- TH04:10 月 10 日交接记录包含可运行的 DOS 重建版、维护者完成的 Normal 路线测试,以及当前的 64 位移植阶段。
- TH08 校验基准修正:道具自动收集 bug 报告、源码与比较工具修复、全部浮点常量审计。
- 语义重建:TH08 可读性指南和Factory 的阶段顺序及两条验证路径。
- 工业史:英国科学博物馆集团的蒸汽机示功器记录介绍了 1796 年的引入及压力记录机制。
- 方法:Factory 的助手自主性与跨游戏知识文档保存了工作原则和经验。