对 IBM BSC (Bisync) 协议进行逆向工程

逆向工程 串行通讯 CRC
2021-06-16 07:40:43

我正在尝试连接到使用 IBM BSC 同步协议的旧通信控制器,但我无法正确获取 CRC。

背景

本文档中对协议本身进行了很好的描述:

http://bitsavers.trailing-edge.com/pdf/ibm/datacomm/GA27-3004-2_General_Information_Binary_Synchronous_Communications_Oct70.pdf

发送通信处理器采用摩托罗拉MC6852芯片。但是芯片没有硬件crc电路,所以在comm.js里面有软件。执行 crc 的处理器。

实际的通信控制器描述如下:http : //storage.datormuseum.se/u/96935524/Datormusuem/Alfaskop/Alfaskop_System_41_Reference_Manual_IBM3270_Emulation.pdf

第 89 页及以后描述了它对 BSC 的使用。

那么由于这台设备是IBM 3274 C型兼容本手册适用:http : //bitsavers.informatik.uni-stuttgart.de/pdf/ibm/3274/GA23-0061-1_3274_Control_Unit_Description_and_Programmers_Guide_Jan84.pdf

第 159 页及以后的页面与其他文档具有基本相同的信息。

实际消息

我捕获了实际通信处理器发送的两条消息。请注意,消息以 EBCDIC 而不是 ASCII 编码。这些是对 POLL 消息的响应。上面 IBM 文档中的第 172 和 175 页:

32 01 6C D9 02 40 40 40 70 03 26 88 和 32 01 6C D9 02 40 C8 40 50 03 0D 28

根据我对 IBM 文档的阅读,CRC 算法将在看到 01 (SOH) 或 02 (STX) 时重置,然后累积直到看到 03 (ETX)。但是,SOH 后跟 STX 不会在 STX 再次重置 CRC。本质上,这意味着上述消息中的 CRC 字节是 2688 和 0D28。有一个前导 SYN (32) 但它不包括在 CRC 计算中,因为它在 SOH 字符之前。用于 CRC 计算的消息则分别为:6C D9 02 40 40 40 70 03 和 6C D9 02 40 C8 40 50 03。SOH 不是计算的一部分,但是 CRC 之前的尾随 ETX 是 CRC 计算的一部分。

上面的消息是由 Intel 8274 芯片接收的。不过,英特尔芯片中没有进行 CRC 检查。

由于英特尔 8274 芯片确实包含一个 CRC 检查器/生成器,我应该能够生成正确格式的消息并接收消息以进行进一步检查和调查。我将沿着这条路径走一点,看看我是否可以使用 8274 芯片接收和发送以及生成什么 CRC 值。

8274芯片本身支持两种CRC算法。CRC-16 和 CCITT CRC-16。我的理解是 IBM 将 CRC-16 与多项式 X^16+X^15+X^2+1 一起使用。即 8005。我所看到的任何地方都没有描述使用了 crc 的初始值。一个很好的猜测是 0000h 或可能是 ffffh。

情况是我想用一个小的STM32微控制器来处理BSC通信。我成功地让程序实现了与传入数据的同步并提取了正确格式的消息。但显然,除非我能够正确计算 CRC,否则通信将无法进行。在制品:https : //github.com/MattisLind/alfaskop_emu/tree/master/Utils/BSCGateway

CRC报仇烦恼

我已尝试使用 crc reveng 工具来计算 CRC 数字,但无法与上述数据匹配。我也不能使用 crc reveng 来搜索算法。它不断报告说找不到模型。

使用 crc reveng 生成 CRC 并将上述消息作为数据输入和多项式 8005 不会给出相应的输出 CRC 数据。我为 CRC 尝试了几个初始值,还测试了位顺序选项的各种变体,但没有匹配。

然后我尝试了一些在互联网上找到的 C 中的 CRC 算法。它们在上述消息上都给出了相同的 CRC 值,但没有一个与消息中的值匹配,也不是来自 crc reveng 的输出。

很可能我在应用crc reveng时做错了什么,但我无法弄清楚是什么。

crc复仇的又一考验

为了更好地理解 crc reveng,我尝试了一个示例消息,其中输入数据缓冲区、初始 CRC 值和输出 CRC 值是众所周知的:https : //stackoverflow.com/questions/23638939/crc-16-ibm-reverse -c 中查找

Mark Adler 的第一个答案中的代码给出的结果与 Maxim 文章中提到的结果相匹配。但不幸的是,我无法在 crc reveng 中重新创建它。

请提示我做错了什么!

2个回答

如果您有已知数据和已知 CRC,以及一个未知值(如初始 CRC 值或最终 XOR 值),您始终可以遍历所有可能的值并找到那些给您想要的答案的值。对于 32 位 CRC,它可能不实用,但对于 8 位和 16 位 CRC,它不应该花费太长时间来运行。

不过,您至少需要两组已知数据才能获得更准确的值,因为 65,536 个可能的值中的许多值将为单个消息提供正确的答案。但是对于两个,很少有值会为两个消息产生正确的 CRC。只需在循环中生成两个 CRC,如果两者都产生正确的结果,则打印使用的值并继续下一个。幸运的是,最后您将拥有该实现使用的正确常量 - 当然假设算法的其余部分是正确的!

此外,请确保您的 CRC 实现正确处理字长,例如,32 位架构上的 16 位实现可能会意外使用 15 位以上的位,而这些位在原始 16 位架构中刚刚丢失。

我以前没有使用过 CRC RevEng,但听起来它就是这样做的,所以我不确定为什么你没有得到任何结果。在你的情况下,算法似乎定义得很好,但我只是对一个被记录为 CRC-8 的算法进行了逆向工程,但实际上它看起来更像是一个校验和而不是一个完整的 CRC 算法,并且是 16 位不是8 位,所以你不能总是相信文档!可能如果算法在某种程度上是非标准的,这就是 CRC RevEng 无法接受的原因。

解决方案

我从一个叫彼得的人​​那里得到了帮助。他给了我一段 C 语言的测试代码。 CRC 算法看起来与我已经尝试过的算法非常相似。但重要的是他指出第一个示例消息很可能有一点错误。

#include <stdio.h>

int crc16(unsigned char *ptr, int count)
{
    unsigned int crc;
    char i;

    crc = 0x0000;
    while (--count >= 0)
    {
        crc = crc ^ (unsigned int) *ptr++;
        i = 8;
        do
        {
            if (crc & 0x0001)
                crc = (crc >> 1) ^ 0xA001;  /* 0x8005 bit reversed */
            else
                crc = (crc >> 1);
        } while(--i);
    }
    return (crc);
}

void main()
{                   
                     /* 32  01  6C  D9  02  40  40  40  70  03  26  88 */

   unsigned char data1[] = {0x6c, 0xd9, 0x02, 0x40, 0x40, 0x40, 0x50, 0x03};

                     /* 32  01  6C  D9  02  40  C8  40  50  03  0D  28 */

   unsigned char data2[] = {0x6c, 0xd9, 0x02, 0x40, 0xc8, 0x40, 0x50, 0x03};

   printf("crc sent: 8826 computed: %4.4x\n", crc16(data1, sizeof(data1)));

   printf("crc sent: 280d computed: %4.4x\n", crc16(data2, sizeof(data2)));

   return;
}

当使用 crc reveng 测试第一个更正的消息和第二个消息时,它找到了算法

$ ./reveng -w 16  -s 6cd90240c84050030d28
./reveng: warning: you have only given 1 sample
./reveng: warning: to reduce false positives, give 4 or more samples
width=16  poly=0x8005  init=0x0000  refin=true  refout=true  xorout=0x0000  check=0xbb3d  residue=0x0000  name="CRC-16/ARC"
MattisMacBook:reveng-2.1.0 mattis$ ./reveng -w 16  -s 6CD90240404070032688
./reveng: warning: you have only given 1 sample
./reveng: warning: to reduce false positives, give 4 or more samples
./reveng: no models found
$ ./reveng -w 16  -s 6CD90240404050032688
./reveng: warning: you have only given 1 sample
./reveng: warning: to reduce false positives, give 4 or more samples
width=16  poly=0x8005  init=0x0000  refin=true  refout=true  xorout=0x0000  check=0xbb3d  residue=0x0000  name="CRC-16/ARC"

然后我尝试让 crc reveng 进行与 Peter 上面提供的代码相同的计算。花了一段时间才找到正确的选项。出于某种原因,我必须以相反的位顺序指定多项式才能使其工作。

$ ./reveng -w 16 -P a001 -i 0000  -x 0000  -l  -d 
width=16  poly=0x8005  init=0x0000  refin=true  refout=true  xorout=0x0000  check=0xbb3d  residue=0x0000  name=(none)
$ ./reveng -w 16 -P a001 -i 0000  -x 0000  -l  -c 6CD9024040405003
2688

结论和经验教训

我从没想过接收到的数据会出错。那是愚蠢的。在 9600 bps 连接上不太可能,但可能会发生。然后我太专注于同时测试两条消息,从未看到第二条消息实际上返回了 OK CRC,尽管它交换了字节。

所以我自己的教训是:

  1. 拥有更多样本,以便更容易发现传输错误
  2. 不要假设所有消息都是正确的。
  3. crc reveng 有很多选择,乍一看很难做到正确 - 继续尝试!

感谢所有帮助过的人!