这些数据包使用什么校验和算法?
What checksum algorithm do to these packets use?
我正在构建一个 python 库来控制我的廉价中文 iGK64 机械键盘的照明和可编程性功能,因为 Windows 驱动程序应用程序无法在 Linux.
我在 Windows VM 中 运行 制造商的驱动程序应用程序并捕获 USB 数据包进行分析。在过去几天的空闲时间里,我一直在分解这些数据包的内容,以确定不同的部分是什么,以及它们的作用。
到目前为止我已经确定了这些事实:
- 发送到键盘和从键盘接收的每个数据包都是 64 字节。
- 第一个字节是某种目的地指示符。我将其称为 "register id",可能更准确地说是 "page id"。这个字段是 1 个字节长。
- 第二个字节是 "instruction"。例如,"write" 的 0x02,"read" 的 0x01,我还看到了 0x09(我认为是 "execute")和 0x00(我认为是 noop 或 ping)。这个字段是 1 个字节长。
- 下一部分是 "address",它是一个 16 位无符号整数,指示 读取或写入发生的位置。此字段为 2 个字节长,小端。
- 接下来是有效负载长度。一个 16 位无符号整数,指示读取或写入的字节数。此字段为 2 个字节长,小端。
- 负载本身之前是校验和。一个 16 位的值,我对此知之甚少。字段长 2 个字节,我假设是小端。
- 负载在最后。它的长度在 0 到 56 字节之间,但用零填充,因此总数据包大小为 64 位。
- 全部看起来像
reg:{} instr: {} addr: {} len: {} checksum: {} payload: {}
这是一个数据包示例:
原始:
0x220200003800E670FFFFFFFFFFFFFFFF010000020200000204000002080000021000000220000002FFFFFFFFFFFFFFFF00040002000500020006000200070002
解构:
reg: 0x22 instr: 0x02 addr: 0x0000 len: 56 (0x3800) sum: 0xE670
payload: 0xFFFFFFFFFFFFFFFF010000020200000204000002080000021000000220000002FFFFFFFFFFFFFFFF00040002000500020006000200070002
我一直在确定用于计算校验和的算法。我尝试了一些基本的异或序列和一些 add/substract 方法,但是 none 是正确的。
他是两个几乎相同的数据包的示例,都指向相同的寄存器,有效负载长度为零,唯一的区别是指令和地址。但是看到校验和不一样了。
原始数据 1:
0x210201000000B63D0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
解构1:
reg: 0x21 instr: 0x02 addr: 0x0100 len: 00 (0x0000) sum: 0xB63D
payload: 0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
原始数据 2:
0x21000000000092610000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
解构2:
reg: 0x21 instr: 0x00 addr: 0x0000 len: 00 (0x0000) sum: 0x9261
payload: 0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
在这种情况下,这是从主机到外设的通信(写入 tr 寄存器 0x21,地址 0x100,零负载),然后从外设到主机(寄存器 0x21 "ack")。
我很确定数据包的每个 属性 都用于计算校验和,包括 reg id、instr、addr、len 和整个有效负载。
这里还有一些示例可能有助于阐明校验和的计算方式:
Raw3(这是一个 PING,或 "alive" 数据包每秒在主机和外围设备之间发送几次):
0x0C0000000000A70D0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
解构3:
reg: 0x0C instr: 0x00 addr: 0x0000 len: 00 (0x0000) sum: 0xA70D
payload: 0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Raw4(有效载荷全部为 0xFF):
0x220288013800BC74FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
解构4:
reg: 0x22 instr: 0x02 addr: 0x8801 len: 56 (0x3800) sum: 0xBC74
payload 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
我有几个较大的原始通信转储,但与此处提供的示例相比,它们对于确定校验和算法可能没有用。
如有任何帮助,我们将不胜感激!
为了帮助其他人,我在此处添加了 Ashley 如何为原始数据得出正确的校验和
2202880138000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
Came up with 0x74BC
2202000038000000FFFFFFFFFFFFFFFF010000020200000204000002080000021000000220000002FFFFFFFFFFFFFFFF00040002000500020006000200070002
Came up with 0x70E6 on CRC-CCITT (0xFFFF) 0x70E6
现场https://www.lammertbies.nl/comm/info/crc-calculation.html
要在原始数据包中获得正确的校验和,只需从原始数据包中删除校验和并将其输入crc-计算站点以查找校验和类型。
这是确定校验和的代码,来自 Whosebug 的 faltru:
( 你需要 (pip) 或 pip3 安装 crc16)
import binascii
import crc16
def crccitt(hex_string):
byte_seq = binascii.unhexlify(hex_string)
crc = crc16.crc16xmodem(byte_seq, 0xffff)
return '{:04X}'.format(crc & 0xffff)
#In [387]: #crccitt('21020100000000000000000000000000000000000000000000000000000000000#000000000000000000000000000000000000000000000000000000000000000')
#Out[387]: '3DB6'
我正在构建一个 python 库来控制我的廉价中文 iGK64 机械键盘的照明和可编程性功能,因为 Windows 驱动程序应用程序无法在 Linux.
我在 Windows VM 中 运行 制造商的驱动程序应用程序并捕获 USB 数据包进行分析。在过去几天的空闲时间里,我一直在分解这些数据包的内容,以确定不同的部分是什么,以及它们的作用。
到目前为止我已经确定了这些事实:
- 发送到键盘和从键盘接收的每个数据包都是 64 字节。
- 第一个字节是某种目的地指示符。我将其称为 "register id",可能更准确地说是 "page id"。这个字段是 1 个字节长。
- 第二个字节是 "instruction"。例如,"write" 的 0x02,"read" 的 0x01,我还看到了 0x09(我认为是 "execute")和 0x00(我认为是 noop 或 ping)。这个字段是 1 个字节长。
- 下一部分是 "address",它是一个 16 位无符号整数,指示 读取或写入发生的位置。此字段为 2 个字节长,小端。
- 接下来是有效负载长度。一个 16 位无符号整数,指示读取或写入的字节数。此字段为 2 个字节长,小端。
- 负载本身之前是校验和。一个 16 位的值,我对此知之甚少。字段长 2 个字节,我假设是小端。
- 负载在最后。它的长度在 0 到 56 字节之间,但用零填充,因此总数据包大小为 64 位。
- 全部看起来像
reg:{} instr: {} addr: {} len: {} checksum: {} payload: {}
这是一个数据包示例:
原始:
0x220200003800E670FFFFFFFFFFFFFFFF010000020200000204000002080000021000000220000002FFFFFFFFFFFFFFFF00040002000500020006000200070002
解构:
reg: 0x22 instr: 0x02 addr: 0x0000 len: 56 (0x3800) sum: 0xE670
payload: 0xFFFFFFFFFFFFFFFF010000020200000204000002080000021000000220000002FFFFFFFFFFFFFFFF00040002000500020006000200070002
我一直在确定用于计算校验和的算法。我尝试了一些基本的异或序列和一些 add/substract 方法,但是 none 是正确的。
他是两个几乎相同的数据包的示例,都指向相同的寄存器,有效负载长度为零,唯一的区别是指令和地址。但是看到校验和不一样了。
原始数据 1:
0x210201000000B63D0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
解构1:
reg: 0x21 instr: 0x02 addr: 0x0100 len: 00 (0x0000) sum: 0xB63D
payload: 0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
原始数据 2:
0x21000000000092610000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
解构2:
reg: 0x21 instr: 0x00 addr: 0x0000 len: 00 (0x0000) sum: 0x9261
payload: 0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
在这种情况下,这是从主机到外设的通信(写入 tr 寄存器 0x21,地址 0x100,零负载),然后从外设到主机(寄存器 0x21 "ack")。
我很确定数据包的每个 属性 都用于计算校验和,包括 reg id、instr、addr、len 和整个有效负载。
这里还有一些示例可能有助于阐明校验和的计算方式:
Raw3(这是一个 PING,或 "alive" 数据包每秒在主机和外围设备之间发送几次):
0x0C0000000000A70D0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
解构3:
reg: 0x0C instr: 0x00 addr: 0x0000 len: 00 (0x0000) sum: 0xA70D
payload: 0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Raw4(有效载荷全部为 0xFF):
0x220288013800BC74FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
解构4:
reg: 0x22 instr: 0x02 addr: 0x8801 len: 56 (0x3800) sum: 0xBC74
payload 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
我有几个较大的原始通信转储,但与此处提供的示例相比,它们对于确定校验和算法可能没有用。
如有任何帮助,我们将不胜感激!
为了帮助其他人,我在此处添加了 Ashley 如何为原始数据得出正确的校验和
2202880138000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
Came up with 0x74BC
2202000038000000FFFFFFFFFFFFFFFF010000020200000204000002080000021000000220000002FFFFFFFFFFFFFFFF00040002000500020006000200070002
Came up with 0x70E6 on CRC-CCITT (0xFFFF) 0x70E6
现场https://www.lammertbies.nl/comm/info/crc-calculation.html
要在原始数据包中获得正确的校验和,只需从原始数据包中删除校验和并将其输入crc-计算站点以查找校验和类型。
这是确定校验和的代码,来自 Whosebug 的 faltru: ( 你需要 (pip) 或 pip3 安装 crc16)
import binascii
import crc16
def crccitt(hex_string):
byte_seq = binascii.unhexlify(hex_string)
crc = crc16.crc16xmodem(byte_seq, 0xffff)
return '{:04X}'.format(crc & 0xffff)
#In [387]: #crccitt('21020100000000000000000000000000000000000000000000000000000000000#000000000000000000000000000000000000000000000000000000000000000')
#Out[387]: '3DB6'