Z_DATA_ERROR на полпути через инфляцию - PullRequest
0 голосов
/ 13 мая 2018

Мне нужно распаковать некоторые сжатые zlib файлы, найденные в данных сохранения игры.У меня нет доступа к источнику игры.Каждый файл начинается с 0x789C, что говорит мне, что они действительно сжаты с помощью zlib.Однако все вызовы для раздувания этих файлов не могут полностью распаковать и вернуть Z_DATA_ERROR.Использование zlib версий 1.2.5, 1.2.8 и 1.2.11 с одинаковыми результатами.

Несмотря на то, что zlib сообщает мне, что входные данные повреждены, я уверен, что это не так, поскольку игра способнараспаковывать эти файлы без проблем И это не изолировано ни одному потоку данных.У меня сотни тысяч уникальных потоков данных, сжатых одинаково, и все они выбрасывают Z_DATA_ERROR где-то в середине декомпрессии.

Кроме того, частично распакованные данные, которые успешнораспакован, правильно.Вывод точно такой, как ожидалось.

Кроме того, примерно в 10% случаев zlib будет распаковывать весь файл, однако результат будет неправильным.Большие фрагменты распакованных данных содержат один и тот же байт, повторяемый снова и снова, что говорит мне, что это был ложный положительный результат.

Вот мой код декомпрессии:

//QByteArray is a Qt wrapper for a char *
QByteArray Compression::DecompressData(QByteArray data)
{
    QByteArray result;

    int ret;
    z_stream strm;
    static const int CHUNK_SIZE = 1;//set to 1 just for debugging
    char out[CHUNK_SIZE];

    strm.zalloc = Z_NULL;
    strm.zfree = Z_NULL;
    strm.opaque = Z_NULL;
    strm.avail_in = data.size();
    strm.next_in = (Bytef*)(data.data());

    ret = inflateInit2(&strm, -15);
    if (ret != Z_OK)
    {
        qDebug() << "init error" << ret;
        return QByteArray();
    }

    do
    {
        strm.avail_out = CHUNK_SIZE;
        strm.next_out = (Bytef*)(out);

        ret = inflate(&strm, Z_NO_FLUSH);
        qDebug() << "debugging output: " << ret << QString::number(strm.total_in, 16);//This tells me which input byte caused the failure
        Q_ASSERT(ret != Z_STREAM_ERROR);

        switch (ret)
        {
        case Z_NEED_DICT:
            ret = Z_DATA_ERROR;
        case Z_DATA_ERROR:
        case Z_MEM_ERROR:
            (void)inflateEnd(&strm);
            return result;
        }

        result.append(out, CHUNK_SIZE - strm.avail_out);
    } while (strm.avail_out == 0);

    inflateEnd(&strm);
    return result;
}

Вот вставка изданные файла примера сжатые данные с удаленным 0x789C и конечным CRC.Я могу предоставить буквально бесконечные примеры файлов.Все они имеют одну и ту же проблему.

Выполнение этих данных с помощью вышеуказанной функции правильно распаковывает начало потока, но приводит к сбою входного байта 0x18C.Вы можете сказать, что он распакован правильно, когда начало файла начинается с 0x000B, а распакованные данные длиннее входных данных.

Хотелось бы знать больше о сжатии с дефляцией, чтобы решить эту проблему самостоятельно.Мои первые мысли заключаются в том, что игра решила использовать пользовательскую версию zlib или чтобы zlib нужно было предоставить дополнительный параметр, чтобы правильно распаковать ее.Я много раз спрашивал и много раз пробовал, и мне действительно нужен кто-то со знанием предмета, чтобы взвесить здесь.Спасибо за ваше время!

1 Ответ

0 голосов
/ 13 мая 2018

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

Как вы заметили, по смещению 396 находится первое из десяти расстояний слишком далеко назад. Вот где надувать останавливается. По смещению 3472, почти в конце, находится сохраненный блок с длиной, которая не проверяет его дополнение.

Для слишком больших расстояний вы можете попробовать установить словарь из 32K нулевых байтов, используя inflateSetDictionary() сразу после inflateInit2(). Затем происходит декомпрессия, заполняющая указанные места нулями. Это может или не может быть тем, что делает игра. Для ошибки хранимого блока нет очевидного решения.

Действительно, автор игры может намеренно связываться с вами или любым человеком, пытающимся распаковать свои внутренние данные, изменив zlib для собственного использования.

...