2015-10-02 5 views
6

Stavo aggiornando il codice di un progetto da una versione 1998 di zlib a una versione 2013 di zlib. Una cosa che sembra aver cambiato è che ha usato per essere una bandiera "use_crc" sulla funzione di decompressione, che sembrava aver scomparso:Come imitare un flag "use_crc" su (hacked) 1998 uncompress() nel 2013 interfaccia zlib API?

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

(UPDATE: come ha sottolineato @ Joe, questo è probabilmente un third-party modification. Titolo aggiornato di conseguenza. il resto della domanda è ancora applicabile, come in "come dovrei meglio farlo con l'odierna magazzino zlib".)

nel codice che sto studiando, uncompress () viene chiamato da qualcosa che decostruisce il formato binario di un .zip e passa in un "carico utile" di dati. Il codice aveva passato il flag crc come 1. Se il flag non fosse usato, otterrebbe un Z_DATA_ERROR (-3). (Un Zlib senza flag use_crc ottiene Z_DATA_ERROR come se il flag fosse stato falso.)

In esperimenti, ho trovato che file molto piccoli funzionavano senza use_crc. Quindi i piccoli file di conteggio sono passati a non lavorare tra "123456789" e "123456789". La ragione era: questo è il primo file che è stato sgonfiato invece memorizzato compresso (a quale zip chiamato un risparmio di "6%")

In dibatte con opzioni per ottenere zlib ad accettarlo, ho provato molte cose. Questo comprendeva provare il 16 + MAX_WBITS. Nulla sembrava elaborare il carico utile da zip test.zip test.txt come il vecchio codice.

Se volevo sottrarre una delle dimensioni della mia destinazione, mi sembrava di essere in grado di sopprimere il controllo errato ... alla perdita di un byte. Ecco il semplice programma di test con il minimo zip payload hardcoded:

#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; 
} 

L'output è:

inflazione successo: 123456789X

Mostrando i dati sta diventando non compressi, ma abbiamo bisogno di tutti 16 byte. (C'è una nuova riga dal file che deve essere ricevuto.) 16 + MAX_WBITS non possono nemmeno averlo.

Qualche idea cosa non va? Nessuna permutazione delle impostazioni sembra arrivare senza errori.

+3

Quale versione di zlib è presente? Ho solo fatto qualche ricerca attraverso https://github.com/madler/zlib/blob/v1.1.1/uncompr.c e guardando le diverse versioni dei tag e non ho trovato alcun ref "use_crc'. Possibile questa è stata una patch di zlib ufficiale da parte di qualche terza parte? – Joe

+0

@Joe Potrebbe non essere ufficiale, buon punto. È nella base di codice Rebol, che aveva un file estratto: [u-zlib.c] (https://github.com/rebol/rebol/blob/25033f897b2bd466068d7663563cd3ff64740b94/src/core/u-zlib.c#L2063). Non c'erano note sull'aggiunta, ma guardandolo su GitHub ha un tabù insolito, suggerendo che probabilmente hai ragione. Il mio vero obiettivo è quello di decodificare quel file binario, quindi aggiornerò la domanda. – HostileFork

+2

Penso che la migliore risposta sia non provare nemmeno a portarla su uno zlib più recente. Tratta questi file come se non fossero affatto zlib (che in realtà non lo sono, dal momento che sono generati da uno zlib hackerato). Fai finta che l'unico modo per decomprimerli sia con lo stesso strumento che li ha compressi. Sei collegato al github. Decomprimi i tuoi file con rebol, salvali in un formato più ragionevole e non ripetere l'errore di usare rebol (o il suo zlib (o il suo flag use_crc)) in futuro –

risposta

4

No, non sono state apportate modifiche incompatibili all'interfaccia zlib da quando è stato introdotto più di 20 anni fa. Non c'è mai stato un argomento use_crc su uncompress().

L'esempio che dai è un'intestazione zlib due byte, dati sgonfiare-compresso, il CRC-32 dei dati si sgonfiano in grande ordine -endian, seguita da una lunghezza di quattro byte in poco -endian ordine. Questo è un miscuglio davvero insolito dei wrapper zlib e gzip e non ha assolutamente nulla a che fare con il formato zip, che continui a menzionare. (Cosa intendi con "payload all'interno di file zip"?) Zlib ha un Adler-32 alla fine nell'ordine big-endian mentre gzip ha un CRC-32 in ordine little-endian seguito da una lunghezza di quattro byte in little- ordine endian.Questo li mescola, incluso l'ordinamento dei byte, e quindi in modo deliberatamente fuorviante mette un intestazione zlib valida sulla cosa, che è un affronto a tutto ciò che è buono e decente in questo mondo.

Sono abbastanza sicuro che chiunque abbia inventato questo formato fosse ubriaco al momento.

Per decodificare questo è necessario:

  1. eliminare i primi due byte del flusso. (È possibile verificare che sia un'intestazione zlib valida, ma risulta essere priva di significato nell'interpretazione del resto del flusso.)

  2. Utilizzare lo svuotamento grezzo, inizializzando con inflateInit2(&strm, -15), per decomprimere i dati. Durante la decompressione, tenere traccia della lunghezza totale e calcolare il CRC-32 utilizzando crc32().

  3. Dopo aver completato i dati di svuotamento, leggere i quattro byte successivi, assemblarli in ordine big-endian su un valore a 32 bit e confrontarlo con il CRC-32 calcolato. Se non corrisponde, il flusso è corrotto o non è uno di questi flussi con formattazione strana. (Forse riprovare, decodificandolo come un normale flusso di zlib. Se avesse una buona intestazione di zlib, allora forse è quello che effettivamente è, al contrario di uno di questi flussi di Frankenstein.)

  4. Leggi i prossimi quattro byte e assemblare quelli in ordine little-endian e confrontarli con la lunghezza dei dati non compressi. Se non corrisponde, lo stream è corrotto o non è quello che pensi.

  5. Se i dati non finiscono qui, allora sta accadendo qualcos'altro. Consultare la persona ubriaca.

+3

E per favore, per favore, per favore non modificare zlib per elaborare questa atrocità, e se lo fai, per l'amor di dio, mai e poi mai distribuire una cosa del genere. zlib può essere usato così come è per elaborare questi dati, come ho descritto. –

+0

Felice di ascoltare l'Uomo stesso! * (Tenete a mente, non ho mai trattato con Zlib prima, e colui che ha ottenuto volontariato-cordata per "il buon lavoro" di "eliminazione delle atrocità" cercando di sventrare il codice e collegare un nuovo zlib canonico. voglio gridare a qualcuno [scrivi questo ragazzo] (https://en.wikipedia.org/wiki/Carl_Sassenrath).) * Ma quando dico "payload in un file zip" intendo che questo è ciò che è stato passato a 'uncompress() "w/use_crc da un lettore di zip. Sembra che tu stia dicendo che devo andare a dare un'occhiata all'origine del lettore zip che ha fornito questo, e andrò a farlo armata di queste informazioni e riferirò. – HostileFork

+0

La situazione è esattamente come hai descritto testualmente.Il pezzo di codice che stava decomprimendo .ZIP lo ha appena inventato.Togliere tutto ciò e usare solo -15 ha funzionato.Grazie per i suggerimenti e l'aiuto rapido! – HostileFork