Как рассчитать CRC заголовка файла WinRAR? - PullRequest
1 голос
/ 19 сентября 2011

Говоря об этом: http://www.win -rar.com / index.php? Id = 24 & kb_article_id = 162

Я могу рассчитать правильный CRC заголовка архива (MAIN_HEAD), выполнив:

$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 to RESERVED2 », как указано в документации.Как я уже отметил, он прекрасно работает для заголовка архива.

Когда я пытаюсь вычислить CRC заголовка файла, он всегда выдает неправильный CRC по неизвестной причине.Я сделал, как сказано в документации - «CRC полей от HEAD_TYPE до FILEATTR », но это просто не работает.Я также пробовал разные варианты длины чтения на случай, если документация неверна и на самом деле это может быть от HEAD_TYPE до FILE_NAME .Все без успеха.

Кто-нибудь может дать мне подсказку?Я также проверил исходный код unrar, но он не делает меня умнее, вероятно, потому что я вообще не знаю языка C ...

1 Ответ

1 голос
/ 21 сентября 2011

Я написал код, который делает то же самое. Вот это с некоторыми дополнительными фрагментами для лучшего понимания:

$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 () для сравнения. Кроме того, количество полей в блоке файла может варьироваться, если установлены некоторые флаги заголовка: возможно, вы выбрали неправильный размер.

...