我正试图逆向工程一个BLE设备(Gimbal)。在嗅探btsnoop_hci.log
之后,我已经成功地复制了精确的命令,下面是其中的几个:
* AF: a55a030232200001 00 03 bd03
* TF: a55a030232200001 00 02 9c13
* HF: a55a030232200001 00 01 ff23
* LK: a55a030232200001 00 00 de33
这些命令将操作模式(我猜是用HEX编码的)从01
更改为03
。有四个人,所以这是有道理的。但是,在最后有四个字符,IMHO是某种校验和,但我不知道是什么样的。尝试过这个在线工具,但没有成功。
为什么我需要知道如何计算校验和?因为,我也想用模拟操纵杆控制,电机,,我不能只复制粘贴数千个值并映射它们。
此外,以下是发动机本身的更多价值:
(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:运行命令(马达命令中的最后两个字节被反转):
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)
步骤2:运行命令(模式命令中的最后两个字节被反转):
reveng -w 16 -s a55a030232200001000303bd a55a0302322000010002139c a55a030232200001000123ff a55a030232200001000033de
步骤2-结果:
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)在不同类型的消息中匹配。
但是,如果我使用函数:
#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);
应该导致139c
(从原来交换),但是我得到:1fb1
,这是实际值(a55a030232200001 00 02 9c13
),它是从.
更新:重新检查所有14字节(马达)值(最后一个字节被交换),以确保:
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)
相应地(有两个10字节和两个14字节值):
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,返回错误的十六进制?
发布于 2020-06-08 02:30:52
您可以对样本进行异或,以减少变量的数量,因为这消除了任何初始值或最终的XOR (好像两者都是0),并且搜索只需要查找多项式,以及它是否是非反射的(左移位)或反射(右移)。对于CRC16,左移位只有64k循环,右移位只有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
起初,我假设最后两个字节是交换的,所以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。
位级代码示例:
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");
虽然这对这4种情况有效,但我不能确定这是实际使用的CRC没有更多的情况。
然后,我建议交换12字节和16字节消息的最后2个字节,并使用reveng。这意味着左移和保利的0x1021是一个可能的多元数,所以我重复了我的测试,最后得到了与收入相同的结果:
对于左移的CRC,代码是不同的:
#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);
}
假设左移== 0x1021,代码确定INIT == 0xa55a和FXOR == 0x0000适用于我测试的8例病例。自从XFOR == 0x0000以来,它只需要运行64k循环。
https://stackoverflow.com/questions/62253245
复制相似问题