2009-11-30 20 views
11

Hy vọng bạn đã nghe về neat hack cho phép bạn kết hợp tệp JPG và tệp Zip thành một tệp và đó là tệp hợp lệ (hoặc ít đọc được) cho cả hai định dạng. Vâng, tôi nhận ra rằng kể từ khi JPG cho phép các công cụ tùy ý ở phần cuối, và ZIP ngay từ đầu, bạn có thể thêm một định dạng nữa vào đó - ở giữa. Vì mục đích của câu hỏi này, giả sử dữ liệu ở giữa là dữ liệu nhị phân tùy ý không xung đột với định dạng JPG hoặc ZIP (có nghĩa là nó không chứa tiêu đề zip ma thuật 0x04034b50). Minh họa:JPG + Zip Sự cố kết hợp tệp với định dạng zip

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

Tôi catting như thế này:

mèo "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

Điều này tạo ra một tệp 6.318 KB. Nó không mở trong 7-Zip. Tuy nhiên, khi tôi mèo một ít 'đúp' (nên thay vì 13 filea và b của, 12):

mèo "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

Nó tạo ra một tập tin 5996 KB rằng không mở trong 7-Zip.

Vì vậy, tôi biết dữ liệu nhị phân tùy ý của mình không có Đầu đề tệp Zip ma thuật để vít nó lên. Tôi có các tệp tham chiếu của working jpg+data+zipnon-working jpg+data+zip (lưu làm nguyên nhân khiến trình duyệt nghĩ rằng chúng là hình ảnh và tự thêm chính tiện ích mở rộng zip).

Tôi muốn biết tại sao nó không thành công với 13 kết hợp và không phải với 12. Đối với điểm thưởng, tôi cần phải nhận được xung quanh bằng cách nào đó.

+1

Chỉ muốn chỉ ra rằng đây có thể là vấn đề với thuật toán của 7Zip, vì File Roller cũng đã quản lý để mở ví dụ không hoạt động. – laginimaineb

+1

Neat trick - Từ bây giờ tôi sẽ sử dụng kỹ thuật này để chèn một hình ảnh của bản thân mình trong tất cả java của tôi .jar (thực thi jar-pegs) – Seth

Trả lời

10

Trên thực tế nó là một câu trả lời hai phần thực sự :)

Trước hết không có vấn đề gì mọi người nói các file zip có thể không kỹ thuật được đặt đúng nguyên văn ở phần cuối của tập tin. Phần cuối của bản ghi thư mục trung tâm có một giá trị chỉ ra độ lệch byte từ đầu của đĩa hiện tại (nếu bạn chỉ có một tệp .zip, có nghĩa là tệp hiện tại). Bây giờ rất nhiều bộ vi xử lý bỏ qua điều này, mặc dù thư mục zip của Windows không nên bạn cần sửa giá trị đó để làm cho nó hoạt động trong Windows explorer (không phải bạn có thể quan tâm; P) Xem Zip APPNOTE để biết thông tin về định dạng tệp. Về cơ bản bạn tìm thấy trong một trình soạn thảo hex (hoặc viết một công cụ) để tìm giá trị "bù đắp của bắt đầu của thư mục trung tâm đối với số lượng đĩa bắt đầu". Sau đó tìm "chữ ký đầu trang tập tin trung tâm" đầu tiên (hex của 504b0102) và đặt giá trị cho offset đó.

Hiện tại, các định dạng không sửa lỗi 7zip nhưng đó là do cách 7zip cố đoán định dạng tệp. Về cơ bản nó sẽ chỉ tìm kiếm ~ 4MiB đầu tiên cho chuỗi nhị phân 504b0304, nếu nó không tìm thấy nó, nó giả định nó không phải là Zip và cố định các định dạng lưu trữ khác của nó. Điều này rõ ràng là lý do tại sao thêm một tệp nữa phá vỡ mọi thứ, nó đẩy nó vượt quá giới hạn cho tìm kiếm.

Bây giờ để khắc phục những gì bạn cần làm là thêm chuỗi hex đó vào jpeg mà không phá vỡ nó. Một cách để làm điều này là thêm ngay sau tiêu đề JPEG SOI FFD8 dữ liệu hex sau đây, FFEF0005504B030400. Điều đó cho biết thêm một khối tùy chỉnh với trình tự của bạn và là chính xác để tiêu đề jpeg chỉ nên bỏ qua nó.

+0

Điều này có tôi 60% con đường ở đó. Tôi cũng đã phải sửa đổi các mục 504b0102 để thay đổi OFIR bù đắp nếu không nó mở ra nhưng không cho phép bạn trích xuất các tập tin. Tôi nghĩ rằng ** Tôi có một jpg/zip làm việc trong Windows Explorer và 7-Zip, nhưng tôi cần phải làm thử nghiệm nhiều hơn vào ngày mai. –

20

Tôi đã tải xuống nguồn cho 7-Zip và đã tìm ra nguyên nhân gây ra điều này.

Trong CPP/7zip/UI/Common/OpenArchive.cpp, bạn sẽ thấy như sau:

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

Điều đó có nghĩa rằng chỉ có 4.194.304 byte đầu tiên của tập tin sẽ được tìm kiếm tiêu đề. Nếu nó không được tìm thấy ở đó, 7-Zip coi nó là một tập tin không hợp lệ.

Bạn có thể tăng gấp đôi giới hạn đó bằng cách thay đổi 1 << 22 thành 1 << 23. Tôi đã thử nghiệm thay đổi đó bằng cách xây dựng lại 7-Zip và nó hoạt động.

EDIT: Để khắc phục sự cố này, bạn có thể download the source, thực hiện thay đổi ở trên và xây dựng nó. Tôi đã xây dựng nó bằng cách sử dụng VS 2008. Mở dấu nhắc lệnh VS, điều hướng đến trích xuất nguồn-vị trí \ CPP \ 7zip \ Gói và nhập 'nmake'. Sau đó, trong thư mục Alone chạy '7za t nonworking.jpg 'và bạn sẽ thấy' Mọi thứ đều OK '.

+0

Incredible tốt sir. Tôi tự hỏi nếu tôi có thể đặt một tập tin giả của các hình thức chính xác trong khoảng đầu tiên của byte và lừa 7-Zip ... Tôi sẽ chơi một chút (và cũng chờ một chút trước khi chấp nhận, không có hành vi phạm tội) –

4

Vì vậy, cho bất cứ ai khác tìm câu hỏi này, đây là câu chuyện:

Vâng, Andy là nghĩa đen đúng là tại sao 7-Zip là không vào file, nhưng nó không giúp vấn đề của tôi kể từ khi tôi có thể' t chính xác khiến mọi người sử dụng phiên bản 7-Zip của MY.

Tuy nhiên, tyranid đã cho tôi giải pháp.

  • Trước tiên, thêm một phần nhỏ vào JPG như anh đề xuất sẽ cho phép 7-Zip mở nó. Tuy nhiên, nó hơi lệch so với một đoạn JPG hợp lệ, nó cần phải là FFEF00 504B030400 - độ dài bị giảm 2 byte.
  • Điều này cho phép 7-Zip mở nó, nhưng không giải nén tập tin, nó không âm thầm. Điều này là do các mục trong thư mục trung tâm có con trỏ nội bộ/offsets trỏ đến mục nhập của tập tin. Kể từ khi bạn đặt một loạt các công cụ trước đó, bạn cần phải sửa tất cả những con trỏ!
  • Để mở khóa bằng Windows được hỗ trợ zip, bạn cần, như tyranid nói, sửa "độ lệch bắt đầu của thư mục trung tâm đối với số đĩa khởi động". Dưới đây là một kịch bản python để làm hai cuối cùng, mặc dù đó là một mảnh, không copypasta-ready-to-sử dụng

#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

Cảm ơn bạn đã chia sẻ mã của mình (và tiết lộ rằng ý nghĩa là 42;)). Và không cần phải giải thích - tôi đã học được rất nhiều và nó vẫn vui. –

+0

Xin lỗi nếu tôi có một vài thứ. Cảm ơn mặc dù :) – tyranid

2

Bạn có thể sản xuất hybrid JPG + file ZIP sử dụng DotNetZip. DotNetZip có thể lưu vào một luồng, và nó đủ thông minh để nhận ra độ lệch ban đầu của luồng đã tồn tại trước khi nó bắt đầu viết nội dung zip vào nó. Do đó, trong mã giả, bạn có thể nhận được JPG + ZIP theo cách này:

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 

Tất cả các offset được tìm đúng. Kỹ thuật tương tự được sử dụng để tạo ra một kho lưu trữ tự giải nén. Bạn có thể mở luồng trên EXE, sau đó tìm cách kết thúc và ghi nội dung ZIP vào luồng đó. Tất cả các offsets được tính toán một cách chính xác nếu bạn làm điều đó theo cách này.

Một điều khác - liên quan đến một trong các nhận xét trong bài đăng khác ... ZIP có thể có dữ liệu tùy ý ở đầu ở cuối tệp. Không có yêu cầu như xa như tôi biết rằng thư mục trung tâm zip cần phải được ở phần cuối của tập tin, mặc dù đó là điển hình.

Các vấn đề liên quan