2009-11-30 15 views
11

Espero que hayas oído hablar del neat hack que te permite combinar un archivo JPG y un archivo Zip en un solo archivo y es un archivo válido (o al menos legible) para ambos formatos. Bueno, me di cuenta de que, dado que JPG deja cosas arbitrarias al final, y ZIP al principio, puedes pegar un formato más allí: en el medio. A los efectos de esta pregunta, suponga que los datos intermedios son datos binarios arbitrarios garantizados para no entrar en conflicto con los formatos JPG o ZIP (lo que significa que no contiene el encabezado mágico de zip 0x04034b50). Ilustración:JPG + Archivo Zip Problema de combinación con formato Zip

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

estoy Catting así:

gato "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

Esto produce un archivo de 6,318 KB. Es no abierto en 7-Zip. Sin embargo, cuando gato uno menos 'doble' (lo que en lugar de 13 FILEA y B, 12):

cat "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 archivo 5996 KB que hace abierta en 7-Zip.

Así que sé que mis datos binarios arbitrarios no tienen el Encabezado del Archivo Zip mágico para arruinarlo. Tengo archivos de referencia del working jpg+data+zip y el non-working jpg+data+zip (salvo porque el navegador cree que son imágenes y añada las extensiones zip por su cuenta).

Quiero saber por qué falla con 13 combinaciones y no con 12. Para obtener puntos de bonificación, tengo que solucionar esto de alguna manera.

+1

Solo quería señalar que esto probablemente sea un problema con el algoritmo de 7Zip, ya que File Roller también logró abrir el ejemplo que no funcionaba. – laginimaineb

+1

Buen truco - A partir de ahora voy a utilizar esta técnica para insertar una imagen de mí mismo en todos mis java .jar's (ejecutable jar-pegs :) – Seth

Respuesta

10

En realidad se trata de una respuesta en dos partes realmente :)

En primer lugar, no importa lo que digan los archivos zip no pueden técnicamente pueden poner pie de la letra al final de los archivos. El final del registro del directorio central tiene un valor que indica el desplazamiento del byte desde el inicio del disco actual (si tiene solo un archivo .zip, es decir, el archivo actual). Ahora, muchos procesadores ignoran esto, aunque la carpeta zip de Windows no lo hace, por lo que necesita corregir ese valor para que funcione en el explorador de Windows (no es que le importe; P) Consulte Zip APPNOTE para obtener información sobre el formato de archivo. Básicamente, usted encuentra en un editor hexadecimal (o escribe una herramienta) para encontrar el valor de "compensación del inicio del directorio central con respecto al número de disco inicial". A continuación, busque la primera "firma del encabezado del archivo central" (hex. De 504b0102) y establezca el valor en ese desfase.

Ahora, por desgracia, eso no soluciona 7zip, pero eso se debe a la forma en que 7zip intenta adivinar el formato del archivo. Básicamente solo buscará los primeros ~ 4MiB para la secuencia binaria 504b0304, si no lo encuentra, asume que no es Zip y prueba con sus otros formatos de archivo. Obviamente, esta es la razón por la que agregar un archivo más rompe las cosas, lo lleva más allá del límite de la búsqueda.

Ahora, para solucionarlo, lo que debes hacer es agregar esa cadena hexadecimal al jpeg sin romperla. Una forma de hacerlo es agregar justo después del encabezado FFD8 JPEG SOI los siguientes datos hexadecimales, FFEF0005504B030400. Eso agrega un bloque personalizado con su secuencia y es correcto para que los encabezados de jpeg simplemente lo ignoren.

+0

Esto consiguió yo el 60% del camino allí. También tuve que modificar las entradas 504b0102 para cambiar SUS compensaciones, de lo contrario, se abrió pero no le permitió extraer archivos. Creo que ** tengo un jpg/zip en funcionamiento en Windows Explorer y 7-Zip, pero necesito hacer más pruebas mañana. –

20

He descargado la fuente de 7-Zip y he averiguado qué está causando esto.

En CPP/7zip/UI/Común/OpenArchive.cpp, verá lo siguiente:

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

Eso significa que sólo los primeros 4194304 bytes del archivo serán buscados para la cabecera. Si no se encuentra allí, 7-Zip lo considera un archivo inválido.

Puede duplicar ese límite cambiando 1 << 22 a 1 << 23. Probé ese cambio reconstruyendo 7-Zip y funciona.

EDIT: Para solucionar este problema, puede download the source, realice los cambios anteriores y compilelo. Lo construí utilizando VS 2008. Abra el símbolo del sistema de VS, navegue hasta extraído-fuente-ubicación \ CPP \ 7zip \ Bundles y escriba 'nmake'. Luego, en el directorio Alone, ejecuta '7za t nonworking.jpg 'y debería ver' Todo está bien '.

+0

Increíble buen señor. Me pregunto si puedo poner un archivo falso de la forma correcta en ese primer lapso de bytes y truco 7-Zip ... Voy a jugar un poco (y también esperar un poco antes de aceptar, sin ofender) –

4

Así que para cualquier otra persona encontrar esta pregunta, aquí está la historia:

Sí, Andy es literalmente correcta en cuanto a porqué 7-Zip está fallando en el archivo, pero no ayuda a mi problema ya que puede' Es exactamente lo que hace que la gente use mi versión de 7-Zip.

tyranid sin embargo me dieron la solución.

  • En primer lugar, agregando una pequeña cadena de bytes al JPG, como sugiere, permitirá que 7-Zip lo abra. Sin embargo, está un poco fuera de un fragmento JPG válido, necesita ser FFEF00 504B030400 - la longitud estaba desactivada en 2 bytes.
  • Esto permite que 7-Zip lo abra pero no extraiga archivos, falla silenciosamente. Esto se debe a que las entradas en el directorio central tienen punteros/desplazamientos internos que apuntan a la entrada del archivo. ¡Ya que pusiste un montón de cosas antes de eso, necesitas corregir todos esos indicadores!
  • Para tener abierto el cierre con el soporte integrado de Windows, necesita, como dice tyranid, corregir el "desplazamiento del inicio del directorio central con respecto al número de disco inicial". Aquí es un script en Python que ver los dos últimos, aunque es un fragmento, no copypasta lista para usar

#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

Gracias por compartir su código (y revelar que el significado es 42;)). Y no hay necesidad de explicar, aprendí mucho y fue divertido de todos modos. –

+0

Lo siento si tengo algunas cosas. Gracias, sin embargo :) – tyranid

2

Puede producir archivos ZIP utilizando DotNetZip JPG + híbrida. DotNetZip puede guardar en una secuencia, y es lo suficientemente inteligente como para reconocer la compensación original de una secuencia preexistente antes de que comience a escribir contenido zip en ella. Por lo tanto, en pseudo código, se puede obtener un archivo JPG + ZIP de esta manera:

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 

Todas las compensaciones se calculan correctamente. La misma técnica se usa para producir un archivo autoextraíble. Puede abrir la secuencia en el EXE, luego buscar hasta el final y escribir el contenido ZIP en esa secuencia. Todos los desplazamientos se calculan correctamente si lo haces de esta manera.

Otra cosa: con respecto a uno de los comentarios en otra publicación ... ZIP puede tener datos arbitrarios al principio y al final del archivo. No hay ningún requisito por lo que sé que el directorio zip central debe estar al final del archivo, aunque eso es típico.

Cuestiones relacionadas