adm-zip icon indicating copy to clipboard operation
adm-zip copied to clipboard

Extracting from Buffer with trailing zeros cause 'Invalid or unsupported zip format. No END header found' error

Open verebes opened this issue 7 years ago • 2 comments

Problem

I try to call getEntries() on an AdmZip object initialized with a Buffer object. The buffer is larger than the actual zip content so there are trailing zeros after the ENDSIG (PK\005\006). When I try to extract the file I get "Invalid or unsupported zip format. No END header found" error.

How to reproduce:

  • Initialize a large buffer with zeros
  • Copy the zip content into the buffer ( leave at least 65535 zeros in the buffer after the zip content )
  • Create an AdmZip object with the buffer
  • Try to call the getEntries() method on the AdmZip ---> you should get "Invalid or unsupported zip format. No END header found" error

Reason:

In the zipFile.js, readMainHeader() checks the existence of the END header (PK\005\006). But it is assumed that the END header is in the last 0xFFFF bytes, because this is the maximum zip file comment length. But this is not true if there are trailing zero bytes.

How to fix:

skip the trailing zero bytes before searching the END header. Take care, there can be trailing zeros in the END header too, so we can not start the search from the end - 22 bytes (where 22 bytes is the size of the end header)


	function readMainHeader() {
		var i = inBuffer.length -1,			
			endOffset = -1; // Start offset of the END header
		while ( inBuffer[i] === 0x00 ) {
			i--;
		} 
		// i is the index of the last non-zero value

		var n = Math.max(0, i - ( 0xFFFF + Utils.Constants.ENDHDR)); // 0xFFFF is the max zip file comment length
		i = Math.max(0, i - 3); //  "PK\005\006"
		for (i; i >= n; i--) {
			if (inBuffer[i] !== 0x50) continue; // quick check that the byte is 'P'
			if (inBuffer.readUInt32LE(i) === Utils.Constants.ENDSIG) { // "PK\005\006"
				endOffset = i;
				break;
			}
		}
		if (!~endOffset)
			throw Utils.Errors.INVALID_FORMAT;

		mainHeader.loadFromBinary(inBuffer.slice(endOffset, endOffset + Utils.Constants.ENDHDR));
		if (mainHeader.commentLength) {
			_comment = inBuffer.slice(endOffset + Utils.Constants.ENDHDR);
		}
		readEntries();
	}

verebes avatar Nov 13 '18 21:11 verebes

It is not wrong approach what adm-zip does, but many programs search header from entire file. So you can include something like recovery records, signatures etc to the end of you file.

5saviahv avatar May 28 '19 12:05 5saviahv

I have the same problem, how can I solve this problem

Month7 avatar May 11 '21 08:05 Month7