如何计算WinRAR文件头的CRC?

时间:2011-09-19 08:55:47

标签: php header crc rar winrar

谈论这个:http://www.win-rar.com/index.php?id=24&kb_article_id=162

我可以通过执行以下操作来计算归档标头(MAIN_HEAD)的正确CRC:

$crc = crc32(mb_substr($data, $blockOffset + 2, 11, '8bit'));
$crc = dechex($crc);
$crc = substr($crc, -4, 2) . substr($crc, -2, 2);
$crc = hexdec($crc);

第一行将“字段的CRC HEAD_TYPE设置为RESERVED2 ”作为文档中的状态。正如我所指出的,它适用于归档头。

当我尝试计算文件头的CRC时,它总是会因为未知原因而吐出错误的CRC。我做的文档说 - “字段从HEAD_TYPE到FILEATTR ”,但它根本不起作用。我还尝试了不同的读取长度变化,以防文档错误,实际上可能是从HEAD_TYPE到FILE_NAME 。一切都没有成功。

任何人都可以给我一个暗示吗?我还检查了unrar源代码,但它并没有让我更聪明,可能是因为我根本不懂C语言......

1 个答案:

答案 0 :(得分:1)

我写了一些做同样事情的代码。这是一些额外的片段,以便更好地理解:

$this->fh = $fileHandle;
$this->startOffset = ftell($fileHandle); // current location in the file

// reading basic 7 byte header block
$array = unpack('vheaderCrc/CblockType/vflags/vheaderSize', fread($this->fh, 7));
$this->headerCrc = $array['headerCrc'];
$this->blockType = $array['blockType'];
$this->flags = $array['flags'];
$this->hsize = $array['headerSize'];
$this->addSize = 0; // size of data after the header


// -- check CRC of block header --
$offset = ftell($this->fh);
fseek($this->fh, $this->startOffset + 2, SEEK_SET);
$crcData = fread($this->fh, $this->hsize - 2);
// only the 4 lower order bytes are used
$crc = crc32($crcData) & 0xffff;
// igonore blocks with no CRC set (same as twice the blockType)
if ($crc !== $this->headerCrc && $this->headerCrc !== 0x6969 // SRR Header
            && $this->headerCrc !== 0x6a6a // SRR Stored File
            && $this->headerCrc !== 0x7171 // SRR RAR block
            && $this->blockType !== 0x72 // RAR marker block (fixed: magic number)
) {
    array_push($warnings, 'Invalid block header CRC found: header is corrupt.');
}
// set offset back to where we started from
fseek($this->fh, $offset, SEEK_SET);

我在几个SRR文件上测试了它,它按预期工作。我开始阅读基本的7字节标题。标题的大小可以在那里找到。我用它来获取crc32函数的正确数据量。我注意到当你将它转换为十六进制时,你可以在比较时得到误报:'0f00'!='f00'。你需要用零填充它。这就是为什么我保留crc32()和unpack()的十进制表示来进行比较。此外,如果设置了一些标题标志,则文件块的字段数可能会有所不同:您可能采用了错误的大小。