【问题标题】:Find used CRC-16 algorithm查找使用过的 CRC-16 算法
【发布时间】:2020-03-19 20:43:59
【问题描述】:

我正在努力对与 CRC-16 校验和相关的一段数据进行逆向工程。 我知道用于计算原始校验和的多项式是 0x8408 但仅此而已,我不知道初始值(如果有)、最终 XOR 值(如果有)、是否反映了输入或结果...

似乎有一个使用事物多项式的已知 CRC-16 生成器,CRC-16-CCITT 但尽管我已经尝试了一切,但我还是无法理解原始校验和是如何计算的.

这是我得到的数据及其各自的校验和。我还包括了一个位于数据和校验和之间的字节,它是增量的,我不知道它是否计算过。 (看最后两行,数据几乎一样,增量不一样但校验和相同)

|                           DATA                           |Inc|CRC|
|----------------------------------------------------------|---|---|
00 00 00 00 00 00 01 ef f7 fe ef ff fd ef fb fa fd a2 aa 21 01 f4 e0
00 00 00 00 00 00 01 ef f7 fd ef ff fd fe fb fa fd a2 aa 21 02 f4 d1
00 00 00 00 00 00 01 f7 fe fd fd ff fd df ff fb fd a2 aa 21 03 f4 cd
00 00 00 00 00 00 01 f7 fe fe fd ff f7 ef ff fa fd a2 aa 21 04 f4 c2
00 00 00 00 00 00 01 ef f7 fe ef ff fe ef fb fa fd a2 aa 21 05 f4 db
00 00 00 00 00 00 01 ef f7 fe ef ff fd ef fb fa fd a2 aa 21 06 f4 db

【问题讨论】:

  • 你确定这是一个带有 poly 0x8408 的 CRC16 吗?如果你对最后两行进行异或,它会取消 crc 初始值并异或,你会得到 {00 00 00 00 00 00 00 00 00 00 00 00 03 00 00 00 00 00 00 00 03 00 00},这不太可能是一个 CRC,因为两个 03 和 CRC == 0 意味着循环周期是 64 位(8 个字节),这太短了。如果不包括第二个 03,则会得到 {{00 00 00 00 00 00 00 00 00 00 00 00 03 00 00 00 00 00 00 00 00 00},对于非零数据,得到 CRC = 0。
  • @rcgldr 好吧,我不能说我 100% 确定这一点,因为我无法访问用于计算校验和的代码,但我得到了 poly 值,校验和的长度(2 个字节)及其在与该数据相关的软件的 SQL 表中的数据包中的位置。
  • @rcgldr 另外,在 SQL 表中,一些字段清楚地表明它是 CRC。另外,校验和的第一个字节是如何从不改变的,这对你来说是不是很奇怪? CRC算法不是设计用来使校验和不同,即使单个数据字节改变?
  • 是的,通常 CRC 的两半都会随着数据的任何变化而变化。在最后两行中,附加的和是相同的,“校验和”是相同的,让我认为这是某种形式的校验和。
  • @rcgldr 所以你认为这不是 CRC 吗?这与我最初的问题有点不同,但有什么方法可以测试已知的校验和算法,然后找出使用的是哪一个?此外,无论如何,数据+“CRC”在由摩托罗拉 MPC CPU 驱动的嵌入式系统上结束。

标签: reverse-engineering checksum crc crc16


【解决方案1】:

每行的最后一个字节似乎是 0xF3 + 除了最后一个字节(包括 0xF4)之外的所有字节的负和。此代码适用于 5 个示例:

typedef unsigned char uint8_t;

static uint8_t data0[] = 
   {0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xef,0xf7,0xfe,0xef,
    0xff,0xfd,0xef,0xfb,0xfa,0xfd,0xa2,0xaa,0x21,0x01,0xf4,0xe0};
static uint8_t data1[] = 
   {0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xef,0xf7,0xfd,0xef,
    0xff,0xfd,0xfe,0xfb,0xfa,0xfd,0xa2,0xaa,0x21,0x02,0xf4,0xd1};
static uint8_t data2[] = 
   {0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xf7,0xfe,0xfd,0xfd,
    0xff,0xfd,0xdf,0xff,0xfb,0xfd,0xa2,0xaa,0x21,0x03,0xf4,0xcd};
static uint8_t data3[] = 
   {0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xf7,0xfe,0xfe,0xfd,
    0xff,0xf7,0xef,0xff,0xfa,0xfd,0xa2,0xaa,0x21,0x04,0xf4,0xc2};
static uint8_t data4[] = 
   {0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xef,0xf7,0xfe,0xef,0xff,
    0xfe,0xef,0xfb,0xfa,0xfd,0xa2,0xaa,0x21,0x05,0xf4,0xdb};
static uint8_t data5[] = 
   {0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xef,0xf7,0xfe,0xef,0xff,
    0xfd,0xef,0xfb,0xfa,0xfd,0xa2,0xaa,0x21,0x06,0xf4,0xdb};

int main()
{
size_t i;
uint8_t c = 0xf3;
uint8_t s;
    s = c;
    for(i = 0; i < sizeof(data0)-1; i++)
        s -= data0[i];
    if (data0[i] != s)
        printf("mismatch\n");
    s = c;
    for (i = 0; i < sizeof(data1) - 1; i++)
        s -= data1[i];
    if (data1[i] != s)
        printf("mismatch\n");
    s = c;
    for (i = 0; i < sizeof(data2) - 1; i++)
        s -= data2[i];
    if (data2[i] != s)
        printf("mismatch\n");
    s = c;
    for (i = 0; i < sizeof(data3) - 1; i++)
        s -= data3[i];
    if (data3[i] != s)
        printf("mismatch\n");
    s = c;
    for (i = 0; i < sizeof(data2) - 1; i++)
        s -= data4[i];
    if (data4[i] != s)
        printf("mismatch\n");
    return 0;
}

【讨论】:

  • 刚刚用更多的数据对其进行了测试,它就像一个魅力!感谢您抽出宝贵时间,但我仍然很好奇您是如何找到它的。
  • @Spacebrain - 我注意到最后两行的算术和是相同的,所以这意味着校验和可能是一个常数±总和。可以在第一次尝试时确定常数,最初假设它为零,然后设置调整常数以匹配最后一个字节。当 + sum 不起作用时,我切换到 - sum。常量可能是倒数第二个字节 - 1,对于上面的示例,0xF4 - 0x01 = 0xF3,反之亦然 0xF4 = 0xF3 + 1。
猜你喜欢
  • 1970-01-01
  • 2021-08-09
  • 1970-01-01
  • 2023-03-30
  • 2022-11-17
  • 1970-01-01
  • 2018-02-21
  • 1970-01-01
  • 2014-10-04
相关资源
最近更新 更多