1

谈论这个: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);

作为文档中的状态,第一行将读取“字段HEAD_TYPE 到 RESERVED2的 CRC”。正如我所指出的,它适用于存档标题。

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

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

4

1 回答 1

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 () 的十进制表示进行比较的原因。此外,如果设置了某些标头标志,文件块的字段数可能会有所不同:您可能选择了错误的大小。

于 2011-09-21T18:23:44.260 回答