Question

J'espère que vous avez entendu parler de neat hack qui vous permet de combiner un fichier JPG et un fichier Zip en un seul fichier. Il s’agit d’un fichier valide (ou au moins lisible) pour les deux formats. Eh bien, je me suis rendu compte que puisque JPG laissait des trucs arbitraires à la fin, et ZIP au début, vous pouviez coller un format supplémentaire: le milieu. Pour les besoins de cette question, supposons que les données du milieu soient des données binaires arbitraires garanties de ne pas entrer en conflit avec les formats JPG ou ZIP (ce qui signifie qu’elles ne contiennent pas l’en-tête zip magique 0x04034b50). Illustration:

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

Je suis comme ça:

  

chat " mss_1600.jpg " filea fileb   fichier fichier fichier fichier fichier fichier   fichier fichier fichier fichier fichier fichier fichier   fichier fichier fichier fichier fichier fichier fichier   fichier fichier fichier fichier fichier fichier fichier   fileb " null.bytes "   " randomzipfile.zip " > temp.zip

Ceci produit un fichier de 6 318 Ko. Il ne s’ouvre pas dans 7-Zip. Cependant, lorsque je cloue un chat moins un double (donc au lieu de 13 fichiers et 12, 12):

  

chat " mss_1600.jpg " filea fileb   fichier fichier fichier fichier fichier fichier   fichier fichier fichier fichier fichier fichier fichier   fichier fichier fichier fichier fichier fichier fichier   fileb fileea fileb fileea fileb   " null.bytes " " randomzipfile.zip " >   temp.zip

Il génère un fichier de 5 996 Ko que ouvre dans 7-Zip.

Donc, je sais que mes données binaires arbitraires n’ont pas l’en-tête de fichier Zip magique pour le bousiller. J'ai des fichiers de référence du jpg + données + zip et du jpg non fonctionnel + données + zip (enregistrer sous le motif que le navigateur pense être des images, puis ajoutez le zip extensions vous-même).

Je veux savoir pourquoi cela échoue avec 13 combinaisons et pas avec 12. Pour les points bonus, je dois contourner le problème.

Était-ce utile?

La solution

En fait, c’est vraiment une réponse en deux parties :)

Premièrement, peu importe ce que les gens disent, les fichiers zip ne peuvent pas techniquement être placés textuellement à la fin des fichiers. L'enregistrement de fin de répertoire central a une valeur qui indique le décalage d'octet à partir du début du disque actuel (si vous n'avez qu'un seul fichier .zip, cela signifie le fichier actuel). Maintenant, beaucoup de processeurs l'ignorent, bien que le dossier zip de Windows ne l'ait pas, vous devez donc corriger cette valeur pour que cela fonctionne dans l'explorateur Windows (vous ne voudrez peut-être pas s'en soucier; P) Voir Zip APPNOTE pour obtenir des informations sur le format de fichier. En gros, vous trouvez dans un éditeur hexadécimal (ou écrivez un outil) le décalage & "; De début du répertoire central par rapport au numéro de disque de départ &"; valeur. Recherchez ensuite la première & Quot; signature d'en-tête de fichier central & Quot; (hex de 504b0102) et définissez la valeur sur ce décalage.

Maintenant, hélas, cela ne corrige pas 7zip, mais cela est dû à la façon dont 7zip essaie de deviner le format du fichier. Fondamentalement, la séquence binaire 504b0304 ne sera recherchée que dans le premier ~ 4 Mo. Si elle ne la trouve pas, elle suppose qu'elle n'est pas Zip et essaie ses autres formats d'archive. C’est évidemment pour cette raison que l’ajout d’un fichier supplémentaire casse les choses, il le dépasse au-delà de la limite fixée pour la recherche.

Maintenant, pour résoudre ce problème, vous devez ajouter cette chaîne hexadécimale au jpeg sans la casser. Une façon de procéder consiste à ajouter, juste après l'en-tête FFD8 JPEG SOI, les données hexadécimales suivantes, FFEF0005504B030400. Cela ajoute un bloc personnalisé avec votre séquence et est correct, les en-têtes jpeg doivent simplement l’ignorer.

Autres conseils

J'ai téléchargé le code source de 7-Zip et découvert la cause de ce problème.

Dans CPP / 7zip / UI / Common / OpenArchive.cpp, vous verrez les éléments suivants:

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

Cela signifie que seuls l'en-tête sera recherché dans les 4194304 octets du fichier. S'il ne s'y trouve pas, 7-Zip considère qu'il s'agit d'un fichier non valide.

Vous pouvez doubler cette limite en remplaçant 1 << 22 par 1 << 23. J'ai testé ce changement en reconstruisant 7-Zip et cela fonctionne.

MODIFIER : pour résoudre ce problème, vous pouvez télécharger le code source. , apportez les modifications ci-dessus et construisez-les. Je l'ai construite à l'aide de VS 2008. Ouvrez l'invite de commande VS, accédez à emplacement-source-extrait \ CPP \ 7zip \ Bundles et tapez "nmake". Ensuite, dans le répertoire Alone, exécutez "7za t nonworking.jpg" et vous devriez voir "Tout va bien".

Donc, pour tous ceux qui trouvent cette question, voici l'histoire:

Oui, Andy a littéralement raison de la raison pour laquelle 7-Zip échoue dans le fichier, mais cela ne résout en rien mon problème, car je ne parviens pas à utiliser les utilisateurs de ma version de 7-Zip.

tyranid m'a cependant la solution.

  • Tout d'abord, ajouter un petit bytest au JPG, comme il le suggère, laissera 7-Zip l'ouvrir. Cependant, il s’agit d’un léger décalage par rapport à un fragment JPG valide. Il doit être FFEF00 07 504B030400 - la longueur était décalée de 2 octets.
  • Cela permet à 7-Zip de l’ouvrir, mais pas d’extraire des fichiers, cela échoue en silence. En effet, les entrées du répertoire central ont des pointeurs / décalages internes qui pointent vers l'entrée du fichier. Puisque vous avez mis beaucoup de choses avant cela, vous devez corriger tous ces indicateurs!
  • Pour que le zip soit ouvert avec le support zip intégré de Windows, vous devez, comme le dit tyranid, corriger le décalage & du début du répertoire central par rapport au numéro de disque de départ &. Voici un script python pour effectuer les deux derniers, bien qu’il s’agisse d’un fragment et non de copypasta-prêt à utiliser

#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()

Vous pouvez créer des fichiers JPG + ZIP hybrides à l'aide de DotNetZip . DotNetZip peut enregistrer dans un flux, et il est suffisamment intelligent pour reconnaître le décalage d'origine d'un flux préexistant avant qu'il ne commence à écrire du contenu zip dans celui-ci. Par conséquent, en pseudo-code, vous pouvez obtenir un fichier JPG + ZIP de la manière suivante:

 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

Tous les décalages sont correctement calculés. La même technique est utilisée pour produire une archive auto-extractible. Vous pouvez ouvrir le flux sur le fichier EXE, puis chercher jusqu'au bout et écrire le contenu ZIP dans ce flux. Tous les décalages sont calculés correctement si vous le faites de cette façon.

Autre chose - en ce qui concerne l’un des commentaires dans un autre message ... ZIP peut contenir des données arbitraires au début et à la fin du fichier. Pour autant que je sache, le répertoire central zip doit figurer à la fin du fichier, bien que ce soit typique.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top