基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
  • 知识卡片碎片时间过考点
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
    • AI 热点每日 AI 资讯与动向
AI 工作台
简历
旧版
AIHT
内容
精选全部 AI 动态热点榜AI 日报收藏
分类
模型行业编程产品技术观点开源
更多
Agent 接入
返回首页开发者导航
AIHT
精选 / 资讯详情
8.0
热点
AI SCORE
技术实践2026-11-09 15:54

AI逆向GBA实录:找到重力,未解跳跃

dev.to · AI#逆向工程#MCP#游戏开发
Editor brief · 编辑速览

作者使用开源REA MCP服务器与Claude分析一份无源码、无符号的GBA ROM,尝试恢复角色移动和跳跃参数。实验提取了部分物理参数并用于原创浏览器游戏,同时披露未能还原的跳跃逻辑。

文章思维导图
Knowledge map
拖拽缩放
AI deep read

AI 深度解读

把一个没有源码、符号和文档的 GBA ROM 交给 AI,能找回角色的跳跃手感吗?作者用 Claude Opus 5.5 配合 REA 和 Ghidra,找到了重力、移动速度等参数,却没找到起跳速度和最大下落速度。

这次实验值得看的,是它把「工具证据」「代码解释」和「自行调参」分开了。对于用 AI 读陌生代码的程序员,这比生成一个能跑的游戏更有参考价值:找到常量只是开始,证明它代表什么才是难点。

AI 能读懂 ROM,靠的是工具和证据

实验对象是 Aladdin Game.gba,大小为 3,987,712 字节。GBA 将卡带 ROM 映射到固定地址执行,它没有常见可执行文件里的导入表和函数名。直接把十六进制数据贴给模型,很容易得到听起来合理的猜测。

作者使用的 REA,全称 Reverse Engineer Anything,是一个开源 MCP server。它让 AI 能调用真正的逆向工具,执行加载二进制、反编译函数、读取字节、追踪调用者和交叉引用等操作。底层使用 Ghidra,这是 NSA 在 2019 年开源的逆向工具。

模型负责提出搜索方向,反编译器负责返回可检查的证据。

REA 每次工具调用都会返回 evidence_id、文件的 SHA-256、Ghidra 版本和限制说明。于是,「某函数写入了重力常量」可以追溯到具体文件和反编译结果。它分析的是临时副本;注释存在会话数据库里,关闭时默认删除,需要保留则请求 snapshot。

环境搭建反而更费时间。作者先升级 Node,随后发现 Homebrew 安装的 Ghidra 太新,与 REA 6.8.0 不兼容,只好另装 Ghidra 12.1.4。官方压缩包缺少 Apple Silicon 原生反编译器,Claude 从随包 C++ 源码构建,第一次生成 x86_64,第二次才改成 arm64。期间还处理了 JDK 升级,最终通过 rea doctor,注册到 Claude Code 并重启。

这里还有一个影响结论的细节:REA 尚未配置成功时,Claude 已用 Ghidra headless scripts 做过首轮分析。之后才通过 REA 重跑关键步骤。因此,后来的少量工具调用不能当作从零定位问题的成本。

没有函数名,就从行为反向找

REA 没有 GBA loader,加载时需要指定 format: "raw-binary"、architecture: "arm",并把 entry_point 设为 0x08000000,也就是卡带映射地址。

文件头显示标题为 ALADDIN、游戏代码为 BADP,末尾的 P 表示欧洲版本。作者据此识别为 2004 年 3 月在欧洲发行的 Capcom SNES 移植版。Ghidra 自动分析找到 1,732 个过程、448 个字符串;首轮分析还发现,代码几乎都是 Thumb,即紧凑的 16 位指令集,并调用 GBA BIOS 完成 LZ77 解压、除法和平方根计算。

定位输入有一个明确入口:0x04000130,即 KEYINPUT 寄存器。它采用低电平有效,按钮按下时对应位为 0。Claude 顺着引用找到 0x08014d9c,发现函数会取反输入,再重新映射十个按钮。

作者推测这是适配 SNES 按键布局的移植层,但没有把推测写成已证实的事实。后续游戏逻辑读取的是映射结果,继续找跳跃判断就必须沿这条路径走。

重力则靠另一种行为特征定位:寻找每帧把对象某个字段加到另一个字段上的函数。最终找到 0x08010024:

// 0x08010024, called once per frame for objects affected by gravity
void apply_gravity(GameObject *object) {
    object->velocity_y += object->gravity;   // +0x30 += byte at +0x34
}

关键是 velocity_y += gravity:它揭示了更新关系,但还没解释谁决定重力值。

结合首轮 headless 分析,对象的 X、Y 位置分别位于 +0x10、+0x14,水平速度在 +0x28,垂直速度在 +0x30,单字节重力在 +0x34。位置使用定点数,每单位相当于 1/256 像素。

REA 的 procedure_callers 找到十个调用者。首轮分析中的 0x0800EFA0 会在垂直速度越过 0x80 时切换上升、下降标记,作者据此将其视为跳跃顶点判断。

继续追踪写入,0x08018EE0 默认把重力设为 0x38,三个标志条件满足时改为 0x80。另一个函数 0x080191E0 将水平速度限制为 0x180,另一分支直接设为 0x200。

数字找到了,含义仍有空白。作者把相关标志解释为腾空、松开跳跃键和奔跑输入,但这些解释尚未得到运行时验证。

找回重力,不等于还原跳跃

按 1/256 像素换算,0x180 和 0x200 分别是每帧 1.5、2 像素。按 60 帧计算,就是每秒 90、120 像素,放在宽 240 像素的屏幕上,移动尺度已经比较清楚。

跳跃还缺两个关键值:起跳速度和最大下落速度。作者怀疑起跳速度来自数据表,但静态分析没有把表与使用位置连接起来。他建议接入 mGBA 一类模拟器调试器继续追踪,本次实验则停在静态分析。

作者随后用恢复的参数制作了原创游戏 Arena Run。它采用纯 JavaScript 和 Canvas 2D,以 GBA 原生的 240×160 分辨率绘制,再用最近邻方式放大。

这段配置最能体现结果的边界:恢复值和自选值都在代码里标明了来源。

// Every value is in subpixels (1/256 px) per frame, at 60 frames per second.
export const PhysicsTuning = Object.freeze({
  walkSpeed: 0x180,     // ROM: speed cap in the routine at 0x080191E0
  runSpeed: 0x200,      // ROM: run branch of the same routine
  risingGravity: 0x38,  // ROM: gravity byte (+0x34) set at 0x08018EE0
  fallingGravity: 0x80, // ROM: written at 0x08018EE0 when three flags line up
  apexThreshold: 0x80,  // ROM: rising/falling flag at 0x0800EFA0
  jumpVelocity: -0x480, // not found in the ROM, my choice
  maxFallSpeed: 0x500,  // not found in the ROM, my choice
});

要留意最后两行,以及 risingGravity、fallingGravity 的命名:前者是作者调参,后者把已经找到的常量赋予了尚待验证的玩法含义。

游戏使用整数子像素和固定 60 Hz 时间步,按累计时间推进完整逻辑帧,避免 144 Hz 显示器改变跳跃结果。不过 GBA 实际约为 59.73 Hz,这里仍有时间尺度差异。

演示也有明确说明:操作来自搜索输入序列的 bot,22.8 秒通关,拿到 38 枚金币中的 36 枚,保住全部生命。它证明关卡可以完成,不能证明原版手感已经复现。

我的判断

我认可的是证据管理和搜索方法。输入寄存器、字段累加、速度限幅,都比要求 AI「找出跳跃代码」更具体,也更容易验证。REA 让每项发现带上文件身份和工具记录,适合需要复查的分析任务。

但文件哈希只能证明分析对象是谁,无法证明解释正确。「代码在条件满足时写入 0x80」和「松开跳跃键会加重重力」之间,还差一次行为验证。

作者没有提供与人工分析、直接使用 Ghidra scripts,或其他模型的对照数据。「比手工快很多」可以作为个人经验,不能据此估算普通团队的效率收益。REA 提高了可追溯性,文章自身也证明,没有它仍能完成部分分析。

整数子像素便于复刻原程序的数值规则,但原文将其描述为避免浏览器间浮点漂移,论证不够充分;是否使用固定时间步、运算顺序是否一致同样重要。加上缺失的跳跃参数和未确认的标志语义,Arena Run 更适合称为借用了恢复参数的原创作品。

作者选择不复刻原作角色、美术和关卡,是本次项目的边界。原文也承认逆向规则因国家而异,不能把其中关于参数和创作素材的区分直接当作通用法律结论。

能拿来做什么

  • 用 AI 阅读陌生前端或 Node 代码时,先给出可观察行为,例如「哪里每帧更新垂直速度」或「哪里限制输入值」,再要求返回调用链和具体位置。
  • 把分析结果分成代码直接证明、根据上下文推断、为实现自行选择三类,并在注释中保留来源,避免后续开发把假设当成既定规则。
  • 做 Canvas 2D 动作游戏时,可以参考整数子像素与固定时间步的组织方式,同时明确目标逻辑频率;要复现手感,还得验证起跳速度、重力切换条件和下落限速。
  • 当静态分析卡在数据表、运行时计算或函数指针时,改用调试器观察输入和状态变化,别让模型继续用解释填补证据缺口。
Original source

本文由 AI 通读原文后重新编写,观点部分为站内判断,细节以原文为准,来源 dev.to · AI,原文版权归原作者所有。

阅读原文
上一篇
0sec开源本地AI安全工具0
下一篇
从故障复现到传感器溯源的SLAM排障方法

资讯速览

dev.to · AI · 2026-11-09 15:54

AI 评分 8.0 / 10

相关标签

#逆向工程#MCP#游戏开发

继续阅读

  • Firebase Studio 定于明年三月关闭并删数据
  • 0sec开源本地AI安全工具0
  • 从故障复现到传感器溯源的SLAM排障方法
  • 编程 Agent 达标近七成,全部完成仅两成六
  • A2A 接入实例:发现、接口与限流