sergiopolog/tlcs90-rom-reader

GitHub: sergiopolog/tlcs90-rom-reader

一款利用定制 PCB 和中断劫持机制从东芝 TLCS-90 系列 MCU 中提取内部 ROM 固件的硬件读取工具,主要用于复古街机主板的固件保存与模拟器开发。

Stars: 15 | Forks: 1

# TLCS-90 Internal ROM 读取工具 TLCS-90 ROM Reader 是一款定制工具,旨在读取东芝 TLCS-90 系列 MCU 内部具有的内部 ROM 内容,至少适用于支持该功能的型号。 [

TLCS90 ROM Reader

](img/mcu-nmk215.jpeg) 东芝 TLCS-90 系列设备是采用 Z80 内核且指令集非常相似的 MCU,但相比 Zilog 的原始 CPU,它们具有更多附加功能,例如: - 内部计数器 - 看门狗 - A/D 转换器 - 串口支持 - 步进电机支持 - 以及更多... 该系列中还有一些设备在其内存映射中预留了内部 ROM 和 RAM 空间,从而允许在单芯片中包含完整的微型计算机系统(程序代码和工作 RAM 可以包含在芯片内部)。 ## 起源 做这件事的动机始于几年前,当时我弄到了一块状况非常糟糕的 NMK(1992 年)街机游戏 GunNail 的 PCB,包括大量生锈和腐烂的组件及走线。 该 PCB 上包含的一些芯片明显有故障,引脚断裂且损坏严重。其中一个标记为 NMK-215,顾名思义,这是当时 NMK 制造的具有定制行为的定制芯片。 经过一些调查,我意识到该组件实际上是一颗东芝 MCU,因为其引脚排列与他们数据手册中该系列的某一型号相匹配,至少电源引脚(Vcc 和 Ground)、复位、时钟、地址和数据总线是匹配的。 如上所述,这类 MCU 可以拥有内部 ROM,用于存储由 MCU 自身执行的程序。而那块 NMK 板子很可能就是这种情况。 然后,第一次尝试读取内部 ROM 是物理方法。前阵子我把芯片寄给 [Furrtek](http://furrtek.free.fr) 进行开盖,并且幸运的话,可以通过光学方式从裸片中读取 ROM,但那次尝试运气不佳。裸片没有显示出可见的 ROM 区域,至少从顶视图来看是如此,~~并且应该执行分层剥离(更复杂的方法)来检查顶层金属层下方是否能看到 ROM 区域。~~ -> 感谢 [Travis Goodspeed](https://x.com/travisgoodspeed) 指出 TLCS-47 系列具有 _Implant ROM_(东芝极有可能在较新的 TLCS-90 系列中使用相同的技术),这意味着 P 硅和 N 硅之间的差异描述了该数据位,而且事实上,即使在进行分层剥离之后,它也无法通过光学方式可见,因为它们的颜色完全相同。 因此,在这次尝试之后,接下来的精力都花在了试图寻找一种方法来利用该设备并使用某些外部流程从外部读取内容,就像其他一些 MCU 设备被成功 dump 的那样。 这个项目就是这样开始的。在此过程中,为了了解 MCU 在不同场景下的行为及其许多功能,我们制作了 3 个不同版本的 PCB 和软件,目前它已经可以处理许多经过测试的设备。 从多台设备中 dump 出的内部 ROM 帮助改进了 MAME,甚至成功完成了某些游戏的模拟。 ## TLCS-90 系列 MCU | ROM | RAM | CMOS MASK ROM MCU | CMOS NO ROM | PROM MCU | RESET PIN | 受读取器支持 | | --- | --- | ----------------- | ----------- | ---------- | --------- | --------- | | - | - | - | TMP90C041N | - | 22 | (不需要) | | - | 1K | - | TMP90C141N | - | 22 | (不需要) | | 4K | 128 | TMP90C400N | TMP90C401N | TMP90P800N | 35 | 是(使用转接板) | | 8K | 256 | TMP90C800N | TMP90C801N | TMP90P800N | 35 | 是(使用转接板) | | **8K** | **256** | **TMP90C840AN** | **TMP90C841AN** | **TMP91P640N** | **22** | **是** | | 8K | 256 | TMP90C844AN | TMP90C845AN | TMP90PH44N | 47 | 否 | | 16K | 320 | TMP91C642AN | - | TMP91P642N | 46 | 否 | | **16K** | **512** | **TMP91C640N** | **TMP91C641N** | **TMP91P640N** | **22** | **是** | | 16k | 512 | TMP90CH44N | TMP90CH45N | TMP90PH44N | 47 | 否 | | **32K** | **1K** | **TMP90CM40AN** | **TMP90C141N** | **TMP90PM40N** | **22** | **是** (尚未测试) | **加粗** 项具有与 NMK-215 相同的引脚排列。 不受支持的设备具有略微不同的架构,缺少 /NMI 引脚,使得读取器 PCB 无法完成该流程。 400N 和 800N 型号(理论上)受支持,但需要使用引脚排列转接板才能将它们与读取器 PCB 一起使用。然而,目前尚未经过测试,因为我无法找到这些型号的任何设备来进行检查。 该工具由定制 PCB、旨在目标 MCU 本身上执行的程序代码、使所有部件协同工作的 PLD 和胶合逻辑共同组成。该工具可自行运行,无需连接到其他硬件等,只需要安装合适的组件并使用 +5V 为其供电即可。 ## 免责声明 使用本项目的任何行为均由**您个人承担责任**。**您**将负责检查电路板的正确安装和功能,以及**您**插入其中的芯片的兼容性。使用本项目即表示**您**同意,如果它导致您的任何设备损坏、烧毁您的房屋或造成其他任何后果,均不由我负责。 **不要**找我寻求手把手的指导。它**不是**一个即插即用的工具,这是我为自己研究和使用而创建的东西,我发布它只是以防有人可能用得上它。 ## 组装 PCB 设计中使用的所有组件均为“通孔”组件。这使得组装更加容易。 1. 使用 [pcb/gerbers](pcb/gerbers) 文件夹中的 gerber 文件制作 PCB。 2. 将 [src](src) 文件夹中二进制文件里的程序代码烧录到 27C512 EPROM 中。 3. 将 [pld](pld) 文件夹中 jedec 文件里的 PLD 烧录到 GAL22V10 设备中。 4. 将所有组件安装到 PCB 上。建议至少为 MCU、EPROM、EEPROM 和 PLD 设备使用插座。[pcb/bom](pcb/bom) 中有一个基于 HTML 的交互式 BOM 文件,在填充电路板时非常有用。 ## 如何使用 首先,请确保 28C256 EEPROM 未受保护。此类设备可以受到保护,从而拒绝对该设备执行的任何写入操作。因此,在将其安装到电路板上之前,您必须始终确保对该设备进行“关闭保护”操作。在将 EEPROM 插入读取器 PCB 的插槽之前,除了对其解除保护外,不要对其执行任何其他操作。(感谢 **kuze** 发现并测试了这一点) 1. 将 `DSW2` 的初始值设置为 **4** (0100)。 2. 使用 `DSW1` 选择目标设备的内部 ROM 大小。如果设备型号未知,请选择 32K 选项以执行完整读取。也许在读取过程之后应该丢弃一些空间。 3. 将 `/EA` 开关设置到左侧位置 **(ON)**(外部模式) 4. 打开电源。为电路板供电有两种选择: - 通过 Mini-molex 软驱连接器直接从 ATX PSU 或类似设备供电。这种情况下,请仅将电源连接器连接到 `J1`,并**仅**使用 `SW1` 打开电路板。确保左侧引脚为 +5V,且中间两个引脚为 GND。这是此类连接器的标准引脚排列。 - 通过直流连接器(**头端正 - 环负极!!**)从外部 PSU 输入最高 12V 电压。这种情况下,请仅将直流连接器连接到 `J2`,并**仅**使用 `SW2` 打开电路板。(它在 9V 和 12V 外部电源下工作良好,但如果使用 12V,强烈建议在 `U15` - L7805 上安装散热片) 5. 短按 `/RESET` 按钮,`D2` 处的绿色 LED 将亮起,表明 PCB 已准备就绪。 6. 将 `/EA` 开关拨动到右侧位置 **(OFF)**(内部模式) 7. 再次按下 `/RESET` 按钮以启动读取过程。绿色 LED 熄灭。 8. 当绿色 LED 再次亮起时,说明流程已成功结束。读取过程所花费的时间取决于 MCU 型号及其内部 ROM 的大小。如果 PCB 上使用的是 4MHz XTAL,读取 8K 内部 ROM 大约需要 55 秒,16K 大约需要 110 秒,32K 大约需要 220 秒。它可以升级到 10MHz(MCU 允许的最大频率),以减少这些 dump 时间,但这并不是真正需要的。 9. 内部 ROM 的内容将写入到位于 `U3` 的 EEPROM 中。小心地将其从插槽中拔出,并使用合适的 EPROM 读取器读取内容。 如果初始 ROM 大小未知,并且该型号实际上并不是 32K 设备,那么该过程会读取一些额外内容,并将其放置在 dump 文件的末尾。在该文件中,某些特定地址可能会有一些标志值,标明真正的内部 ROM 大小: * 如果在 `$2000` 处发现 **"3B"** 值,则内部 ROM 仅为 8K,应舍弃 dump 文件中 `$2000 - $8000` 之间的内容。 * 如果在 `$4000` 处发现 **"4B"** 值,则内部 ROM 仅为 16K,应舍弃 dump 文件中 `$4000 - $8000` 之间的内容。 * 如果这些位置均不存在这些值,则 dump 确实为 32K 长度,不应舍弃任何内容。 使用直流连接器和外部 9V DC 电源为电路板供电(**头端正极!**): [Barrel Connector Polatiry](img/polarity-center-positive.jpg) [

Barrel Connector PCB

](img/Powered_by_Barrel_Connector.jpeg) ## 工作原理 ### TLCS-90 功能 此工具中实现的 dump 方法依赖于 TCLS-90 MCU 的以下功能/行为: * 该 MCU 提供了一个名为 `/EA`(“外部访问”)的输入引脚,当被置位(低电平)时,MCU 会忽略内部 ROM(和 RAM)空间,并使用地址端口引脚将其寻址到外部。当未被置位时,它使用位于内存映射起始位置($0000 - $2000、$0000 - $4000 等,具体取决于特定的 MCU 型号)的内部 ROM。因此,我们可以从外部控制 MCU 是从外部还是内部模式启动。 * `/EA` 引脚不支持热插拔,当 MCU 运行时,它仅在复位设备时设置该值。 * 与普通的 Z80 CPU 一样,复位后获取的第一条指令位于 `$0000` 地址。如果启用了内部模式,则该获取操作将从内部 ROM 中完成。 * 复位过程仅会清除 MCU 中少数寄存器的值。这些寄存器是 PC 寄存器、AF 寄存器对和 IFF 标志。其余寄存器(包括 SP(堆栈指针))将保持与之前执行(如果有)时一样不变。 * 在内部模式下复位设备时,地址引脚默认被设置为输入端口,如果需要,应通过编程方式将其配置为地址引脚。 * 外部中断处理基本上与普通的 Z80 相同,将 PC 值和 AF 值保存到堆栈中,并在结束中断子程序后恢复它们。 ### Exploit 考虑到这一点,这就是 dump 方法的基本工作原理: 1. 在外部模式下启动设备,程序代码将一个外部地址值放入堆栈指针寄存器(SP)中。然后,程序使设备暂停等待复位。 2. 手动切换 /EA 引脚以切换到内部模式,然后再次复位。 3. 由于在该复位后 SP 值保持不变,因此如果发生任何中断请求,设备会将 PC 值和其他一些值存储到堆栈中,而该堆栈现在正位于由先前 SP 值指向的外部区域。 4. 在第二次释放之后紧接着,PCB 逻辑会在 `/NMI` 引脚上产生一个脉冲,以发送(不可屏蔽)中断。设备没有足够的时间在 `$0000` 处获取第一条指令(这可能会将 SP 设置为其自身的值),从而转向处理中断。 5. 设备将 PC 和其他值存储到堆栈中,该堆栈目前位于外部区域,但在复位后地址端口被配置为输入端口,因此它实际上不会在设备的地址引脚上输出地址以存储这些值,但它并不在乎,因为它们不会被使用。 6. 在运行中断子程序(通常它只是返回控制权,而不执行任何与外部相关的其他事情)之后,PC 值(及其他值)需要从堆栈中返回,设备尝试从外部区域读取它们。 7. PCB 逻辑使用 `/RD` 引脚来计算每次获取的次数,人为地发送一个新的、方便的 PC 值,因此现在设备中的 PC 指向了我们想要的区域(外部区域)。 8. 设备尝试从新注入的 PC 地址值获取指令,但复位后地址端口仍然作为输入端口,因此它不会输出正确的地址值来获取指令。 9. PCB 逻辑再次使用 `/RD` 引脚来计算随后的获取操作,人为地发送一段 6 字节的序列,构成了 2 条供设备执行的指令。这些指令是经过精心挑选的,旨在使地址引脚能够有效地充当地址端口(输出)。 10. 设备在下一个 PC 值处使用地址端口正常获取下一条指令,然后我们最终获得了对设备的控制权。 11. 下一步是初始化设备的其余寄存器和端口,并运行存储在外部 EPROM 中的定制程序。 12. MCU 自身通过运行 EPROM 中的程序代码,将内部 ROM 内容($0000 到 $1FFF,或到 $3FFF,或到 $7FFF)复制到安装在 PCB 上的 EEPROM(非易失性存储器)中。 ### 攻击时序 下图展示了攻击中涉及的主要信号及其在攻击过程中的演变方式: [

TLCS90 ROM Reader Attack Timing

](img/tlcs90-attack-timing.jpg) ### 特殊情况 如果中断程序在返回控制权之前,通过寻址外部区域执行了一次或多次读取,或者在该中断子程序期间从堆栈中压入/弹出值(堆栈指针仍然指向外部区域,并在那里引发写入/读取),PCB 上的计数器将会混淆,并且不会在正确的时间注入正确的值。因此,如果内部代码这样做,此方法在初始配置下将不起作用。不过,NMI 程序从外部区域进行数据获取的情况非常罕见。 在这种情况下,一种变通方法可能会有效。那就是尝试定位中断子程序在何处结束,以及在 RETI 指令期间从堆栈中提取 AF 寄存器然后是 PC 寄存器的第一次获取发生在什么时候。通过调整 DSW2,从初始配置值中减去几个单位,将延迟读取计数,以便将 RETI 尝试从堆栈获取 PC 值的时间与 PCB 逻辑将其注入数据总线的时间同步(例如:4 -> 2)。 另一种可能发生的罕见情况是,在结束中断子程序时使用了 RET 指令而不是 RETI。区别在于 RET 仅执行 “POP PC”,而 RETI 先执行 “POP AF” 然后执行 “POP PC”,因此从中断返回时将少两个读取周期。这可以通过 DSW2 在那里配置的值上增加两个单位来进行调整(例如:4 -> 6),以便以与前一种情况相同的方式同步注入新 PC 值的时间。 在所有这些罕见的情况下,解决方法是改变 DSW2 上的不同值,通过在其配置的值上加或减几个单位,直到同步应该注入新 PC 值的时间。 显然,如果中断例程执行了许多复杂的操作,则应针对攻击该特定设备制作定制解决方案。逻辑分析仪将成为检查读取器 PCB 逻辑生成 NMI 脉冲后所发生情况的巨大助力。 在一个奇怪的案例中,我发现某个程序在中断子程序中进行了直接跳转,而不是使用 RETI 指令。在这种情况下,程序跳转到远程程序地址(内部 ROM 内部)并继续执行指令,直到它调用一个子程序。在那一刻,PC 的值被存储在堆栈中(仍然指向外部区域),当子程序结束时,程序尝试从堆栈中取回 PC 值,此时新 PC 值被注入。在所有这些执行时间内,没有执行任何外部获取,因此第一次获取是为了返回该 PC 值,随后注入了新值。 ## 已知基于 TLCS-90 的设备 下表列出了目前已知的基于 TLCS-90 系列 MCU 的设备、型号、功能以及其内容目前是否已被 dump。 | 设备参考 | 设备型号 | 封装 | 开发公司 | 发现于硬件 | 已 Dump? | Dump 使用的配置 (DSW2) | 图片 | | --- | --- | ----------------- | ----------------- | ----------- | ----------- | ----------- | ----------- | | NMK-004 | TMP90840 | QFP64 | NMK | 许多 NMK 游戏(音频 CPU) | [**是**](https://github.com/mamedev/mame/blob/0006fba49565386afa9b66d9fb8e02f744cf7cdb/src/mame/nmk/nmk004.cpp#L83)
(使用 [trap15 方法](http://daifukkat.su/blog/archives/2014/09/13/nmk004_rom_dumping_part_5_the_release/))
也使用 **TLCS90-ROM-Reader** 和位于 [adapter/tmp90c840-qfc2sdip](adapter/tmp90c840-qfc2sdip) 的转接板进行了 dump | 2 | [链接](img/mcu-nmk004.jpeg) | | NMK-110 | TMP91640 | SDIP64 | NMK | ddealer & tdragon
(每个都有不同的内部 ROM) | [**是**](https://github.com/mamedev/mame/blob/0006fba49565386afa9b66d9fb8e02f744cf7cdb/src/mame/nmk/ddealer.cpp#L463) 和 [**是**](https://github.com/mamedev/mame/blob/0006fba49565386afa9b66d9fb8e02f744cf7cdb/src/mame/nmk/nmk16.cpp#L6447) | 4 | [链接](img/mcu-nmk110.jpeg) | | NMK-113 | TMP91640 | SDIP64 | NMK | hachamf | [**是**](https://github.com/mamedev/mame/blob/0006fba49565386afa9b66d9fb8e02f744cf7cdb/src/mame/nmk/nmk16.cpp#L6801) | 4 | [链接](img/mcu-nmk113.jpeg) | | NMK-215 | TMP90840 | SDIP64 | NMK | sabotenb, bjtwin, macross, gunnail | [**是**](https://github.com/mamedev/mame/blob/0006fba49565386afa9b66d9fb8e02f744cf7cdb/src/mame/nmk/nmk16.cpp#L7480) | 4 | [链接](img/mcu-nmk215.jpeg) | | - | TMP90840 | SDIP64 | Dynax | mjvegas | [**是**](https://github.com/mamedev/mame/blob/26072bb747281a3abb519dc2a2c38884b9c5d479/src/mame/dynax/royalmah.cpp#L5159) | 2 | [链接](img/mcu-mjvegas.jpeg) | | - | TMP90840 | SDIP64 | Dynax | cafedoll | [**是**](https://github.com/mamedev/mame/blob/26072bb747281a3abb519dc2a2c38884b9c5d479/src/mame/dynax/royalmah.cpp#L5042) | 2 | [链接](img/mcu-cafedoll.jpeg) | | - | TMP90840 | SDIP64 | Dynax | cafetime | [**是**](https://github.com/mamedev/mame/blob/26072bb747281a3abb519dc2a2c38884b9c5d479/src/mame/dynax/royalmah.cpp#L98) | 2 | [链接](img/mcu-cafetime.jpeg) | | - | TMP91640 | SDIP64 | Dynax | cafebrk | [**是**](https://github.com/mamedev/mame/blob/26072bb747281a3abb519dc2a2c38884b9c5d479/src/mame/dynax/royalmah.cpp#L5340) | 2 | [链接](img/mcu-cafebrk.jpeg) | | - | TMP91640 | SDIP64 | Dynax | cafepara | [**是**](https://github.com/mamedev/mame/blob/26072bb747281a3abb519dc2a2c38884b9c5d479/src/mame/dynax/royalmah.cpp#L5072) | 2 | [链接](img/mcu-cafepara.jpeg) | | - | TMP90840 | SDIP64 | Dynax | mjtensin | [**是**](https://github.com/mamedev/mame/blob/fe923e9b3c464d7e373dd1992c6001b47b572e19/src/mame/dynax/royalmah.cpp#L4868)
*(未被游戏代码使用)* | 4 | [链接](img/mcu-mjtensin.jpeg) | | - | TMP91640 | SDIP64 | Dynax | majrjh | [**是**](https://github.com/mamedev/mame/blob/000c31fae55296ae3a853f2ffbe44a6d46dc7a3a/src/mame/dynax/royalmah.cpp#L4970) | 2 | [链接](img/mcu-majrjhdx.jpeg) | | - | TMP91640 | SDIP64 | Dynax | majrjhdx | [**是**](https://github.com/mamedev/mame/blob/000c31fae55296ae3a853f2ffbe44a6d46dc7a3a/src/mame/dynax/royalmah.cpp#L4955)
*(与 majrjh 的 dump 相同)* | 2 | [链接](img/mcu-majrjhdx.jpeg) | | - | ? | SDIP64 | Dynax | gekisha | 否 | - | - | | - | TMP91640 | SDIP64 | Dynax | tenkai | [**是**](https://github.com/mamedev/mame/blob/88a47305a4a5987fbe0e9160d8dd6b6a9c3a2314/src/mame/dynax/dynax.cpp#L6820)
*(之前已被 dump)*
*(等待使用此方法进行 dump)* | - | - | | - | ? | SDIP64 | Dynax | tenkai2b | 否 | - | - | | - | TMP90840 | SDIP64 | Dynax | ougonhai | [**是**](https://github.com/mamedev/mame/blob/fe923e9b3c464d7e373dd1992c6001b47b572e19/src/mame/dynax/dynax.cpp#L7021) | 2 | [链接](img/mcu-ougonhai.jpeg) | | - | TMP90840 | SDIP64 | Dynax | mjreach | [**是**](https://github.com/mamedev/mame/blob/fe923e9b3c464d7e373dd1992c6001b47b572e19/src/mame/dynax/dynax.cpp#L6662) | 2 | [链接](img/mcu-mjreach.jpeg) | | - | TMP90840 | SDIP64 | Dynax | mjreach2 | [**是**](https://github.com/mamedev/mame/blob/3f9d6b905f18b8800a9420abdd981ee51502d85e/src/mame/dynax/dynax.cpp#L6751) | 2 | [链接](img/mcu-mjreach2.jpeg) | | - | TMP91640 | SDIP64 | Jaleco | avspirit | [**是**](https://github.com/mamedev/mame/blob/afd6f2419ae0572972312e9570d8670b434b9793/src/mame/jaleco/megasys1.cpp#L2734)
感谢 **Tailsnic Retroworks** 提供 MCU 芯片
由*我*进行 dump。 | 4 | [链接](img/mcu-avspirit.jpeg) | | - | TMP91640 | SDIP64 | Jaleco | edf | [**是**](https://github.com/mamedev/mame/blob/df3e2de8e1815f0c22419c298471fbb8776858a2/src/mame/jaleco/megasys1.cpp#L3145)
感谢 **Darren Olafson**
由*我*进行了二次验证。 | 6 | [链接](img/mcu-edf.jpeg) | | MO-91009 | TMP91640 | SDIP64 | Jaleco | 64street | [**是**](https://github.com/mamedev/mame/blob/7b047641fe763667882a8c3320ad24163c63d327/src/mame/jaleco/megasys1.cpp#L2297) | 6 | [链接](img/mcu-mo91009.jpeg) | | MO-91021 | TMP91640 | SDIP64 | Jaleco | bigstrik | [**是**](https://github.com/mamedev/mame/blob/7b047641fe763667882a8c3320ad24163c63d327/src/mame/jaleco/megasys1.cpp#L2879) | 6 | [链接](img/mcu-mo91021.jpeg) | | MO-91028 | TMP91640 | SDIP64 | Jaleco | chimerab | [**是**](https://github.com/mamedev/mame/blob/7b047641fe763667882a8c3320ad24163c63d327/src/mame/jaleco/megasys1.cpp#L2927)
*(与 cybattlr 的 dump 相同)*
感谢 **kuze** | 6 | [链接](img/mcu-mo91028.jpeg) | | - | ? | SDIP64 | Jaleco | chimeraba | 否 | - | - | | MO-91028 | TMP91640 | SDIP64 | Jaleco | cybattlr | [**是**](https://github.com/mamedev/mame/blob/7b047641fe763667882a8c3320ad24163c63d327/src/mame/jaleco/megasys1.cpp#L3049)
感谢 **kuze** | 6 | [链接](img/mcu-mo91028.jpeg) | | MO-91044 | ? | SDIP64 | Jaleco | hayaosi1 | 否 | - | - | | MO-92033 | TMP91640 | SDIP64 | Jaleco | peekaboo | [**是**](https://github.com/mamedev/mame/blob/225c0586cb9f0f3c8fb234736ba2863dffa12c69/src/mame/jaleco/megasys1.cpp#L4424) | 4 | [链接](img/mcu-mo92033.jpeg) | | - | TMP90840 | QFP64 | Toshiba | T1600 Laptop PSU | [**是**](bin/mcu-t1600psu.bin)
使用位于 [adapter/tmp90c840-qfc2sdip](adapter/tmp90c840-qfc2sdip) 的转接板 | 4 | [链接](img/mcu-t1600psu.jpeg) | 如果您发现更多基于此 MCU 系列的设备、有附加信息或成功 dump 了某些内容,请告诉我,以便我将它们添加到上表中,仅供参考。 ## 原型和先前版本 在此过程中,为了了解 MCU 在某些特殊情况下的行为,并对其进行测试不同的攻击,我们制造并测试了几个先前版本的电路板。 ### 版本 1(Proto - 测试板) 这是有史以来制作的第一块板子,其目的是测试 TLCS90 设备的行为,并进行一些简单的攻击尝试,以观察设备在受到攻击时的表现。 [

TLCS90 ROM Reader v1

](img/TLCS90-rom-reader-v1.jpg) ### 版本 2(Proto - 攻击板) 使用从第一个版本编译的数据,第二个版本包含了主要攻击的实现以及一些细微的变体,以便在真实设备上进行测试。 [

TLCS90 ROM Reader v2 front

](img/TLCS90-rom-reader-v2-front.jpg) 为了修复错误并测试攻击的微小变化,需要直接在 PCB 上进行多次补丁修改 :D [

TLCS90 ROM Reader v2 back

](img/TLCS90-rom-reader-v2-back.jpeg) ### 版本 3(最终版本) 在确认攻击对多个设备成功后,移除了未使用的部件并简化了布局。增加了对选择设备类型(通过其内部 ROM 大小)的支持。还增加了通过直流连接器为电路板供电的附加选项。 [

TLCS90 ROM Reader v3

](img/mcu-nmk215.jpeg) ## 联系方式 X (_Twitter_) 上的 [@Recre_Piscis](https://x.com/Recre_Piscis)。 ## License 有关更多详细信息,请参阅 [LICENSE](LICENSE)。
标签:ROM读取器, 云资产清单, 后端开发, 嵌入式系统, 微控制器, 硬件修复, 硬件工具, 逆向工程