如何在保持 CRC-32 校验和的同时修改文件?
How do I modify a file while maintaining its CRC-32 checksum?
我正在尝试 mod 的一个老游戏有 CRC-32 检查。我无权访问 CRC 校验和本身,因此我必须 mod 验证文件,同时保持相同的校验和输出。
我有的信息
文件,如果文件本身是CRC-32程序的唯一输入,我可以计算出CRC-32校验和应该是多少。
32位多项式代码。
如果文件的大小不需要保持不变,您可以根据需要简单地修改其内容,并添加一些字节 (4) 来修复校验和。
添加哪些字节即可
a)计算,如果你了解所用的CRC算法或者
b) 尝试暴力尝试找到合适的字节(可能需要一段时间,但如果你不需要经常这样做,它仍然是一个可行的尝试
正如@MrSmith42 所说,只要您不需要保持文件长度不变,就可以轻松计算出 "collision"(为产生相同散列的两个输入消息指定的名称)。
它很繁琐,有很多小动作,但速度很快。
假设原始文件是十六进制的:
1122334455667788
那么它的 CRC-32 校验和将是 0x9118E1C2
使用标准的 CRC32 多项式。如果使用的算法不标准,可以替换。为了演示目的,我将坚持使用标准。
首先,根据需要更改文件。例如,我在中间改变一个字节:
11223344FF667788
恢复 CRC 的第一步是用 4 个零字节填充文件:
11223344FF66778800000000
CRC 校验和现在是 0x6BBE83C9
。
第二步,异或两个校验和:
0x9118E1C2 XOR 0x6BBE83C9 = 0xFAA6620B
第三步,位反转结果:
Bit reverse of 0xFAA6620B = 0xD046655F
第四步,这有点古怪,所以请看下面,执行反向 CRC32 计算:
0xD046655F * inverse(x32) mod crc_poly = 0xe4c7d232
第五步,对结果进行位反转,这次是按字节:
0xe4c7d232 bit reversed byte-wise = 0x27E34B4C
第六步,用结果替换填充的字节
11223344FF66778827E34B4C
瞧,CRC32 校验和值现在回到 0x9118E1C2。
据我所知,进行反向 CRC 计算的最简单方法是使用 Python 中的 BitVector 包:
>>> import BitVector as bv
>>> poly = bv.BitVector(intVal = 0x104C11DB7) # "standard" CRC32 polynomial
>>> inv = bv.BitVector(intVal = 0x100000000).gf_MI(poly, 32)
>>> k = 0xD046655F
>>> p = bv.BitVector(intVal = k).gf_multiply_modular(inv, poly, 32)
>>> print(p.getHexStringFromBitVector())
e4c7d232
此算法由 Redditor /u/supersaw7 发表于 this thread。我没有遇到更好的版本,尽管更简单的版本非常可能。
使用spoof。修改文件后,您需要确定一组允许将 CRC 更改为 return 原始值的位位置。您需要提供包含您想要 return 的原始 CRC 的异或的恶搞,以及当前的 CRC,以及您不关心的位位置,例如在字符串中,以及一些关于 CRC 本身和文件长度的信息。 spoof 然后将解决翻转这些位中的哪些位以获得所需的 CRC。该文档提供了有关您需要提供多少个可变位的指导。
您可以保留文件相同的长度,或者您可以向文件添加字节以创建您认为可以更改的位置。
我正在尝试 mod 的一个老游戏有 CRC-32 检查。我无权访问 CRC 校验和本身,因此我必须 mod 验证文件,同时保持相同的校验和输出。
我有的信息
文件,如果文件本身是CRC-32程序的唯一输入,我可以计算出CRC-32校验和应该是多少。
32位多项式代码。
如果文件的大小不需要保持不变,您可以根据需要简单地修改其内容,并添加一些字节 (4) 来修复校验和。
添加哪些字节即可
a)计算,如果你了解所用的CRC算法或者
b) 尝试暴力尝试找到合适的字节(可能需要一段时间,但如果你不需要经常这样做,它仍然是一个可行的尝试
正如@MrSmith42 所说,只要您不需要保持文件长度不变,就可以轻松计算出 "collision"(为产生相同散列的两个输入消息指定的名称)。
它很繁琐,有很多小动作,但速度很快。
假设原始文件是十六进制的:
1122334455667788
那么它的 CRC-32 校验和将是 0x9118E1C2
使用标准的 CRC32 多项式。如果使用的算法不标准,可以替换。为了演示目的,我将坚持使用标准。
首先,根据需要更改文件。例如,我在中间改变一个字节:
11223344FF667788
恢复 CRC 的第一步是用 4 个零字节填充文件:
11223344FF66778800000000
CRC 校验和现在是 0x6BBE83C9
。
第二步,异或两个校验和:
0x9118E1C2 XOR 0x6BBE83C9 = 0xFAA6620B
第三步,位反转结果:
Bit reverse of 0xFAA6620B = 0xD046655F
第四步,这有点古怪,所以请看下面,执行反向 CRC32 计算:
0xD046655F * inverse(x32) mod crc_poly = 0xe4c7d232
第五步,对结果进行位反转,这次是按字节:
0xe4c7d232 bit reversed byte-wise = 0x27E34B4C
第六步,用结果替换填充的字节
11223344FF66778827E34B4C
瞧,CRC32 校验和值现在回到 0x9118E1C2。
据我所知,进行反向 CRC 计算的最简单方法是使用 Python 中的 BitVector 包:
>>> import BitVector as bv
>>> poly = bv.BitVector(intVal = 0x104C11DB7) # "standard" CRC32 polynomial
>>> inv = bv.BitVector(intVal = 0x100000000).gf_MI(poly, 32)
>>> k = 0xD046655F
>>> p = bv.BitVector(intVal = k).gf_multiply_modular(inv, poly, 32)
>>> print(p.getHexStringFromBitVector())
e4c7d232
此算法由 Redditor /u/supersaw7 发表于 this thread。我没有遇到更好的版本,尽管更简单的版本非常可能。
使用spoof。修改文件后,您需要确定一组允许将 CRC 更改为 return 原始值的位位置。您需要提供包含您想要 return 的原始 CRC 的异或的恶搞,以及当前的 CRC,以及您不关心的位位置,例如在字符串中,以及一些关于 CRC 本身和文件长度的信息。 spoof 然后将解决翻转这些位中的哪些位以获得所需的 CRC。该文档提供了有关您需要提供多少个可变位的指导。
您可以保留文件相同的长度,或者您可以向文件添加字节以创建您认为可以更改的位置。