Skip to content

Instantly share code, notes, and snippets.

@p3ppi
Forked from stevenswafford/zipdump.py
Created May 9, 2022 07:55
Show Gist options
  • Save p3ppi/70dc009181e7b11d2db219d9e6814e0f to your computer and use it in GitHub Desktop.
Save p3ppi/70dc009181e7b11d2db219d9e6814e0f to your computer and use it in GitHub Desktop.

Revisions

  1. @stevenswafford stevenswafford created this gist Jun 3, 2015.
    216 changes: 216 additions & 0 deletions zipdump.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,216 @@
    #!/usr/bin/env python

    import optparse
    import zipfile
    import hashlib
    import signal
    import sys
    import os
    import cStringIO
    import textwrap

    STANDARD_MALWARE_SAMPLE_PASSWORD = 'infected'
    QUOTE = '"'

    def PrintManual():
    manual = '''
    Manual:
    zipdump allows you to inspect ZIP files.
    By default, the output is a csv file with the filename, encrypted flag, md5 and timestamp of each file inside the zip file.
    Example: zipdump.py test.zip
    Output:
    zipfilename;encrypted;MD5;Timestamp
    file1.txt;0;23ac1d8f3680efd3b31fb988e6438cc5;2014-08-10 14:11:32
    file2.txt;0;c749903dd4a3e98b26c7f58ec93fe808;2014-08-10 14:11:50
    zipdump also accepts stdin, then you have to use - as filename:
    cat test.zip | zipdump.py -
    The contents of the compressed files can be dumped (-d), hexdumped (-x) and ascii dumped (-a).
    If you do not provide a filename to dump, the first file is dumped.
    Example:
    zipdump.py -a files.zip
    00000000: 46 69 72 73 74 20 66 69 6C 65 21 0D 0A 0D 0A 53 First file!....S
    00000010: 6F 6D 65 20 64 61 74 61 2E ome data.
    Example with the filename to dump:
    zipdump.py -a files.zip file2.txt
    00000000: 53 65 63 6F 6E 64 65 20 66 69 6C 65 21 0D 0A 0D Seconde file!...
    00000010: 0A 53 6F 6D 65 20 6D 6F 72 65 20 64 61 74 61 2E .Some more data.
    You can select another separator than ; for the csv file with option -s.
    Option -o allows you to write the csv file to disk.
    '''
    for line in manual.split('\n'):
    print(textwrap.fill(line))

    def FixPipe():
    try:
    signal.signal(signal.SIGPIPE, signal.SIG_DFL)
    except:
    pass

    def ToString(value):
    if type(value) == type(''):
    return value
    else:
    return str(value)

    def Quote(value, separator, quote):
    value = ToString(value)
    if separator in value:
    return quote + value + quote
    else:
    return value

    def MakeCSVLine(row, separator, quote):
    return separator.join([Quote(value, separator, quote) for value in row])

    def Print(line, f):
    if f == None:
    print(line)
    else:
    f.write(line +'\n')

    dumplinelength = 16

    # CIC: Call If Callable
    def CIC(expression):
    if callable(expression):
    return expression()
    else:
    return expression

    # IFF: IF Function
    def IFF(expression, valueTrue, valueFalse):
    if expression:
    return CIC(valueTrue)
    else:
    return CIC(valueFalse)

    class cDumpStream():
    def __init__(self):
    self.text = ''

    def Addline(self, line):
    if line != '':
    self.text += line + '\n'

    def Content(self):
    return self.text

    def HexDump(data):
    oDumpStream = cDumpStream()
    hexDump = ''
    for i, b in enumerate(data):
    if i % dumplinelength == 0 and hexDump != '':
    oDumpStream.Addline(hexDump)
    hexDump = ''
    hexDump += IFF(hexDump == '', '', ' ') + '%02X' % ord(b)
    oDumpStream.Addline(hexDump)
    return oDumpStream.Content()

    def CombineHexAscii(hexDump, asciiDump):
    if hexDump == '':
    return ''
    return hexDump + ' ' + (' ' * (3 * (16 - len(asciiDump)))) + asciiDump

    def HexAsciiDump(data):
    oDumpStream = cDumpStream()
    hexDump = ''
    asciiDump = ''
    for i, b in enumerate(data):
    if i % dumplinelength == 0:
    if hexDump != '':
    oDumpStream.Addline(CombineHexAscii(hexDump, asciiDump))
    hexDump = '%08X:' % i
    asciiDump = ''
    hexDump+= ' %02X' % ord(b)
    asciiDump += IFF(ord(b) >= 32 and ord(b), b, '.')
    oDumpStream.Addline(CombineHexAscii(hexDump, asciiDump))
    return oDumpStream.Content()

    #Fix for http://bugs.python.org/issue11395
    def StdoutWriteChunked(data):
    while data != '':
    sys.stdout.write(data[0:10000])
    sys.stdout.flush()
    data = data[10000:]

    def ZIPDump(zipfilename, targetfilename, options):
    FixPipe()
    if zipfilename == '-':
    if sys.platform == 'win32':
    import msvcrt
    msvcrt.setmode(sys.stdin.fileno(), os.O_BINARY)
    oZipfile = zipfile.ZipFile(cStringIO.StringIO(sys.stdin.read()), 'r')
    else:
    oZipfile = zipfile.ZipFile(zipfilename, 'r')
    if options.output:
    fOut = open(options.output, 'w')
    else:
    fOut = None
    if options.dump or options.hexdump or options.asciidump:
    if options.dump:
    DumpFunction = lambda x:x
    if sys.platform == 'win32':
    import msvcrt
    msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
    elif options.hexdump:
    DumpFunction = HexDump
    else:
    DumpFunction = HexAsciiDump
    for oZipInfo in oZipfile.infolist():
    if targetfilename == None or targetfilename == oZipInfo.filename:
    file = oZipfile.open(oZipInfo, 'r', STANDARD_MALWARE_SAMPLE_PASSWORD)
    StdoutWriteChunked(DumpFunction(file.read()))
    file.close()
    if targetfilename == None:
    break
    else:
    Print(MakeCSVLine(['zipfilename', 'encrypted', 'MD5', 'Timestamp'], options.separator, QUOTE), fOut)
    for oZipInfo in oZipfile.infolist():
    if targetfilename == None or targetfilename == oZipInfo.filename:
    file = oZipfile.open(oZipInfo, 'r', STANDARD_MALWARE_SAMPLE_PASSWORD)
    filehash = hashlib.md5(file.read()).hexdigest()
    file.close()
    Print(MakeCSVLine([oZipInfo.filename, oZipInfo.flag_bits & 1, filehash, '%04d-%02d-%02d %02d:%02d:%02d' % oZipInfo.date_time], options.separator, QUOTE), fOut)
    if fOut:
    fOut.close()
    oZipfile.close()

    def Main():
    oParser = optparse.OptionParser(usage='usage: %prog [options] zipfile [filename]\n' + __description__, version='%prog ' + __version__)
    oParser.add_option('-s', '--separator', default=';', help='Separator character (default ;)')
    oParser.add_option('-o', '--output', help='Output to file')
    oParser.add_option('-d', '--dump', action='store_true', default=False, help='perform dump')
    oParser.add_option('-x', '--hexdump', action='store_true', default=False, help='perform hex dump')
    oParser.add_option('-a', '--asciidump', action='store_true', default=False, help='perform ascii dump')
    oParser.add_option('-m', '--man', action='store_true', default=False, help='print manual')
    (options, args) = oParser.parse_args()

    if options.man:
    oParser.print_help()
    PrintManual()
    return

    if len(args) < 1:
    oParser.print_help()
    print('')
    print(' Source code put in the public domain by Didier Stevens, no Copyright')
    print(' Use at your own risk')
    print(' https://DidierStevens.com')
    return
    elif len(args) == 1:
    ZIPDump(args[0], None, options)
    else:
    ZIPDump(args[0], args[1], options)

    if __name__ == '__main__':
    Main()