문제

바라건대 당신은 깔끔한 해킹 이를 통해 jpg와 zip 파일을 단일 파일로 결합 할 수 있으며 두 형식 모두에 대해 유효한 (또는 적어도 읽을 수있는) 파일입니다. 글쎄, 나는 JPG가 마지막에 임의의 물건을 허용하고 처음에는 지퍼를 만들기 때문에 중간에 하나 더 형식을 더 붙일 수 있음을 깨달았습니다. 이 질문의 목적 상, 중간 데이터가 JPG 또는 Zip 형식과 충돌하지 않도록 임의의 이진 데이터라고 가정합니다 (즉, Magic Zip 헤더 0x04034B50을 포함하지 않음). 삽화:

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

나는 이렇게 함유하고있다 :

고양이 "mss_1600.jpg"filea fileb filea fileb filea fileb filea fileb filea fileb filea fileb filea fileb filea fileb fileb filea filea fileb filea fileb "null.bytes" "randomzipfile.zip"> temp.zip

이것은 6,318kb 파일을 생성합니다. 그것 하지 않습니다 7- ZIP에서 열립니다. 그러나 내가 고양이가 하나도 '더블'을 적게 할 때 (13 Filea와 B 대신, 12) :

고양이 "mss_1600.jpg"filea fileb filea fileb filea fileb filea fileb filea fileb filea fileb filea fileb filea fileb filea fileb fileb filea fileb "null.bytes" "randomzipfile"> temp.zip

5,996kb 파일을 생성합니다 하다 7- ZIP에서 열립니다.

그래서 임의의 이진 데이터에는 Magic Zip 파일 헤더가 없다는 것을 알고 있습니다. 나는 참조 파일이있다 작업 JPG+Data+Zip 그리고 비 작업 JPG+Data+Zip (저장-브라우저는 이미지가 이미지를 생각하고 지퍼 확장을 직접 추가합니다).

나는 그것이 13 개의 조합으로 실패하고 12 명으로 실패하는 이유를 알고 싶습니다. 보너스 포인트의 경우 어떻게 든이 문제를 해결해야합니다.

도움이 되었습니까?

해결책

사실 그것은 정말로 두 부분 대답입니다. :)

첫째, 사람들이 Zip 파일을 말하는 것은 할 수 없습니다 기술적으로 파일 끝에 구두를 넣어야합니다. 중앙 디렉토리 레코드의 끝에는 현재 디스크의 시작부터 바이트 오프셋을 나타내는 값이 있습니다 (.zip 파일이 하나만있는 경우 현재 파일을 의미합니다). Windows의 Zip 폴더는 Windows Explorer에서 작동하도록 해당 값을 수정해야하지만 이제는 많은 프로세서를 무시합니다. zip appnote 파일 형식에 대한 정보 기본적으로 HEX 편집기 (또는 도구를 작성)에서 "시작 디스크 번호와 관련하여 중앙 디렉토리의 시작 오프셋"값을 찾을 수 있습니다. 그런 다음 첫 번째 "중앙 파일 헤더 서명"(504B0102의 16 진수)을 찾아 해당 오프셋으로 값을 설정하십시오.

이제 7zip을 수정하지는 않지만 7zip이 파일 형식을 추측하려고하는 방식 때문입니다. 기본적으로 바이너리 시퀀스 504B0304에 대한 첫 번째 ~ 4MIB 만 검색합니다. 찾지 못하면 ZIP가 아니라고 가정하고 다른 아카이브 형식을 시도합니다. 그렇기 때문에 파일 하나를 추가하면 파일을 더 해소하여 검색 한계를 넘어옵니다.

이제해야 할 일을 고치는 것은 16 진 문자열을 jpeg에 끊지 않고 추가하는 것입니다. 이 작업을 수행하는 한 가지 방법은 FFD8 JPEG SOI 헤더 직후 다음 HEX 데이터 인 FFEF0005504B030400을 추가하는 것입니다. 시퀀스와 함께 사용자 정의 블록을 추가하고 올바른 블록이므로 JPEG 헤더는이를 무시해야합니다.

다른 팁

나는 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을 재건함으로써 그 변화를 테스트했으며 그것이 작동합니다.

편집하다:이 문제를 해결하려면 가능합니다 소스를 다운로드하십시오, 위의 변화를 만들고 구축하십시오. VS 2008을 사용하여 구축했습니다. VS 명령 프롬프트를 열고 추출 된 소스-위치cpp 7zip 번들 및 'nmake'를 입력합니다. 그런 다음 혼자 디렉토리에서 '7za t nonworking.jpg'에서 실행되면 '모든 것이 괜찮다'는 것을 볼 수 있습니다.

그래서 다른 사람 이이 질문을 찾는 사람은 다음과 같습니다.

예, Andy는 7-zip이 파일에 실패한 이유에 대해 문자 그대로 정확하지만 사람들이 내 버전의 7-zip을 정확히 사용하도록 할 수 없기 때문에 내 문제에 도움이되지 않습니다.

그러나 티라니드는 저에게 해결책을 얻었습니다.

  • 먼저, JPG에 작은 바이트를 추가하면 7-zip을 열게합니다. 그러나 유효한 JPG 조각에서 약간 벗어 났으므로 ffef00이어야합니다. 07 504B030400- 길이는 2 바이트 씩 꺼졌습니다.
  • 이렇게하면 7-zip을 열 수 있지만 파일을 추출하지는 않지만 조용히 실패합니다. 중앙 디렉토리의 항목에는 파일의 입력을 가리키는 내부 포인터/오프셋이 있기 때문입니다. 그 전에 많은 물건을 넣으므로 모든 포인터를 수정해야합니다!
  • 지퍼 지지대가 내장 된 Windows를 개방하려면 Tyranid가 말했듯이 "시작 디스크 번호와 관련하여 중앙 디렉토리의 시작 오프셋"을 수정해야합니다. 다음은 마지막 두 가지를 수행하는 파이썬 스크립트입니다.

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

하이브리드 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 Central 디렉토리가 파일의 끝에 있어야한다는 것을 아는 한 요구 사항은 없습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top