当前位置: 首页 > 知识库问答 >
问题:

逆向工程BLE设备-校验和?

濮阳宁
2023-03-14

我正试图反向工程一个BLE装置(万向节)。在嗅探btsnoop_hci.log之后,我已经成功地复制了精确的命令,下面是其中的一些命令:

* AF: a55a030232200001 00 03 bd03
* TF: a55a030232200001 00 02 9c13
* HF: a55a030232200001 00 01 ff23
* LK: a55a030232200001 00 00 de33
                      (Speed 1) (Dir 1)  (Speed 2) (Dir 2) (CRC???)
a55a03000e0000050000      6f      00        00       00     f0c8   (Goes Left)
a55a03000e0000050000      ff      00        00       00     6f0e   (Goes Left Fast)
a55a03000e0000050000      96      ff        00       00     a96b   (Goes Right)

a55a03000e0000050000      01      ff        00       00     1bfc   (Goes Right Fast)
a55a03000e0000050000      00      00        01       ff     0d68   (Goes Up)
a55a03000e0000050000      00      00        ff       00     3346   (Goes Down)

更新:我使用reveng强制POLY&init:

步骤1:运行命令(电机命令中的最后两个字节反转):

reveng -w 16 -s a55a03000e00000500006f000000c8f0 a55a03000e0000050000ff0000000e6f a55a03000e000005000096ff00006ba9 a55a03000e000005000001ff0000fc1b

步骤1-结果:

width=16  poly=0x1021  init=0xa55a  refin=false  refout=false  xorout=0x0000  check=0x0459  residue=0x0000  name=(none)
reveng -w 16 -s a55a030232200001000303bd a55a0302322000010002139c a55a030232200001000123ff a55a030232200001000033de
width=16  poly=0x1021  init=0xa55a  refin=false  refout=false  xorout=0x0000  check=0x0459  residue=0x0000  name=(none)
width=16  poly=0x4dd7  init=0xd565  refin=true  refout=true  xorout=0x0000  check=0x39bd  residue=0x0000  name=(none)

但是,如果我使用函数:

#define POLY (0x1021)
#define INIT (0xa55a)

uint16_t crc16(uint8_t * bfr, size_t size)
{
uint16_t crc = INIT;
int i;
    while(size--){
        crc ^= *bfr++;
        for(i = 0; i < 8; i++)
            /* assumes two's complement */
            crc = (crc>>1)^((0-(crc&1))&POLY);
    }
    return(crc);
}

CRC值仍然与原始值不匹配。在我的知识中,有些东西我漏掉了。

示例:

uint8_t bfr[] = { 0xa5, 0x5a, 0x03, 0x02, 0x32, 0x20, 0x00, 0x01, 0x00, 0x02 };
uint16_t crc = crc16(bfr, 10);
a55a03000e00000500006f000000c8f0
a55a03000e0000050000ff0000000e6f
a55a03000e000005000096ff00006ba9
a55a03000e000005000001ff0000fc1b
a55a03000e0000050000000001ff680d
a55a03000e00000500000000ff004633
reveng -w 16 -s a55a03000e00000500006f000000c8f0 a55a03000e0000050000ff0000000e6f a55a03000e000005000096ff00006ba9 a55a03000e000005000001ff0000fc1b a55a03000e0000050000000001ff680d a55a03000e00000500000000ff004633

reveng -w 16 -s a55a030232200001000303bd a55a0302322000010002139c a55a03000e00000500006f000000c8f0 a55a03000e0000050000ff0000000e6f
width=16  poly=0x1021  init=0xa55a  refin=false  refout=false  xorout=0x0000  check=0x0459  residue=0x0000  name=(none)
width=16  poly=0x1021  init=0xa55a  refin=false  refout=false  xorout=0x0000  check=0x0459  residue=0x0000  name=(none)
width=16  poly=0x1021  init=0x5545  refin=false  refout=false  xorout=0xf01f  check=0x0459  residue=0xf01f  name=(none)
//                 a5    5a    03    00    0e    00    00    05    00    00    6f    00   00     00     f0c8 (swapped c8f0)
uint8_t bfr[] = { 0xa5, 0x5a, 0x03, 0x00, 0x0e, 0x00, 0x00, 0x05, 0x00, 0x00, 0x6f, 0x00, 0x00, 0x00 };



uint16_t crc = crc16(bfr, 14);

我得到十六进制的输出:532。我不明白。为什么我生成Poly&Init的代码返回了错误的十六进制?

共有1个答案

夏侯浩气
2023-03-14

您可以对样本进行异或以减少变量的数量,因为这消除了任何初始值或最终异或(就像两者都是0),搜索只需要寻找多项式,以及它是否没有反射(左移)或反射(右移)。对于CRC16,左移位和右移位只有64K循环。有可能得到多个似乎有效的多项式,所以需要更多的样本来确认。

* AF: a55a030232200001 00 03 bd03
* TF: a55a030232200001 00 02 9c13
      0000000000000000 00 01 2110

* HF: a55a030232200001 00 01 ff23
* LK: a55a030232200001 00 00 de33
                          01 2110

起初,我假设最后2个字节被交换了,所以01 211 0将是01 10 21,一个常见的左移(未反射)CRC,但由于我的错误(我在一个检查中的大小错误),我没有让它工作。

然后我假设最后2个字节是大endpoint0x2110,对于单个数据字节0x01上的左移CRC,CRC与多项式相同。然而,多项式的最低有效位(位0)需要为1,而0x2110的位0为0,所以我尝试了右移CRC。

然后对初始值和最终xor=0x0000或0xFFFF进行强力搜索,以匹配所有4个示例,初始值=0xA6AB,最终xor=0x0000。

位级代码示例:

typedef unsigned char   uint8_t;
typedef unsigned short uint16_t;

#define POLY (0xebb2)    /* polynomial */
#define INIT (0xa6ab)    /* initial value */
#define FXOR (0x0000)    /* final xor == xor out */

uint16_t crc16(uint8_t * bfr, size_t size)
{
uint16_t crc = INIT;
int i;
    while(size--){
        crc ^= *bfr++;
        for(i = 0; i < 8; i++)
            /* assumes two's complement */
            crc = (crc>>1)^((0-(crc&1))&POLY);
    }
    return(crc^FXOR);
}

如果将CRC与交换字节进行比较,则得到的CRC将与4个示例相匹配:

crc = crc16(bfr, 10);
if((bfr[10] == crc>>8) && (bfr[11] == crc&0xff))
    printf("match\n");
#define POLY (0x1021)    /* polynomial */
#define INIT (0xa55a)    /* initial value */
#define FXOR (0x0000)    /* final xor == xor out */

uint16_t crc16(uint8_t * bfr, size_t size)
{
uint16_t crc = INIT;
int i;
    while(size--){
        crc ^= ((uint16_t)(*bfr++))<<8;
        for(i = 0; i < 8; i++)
            /* assumes two's complement */
            crc = (crc<<1)^((0-(crc>>15))&POLY);
    }
    return(crc^FXOR);
}

这是我使用的蛮力搜索代码。它可能需要40亿次循环,但这只需要几分钟,所以我没有费心优化它。可以使用基于多项式的表查找或使用带有SSSE3 xmm寄存器的汇编代码来优化它(大约是表查找的8倍)。

#include <stdio.h>

typedef unsigned char   uint8_t;
typedef unsigned short uint16_t;

#define POLY (0x1021)           /* polynomial */
static uint16_t INIT;           /* initial value */
static uint16_t FXOR;           /* final xor == xor out */

/* left shifting crc using POLY == 0x1021 */

uint16_t crc16(uint8_t * bfr, size_t size)
{
uint16_t crc = INIT;
int i;
    while(size--){
        crc ^= (uint16_t)(*bfr++)<<8;
        for(i = 0; i < 8; i++)
            /* assumes two's complement */
            crc = (crc<<1)^((0-(crc>>15))&POLY);
    }
    return(crc^FXOR);
}

/* assume last 2 bytes are swapped versus nomral CRC */

int main(int argc, char**argv)
{
uint16_t crc;
uint8_t bfr0[] = {0xa5,0x5a,0x03,0x02,0x32,0x20,0x00,0x01,0x00,0x00,0xde,0x33};
uint8_t bfr1[] = {0xa5,0x5a,0x03,0x02,0x32,0x20,0x00,0x01,0x00,0x01,0xff,0x23};
uint8_t bfr2[] = {0xa5,0x5a,0x03,0x02,0x32,0x20,0x00,0x01,0x00,0x02,0x9c,0x13};
uint8_t bfr3[] = {0xa5,0x5a,0x03,0x02,0x32,0x20,0x00,0x01,0x00,0x03,0xbd,0x03};
uint8_t bfr4[] = {0xa5,0x5a,0x03,0x00,0x0e,0x00,0x00,0x05,0x00,0x00,0x96,0xff,0x00,0x00,0xa9,0x6b};
uint8_t bfr5[] = {0xa5,0x5a,0x03,0x00,0x0e,0x00,0x00,0x05,0x00,0x00,0x6f,0x00,0x00,0x00,0xf0,0xc8};
uint8_t bfr6[] = {0xa5,0x5a,0x03,0x00,0x0e,0x00,0x00,0x05,0x00,0x00,0x00,0x00,0xff,0x00,0x33,0x46};
uint8_t bfr7[] = {0xa5,0x5a,0x03,0x00,0x0e,0x00,0x00,0x05,0x00,0x00,0x00,0x00,0x01,0xff,0x0d,0x68};
    FXOR = 0;
    do{
        INIT = 0;
        do{
            crc = crc16(bfr0, 10);
            if(crc != 0x33de)
                continue;
            crc = crc16(bfr1, 10);
            if(crc != 0x23ff)
                continue;
            crc = crc16(bfr2, 10);
            if(crc != 0x139c)
                continue;
            crc = crc16(bfr3, 10);
            if(crc != 0x03bd)
                continue;
            crc = crc16(bfr4, 14);
            if(crc != 0x6ba9)
                continue;
            crc = crc16(bfr5, 14);
            if(crc != 0xc8f0)
                continue;
            crc = crc16(bfr6, 14);
            if(crc != 0x4633)
                continue;
            crc = crc16(bfr7, 14);
            if(crc != 0x680d)
                continue;
            goto match0;
        }while(++INIT != 0);
    }while(++FXOR != 0);
match0:
    printf("%04x %04x\n", INIT, FXOR);
    crc = crc16(bfr0, 10);
    printf("%04x\n", crc);
    crc = crc16(bfr1, 10);
    printf("%04x\n", crc);
    crc = crc16(bfr2, 10);
    printf("%04x\n", crc);
    crc = crc16(bfr3, 10);
    printf("%04x\n", crc);
    crc = crc16(bfr4, 14);
    printf("%04x\n", crc);
    crc = crc16(bfr5, 14);
    printf("%04x\n", crc);
    crc = crc16(bfr6, 14);
    printf("%04x\n", crc);
    crc = crc16(bfr7, 14);
    printf("%04x\n", crc);
    return(0);
}

假设左移POLY==0x1021,代码确定INIT==0xA55A和FXOR==0x0000适用于我测试的8个情况。由于XFOR==0x0000,它只需要运行64K循环。

 类似资料:
  • null 我不确定校验和是只在数据上计算还是在开始结构上计算(以十六进制为910H) 我附上了一些交流信息,每行是一条信息。我尝试了诸如、和等算法;不幸的是没有任何运气。 更新:我现在有了更多的进步,我现在不再确定它是校验和还是CRC。我已经生成并发送了从0到34的数据值,系统生成了以下“校验和” null Upadte2:我现在已经生成了数据,其中数据结构的一个位是1

  • 逆向工程 是模型其中一个主要功能。这功能让你加载现有的数据库结构以创建新的图表。它支持导入 MySQL、 PostgreSQL、Oracle、SQLite、SQL Server 或 MariaDB 数据库、模式、表或视图。 Navicat 提供一个步骤的向导让你完成任务: 选择 工具 -> 从数据库导入。 选择连接。 选择你要导入的数据库、模式或表。 点击 开始。 你也可以简单地在 Navicat

  • 逆向工程是模型的其中一个主要功能。这功能让你加载现有的数据库结构以创建新的图表。它支持导入数据库、模式、表或视图。 Navicat 提供一个向导,一步一步指导你完成任务: 选择“文件”->“从数据库导入”。 选择一个连接。 选择你要导入的数据库、模式、表或视图。 点击“开始”。 你也可以简单地在 Navicat 主窗口使用逆向工程创建一个新模型。右击一个已打开的数据库或模式、表或视图并在弹出式菜单

  • 逆向工程是模型的其中一个主要功能。这功能让你加载现有的数据库结构以创建新的图表。它支持导入数据库、模式、表或视图。 Navicat 提供一个向导,一步一步指导你完成任务: 选择“文件”->“从数据库导入”。 选择一个连接。 选择你要导入的数据库、模式、表或视图。 点击“开始”。 你也可以简单地在 Navicat 主窗口使用逆向工程创建一个新模型。按住 Control 键并点按一个已打开的数据库或模

  • 逆向工程是模型的其中一个主要功能。这功能让你加载现有的数据库结构以创建新的图表。它支持导入数据库、模式、表或视图。 Navicat 提供一个向导,一步一步指导你完成任务: 选择“文件”->“从数据库导入”。 选择一个连接。 选择你要导入的数据库、模式、表或视图。 点击“开始”。 你也可以简单地在 Navicat 主窗口使用逆向工程创建一个新模型。右击一个已打开的数据库或模式、表或视图并在弹出式菜单

  • 主要内容:1. 下载jar包,2. 创建数据表,3. 创建项目Mybatis 提供了一个逆向工程工具,该工具可以根据数据表自动生成针对单表的 po 类、mapper 映射文件和 mapper 接口。大大缩减了开发时间,可以让开发人员将更多的精力放在繁杂的业务逻辑上。 之所以强调单表两个字,是因为 MyBatis 逆向工程生成的 Mapper 中的操作都是针对单表的。在大型项目中,很少有复杂的多表关联查询,所以该工具作用还是很大的。 1. 下载jar包 jar