逆向工程校验和算法

逆向工程 硬件 CRC 二元诊断
2021-06-14 23:20:24

我正在尝试为已停产的硬件鼓合成器实现一个编辑器,它使用未记录的系统专用 MIDI 消息进行通信。我已经弄清楚了补丁格式,但是我在使用校验和算法时遇到了麻烦。我尝试了各种方法和工具(例如复仇)来尝试计算并达到我的能力极限。

由于 MIDI 被限制为消息中的 7 位(页眉和页脚字节 F0/F7 除外),这一切都变得复杂了。所以还有一个额外的问题是如何处理溢出。

我试图理解两种类型的消息:

语音请求:

F0 33 7F 7F 08 03 07 40 00 0E F7

或者

F0 33 7F 7F 08 03 05 00 13 F7

其中倒数第二个字节(示例中为 0E,13)是某种校验和。我假设这两条消息使用相同的算法,但我什至不确定校验和计算实际上考虑了哪些字节(因为 0xF0 0x33 0x7F 总是存在于该仪器发送或接收的每条消息,它可能会被排除在外,但我不能确定)。这里还有一些示例:

F0 33 7F 7F 08 03 07 40 1A 57 F7
F0 33 7F 7F 08 03 07 40 1B 5F F7
F0 33 7F 7F 08 03 07 40 1C 67 F7
F0 33 7F 7F 08 03 07 40 1D 6F F7
F0 33 7F 7F 08 03 07 40 1E 77 F7
F0 33 7F 7F 08 03 07 40 1F 7F F7
F0 33 7F 7F 08 03 07 40 20 1C F7
F0 33 7F 7F 08 03 07 40 21 14 F7
F0 33 7F 7F 08 03 07 40 22 0C F7
F0 33 7F 7F 08 03 07 40 23 04 F7
F0 33 7F 7F 08 03 07 40 24 3C F7
F0 33 7F 7F 08 03 07 40 25 34 F7
F0 33 7F 7F 08 03 07 40 26 2C F7
F0 33 7F 7F 08 03 07 40 27 24 F7
F0 33 7F 7F 08 03 07 40 28 5C F7
F0 33 7F 7F 08 03 07 40 29 54 F7

或按校验和分组:

F0 33 7F 7F 08 03 07 44 0D 00 F7
F0 33 7F 7F 08 03 07 45 1F 00 F7
F0 33 7F 7F 08 03 07 47 2A 00 F7

F0 33 7F 7F 08 03 07 44 1C 01 F7
F0 33 7F 7F 08 03 07 45 0E 01 F7
F0 33 7F 7F 08 03 07 46 29 01 F7

F0 33 7F 7F 08 03 07 44 2F 02 F7
F0 33 7F 7F 08 03 07 46 1A 02 F7
F0 33 7F 7F 08 03 07 47 08 02 F7

F0 33 7F 7F 08 03 07 45 2C 03 F7
F0 33 7F 7F 08 03 07 46 0B 03 F7
F0 33 7F 7F 08 03 07 47 19 03 F7

F0 33 7F 7F 08 03 07 40 23 04 F7
F0 33 7F 7F 08 03 07 41 31 04 F7
F0 33 7F 7F 08 03 07 42 16 04 F7
F0 33 7F 7F 08 03 07 43 04 04 F7

F0 33 7F 7F 08 03 07 41 20 05 F7
F0 33 7F 7F 08 03 07 42 07 05 F7
F0 33 7F 7F 08 03 07 43 15 05 F7

F0 33 7F 7F 08 03 07 40 01 06 F7
F0 33 7F 7F 08 03 07 41 13 06 F7
F0 33 7F 7F 08 03 07 43 26 06 F7

F0 33 7F 7F 08 03 07 40 10 07 F7
F0 33 7F 7F 08 03 07 41 02 07 F7
F0 33 7F 7F 08 03 07 42 25 07 F7

F0 33 7F 7F 08 03 07 44 0F 10 F7
F0 33 7F 7F 08 03 07 45 1D 10 F7
F0 33 7F 7F 08 03 07 47 28 10 F7

校验和涵盖从 00 到 7F 的完整 7 位范围,但低 4 位的出现似乎与 0x4n 字节的低 4 位有关。

另一种类型的消息是实际的语音数据。此数据在数据包末尾使用 28 位(4 字节)校验和(总共 212 字节):

F0337F19 08030600 00040000 00000000 03600000 02540070 18001640 17100D19 16010808 60021219 4B103112 4A000000 06600000 003C0070 18001640 17100D19 32652008 34033D48 03102C4F 0A000000 16420000 00580110 18001640 16580D19 1E012C08 7401760A 13102F17 47000000 16420000 00500070 18001640 16580D19 32007408 68033D75 7B102F57 4C000000 06420000 00500070 18001640 16580D19 32007408 7002517A 13102F17 4A000000 16420000 00580070 18001640 16580D19 32005C09 10023202 13102F57 48000001 5D7C65F7

或者

F0337F19 08030600 00040000 00000000 03610000 02540070 18001640 17100D19 16010808 60021219 4B103112 4A000000 06600000 003C0070 18001640 17100D19 32652008 34033D48 03102C4F 0A000000 16420000 00580110 18001640 16580D19 1E012C08 7401760A 13102F17 47000000 16420000 00500070 18001640 16580D19 32007408 68033D75 7B102F57 4C000000 06420000 00500070 18001640 16580D19 32007408 7002517A 13102F17 4A000000 16420000 00580070 18001640 16580D19 32005C09 10023202 13102F57 48000000 6A7101F7

或者

F0337F19 08030600 00040000 00000000 03620000 02540070 18001640 17100D19 16010808 60021219 4B103112 4A000000 06600000 003C0070 18001640 17100D19 32652008 34033D48 03102C4F 0A000000 16420000 00580110 18001640 16580D19 1E012C08 7401760A 13102F17 47000000 16420000 00500070 18001640 16580D19 32007408 68033D75 7B102F57 4C000000 06420000 00500070 18001640 16580D19 32007408 7002517A 13102F17 4A000000 16420000 00580070 18001640 16580D19 32005C09 10023202 13102F57 48000003 73762BF7

对校验和的第 1 个字节 (01, 00, 03) 的更改以响应对字节 41 (0, 1, 2) 的低 4 位的更改当然是一个提示,但我不明白。

无论如何,如果有人对合理的进行方式有建议,我将不胜感激。制造该仪器的公司无意支持其旧(更)硬件,并且拒绝提供任何类型的系统专有文档。该公司出于类似目的在其他仪器上使用了 CRC 算法,但没有什么与我在这里看到的相符。

如果有任何兴趣,我很乐意提供额外的样本数据(我意识到只有几个样本是不够的)——我有 256 条请求消息和 160 多个完整的语音可供分析。我还可以生成数据来测试对完整消息的不同部分进行更改的效果。谢谢参观。

更新 1:

我已经解决了短消息的校验和。它是 的 CRC16(CCITT) (full message previous to that byte) >> 9 & 0x7F我通过在反汇编程序中破解公司(请求语音库)的基于计算机的实用程序的二进制文件来解决这个问题。我猜长消息是类似的,只是有更多的字节,当我知道更多时会报告。

更新 2:

长消息的倒数第二个字节也使用上述公式。然而,之前的 3 个字节在这一点上仍然是个谜,我在我拥有的二进制文件中没有发现任何明显的东西——这些字节是在硬件上生成的,而不是在“客户端”上生成的。它看起来仍然像一个 16 位值,分布在 3 个 7 位限制字节上。我只是还没有确定这个价值是如何产生的。

2个回答

我发现的唯一 Nord Sys Ex 规范是针对 Nord Stage 的,它显然使用了“7 位校验和(上面所有字节的总和 - 包装)”。所以我昨天尝试了我能想到的所有变体,基本上是求和和屏蔽到 7 位。失败了,我回到了这篇文章。

两个设备之间的消息标头相似(相同和不同的方式与您对产品线的两个版本所期望的方式相同)。ND1 上一个程序的 Sys Ex 转储长度为 110 字节(总计)。

CRC 对我来说是一个新领域,所以我可以稍微澄清一下你对短消息校验和的解释。你的意思是:

  1. 计算完整消息的 CRC16(CCITT);
  2. 右移 9 个字节(除以 512);
  3. 取那个七位掩码?

好的,这适用于 ND1,至少在更改随机位并重新生成校验和并将其发送到单元方面会生成“rcu”消息,表明它正在接收,这与它对错误校验和所做的不同。实际上并没有改变程序,但现在也许实际设置的实际逆向工程会起作用。

尝试一些小的更改并比较转储,恐怕我在 ND1 上看到的行为与您在 ND2 上看到的行为相同,字节 105、106 和 107 随最后一个 CRC 校验和字节一起变化。

恐怕我不会再进一步​​了。你能走到这一步,我印象深刻!我是一名高中 CS 老师,所以这对我来说是一个很好的练习——在过去的两天里,我学到了很多关于校验和和数据错误检测的知识!

ND1 上的一个小发现:在 sys ex 转储中,如果要转储单个程序,则字节 6 为 6,如果要转储所有程序,则为 8。如果您要转储一个程序,则字节 7 为 0;如果您要转储所有程序,则字节 7 为程序编号 (-1)。

也许更有趣——这似乎只改变了最终校验和(字节 110)的值,而不是神秘的其他校验和字节。