知道了!
该算法是具有以下参数的 CRC,作为 big-endian short 存储在这两个字节中:
- 多项式:0x2e97
- 异或值:0
- 异或输出值:0
- 反射输入:真
- 反映:真实
为了弄清楚,我使用了我的数据包捕获数据CRC RevEng和一些 shell 脚本将它们粘合在一起。然后我使用pycrc 即时计算检查值,以使我自己的网络请求在服务器上检查正常。
我认为我的问题得到了回答,因为这种方法可靠地让服务器确认我的自定义请求,但是 Jason 和 ebux 推荐的逆向工程二进制文件看起来仍然是我能够进一步确定它的唯一方法。例如,有一些不同的 CRC 适合我正在处理的所有数据。我通过使用 gdb 和 objdump 学到了很多东西,但很快就被我搞糊涂了。时间会证明我是否只是推迟了不可避免的事情,我想。
更多细节:
首先在 Wireshark 中,我选择了一个很好的数据包范围,一些具有相同的长度,一些具有不同的长度。对于每个我将原始二进制文件导出到一个文件中。(在 Packet Details 框架中,右键单击 Data 显示,单击“Export selected packet bytes...”。)因为我不确定字节是如何组织的,但我很好地猜测了哪些是CRC,我制作了文件的修改版本,其中附加了检查字节而不是开头,dd下面显示了一些笨拙的用法。最终起作用的变体是以 reveng 可以理解的小端格式将字节放在末尾。在 bash shell 中:
dd if=example bs=1 skip=4 > example_crc_reverse
dd if=example bs=1 count=1 skip=3 >> example_crc_reverse
dd if=example bs=1 count=1 skip=2 >> example_crc_reverse
然后将这些修改过的文件输入到 reveng 中。因为我什至不确定可能的 CRC 多项式的宽度,所以我从 1 到 16 循环以查看它会找到什么。再次在 bash 中:
for width in $(seq 1 16); do reveng -w $width -s -f example*_crc_reverse; done
即使有许多数据包,它也会找到许多适合数据的非标准 CRC,但上面的一个是不需要奇怪异或值的最高阶的。在 reveng 输出中发现的那些:
width=1 poly=0x1 init=0x0 refin=false refout=false xorout=0x0 check=0x1 name=(none)
width=1 poly=0x1 init=0x1 refin=false refout=false xorout=0x1 check=0x1 name=(none)
width=1 poly=0x1 init=0x0 refin=true refout=true xorout=0x0 check=0x1 name=(none)
width=1 poly=0x1 init=0x1 refin=true refout=true xorout=0x1 check=0x1 name=(none)
width=3 poly=0x5 init=0x0 refin=true refout=true xorout=0x0 check=0x0 name=(none)
width=4 poly=0x7 init=0x0 refin=true refout=true xorout=0x0 check=0xb name=(none)
width=4 poly=0x7 init=0xd refin=true refout=true xorout=0xb check=0xb name=(none)
width=10 poly=0x381 init=0x000 refin=true refout=true xorout=0x000 check=0x032 name=(none)
width=11 poly=0x083 init=0x000 refin=true refout=true xorout=0x000 check=0x032 name=(none)
width=11 poly=0x083 init=0x781 refin=true refout=true xorout=0x40f check=0x032 name=(none)
width=13 poly=0x058d init=0x0000 refin=true refout=true xorout=0x0000 check=0x1c1f name=(none)
width=14 poly=0x2e97 init=0x0000 refin=true refout=true xorout=0x0000 check=0x3076 name=(none)
width=14 poly=0x2e97 init=0x258d refin=true refout=true xorout=0x2c69 check=0x3076 name=(none)
(我认为没有 xorin/xorout 步骤的 14 位最适合使用,但我没有一个很好的理由。)在 Python 中,将二进制请求准备为整数字节值列表,pycrc可以这样计算校验值:
crc = pycrc.Crc(width=14, poly=0x2e97, reflect_in=True, xor_in=0, reflect_out=True, xor_out=0)
crc_val = crc.table_driven(binary)
crc_val从 pycrc计算出来的已经以服务器期望的字节序存储,所以它可以按原样放置在消息的开头。