返回资讯中心
外部精选
软件工程
#开发者实时流

开发者修改富士X-T30 II固件,实现经BLE向instax Link 3打印照片

来源标题:Show HN: I taught my Fujifilm X-T30 II to print on an instax Link 3 over BLE

一位开发者通过修改富士X-T30 II相机固件,让这款原本不支持蓝牙打印的相机能直接通过BLE向instax mini Link 3打印机输出照片,过程中还发现了富士固件中的一个bug。X-T30 II仅支持旧款Wi-Fi打印机(SP-1/SP-2/SP-3),而Link 3使用不同的BLE协议,富士只为X-S10等较新机型加入支持。该相机已是最新固件,官方不会更新。

Hacker News 最新j_leboulanger2026/11/7 · 今天30 分钟阅读

以下正文由 AI 翻译自 Hacker News 最新(原文版权归原站所有),可能存在偏差,重要内容请以原文为准。

给一台原本不支持蓝牙 instax 打印的富士相机加上这个功能,顺带还发现了富士固件里的一个 bug。

我出门旅行时带着一台富士 X-T30 II 和一个小巧的 instax mini Link 3 打印机,后者是我去中国旅行时买的。我喜欢把照片打印出来送给路上遇到的人,或者夹进明信片里。我也尽量做到不带手机出门旅行。但如今手机成了中间人:先把照片拷到手机上,打开 instax app,再从那里打印。这样确实能用,但又慢又扫兴。

我天真地以为,一台还算新的富士相机应该能原生支持打印。我甚至在菜单里见过“instax printer print”这一项。但它并不支持。X-T30 II 只认得老的 Wi-Fi 打印机(SP-1、SP-2、SP-3)。像 Link 3 这样的新款用的是基于 Bluetooth LE 的另一套协议。富士把它加进了 X-S10 这类更新的相机,却从没加进我这台。而且我这台已经是最新固件了,不会再有更新。

所以唯一的办法就是改固件。我以前从没研究过相机固件。

动手之前,我先定了几条规矩。把相机变砖就是一块昂贵的镇纸,社区里已经有人因为乱碰内存地址把机身搞砖了。

我绝不写 flash,也就是相机存放固件的那块存储芯片。一切都在 RAM 里运行,所以拔掉电池就能恢复原厂相机。每一次对相机的写入都需要我明确同意,而且会先校验原始字节。比起直接探测相机,我更愿意在 Mac 上读文件。我也不浪费相纸,因为一张 instax 相纸大约要一欧元。

这些规矩让项目变慢了,但我一次也没经历过惊慌时刻。

富士会在官网上发布固件更新,每台相机一个 .DAT 文件。格式没有公开文档,但 FujiHack 已经在老机型上完成了一部分工作。

解包分三步。第一步,切掉文件头。开头的字节是这个文件的身份证:相机型号、版本、校验和。代码在后面。然后,把每一位翻转:每个 0 变成 1,每个 1 变成 0。所谓的“加密”就这么多。最后,解压。剩下的是四个压缩块。富士用的是自己的一套 LZ 变体,也就是 ZIP 背后的经典技巧:当一段字节序列重复出现时,不再存一遍,而是替换成“从 300 字节前复制 20 字节”。

我写了一个小 Python 脚本 fujifw.py,把这三步都做了。验证它有个免费的办法:固件里包含一些来自 zlib(一个公开的压缩库)的知名数据表。如果解出来的内容和公开版本逐字节完全一致,就说明解压是对的。

其中三个块是相机处理器的机器码(一颗运行 ThreadX 这个小型实时操作系统的 ARM Cortex-A7)。机器码说白了就是字节。我用 Ghidra 来读它,这是 NSA 发布的一款免费逆向工程工具。你给它一个二进制文件,它会找出函数,把字节变成汇编,再变成类似 C 的代码。没有名字,没有注释,但能读。

Ghidra 首先需要知道每个块在相机内存中的位置。固件里没写,所以我只能自己推算。代码里到处都是指向文本消息的指针。如果一个块的起始地址猜错了,这些指针就会落到莫名其妙的地方。只有一个起始地址能让它们全部落在真实消息的开头。有了这个,Ghidra 找到了大约 59,000 个函数。我是通过脚本而不是它的界面来运行的,这样 Claude 就能直接向它查询任意函数。

59,000 个没有名字的函数是很多。但我有个窍门:X-S10 用同一颗处理器,而且确实能打印到 Link 打印机。所以我也把它的固件解包了,把两者做对比。

我写了一个模糊匹配器。它比较整个函数,忽略函数内部的地址,因为这些地址在不同构建之间会变(后面再细说)。我拿它跑了 X-S10 打印代码的 176 个函数。其中 109 个在我的相机里都有一个至少 90% 相同的对应函数。

这就是最大的惊喜:X-T30 II 里其实已经包含了富士的蓝牙打印 app。裁剪、旋转、JPEG 编码、进度界面,全都在。只有最底层,也就是通过蓝牙和打印机通信的那部分,在富士构建这个固件时被拿掉了。取而代之的是一些空函数,只是返回 0 的桩。

更妙的是,相机本来就会驱动蓝牙设备。Bluetooth LE(低功耗)是蓝牙的低功耗版本,手表、传感器和 Link 3 这类打印机都用它。在每一个连接里,一方是 central,负责扫描、连接和发号施令;另一方是 peripheral,负责等待和应答。通常相机是 peripheral:手机 app 连到它。要打印,它必须当 central,主动去找打印机。

X-T30 II 已经在一个场景里扮演这个角色了:富士的蓝牙快门手柄(很可能是 TG-BT1),一个带快门按钮的小型三脚架手柄,会向相机发送命令。固件里有一个模块会寻找这个手柄并以 central 身份连接它。所以我不需要写蓝牙协议栈,只需要补上缺失的那层胶水。

这个阶段我又发现了一个问题。打印之前,app 需要知道装的是哪种相纸,因为 mini 和 wide 的尺寸、形状都不一样。它不直接问打印机。它读取打印机的序列号,看第一位数字:1 表示 mini,2 表示 wide,其他任何值都表示“未知打印机,停止”。那份列表是按当时存在的打印机写的。稍新一点的 X-S10 还接受 4。我这台 Link 3 的序列号以 7 开头,我看过的所有固件都不认识它,连 X-T30 III 都不认识。所以就算蓝牙完美工作,相机也会拒绝它。修起来很简单:把 7 当作 mini 处理。

(原文较长,此处译出前 6000 字,完整内容请点「打开原文」。)

正文由 探How 从来源站点 RSS 同步,内容未经改写;遇到排版缺失或需要图片、视频时请以原文为准。

打开原文
去社区讨论 →