首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >逆向工程BLE设备-校验和?

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

Stack Overflow用户
提问于 2020-06-08 00:12:50
回答 1查看 499关注 0票数 1

我正试图逆向工程一个BLE设备(Gimbal)。在嗅探btsnoop_hci.log之后,我已经成功地复制了精确的命令,下面是其中的几个:

代码语言:javascript
运行
复制
* AF: a55a030232200001 00 03 bd03
* TF: a55a030232200001 00 02 9c13
* HF: a55a030232200001 00 01 ff23
* LK: a55a030232200001 00 00 de33

这些命令操作模式(我猜是用HEX编码的)从01更改为03。有四个人,所以这是有道理的。但是,在最后有四个字符,IMHO是某种校验和,但我不知道是什么样的。尝试过这个在线工具,但没有成功。

为什么我需要知道如何计算校验和?因为,我也想用模拟操纵杆控制电机,,我不能只复制粘贴数千个值并映射它们。

此外,以下是发动机本身的更多价值:

代码语言:javascript
运行
复制
                      (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)

更新:我用收入来暴力迫使保利和INIT:

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

代码语言:javascript
运行
复制
reveng -w 16 -s a55a03000e00000500006f000000c8f0 a55a03000e0000050000ff0000000e6f a55a03000e000005000096ff00006ba9 a55a03000e000005000001ff0000fc1b

步骤1-结果:

代码语言:javascript
运行
复制
width=16  poly=0x1021  init=0xa55a  refin=false  refout=false  xorout=0x0000  check=0x0459  residue=0x0000  name=(none)

步骤2:运行命令(模式命令中的最后两个字节被反转):

代码语言:javascript
运行
复制
reveng -w 16 -s a55a030232200001000303bd a55a0302322000010002139c a55a030232200001000123ff a55a030232200001000033de

步骤2-结果:

代码语言:javascript
运行
复制
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)

因此,很明显,poly(0x1021)& init (0xa55a)在不同类型的消息中匹配。

但是,如果我使用函数:

代码语言:javascript
运行
复制
#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值仍然与原始值不匹配。在我的知识里我遗漏了一些东西。

示例:

代码语言:javascript
运行
复制
uint8_t bfr[] = { 0xa5, 0x5a, 0x03, 0x02, 0x32, 0x20, 0x00, 0x01, 0x00, 0x02 };
uint16_t crc = crc16(bfr, 10);

应该导致139c (从原来交换),但是我得到:1fb1,这是实际值(a55a030232200001 00 02 9c13),它是从.

更新:重新检查所有14字节(马达)值(最后一个字节被交换),以确保:

代码语言:javascript
运行
复制
a55a03000e00000500006f000000c8f0
a55a03000e0000050000ff0000000e6f
a55a03000e000005000096ff00006ba9
a55a03000e000005000001ff0000fc1b
a55a03000e0000050000000001ff680d
a55a03000e00000500000000ff004633

调用的命令:

代码语言:javascript
运行
复制
reveng -w 16 -s a55a03000e00000500006f000000c8f0 a55a03000e0000050000ff0000000e6f a55a03000e000005000096ff00006ba9 a55a03000e000005000001ff0000fc1b a55a03000e0000050000000001ff680d a55a03000e00000500000000ff004633

reveng -w 16 -s a55a030232200001000303bd a55a0302322000010002139c a55a03000e00000500006f000000c8f0 a55a03000e0000050000ff0000000e6f

结果:

代码语言:javascript
运行
复制
width=16  poly=0x1021  init=0xa55a  refin=false  refout=false  xorout=0x0000  check=0x0459  residue=0x0000  name=(none)

相应地(有两个10字节和两个14字节值):

代码语言:javascript
运行
复制
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)

保利&英特一定是对的。但是,在产生第一部“儿童权利公约”时:

代码语言:javascript
运行
复制
//                 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,返回错误的十六进制?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-06-08 02:30:52

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

代码语言:javascript
运行
复制
* 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

起初,我假设最后两个字节是交换的,所以01 2110将是01 10 21,这是一种常见的左移(未反映) CRC,但由于我的错误(其中一次检查的大小错误),我没有让它工作。

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

对一个数据字节= 0x01的CRC值为0x2110的反射多项式进行蛮力搜索,有3种情况,但其中只有一种有15位== 1,0xEBB 2,这就是假定的多项式。

然后对初始值和最终xor = 0x0000或0xffff执行蛮力搜索,以匹配所有4个示例,初始值= 0xa6ab,最终xor = 0x0000。

位级代码示例:

代码语言:javascript
运行
复制
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个示例:

代码语言:javascript
运行
复制
crc = crc16(bfr, 10);
if((bfr[10] == crc>>8) && (bfr[11] == crc&0xff))
    printf("match\n");

虽然这对这4种情况有效,但我不能确定这是实际使用的CRC没有更多的情况。

然后,我建议交换12字节和16字节消息的最后2个字节,并使用reveng。这意味着左移和保利的0x1021是一个可能的多元数,所以我重复了我的测试,最后得到了与收入相同的结果:

对于左移的CRC,代码是不同的:

代码语言:javascript
运行
复制
#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倍)。

代码语言:javascript
运行
复制
#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);
}

假设左移== 0x1021,代码确定INIT == 0xa55a和FXOR == 0x0000适用于我测试的8例病例。自从XFOR == 0x0000以来,它只需要运行64k循环。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/62253245

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档