逆向工程串行通信CRC算法

逆向工程 串行通讯 CRC 二元诊断
2021-06-13 10:56:49

我正在对一个过时的电子控制系统的串行通信协议进行逆向工程,但我无法弄清楚 CRC 算法和多项式。

我对同一家公司过去制造的另一个类似系统进行了逆向工程。在之前的那个中,我能够从 中转储8051微控制器程序EPROM并将其反汇编。这是我用 C 编写的工作代码,8051注释中有原始反汇编:

unsigned char CalculateChecksum(void) {
    unsigned char r1 = 0;               // MOV R1,#0
    unsigned char r2, r3, c, a;

    for (r2=1; r2<4; r2++) {    // MOV R2,#07
        a = out_buffer[r2];     // MOV A,@R0

        r3 = a;                 // XCH A,R1
        a = r1;
        r1 = r3;

        c = 0;                  // CLR C

        if (a & 0x80) {
            c = 1;              // FAKE CARRY
        }
        a = a << 1;             // RLC A
        if (c == 1) {           // JNC 0x03E8
            a = a ^ 0x19;       // XRL A,#19
        }
        a = a ^ r1;             // XRL A,R1 (0x03E8)
        r1 = a;                 // MOV R1,A
        printf("%d: 0x%x ", r2, a);
    }

    return a;
}

问题是这个功能在这个较新的系统上不起作用。我已经尝试了所有 255 种可能的多项式,因此尚不清楚不同系统之间是否共享算法(也许进行了一些修改?),但是我相信算法之间存在关系。

这是从一个单元传输的一些消息的捕获:

7E 00 12 03 00 50 FB 01 60 
7E 00 12 03 00 50 FB 01 60 
7E 00 12 03 00 50 FB 01 60 
7E 00 12 03 00 50 FB 01 60 
7E 00 12 03 00 51 FB 01 61 
7E 00 12 03 00 51 FB 01 61 
7E 00 12 03 00 51 FB 01 61 
7E 00 12 03 00 51 FF 01 65 
7E 00 12 03 00 51 03 00 69 
7E 00 12 03 00 51 09 00 6F

0x7E 似乎是一个前导码,后跟 7 个字节的数据,然后是校验和字节。任何人都可以弄清楚吗?

1个回答

这个问题似乎比你想象的要简单。

由于正如 OP 所指出的,代码与所讨论的系统中使用的验证机制无关,我将忽略它。这确实无关紧要,如下所示。

由于每条消息中的第一个字节确实看起来像一个序言,我们将忽略它。我们的目标是恢复函数,当应用于给定的第 1-8 个字节(即除了第一个和最后一个字节之外的所有字节)时,提供最后一个字节。

让我们以 OP 提供的第一条消息为例:

00 12 03 00 50 FB 01 60

因此,我们需要找到f这样的

f(00 12 03 00 50 FB 01) = 60

以下 3 条消息是相同的。这很好,它揭示了验证字节相对于消息字节是确定性的事实,但在其他方面毫无用处。

我们将跳到第五条消息并将其与第一条进行比较:

f(00 12 03 00 50 FB 01) = 60
f(00 12 03 00 51 FB 01) = 61

这很好,我们知道消息的第 5 个字节中的单个位增量更改会导致输出完全相同的更改。将 1 添加到第五个字节也会使输出增加 1。

最后两条消息也会发生同样的情况:

f(00 12 03 00 51 03 00) = 69 
f(00 12 03 00 51 09 00) = 6F

9-3 = 6 = 6F-69

只是这次使用了不同的字节和更大的增量。

我们可能愿意假设所有字节和所有增量都保留了这种关系,我们将是正确的。

如果直到现在还不清楚,答案就在我们面前:最后一个字节是所有消息字节的总和,模 257。

在python中,给定m = ['00', '12', '03', '00', '51', '09', '00'],以下代码将提供正确的值0x6F

hex(sum(map(lambda x: int(x, 16), m))%257)

这对于所有提供的输入都是正确的。