2009-11-30 3 views
11

Надеюсь, вы слышали о neat hack, который позволяет объединять JPG и Zip-файл в один файл и является допустимым (или по крайней мере читаемым) файлом для обоих форматов. Ну, я понял, что, поскольку JPG позволяет произвольным материалам в конце, а ZIP в начале, вы можете вставить еще один формат там - посередине. Для целей этого вопроса предположим, что средние данные - это произвольные двоичные данные, которые не конфликтуют с форматами JPG или ZIP (это означает, что он не содержит волшебный zip-заголовок 0x04034b50). Иллюстрация:Проблема с комбинацией JPG + Zip-файлов с Zip-форматом

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

Я catting так:

кошки "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

Это создает файл размером 6,318 КБ. Это не открыть в 7-Zip. Однако, когда я кошка один меньше 'двойной' (так что вместо 13 FiLea и Б, 12):

кошка "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

Он производит 5996 KB файл, который делает открыт в 7-Zip.

Таким образом, я знаю, что у моих произвольных двоичных данных нет волшебного заголовка Zip-файла, чтобы ввернуть его. У меня есть ссылочные файлы working jpg+data+zip и non-working jpg+data+zip (за исключением того, что браузер думает, что это изображения, и добавьте расширения zip самостоятельно).

Я хочу знать, почему он терпит неудачу с 13 комбинациями и не с 12. Для бонусных очков мне нужно как-то обойти это.

+1

Просто хотел указать, что это, вероятно, проблема с алгоритмом 7Zip, так как File Roller удалось открыть нерабочий пример. – laginimaineb

+1

Аккуратный трюк - отныне я собираюсь использовать эту технику, чтобы вставить изображение себя во все мои java .jar (исполняемые jar-pegs :) – Seth

ответ

10

На самом деле это две части ответа на самом деле :)

Во-первых независимо от того, что люди говорят, что файлы почтового индекса не может технически ставить дословно в конце файлов. Конец записи центрального каталога имеет значение, которое указывает смещение байта от начала текущего диска (если у вас есть только один .zip-файл, то есть текущий файл). В настоящее время многие процессоры игнорируют это, хотя в папке zip для Windows это не так, вам нужно исправить это значение, чтобы заставить его работать в проводнике Windows (не то, что вам может быть интересно; P) См. Zip APPNOTE для информации о формате файла. В основном вы найдете в шестнадцатеричном редакторе (или напишите инструмент), чтобы найти значение «смещение начала центрального каталога по отношению к стартовому номеру диска». Затем найдите первую «центральную подпись заголовка файла» (hex из 504b0102) и установите значение для этого смещения.

Теперь увы, что не исправляет 7zip, но это связано с тем, как 7zip пытается угадать формат файла. В основном он будет искать только первый ~ 4MiB для двоичной последовательности 504b0304, если он не найдет его, он предполагает, что он не является Zip и пытается использовать другие его форматы. Это, очевидно, почему добавление еще одного файла приводит к разрыву вещей, оно подталкивает его к пределу для поиска.

Теперь, чтобы исправить это, вам нужно добавить эту шестую строку в jpeg, не нарушая ее. Один из способов сделать это - добавить сразу после заголовка SOI FFD8 JPEG следующие шестнадцатеричные данные, FFEF0005504B030400. Это добавляет пользовательский блок с вашей последовательностью и правильно, поэтому заголовки jpeg должны просто игнорировать его.

+0

мне 60% пути. Мне также пришлось изменить записи 504b0102, чтобы изменить их смещения, иначе он будет открыт, но не позволит вам извлекать файлы. Я ** думаю ** У меня есть рабочий jpg/zip в Windows Explorer и 7-Zip, но завтра мне нужно сделать больше тестов. –

20

Я загрузил источник для 7-Zip и понял, что вызывает это.

В CPP/7zip/UI/Common/OpenArchive.cpp, вы увидите следующее:

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

Это означает, что только первые 4194304 байт файла будет произведен поиск заголовка. Если он не найден там, 7-Zip считает это недопустимым файлом.

Вы можете удвоить этот предел, изменив 1 << 22 на 1 << 23. Я проверил это изменение, восстановив 7-Zip, и он работает.

EDIT: Чтобы обойти эту проблему, вы можете download the source, внесите вышеуказанное изменение и создайте его. Я построил его с помощью VS 2008. Откройте командную строку VS, перейдите к извлеченному источнику-месту \ CPP \ 7zip \ Связки и введите «nmake». Затем в папке «Один» запустите «7za t nonworking».jpg ', и вы должны увидеть «Все хорошо».

+0

Невероятный хороший сэр. Интересно, могу ли я поместить поддельный файл с правильной формой в первый интервал байтов и трюк 7-Zip ... Я собираюсь немного поиграть (а также немного подождать, прежде чем принимать, без обид) –

4

Так что для кого-то найти этот вопрос, вот история:

Да, Энди буквально правильно, почему 7-Zip не удается на файле, но это не помогает моя проблема, так как я могу» t точно заставить людей использовать МОЮ версию 7-Zip.

tyranid однако получил меня решение.

  • Во-первых, добавление небольшого байта к JPG, как он предлагает, позволит 7-Zip открыть его. Тем не менее, он слегка отключен от действительного фрагмента JPG, он должен быть FFEF00 504B030400 - длина отключена на 2 байта.
  • Это позволяет 7-Zip открыть его, но не извлекать файлы, он терпит неудачу. Это связано с тем, что записи в центральном каталоге имеют внутренние указатели/смещения, указывающие на запись файла. Поскольку перед этим вы добавляете кучу вещей, вам нужно исправить все эти указатели!
  • Чтобы открыть почтовый ящик с помощью Windows, основанной на поддержке zip, вам необходимо, по словам тиранида, исправить «смещение начала центрального каталога относительно номера исходного диска». Вот питон скрипт, чтобы сделать два последние, хотя это фрагмент, не copypasta готовым к использованию

#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

Спасибо, что поделились своим кодом (и указав, что значение 42;)). И не нужно объяснять - я многому научился, и все равно было весело. –

+0

Извините, если у меня есть несколько вещей. Спасибо хоть :) – tyranid

2

Вы можете производить гибридные JPG + файлы ZIP с помощью DotNetZip. DotNetZip может сохранять в потоке, и он достаточно интеллектуальный, чтобы распознать исходное смещение уже существующего потока, прежде чем он начнет писать в него почтовый контент. Поэтому в псевдокоде, вы можете получить JPG + ZIP так:

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 

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

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