#!/usr/bin/env python import zipfile, struct class EvilZipStreamWrapper (object): def __init__ (self, victim): self.victim_fd = victim self.position = 0 self.tells = [] self.in_file_data = 0 def tell (self): self.tells.append (self.position) return self.position def seek (self, offset, whence = 0): if offset != 0: if offset == self.tells[0] + 14: # the zipfile module tries to fix up the file header. # write Data descriptor header instead, # the next write from zipfile # is CRC, compressed_size and file_size (as required) self.write ("PK\007\010") elif offset == self.tells[1]: # the zipfile module goes to the end of the file. The next # data written definitely is infrastructure (in_file_data = 0) self.tells = [] self.in_file_data = 0 else: raise "unexpected seek for EvilZipStreamWrapper" def write (self, data): # only test for headers if we know that we're not writing # (potentially compressed) data. if self.in_file_data == 0: if data[:4] == zipfile.stringFileHeader: # fix the file header for extra Data descriptor hdr = list (struct.unpack (zipfile.structFileHeader, data[:30])) hdr[3] |= (1 << 3) data = struct.pack (zipfile.structFileHeader, *hdr) + data[30:] self.in_file_data = 1 elif data[:4] == zipfile.stringCentralDir: # fix the directory entry to match file header. hdr = list (struct.unpack (zipfile.structCentralDir, data[:46])) hdr[5] |= (1 << 3) data = struct.pack (zipfile.structCentralDir, *hdr) + data[46:] self.position += len (data) self.victim_fd.write (data) def __getattr__ (self, name): return getattr (self.victim_fd, name) if __name__=='__main__': import sys, os, traceback outfile = sys.stdout if len (sys.argv) != 2: print >>sys.stderr, "create an ZIP-archive of to stdout" print >>sys.stderr, " usage: %s | cat > outfile.zip" % sys.argv[0] sys.exit (1) src_dir = os.path.abspath (sys.argv[1]) if not os.path.isdir (src_dir): print >>sys.stderr, "create an ZIP-archive of to stdout" print >>sys.stderr, " usage: %s | cat > outfile.zip" % sys.argv[0] sys.exit (1) print >>sys.stderr, """ ------------------------------------------------ Trying to use the zipfile module with sys.stdout ------------------------------------------------ """ try: zfile = zipfile.ZipFile (sys.stdout, 'w', zipfile.ZIP_DEFLATED) stripoff = os.path.dirname (src_dir) + os.sep for root, dirs, files in os.walk (src_dir): for file in files: filename = os.path.join (root, file) if filename[:len (stripoff)] != stripoff: raise RuntimeException, "invalid filename assumptions, please report!" zfile.write (filename, filename[len (stripoff):]) zfile.close () print >>sys.stderr, """ ------------------------------------------------------ Worked OK, apparently stdout was redirected to a file. ------------------------------------------------------ """ except Exception, e: traceback.print_exc () print >>sys.stderr, """ ------------------------------------------------ Failed. Now trying with the EvilZipStreamWrapper ------------------------------------------------ """ ezfile = EvilZipStreamWrapper (sys.stdout) zfile = zipfile.ZipFile (ezfile, 'w', zipfile.ZIP_DEFLATED) stripoff = os.path.dirname (src_dir) + os.sep for root, dirs, files in os.walk (src_dir): for file in files: filename = os.path.join (root, file) if filename[:len (stripoff)] != stripoff: raise RuntimeException, "invalid filename assumptions, please report!" zfile.write (filename, filename[len (stripoff):]) zfile.close () print >>sys.stderr, """ ---------- Worked OK. ---------- """