在C语言中,在消息开头使用CRC哈希进行CRC32计算
我需要计算消息的CRC,并将其放在该消息的开头,以便带有“前置”补丁字节的消息的最终CRC等于0。在几篇文章的帮助下,我可以很容易地做到这一点,但并不是因为我的具体参数。问题是,我必须使用一个给定的CRC32算法来计算内存块的CRC,但我没有计算这4个补丁字节的“反向”算法。给定CRC32算法的参数为:在C语言中,在消息开头使用CRC哈希进行CRC32计算,c,reverse-engineering,crc32,C,Reverse Engineering,Crc32,我需要计算消息的CRC,并将其放在该消息的开头,以便带有“前置”补丁字节的消息的最终CRC等于0。在几篇文章的帮助下,我可以很容易地做到这一点,但并不是因为我的具体参数。问题是,我必须使用一个给定的CRC32算法来计算内存块的CRC,但我没有计算这4个补丁字节的“反向”算法。给定CRC32算法的参数为: 多项式:0x04C11DB7 结束语:大端语 初始值:0xFFFFFF 反映:错误 带:0L的XOR输出 测试流:0x0123、0x4567、0x89AB、0xCDEF导致CRC=0x6127
- 多项式:0x04C11DB7
- 结束语:大端语
- 初始值:0xFFFFFF
- 反映:错误
- 带:0L的XOR输出
- 测试流:0x0123、0x4567、0x89AB、0xCDEF导致CRC=0x612793C3
我花了将近一个星期的时间试图找出正确的多项式/算法/表组合,但运气不好。如果有帮助的话,我提出了与上面的表驱动代码相对应的位算法,尽管这并不难:
uint32 crc32(uint16* data, uint32 len, uint32 crc)
{
uint32 i;
while(len--)
{
for(i = 0; i < 16; i++)
{
// #define POLY 0x04C11DB7
crc = (crc << 1) ^ (((crc ^ *data) & 0x80000000) ? POLY : 0);
}
crc ^= *data++;
}
return crc;
}
我认为在0xFFFF或0x0000字上测试这一点很方便,因为计算方向和尾数并不重要(我希望:D)。因此,请小心使用其他测试字节,因为计算的方向非常曲折:D。您还可以看到,通过向算法(向前和向后)只提供零,结果就是所谓的剩余(0xC704DD7B),这可能会有所帮助
所以…我写了至少10个不同的函数(按位、表格、多项式组合等)试图解决这个问题,但运气不好。我在这里给你们一个功能,我把我的希望放在其中。这是上面表驱动的“反向”算法,当然是不同的表。问题是,我从中得到的唯一正确的CRC是所有0s消息,这并不出乎意料。此外,我还编写了按位算法的反向实现(反向移位等),但只正确返回第一个字节。这是表驱动的,指向数据的指针应该指向消息的最后一个元素,crc输入应该是请求的crc(整个消息为0,或者您可以采取另一种方法-消息的最后4个字节是您要查找的crc:):
正如你所看到的,这个算法有一些额外的功能,使我在循环中运行,我认为我可能在正确的轨道上,但我遗漏了一些东西。我希望多一双眼睛能看到我看不见的东西。我为这篇冗长的帖子感到抱歉(没有土豆:D),但我认为所有这些解释都是必要的。提前感谢您的见解或建议。我将回答您的CRC规范,即a。我将不得不忽略你计算CRC的尝试,因为它们是不正确的 无论如何,为了回答你的问题,我碰巧写了一个程序来解决这个问题。它被称为。它可以非常快速地计算要在消息中更改哪些位以获得所需的CRC。它按照日志(n)时间的顺序执行此操作,其中n是消息的长度。以下是一个例子: 让我们看一看九字节的消息
123456789
(这些数字用ASCII表示)。我们将在它前面加上四个零字节,我们将对其进行更改,以在最后得到所需的CRC。然后,以十六进制显示的消息是:00 00 00 31 32 33 34 35 36 37 38 39
。现在我们计算该消息的CRC-32/MPEG-2。我们得到了373c5870
现在我们用这个输入运行spoof
,它是以位为单位的CRC长度,没有反映的事实,多项式,我们刚刚计算的CRC,以字节为单位的消息长度,以及前四个字节中的所有32位位置(这就是我们允许spoof
改变的):
它为该输出提供了前四个字节中要设置的位:
invert these bits in the sequence:
offset bit
0 1
0 2
0 4
0 5
0 6
1 0
1 2
1 5
1 7
2 0
2 2
2 5
2 6
2 7
3 0
3 1
3 2
3 4
3 5
3 7
然后我们将前四个字节设置为:76A5E5B7
。然后,我们通过计算消息的CRC-32/MPEG-2进行测试76 a5 e5 b7 31 32 33 34 35 36 37 38 39
,得到了所需的结果00000000
您可以根据应用程序调整spoof.c
以下是使用逐位算法在字节流上正确计算CRC-32/MPEG-2的示例:
uint32_t crc32m(uint32_t crc, const unsigned char *buf, size_t len)
{
int k;
while (len--) {
crc ^= (uint32_t)(*buf++) << 24;
for (k = 0; k < 8; k++)
crc = crc & 0x80000000 ? (crc << 1) ^ 0x04c11db7 : crc << 1;
}
return crc;
}
uint32\u t crc32m(uint32\u t crc,常量无符号字符*buf,大小长度)
{
int k;
而(len--){
crc^=(uint32_t)(*buf++)好吧,在我提问几个小时后,一个我不记得名字的人发布了我问题的答案,结果是正确的。不知怎的,这个答案被完全删除了,我不知道为什么或者是谁做的,但我要感谢这个人,如果你会看到这个,请再次发布你的答案,我会删除这个。但是r其他用户,这是他的答案,对我来说很有用,再次感谢,神秘的一个(不幸的是,我不能很好地复制他的笔记和建议,只是代码本身):
编辑:最初的答案来自用户,所以在他发布答案之前,这个答案会一直保留在这里
反向CRC算法:
uint32 revcrc32(uint16* data, uint32 len, uint32 crc)
{
uint32 i;
data += len - 1;
while(len--)
{
crc ^= *data--;
for(i = 0; i < 16; i++)
{
uint32 crc1 = ((crc ^ POLY) >> 1) | 0x80000000;
uint32 crc2 = crc >> 1;
if(((crc1 << 1) ^ (((crc1 ^ *data) & 0x80000000) ? POLY : 0)) == crc)
crc = crc1;
else if(((crc2 << 1) ^ (((crc2 ^ *data) & 0x80000000) ? POLY : 0)) == crc)
crc = crc2;
}
}
return crc;
}
您的CRC计算完全混乱。表项是使用消息中位的异或和CRC的高位选择的。对于您的位CRC例程,您关于是否使用POLY
进行异或的决定与^*数据
无关,因此这甚至不需要存在正确的方法是将数据移到CRC的顶部,然后决定高位。您没有计算您指定的CRC,顺便说一句,它是MPEG2 CRC-32。您是对的,CRC的计算是不正确的,但我不能改变这一点
uint32 crc32tabrev(uint16* data, uint32 len, uint32 crc)
{
uint8 nibble;
int i;
while(len--)
{
for(i = 0; i < 4; i++)
{
nibble = (*data >> i*4) & 0x0F;
crc = (crc >> 4) ^ revtab[((crc ^ nibble) & 0x0F)];
}
data--;
}
return reverse(crc); //reverse() flips all bits around center (MSB <-> LSB ...)
}
static const uint32 revtab[16]=
{
0x00000000, 0x1DB71064, 0x3B6E20C8, 0x26D930AC,
0x76DC4190, 0x6B6B51F4, 0x4DB26158, 0x5005713C,
0xEDB88320, 0xF00F9344, 0xD6D6A3E8, 0xCB61B38C,
0x9B64C2B0, 0x86D3D2D4, 0xA00AE278, 0xBDBDF21C
};
32 0 04C11DB7
373c5870 13
0 0 1 2 3 4 5 6 7
1 0 1 2 3 4 5 6 7
2 0 1 2 3 4 5 6 7
3 0 1 2 3 4 5 6 7
invert these bits in the sequence:
offset bit
0 1
0 2
0 4
0 5
0 6
1 0
1 2
1 5
1 7
2 0
2 2
2 5
2 6
2 7
3 0
3 1
3 2
3 4
3 5
3 7
uint32_t crc32m(uint32_t crc, const unsigned char *buf, size_t len)
{
int k;
while (len--) {
crc ^= (uint32_t)(*buf++) << 24;
for (k = 0; k < 8; k++)
crc = crc & 0x80000000 ? (crc << 1) ^ 0x04c11db7 : crc << 1;
}
return crc;
}
uint32_t crc_table[] = {
0x00000000, 0x04C11DB7, 0x09823B6E, 0x0D4326D9,
0x130476DC, 0x17C56B6B, 0x1A864DB2, 0x1E475005,
0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6, 0x2B4BCB61,
0x350C9B64, 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD
};
uint32_t crc32m_nyb(uint32_t crc, const unsigned char *buf, size_t len)
{
while (len--) {
crc ^= (uint32_t)(*buf++) << 24;
crc = (crc << 4) ^ crc_table[crc >> 28];
crc = (crc << 4) ^ crc_table[crc >> 28];
}
return crc;
}
uint32 revcrc32(uint16* data, uint32 len, uint32 crc)
{
uint32 i;
data += len - 1;
while(len--)
{
crc ^= *data--;
for(i = 0; i < 16; i++)
{
uint32 crc1 = ((crc ^ POLY) >> 1) | 0x80000000;
uint32 crc2 = crc >> 1;
if(((crc1 << 1) ^ (((crc1 ^ *data) & 0x80000000) ? POLY : 0)) == crc)
crc = crc1;
else if(((crc2 << 1) ^ (((crc2 ^ *data) & 0x80000000) ? POLY : 0)) == crc)
crc = crc2;
}
}
return crc;
}
#define CRC_OF_ZERO 0xb7647d
void bruteforcecrc32(uint32 targetcrc)
{
// compute prefixes:
uint16 j;
for(j = 0; j <= 0xffff; j++)
{
uint32 crc = revcrc32(&j, 1, targetcrc);
if((crc >> 16) == (CRC_OF_ZERO >> 16))
{
printf("prefixes: %04lX %04lX\n", (crc ^ CRC_OF_ZERO) & 0xffff, (uint32)j);
return;
}
}
}
uint16 test[] = {0x0123, 0x4567, 0x89AB, 0xCDEF}; // prefix should be 0x0CD8236A
bruteforcecrc32(revcrc32(test, 4, 0L));