修复我的吉他音箱固件
摘要
作者通过UART和JTAG逆向工程了Yamaha THR10c吉他音箱的固件,转储并修补了它,以修复旁路增益问题,并构建了一个API。
<p><a href="https://lobste.rs/s/1fkt8w/patching_my_guitar_amp_s_firmware">评论</a></p>
查看缓存全文
缓存时间: 2026/05/29 07:53
# 修补我的吉他音箱固件 来源:https://mforney.org/blog/2026-05-28-patching-my-guitar-amps-firmware.html 2026年5月28日 目录- 硬件 (https://mforney.org/blog/2026-05-28-patching-my-guitar-amps-firmware.html#hardware) - 识别并焊接连接器 (https://mforney.org/blog/2026-05-28-patching-my-guitar-amps-firmware.html#identifying-and-soldering-the-connectors) - 测试UART (https://mforney.org/blog/2026-05-28-patching-my-guitar-amps-firmware.html#testing-the-uart) - JTAG (https://mforney.org/blog/2026-05-28-patching-my-guitar-amps-firmware.html#jtag) - 软件 (https://mforney.org/blog/2026-05-28-patching-my-guitar-amps-firmware.html#software) - 配置OpenOCD (https://mforney.org/blog/2026-05-28-patching-my-guitar-amps-firmware.html#configuring-openocd) - 转储地址空间 (https://mforney.org/blog/2026-05-28-patching-my-guitar-amps-firmware.html#dumping-the-address-space) - 固件反汇编与分析 (https://mforney.org/blog/2026-05-28-patching-my-guitar-amps-firmware.html#firmware-disassembly-and-analysis) - 重链接固件 (https://mforney.org/blog/2026-05-28-patching-my-guitar-amps-firmware.html#relinking-the-firmware) - 修补固件 (https://mforney.org/blog/2026-05-28-patching-my-guitar-amps-firmware.html#patching-the-firmware) - 更多固件分析 (https://mforney.org/blog/2026-05-28-patching-my-guitar-amps-firmware.html#more-firmware-analysis) - 实现我的修改 (https://mforney.org/blog/2026-05-28-patching-my-guitar-amps-firmware.html#making-my-changes) - 按钮 (https://mforney.org/blog/2026-05-28-patching-my-guitar-amps-firmware.html#buttons) - LED (https://mforney.org/blog/2026-05-28-patching-my-guitar-amps-firmware.html#leds) - 构建API (https://mforney.org/blog/2026-05-28-patching-my-guitar-amps-firmware.html#building-an-api) - 我的代码 (https://mforney.org/blog/2026-05-28-patching-my-guitar-amps-firmware.html#my-code) - 修复旁路增益 (https://mforney.org/blog/2026-05-28-patching-my-guitar-amps-firmware.html#fixing-bypass-gain) - 刷写新固件 (https://mforney.org/blog/2026-05-28-patching-my-guitar-amps-firmware.html#flashing-the-new-firmware) - 固件更新格式 (https://mforney.org/blog/2026-05-28-patching-my-guitar-amps-firmware.html#firmware-update-format) - 应用更新 (https://mforney.org/blog/2026-05-28-patching-my-guitar-amps-firmware.html#applying-the-update) - 未来方向 (https://mforney.org/blog/2026-05-28-patching-my-guitar-amps-firmware.html#future-directions) - MIDI 2 属性交换 (https://mforney.org/blog/2026-05-28-patching-my-guitar-amps-firmware.html#midi-2-property-exchange) - 自定义DSP效果 (https://mforney.org/blog/2026-05-28-patching-my-guitar-amps-firmware.html#custom-dsp-effects) - 组合式"超级固件" (https://mforney.org/blog/2026-05-28-patching-my-guitar-amps-firmware.html#combined-mega-firmware-) - 总体感想 (https://mforney.org/blog/2026-05-28-patching-my-guitar-amps-firmware.html#overall-thoughts)
最近我对逆向工程产生了极大的兴趣,因此当我翻阅吉他音箱(Yamaha THR10c)的维修手册,并在原理图中看到UART接口的标记时,我兴奋不已。我好奇里面是否藏着什么有趣的东西。旁边还有一个JTAG接口。我对JTAG几乎一无所知,但之前听说过它与硬件破解有关,或许它也会有用。
Yamaha THR10c (https://mforney.org/blog/thr10/thr10.jpg) Yamaha THR10c
UART和JTAG原理图 UART和JTAG接口在原理图中的位置
我有一些想对固件进行的修改,所以这个项目的主要目标是找到一种方法来转储固件,并用修改后的固件重新刷写音箱。我最初的一个想法是增加一个开关,用于开启和关闭吉他音箱模拟功能,这样我就可以将其连接到真实的吉他音箱(要么通过增加外接音箱输出接口的改装 (https://www.mylespaul.com/threads/yamaha-thr10c-external-speaker-jacks.313703/),要么连接到TPA3118功放模块 (https://components101.com/modules/tpa3118-mono-amplifier-module))。虽然官方不支持,但在原版固件中,你可以通过电脑或手机通过USB发送特殊的MIDI SysEx命令来实现这一点。然而,切换音箱模型时,音箱模拟会恢复为默认状态,并且音量也会显著增大作为副作用。另一个我想要的功能是:当耳机接口连接时(例如连接到额外音箱或调音台),内置音箱仍然可以发声。
## 硬件
按照维修手册的描述,我打开了音箱,在主PCB上找到了CB3和CB4。
UART和JTAG PCB焊盘 未焊接的UART和JTAG端口
### 识别并焊接连接器
在这些接口上焊接连接器似乎很简单,我只需要确定使用哪种连接器。我测量了CB4的引脚间距为2mm,CB3的引脚间距为1mm。UART连接器很容易识别为JST PH系列(B4B-PH-K)。JTAG连接器就没那么明显了。它是两排交错排列的2mm间距,还是一排1mm间距的交错触点?我搜索了在线连接器识别工具,以及DigiKey和Mouser的产品索引,但没有找到任何看起来匹配的。最后,我注意到电路板另一部分有一个类似的焊盘,使用的是扁平柔性电缆(FFC)。这就是我之前没找到的原因;我没想过要去查FFC连接器。我在那个连接器上看到了JST标记,我认为它属于FMN系列。Mouser没有8引脚反向版本的库存(08FMN-BMTTR-A-TB),所以我选择了兼容的Molex 52808-0870。
连接器 CB3和CB4连接器
收到新连接器后,我从外壳中取出主PCB,然后用吸锡器清理了CB4的通孔。接地引脚有点棘手,它很容易将热量传导到接地层,但经过一些耐心最终清理干净了。然后我焊接上了新的连接器。我很少进行SMD焊接,所以CB3遇到了一些麻烦,但结果我很满意。
焊接好的连接器 (https://mforney.org/blog/thr10/pcb-soldered.jpg) 主PCB上焊接好的CB3和CB4连接器
我将两个新连接器的线缆穿过音箱背部的槽,这样我可以在项目进行期间合上外壳并继续使用音箱。
带线缆的连接器 (https://mforney.org/blog/thr10/connected-cables.jpg)
### 测试UART
现在连接器已经就位,我使用USB-UART线缆将其连接到电脑,并给音箱通电。不幸的是,没有任何输出。我尝试了各种常见的波特率,仍然没有反应。我用示波器确认了TX线上没有活动。真令人沮丧。也许JTAG会有更好的运气。
### JTAG
在阅读了更多关于JTAG及其用途的资料后,它看起来非常有希望。JTAG是一种用于硬件测试的串行接口,通常用于调试嵌入式处理器。它有四个主要引脚:TCK、TMS、TDI和TDO,用于与称为TAP控制器的状态机进行交互。TCK、TMS和TDI都是JTAG适配器的输出;TMS用于导航状态机,TDI提供数据输入,TCK是时钟信号,用于采样输入并进入下一个状态。TDO是TAP控制器的输出,提供数据输出。此外,还有一个可选的TRST引脚用于复位控制器。网上有很多TAP状态机的示意图,我认为有一个基本的思维模型对入门很有帮助。我找到的最佳资源之一是wrongbaud的一篇文章 (https://wrongbaud.github.io/posts/jtag-hdd/),该文章完整介绍了如何对一个完全不了解的设备使用JTAG。
最流行且支持度最好的JTAG适配器似乎是基于FTDI FT2232H的。这款芯片的一个优点是它有两个多用途通道,所以我可以在一个通道上使用JTAG,另一个通道上使用UART(如果能用的话)。这里有很多选择,但UrJTAG和OpenOCD文档中提供的大多数产品链接都已失效。我选择了FTDI FT2232H Mini Module。
FTDI FT2232H Mini Module FTDI FT2232H Mini Module
我的音箱上的JTAG接口(CB3)有8个引脚,其中大部分直接连接到SSP2(音箱的主芯片)的标记引脚上,所以我无需自行发现映射关系。有一个引脚先经过一个与门,然后连接到SSP2上标记为ICN的引脚。与门的另一个输入是R3112N291A-TR-F芯片的输出。这看起来像是某种低电压检测器,数据手册提到它可以用于系统复位,这很合理。
在FT2232H上,AD0-AD3分别用于TCK、TDI、TDO和TMS。AD4-7是常规GPIO引脚,通过软件配置。当我第一次将音箱连接到mini module时,我没有连接复位引脚,结果发现了问题:TRST是低电平有效的,并且被R17下拉到地,因此需要将其拉高才能启用TAP控制器。这可以通过将TRST连接到VCC来实现,但为了允许JTAG软件复位TAP控制器,我们可以使用mini module上的GPIO引脚。我使用AD4作为TRST,AD5作为SRST。
| CB3引脚 | Mini Module引脚 | 描述 |
|---------|----------------|------|
| 1 | VCC | |
| 2 | CN2-14 (AD4) | TRST |
| 3 | CN2-10 (AD1) | TDI |
| 4 | CN2-12 (AD3) | TMS |
| 5 | CN2-7 (AD0) | TCK |
| 6 | CN2-9 (AD2) | TDO |
| 7 | CN2-13 (AD5) | SRST |
| 8 | CN2-6 | GND |
CB3引脚排列
我将所有这些连接到一个2x5排针上,并按照mini module数据手册的描述,从V3V3到VIO加了一根跳线。我还添加了一个从CN3-1到CN3-3的跳线,以便使用USB总线为FT2232H供电。
带有适配器线的Mini Module (https://mforney.org/blog/thr10/mini-module-cb3.jpg) FT2232H Mini Module与适配器线缆
下面是音箱合上外壳,JTAG和UART连接到mini module的样子。
带有Mini Module的音箱 (https://mforney.org/blog/thr10/amp-mini-module.jpg)
## 软件
现在所有硬件部分都已就位,我可以开始使用OpenOCD和UrJTAG等软件通过JTAG与音箱进行交互。我首先尝试了wrongbaud建议的UrJTAG,但在TRST引脚上遇到了一些问题,因为它不可配置。我通过将其连接到VCC使其工作,但我想直接使用OpenOCD会更简单。
### 配置OpenOCD
OpenOCD自带的`interface/ftdi/minimodule.cfg`脚本也没有设置TRST,但可以通过自定义脚本来配置。
```
adapter driver ftdi
ftdi device_desc "FT2232H MiniModule"
ftdi vid_pid 0x0403 0x6010
ftdi layout_init 0x0008 0x000b
ftdi layout_signal nTRST -data 0x0010 -oe 0x0010
ftdi layout_signal nSRST -data 0x0020 -oe 0x0020
```
minimodule.cfg
我使用`openocd -f minimodule.cfg -c 'transport select jtag'`启动OpenOCD,很高兴地看到它发现了TAP控制器。
```
Warn : There are no enabled taps. AUTO PROBING MIGHT NOT WORK!!
Info : JTAG tap: auto0.tap tap/device found: 0x4f1f0f0f (mfg: 0x787 (), part: 0xf1f0, ver: 0x4)
```
我搜索了JTAG ID 4F1F0F0F,这似乎常用于基于ARM7TDMI-S核心的NXP LPC 2xxx系列。可以合理推测SSP2也使用了ARM7TDMI-S核心,于是我创建了一个OpenOCD配置文件。
```
transport select jtag
jtag newtap ssp2 cpu -irlen 4 -expected-id 0x4F1F0F0F
target create ssp2.cpu arm7tdmi -chain-position ssp2.cpu
reset_config trst_and_srst
```
初始 thr10.cfg
果然,它工作了。`openocd -f minimodule.cfg -f thr10.cfg`启动时显示已检测到EmbeddedICE版本7,这提供了对ARM7核心的调试支持。我现在可以使用`gdb -ex 'target extended-remote :3333'`连接gdb,读写内存和寄存器,甚至可以单步执行处理器正在运行的代码!然而,默认的小端序对于这个目标是不正确的。ARM7TDMI核心可以根据输入引脚运行在大端序或小端序,很明显SSP2使用的是大端序,通过逐字节比较内存读取与逐字比较内存读取可以看出:
```
(gdb) x/8xb 0
0x0: 0xe3 0xa0 0xf4 0x02 0xe5 0x9f 0xf0 0x18
(gdb) x/2xw 0
0x0: 0xe3a0f402 0xe59ff018
```
我返回去更新配置文件以纠正字节序。趁此机会,我将JTAG适配器速度提高到2000 KHz,因为THR10使用12.288 MHz时钟,而OpenOCD文档建议使用不超过CPU时钟的六分之一。我还添加了`-ircapture 0x1 -irmask 0xF`,基于ARM7TDMI参考手册;TAP指令寄存器是4位宽,进入CAPTURE-IR状态时会被加载为`0x1`。OpenOCD使用这些参数来验证JTAG是否正常工作。最后,我发现还需要`adapter srst delay 100`才能使系统复位正常工作。
```
transport select jtag
jtag newtap ssp2 cpu -irlen 4 -expected-id 0x4F1F0F0F -ircapture 0x1 -irmask 0xF
target create ssp2.cpu arm7tdmi -chain-position ssp2.cpu -endian big
adapter speed 2000
adapter srst delay 100
reset_config trst_and_srst
```
thr10.cfg
GDB的目标描述格式不指示目标字节序,所以我必须同时为gdb配置大端序。我通过一个包含启动命令的文件来实现。我还启用了`disassemble-next-instruction`,这对跟踪执行过程非常有帮助。
```
target extended-remote :3333
set endian big
set disassemble-next-instruction on
```
thr10.gdb
现在,我可以用`gdb -x thr10.gdb`启动gdb,所有配置都正确了。
### 转储地址空间
为了开始分析固件,我需要将其转储到文件中。经过一番探索,地址0和0x2000000处似乎有一些代码。复位向量(地址0)处执行的第一条指令是跳转到0x2000000。根据原理图,THR10有一个2 MiB的闪存,因此假设这些地址之一是闪存的起始位置,我转储了0x0000000-0x4000000(64 MiB)地址空间到`memory.bin`,这应该足够包含我目前感兴趣的所有内容。
```
(gdb) starti
(gdb) dump memory memory.bin 0 0x4000000
```
这有点慢,大约花了15分钟才完成。
### 固件反汇编与分析
我将`memory.bin`作为ARM:BE:32:v4t:apcs原始二进制文件加载到Ghidra中,并开始分析。跳转到0x2000000后,它做的第一件事是将0x10000字节(64 KiB)从0x2000100复制到0x4000000,然后跳转过去。在接近0x2010000的地方,有一个看起来像构建时间戳和可执行标识符`DTAb`的东西。
```
0200ffd0: 41 75 67 20 32 30 20 32 30 31 32 00 00 00 00 00 Aug 20 2012.....
0200ffe0: 30 39 3a 33 39 3a 33 36 00 00 00 00 00 00 00 00 09:39:36........
0200fff0: 44 54 41 62 ff ff ff ff ff ff ff ff ff ff ff ff DTAb............
```
在0x2110000处有类似的时间戳和标识符。
```
0210ffd0: 41 75 67 20 20 33 20 32 30 31 32 00 00 00 00 00 Aug 3 2012.....
0210ffe0: 31 31 3a 32 36 3a 35 30 00 00 00 00 00 00 00 00 11:26:50........
0210fff0: 44 54 41 6d ff ff ff ff ff ff ff ff ff ff ff ff DTAm............
```
此时我意识到我面对的是两个独立的程序镜像。`DTAb`是引导加载程序,`DTAm`是主固件镜像。在0x2010000处(`DTAm`的起始位置),有一些看起来与复制到0x4000000处(`DTAb`的起始位置)的代码相似的代码。它设置了不同ARM异常模式的堆栈指针,然后将0x1000000处的128 KiB和0x4000000处的256 KiB清零。这些很可能是RAM区域,这很合理,因为主板上有两个SDRAM芯片。之后,它进行了一系列函数调用。
相似文章
逆向工程Creative Katana音箱以从Linux控制
一位开发者逆向工程了专有的Creative Sound Blaster Katana V2X音箱的USB协议,以便从Linux控制它,记录了捕获流量、去混淆固件和分析命令的过程。
HDD固件破解 第一部分
作者详细描述了如何通过硬件和软件技术,在没有AI辅助的情况下,对HDD固件进行转储、分析和修改,以实现Xbox 360的延迟利用。
Tesla Wall Connector 引导程序绕过固件降级棘轮
本文详细介绍了研究人员如何绕过 Tesla Wall Connector 引导程序中的固件降级保护,从而能够在存在安全棘轮的情况下安装旧版固件。
无需触碰,通过音箱入侵你的电脑
一位安全研究人员对 Creative Sound Blaster Katana V2X 的固件进行了逆向工程,发现了漏洞,攻击者可在15米范围内将音箱变成隐蔽的窃听工具和无需物理接触的 Rubber Ducky。
本田思域与邪恶泊车员
一位安全研究人员揭示了本田思域车载信息娱乐系统(headunit)会接受使用公开已知的AOSP测试密钥进行的未签名更新,从而使得通过物理USB访问可以实现“邪恶泊车员”(evil valet)攻击。还发布了如ota-builder和apk-rebuilder等工具,以方便进一步的逆向工程。