2009-11-30 24 views
11

Si spera che abbiate sentito parlare dello neat hack che consente di combinare un file JPG e un file Zip in un singolo file ed è un file valido (o almeno leggibile) per entrambi i formati. Bene, mi sono reso conto che dal momento che JPG lascia materiale arbitrario alla fine, e ZIP all'inizio, puoi inserire un altro formato in là - nel mezzo. Ai fini di questa domanda, supponiamo che i dati medi siano dati binari arbitrari garantiti per non entrare in conflitto con i formati JPG o ZIP (il che significa che non contiene l'header magico 0x04034b50). Illustrazione:Combinazione di file zip JPG + Zip con formato Zip

0xFFD8 <- start jpg data end -> 0xFFD9 ... ARBITRARY BINARY DATA ... 0x04034b50 <- start zip file ... EOF 

sto catting come questo:

gatto "mss_1600.jpg" filea fileB filea fileB filea fileB filea fileB filea fileB filea fileB filea fileB filea fileB filea fileB filea fileB FILEA fileB filea fileB filea fileB "null.bytes" "randomzipfile.zip"> temp.zip

Questo produce un file di 6.318 KB. È non aperto a aperto in 7-Zip. Tuttavia, quando ho gatto uno meno 'doppie' (così invece di 13 fileA e B, 12):

gatto "mss_1600.jpg" filea fileB filea fileB filea fileB filea fileB filea fileB filea fileB filea fileB FILEA fileB filea fileB filea fileB filea fileB filea fileB "null.bytes" "randomzipfile.zip"> temp.zip

produce un file di 5996 KB che fa aperto in 7-Zip.

Quindi so che i miei dati binari arbitrari non hanno la magica intestazione del file zip per rovinarla. Ho i file di riferimento di working jpg+data+zip e non-working jpg+data+zip (salva-perché il browser pensa che siano immagini e aggiungi tu stesso le estensioni zip).

Voglio sapere perché non riesce con 13 combinazioni e non con 12. Per i punti bonus, ho bisogno di aggirare questo in qualche modo.

+1

Volevo solo sottolineare che questo è probabilmente un problema con l'algoritmo di 7Zip, dal momento che File Roller è riuscito ad aprire anche l'esempio non funzionante. – laginimaineb

+1

Trucchetto Niente - D'ora in poi userò questa tecnica per inserire un'immagine di me stesso in tutti i miei java .jar's (pegs-jar eseguibili :) – Seth

risposta

10

In realtà si tratta di una risposta in due parti davvero :)

In primo luogo, non importa quello che dicono i file zip non possono tecnicamente essere messi letteralmente alla fine del file. La fine del record della directory centrale ha un valore che indica lo spostamento del byte dall'inizio del disco corrente (se si ha solo un file .zip, ovvero il file corrente). Ora molti processori ignorano questo, anche se la cartella zip di Windows non ha bisogno di correggere quel valore per farlo funzionare in Windows Explorer (non che tu possa preoccuparti; P) Vedi Zip APPNOTE per informazioni sul formato del file. Fondamentalmente si trova in un editor esadecimale (o si scrive uno strumento) per trovare il valore "offset di inizio della directory centrale rispetto al numero del disco iniziale". Quindi trova la prima "firma di intestazione del file centrale" (esadecimale di 504b0102) e imposta il valore su quell'offset.

Ora ahimè che non aggiusta 7zip ma ciò è dovuto al modo in cui 7zip tenta di indovinare il formato del file. Fondamentalmente cercherà solo il primo ~ 4MiB per la sequenza binaria 504b0304, se non lo trova suppone che non sia Zip e prova i suoi altri formati di archivio. Questo è ovviamente il motivo per cui aggiungere un altro file rompe le cose, lo spinge oltre il limite per la ricerca.

Ora per risolvere il problema è necessario aggiungere quella stringa esadecimale al jpeg senza romperlo. Un modo per farlo è aggiungere subito dopo l'intestazione FFD8 JPEG SOI i seguenti dati esadecimali, FFEF0005504B030400. Ciò aggiunge un blocco personalizzato alla sequenza ed è corretto, quindi le intestazioni jpeg dovrebbero semplicemente ignorarlo.

+0

Questo ottenuto me il 60% del modo lì. Ho anche dovuto modificare le voci 504b0102 per modificare gli offset di THEIR altrimenti si è aperto ma non ti ha permesso di estrarre i file. I ** think ** Ho un jpg/zip funzionante in Windows Explorer e 7-Zip, ma ho bisogno di fare ulteriori test domani. –

20

Ho scaricato il codice sorgente per 7-Zip e ho scoperto cosa sta causando ciò.

In CPP/7zip/UI/comune/OpenArchive.cpp, si vedrà il seguente:

// Static-SFX (for Linux) can be big. 
const UInt64 kMaxCheckStartPosition = 1 << 22; 

Ciò significa che solo i primi 4194304 byte del file verranno ricercati per l'intestazione. Se non viene trovato lì, 7-Zip lo considera un file non valido.

È possibile raddoppiare tale limite modificando 1 << 22 in 1 << 23. Ho provato questo cambiamento ricostruendo 7-Zip e funziona.

MODIFICA: Per ovviare a questo problema, è possibile download the source, apportare le modifiche precedenti e crearlo. L'ho creato utilizzando VS 2008. Apri il prompt dei comandi VS, vai a estratto-source-location \ CPP \ 7zip \ Bundles e digita "nmake". Quindi, nella directory Alone, esegui '7za t nonworking.jpg 'e dovresti vedere' Tutto è ok '.

+0

Incredibile bravo signore. Mi chiedo se posso mettere un file falso della forma corretta in quella prima estensione di byte e trucco 7-Zip ... Ho intenzione di giocare un po '(e anche aspettare un po' prima di accettare, senza offesa) –

4

Quindi per chiunque altro trovare questa domanda, ecco la storia:

Sì, Andy è letteralmente corretto sul perché 7-Zip sta venendo a mancare sul file, ma non aiuta il mio problema dal momento che puo' t esattamente le persone a usare la mia versione di 7-Zip.

tyranid comunque mi ha trovato la soluzione.

  • Prima di tutto, aggiungendo un piccolo bytestring al JPG come suggerisce lascerà 7-Zip per aprirlo. Tuttavia, è leggermente fuori da un frammento JPG valido, deve essere FFEF00 504B030400 - la lunghezza era disattivata di 2 byte.
  • Ciò consente a 7-Zip di aprirlo, ma non di estrarre i file, fallisce silenziosamente. Questo perché le voci nella directory centrale hanno puntatori/offset interni che puntano alla voce del file. Dato che hai messo un sacco di cose prima, devi correggere tutti quei suggerimenti!
  • Per avere la chiusura lampo con supporto integrato di zip di Windows, è necessario, come dice tyranid, correggere "l'offset dell'inizio della directory centrale rispetto al numero del disco iniziale". Ecco uno script python per fare gli ultimi due, anche se è un frammento, non copypasta-ready-to-use

#Now we need to read the file and rewrite all the zip headers. Fun! 
torewrite = open(magicfilename, 'rb') 
magicdata = torewrite.read() 
torewrite.close() 

#Change the Central Repository's Offset 
offsetOfCentralRepro = magicdata.find('\x50\x4B\x01\x02') #this is the beginning of the central repo 
start = len(magicdata) - 6 #it so happens, that on my files, the point is stored 2 bytes from the end. so datadatadatdaata OF FS ET !! 00 00 EOF where OFFSET!! is the 4 bytes 00 00 are the last two bytes, then EOF 
magicdata = magicdata[:start] + pack('I', offsetOfCentralRepro) + magicdata[start+4:] 

#Now change the individual offsets in the central directory files 
startOfCentralDirectoryEntry = magicdata.find('\x50\x4B\x01\x02', 0) #find the first central directory entry 
startOfFileDirectoryEntry = magicdata.find('\x50\x4B\x03\x04', 10) #find the first file entry (we start at 10 because we have to skip past the first fake entry in the jpg) 
while startOfCentralDirectoryEntry > 0: 
    #Now I move a magic number of bytes past the entry (really! It's 42!) 
    startOfCentralDirectoryEntry = startOfCentralDirectoryEntry + 42 

    #get the current offset just to output something to the terminal 
    (oldoffset,) = unpack('I', magicdata[startOfCentralDirectoryEntry : startOfCentralDirectoryEntry+4]) 
    print "Old Offset: ", oldoffset, " New Offset: ", startOfFileDirectoryEntry , " at ", startOfCentralDirectoryEntry 
    #now replace it 
    magicdata = magicdata[:startOfCentralDirectoryEntry] + pack('I', startOfFileDirectoryEntry) + magicdata[startOfCentralDirectoryEntry+4:] 

    #now I move to the next central directory entry, and the next file entry 
    startOfCentralDirectoryEntry = magicdata.find('\x50\x4B\x01\x02', startOfCentralDirectoryEntry) 
    startOfFileDirectoryEntry = magicdata.find('\x50\x4B\x03\x04', startOfFileDirectoryEntry+1) 

#Finally write the rewritten headers' data 
towrite = open(magicfilename, 'wb') 
towrite.write(magicdata) 
towrite.close() 
+0

Grazie per aver condiviso il tuo codice (e aver rivelato che il significato è 42;)). E non c'è bisogno di spiegare - ho imparato molto ed è stato comunque divertente. –

+0

Scusa se ho avuto qualche problema. Grazie comunque :) – tyranid

2

È possibile produrre ibridi file ZIP utilizzando DotNetZip JPG +. DotNetZip può salvare su uno stream ed è abbastanza intelligente da riconoscere l'offset originale di uno stream preesistente prima di iniziare a scrivere il contenuto zip in esso. Quindi in pseudo codice, è possibile ottenere un JPG + Zip in questo modo:

open stream on an existing JPG file for update 
seek to the end of that stream 
open or create a zip file 
call ZipFile.Save to write zip content to the JPG stream 
close 

Tutti gli spostamenti sono correttamente capito. La stessa tecnica viene utilizzata per produrre un archivio autoestraente. È possibile aprire lo stream sul file EXE, quindi cercare fino alla fine e scrivere il contenuto ZIP in quello stream. Tutti gli offset sono calcolati correttamente se lo fai in questo modo.

Un'altra cosa - per quanto riguarda uno dei commenti in un altro post ... ZIP può avere dati arbitrari all'inizio e alla fine del file. Non c'è alcun obbligo per quanto so che la directory centrale di zip deve essere alla fine del file, anche se questo è tipico.