Как имитировать флаг use_crc на (взломанном) 1998 uncompress () в интерфейсе API zlib 2013?

Я обновлял код проекта с версии zlib 1998 года до версии zlib 2013 года. Одна вещь, которая, казалось, изменилась, это то, что раньше был флаг "use_crc" в функции uncompress, который, похоже, пропал:

int ZEXPORT uncompress (dest, destLen, source, sourceLen, use_crc)
    Bytef *dest;
    uLongf *destLen;
    const Bytef *source;
    uLong sourceLen;
    int use_crc; // <-- vanished (?)

(ОБНОВЛЕНИЕ: как указал @Joe, вероятно, это сторонняя модификация. Заголовок обновлен соответствующим образом. Остальная часть вопроса по-прежнему применима, например," как мне лучше всего сделать это с сегодняшним стандартным zlib ".)

В коде, который я изучаю, uncompress () вызывается чем-то, что деконструирует двоичный формат .zip и передает "полезную нагрузку" данных. Код передал флаг crc как 1. Если флаг не использовался, он получил бы Z_DATA_ERROR (-3). (Zlib без флага use_crc получает Z_DATA_ERROR, как если бы флаг был ложным.)

В ходе экспериментов я обнаружил, что очень маленькие файлы работают без use_crc. Затем небольшие файлы подсчета перешли в неработающие между "12345678901234" и "123456789012345". Причина заключалась в следующем: это первый файл, который был спущен, а не сохранен в несжатом (при том, что zip назвал экономию «6%»)

Пытаясь заставить zlib его принять, я пробовал многое. Это включало попытку 16 + MAX_WBITS. Казалось, что ничто не обрабатывает полезную нагрузку из zip test.zip test.txt, как это было в старом коде.

Если бы я был готов вычесть единицу из моего конечного размера, я бы, казалось, смог подавить ошибочную проверку ... при потере одного байта. Вот простая тестовая программа с жестко запрограммированной минимальной полезной нагрузкой zip:

#include <stdio.h>
#include "zlib.h"

int main(int argc, char *argv[]) {
    char compressed[] = { 0x78, 0x9C, 0x33, 0x34, 0x32, 0x36, 0x31, 0x35, 0x33,
        0xB7, 0xB0, 0x34, 0x30, 0x04, 0xB1, 0xB8, 0x00, 0x31, 0x30, 0xB1, 0x30,
        0x10, 0x00, 0x00, 0x00 }; // last 4 bytes are size (16)

    char uncompressed[16 + 1]; // account for null terminator
    int ret; z_stream strm;

    memset(uncompressed, 'X', 16);
    uncompressed[16] = '\0';

    strm.zalloc = strm.zfree = strm.opaque = Z_NULL;
    strm.total_out = 0;
    strm.avail_in = 25;
    strm.next_in = compressed;

    ret = inflateInit2(&strm, MAX_WBITS /* + 16 */); // it is Z_OK

    strm.avail_out = 15; // 16 gives error -3: "incorrect header check" 
    strm.next_out = uncompressed;
    ret = inflate(&strm, Z_NO_FLUSH);

    if (ret != /* Z_STREAM_END */ Z_OK) { // doesn't finish... 
        printf("inflate() error %d: %s\n", ret, strm.msg);
        return 2;
    }

    inflateEnd(&strm);
    printf("successful inflation: %s\n", uncompressed);
    return 0;
}

Результат:

успешная инфляция: 123456789012345X

Показанные данные не сжимаются, но нам нужны все 16 байтов. (Там есть новая строка из файла, который должен быть получен.) 16 + MAX_WBITS даже этого не понять.

Есть идеи, что не так? Кажется, что никакая перестановка настроек не проходит без ошибок.


person HostileFork says dont trust SE    schedule 02.10.2015    source источник
comment
Какая это версия zlib? Я просто немного ковырялся через github.com/madler/zlib/blob /v1.1.1/uncompr.c и просматривая разные версии тегов, не могу найти ни одной use_crc ссылки. Возможно, это был патч к официальному zlib, сделанный какой-то третьей стороной?   -  person Joe    schedule 02.10.2015
comment
@ Джо: Это могло быть неофициально, хороший аргумент. Это кодовая база Rebol, в которой был извлеченный файл: u-zlib.c. О добавлении не было никаких заметок, но, глядя на него на GitHub, у него действительно есть необычные табуляции, что говорит о том, что вы, вероятно, правы. Моя настоящая цель - декодировать этот двоичный файл, поэтому я обновлю вопрос.   -  person HostileFork says dont trust SE    schedule 02.10.2015
comment
Я думаю, что лучший ответ - даже не пытаться перенести эту функцию на новый zlib. Относитесь к этим файлам так, как если бы они вообще не были zlib (что на самом деле таковым не является, поскольку они генерируются взломанным zlib). Представьте, что единственный способ распаковать их - использовать тот же инструмент, который их сжал. Вы связались с github. Распакуйте ваши файлы с помощью rebol, сохраните их в более разумном формате и не повторяйте ошибку использования rebol (или его zlib (или его флага use_crc)) в будущем   -  person    schedule 02.10.2015
comment
@ WumpusQ.Wumbley Rebol не создает этот формат. Это данные, которые передавались обработчиком zip-файлов, и этот файл был создан через zip test.zip test.txt, как я сказал в вопросе. Кажется, теперь мне следует уделить больше внимания процессору. Причина, по которой я этого не делал раньше, заключается в том, что я ничего из этого не писал, кто-то попросил меня разобраться в этом, раньше это работало, а теперь не работает при связывании с zlib 2013 года. Как я сказал Марку Адлеру, я предположил, что предыдущее рабочее декодирование .zip, созданного с помощью zip, предполагало, что двоичный blob является полезной нагрузкой zip, я посмотрю и выясню, почему вы, ребята, говорите, что это не так.   -  person HostileFork says dont trust SE    schedule 02.10.2015
comment
Поскольку вы связались с rebol, чтобы показать нам флаг use_crc, я предположил, что это то, что вы на самом деле использовали. В любом случае, если ваши фактические исходные файлы находятся в формате zip, почему бы не использовать инструмент zip и пропустить всю эту работу с zlib? Или он тоже не соответствует формату zip?   -  person    schedule 02.10.2015
comment
@ WumpusQ.Wumbley Rebol используется для распаковки, а zip - для сжатия. На самом деле цель состоит в том, чтобы заставить Rebol работать как инструмент декомпрессии без использования каких-либо других исполняемых файлов, учитывая, что Rebol будет небольшим кроссплатформенным цель ... плюс внутри него есть zlib (и, если я смогу заставить настройку работать, официальный zlib). Основываясь на советах здесь, я пошел к декодеру zip-контейнера и обнаружил это настоящий дымящийся пистолет. Грех Ребола, кажется, заключался только в добавлении средства проверки CRC32, но клиент делает вещи целиком. Просто раньше на нем не было ошибок, а теперь нет.   -  person HostileFork says dont trust SE    schedule 02.10.2015


Ответы (1)


Нет, несовместимых изменений в интерфейсе zlib не было с момента его появления более 20 лет назад. Для uncompress() никогда не было use_crc аргумента.

Пример, который вы даете, - это двухбайтовый заголовок zlib, сжатые с дефляцией данные, CRC-32 данных с дефляцией в большом -концевом порядке, за которым следует четырехбайтовая длина в маленьком -конечный порядок. Это действительно странное сочетание оболочек zlib и gzip, и оно не имеет никакого отношения к формату zip, о котором вы все время упоминаете. (Что вы имеете в виду «полезные данные внутри zip-файлов»?) Zlib имеет Adler-32 в конце в прямом порядке, тогда как gzip имеет CRC-32 в прямом порядке, за которым следует четырехбайтовая длина в малом порядке. порядок байтов. Этот смешивает их, включая порядок байтов, а затем намеренно вводит в заблуждение и помещает в объект действительный заголовок zlib, что является оскорблением для всего хорошего и достойного в этом мире.

Я почти уверен, что тот, кто придумал этот формат, был тогда пьян.

Чтобы его расшифровать, вам необходимо:

  1. Отбросить первые два байта потока. (Вы можете проверить, что это действительный заголовок zlib, но это оказывается бессмысленным при интерпретации остальной части потока.)

  2. Используйте raw deflate с инициализацией inflateInit2(&strm, -15), чтобы распаковать данные. Во время распаковки отслеживайте общую длину и вычисляйте CRC-32, используя crc32().

  3. После завершения данных deflate прочтите следующие четыре байта, соберите их в порядке обратного порядка байтов до 32-битного значения и сравните его с вычисленным CRC-32. Если он не совпадает, поток поврежден или это не один из этих странно отформатированных потоков. (Возможно, попробуйте еще раз, декодируя его как обычный поток zlib. Если бы у него был хороший заголовок zlib, то, возможно, это то, чем он является на самом деле, в отличие от одного из этих потоков Франкенштейна.)

  4. Прочтите следующие четыре байта и соберите их в порядке прямого байта и сравните их с длиной несжатых данных. Если он не совпадает, значит, поток поврежден или это не то, что вы думаете.

  5. Если данные на этом не заканчиваются, значит, происходит что-то еще странное. Посоветуйтесь с пьяным.

person Mark Adler    schedule 02.10.2015
comment
И, пожалуйста, пожалуйста, пожалуйста, не изменяйте zlib, чтобы обработать это злодеяние, и если вы это сделаете, ради бога, никогда, никогда не распространяйте такие вещи. Как я уже описал, zlib можно использовать как есть для обработки этих данных. - person Mark Adler; 02.10.2015
comment
Рад слышать от самого Человека! (Но имейте в виду, я никогда раньше не имел дела с zlib, и с тем, кто был привлечен добровольцем за хорошую работу по устранению злодеяний, пытаясь распотрошить код и связать новый канонический zlib. Если вы хотите орать на кого-то напиши этого парня.) Но когда я говорю «полезная нагрузка внутри zip» file Я имею в виду, что это то, что было передано в uncompress () w / use_crc программой чтения zip. Похоже, вы говорите, что мне нужно посмотреть исходный код zip reader, который предоставил это, и я сделаю это, вооружившись этой информацией, и доложу. - person HostileFork says dont trust SE; 02.10.2015
comment
Ситуация именно такая, как вы дословно описали. Кусок кода, который распаковывал .ZIP, просто придумал это. Избавиться от всего этого и просто использовать -15 сработало. Спасибо за указатели и оперативную помощь! - person HostileFork says dont trust SE; 05.10.2015