我正在对一个过时的电子控制系统的串行通信协议进行逆向工程,但是我在弄清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接收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个字节中的增量更改会导致输出完全相同的更改。将第五个字节加一个也将使输出也加一。

最后两个消息也是如此:

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)


对于所有提供的输入,此行为均正确。

评论


感谢您的帮助!我尝试了您的Python代码,它对于示例中的数据正常工作,但是如果您使用m = ['00','12','03','00','50','FB','01 ']结果为0x61,应为0x60。我在这里做错什么了吗?

–约翰·沃尔兹(John Voltz)
16-9-29在14:19



实际上,它使用mod 257而不是mod 256可以完美地与所有输入配合使用。感谢您的帮助,我不知道自己是否可以解决这个问题。

–约翰·沃尔兹(John Voltz)
16-9-29在15:35