Created
March 28, 2013 21:18
-
-
Save gwarser/5266894 to your computer and use it in GitHub Desktop.
ZIP bruteforce extractor
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import sys, os | |
import struct | |
import zlib | |
def zipr(file): | |
try: | |
f = open(file, 'rb') | |
except IOError as e: | |
print("IOError: {0}!".format(e)) | |
return 1 | |
numoffiles = 0 | |
while True: | |
data = f.read(4) | |
if 4 != len(data): | |
print('Truncated file! File size: {0} bytes!'.format(f.tell())) | |
f.close() | |
return 2 | |
lfile_hdr = struct.unpack('<L', data)[0] | |
if lfile_hdr != 0x04034b50 and numoffiles == 0: | |
print('Not zip file? Local file header found: {0:#010x}, ' | |
'must be: 0x04034b50!'.format(lfile_hdr)) | |
f.close() | |
return 3 | |
elif lfile_hdr == 0x02014b50 and numoffiles > 0: | |
print('\nEnd of archive? Directory header (0x02014b50) found ' | |
'at {size}B.\nTotal files: {nfiles}.' | |
''.format(nfiles=numoffiles, size=f.tell()-4)) | |
f.close() | |
return 0 | |
data = f.read(14) | |
if 14 != len(data): | |
print('Archive corupted? First part of header nr. {0} truncated. ' | |
'Filesize: {1}.'.format(numoffiles+1, f.tell())) | |
f.close() | |
return 5 | |
fields = struct.unpack('<2B4HL', data) | |
v_spec, v_sys, gen_bitf, comp_meth, modt, modd, crc32 = fields | |
data = f.read(12) | |
if 12 != len(data): | |
print('Archive corupted? Second part of header nr. {0} truncated. ' | |
'Filesize: {1}.'.format(numoffiles+1, f.tell())) | |
f.close() | |
return 6 | |
fields = struct.unpack('<2L2H', data) | |
comp_size, uncomp_size, filenamesize, extra_size = fields | |
filename = f.read(filenamesize) | |
if filenamesize != len(filename): | |
print('Filename "{0}" stripped! Expected: {1}B, get {2}B!' | |
''.format(filename, filenamesize, len(data))) | |
return 7 | |
#utf = 1<<11 | |
if gen_bitf & 0x800: #utf | |
filename = filename.decode('utf-8') + ' (UTF-8)' | |
else: | |
#must be local (for machine that compress) OEM code page, not only cp437 | |
#import ctypes | |
#str(ctypes.windll.kernel32.GetOEMCP()) | |
filename = filename.decode('ascii', 'ignore')#cut bytes > 127 | |
numoffiles += 1 | |
outputstr = 'FNR: {FNR:2d}, '\ | |
'FNS: {FNS:3d}, '\ | |
'FNM: "{FNM}",\n'\ | |
'HDR: {HDR:08x}, '\ | |
'VSY: {VSY:2d}, '\ | |
'VSP: {VSP:2d}, '\ | |
'BFD: {BFD:016b}, '\ | |
'CPM: {CPM:016b},\n'\ | |
'MDT: {MDT:04x}, '\ | |
'MDD: {MDD:04x}, '\ | |
'CRC: {CRC:08x}, '\ | |
'CPS: {CPS:7d}B, '\ | |
'DCS: {DCS:7d}B, '\ | |
'ESE: {ESE:d}B'.format( | |
HDR=lfile_hdr, | |
VSY=v_sys, | |
VSP=v_spec, | |
BFD=gen_bitf, | |
CPM=comp_meth, | |
MDT=modt, | |
MDD=modd, | |
CRC=crc32, | |
CPS=comp_size, | |
DCS=uncomp_size, | |
FNS=filenamesize, | |
FNM=filename, | |
ESE=extra_size, | |
FNR=numoffiles) | |
print(outputstr) | |
f.seek(extra_size, 1) | |
if comp_size > 0: | |
curfilec = f.read(comp_size) | |
if len(curfilec) > 0: | |
try: | |
curfile = zlib.decompress(curfilec, -15) | |
except Exception as e: | |
print('ZLIB ERROR!', e) | |
input() | |
curcrc32 = zlib.crc32(curfile) | |
if curcrc32 == crc32: | |
print('CRC:', hex(curcrc32), 'OK!') | |
else: | |
print('CRC:', hex(curcrc32), 'MISMATCH!') | |
input() | |
try: | |
os.makedirs(os.path.dirname(filename)) | |
except WindowsError: | |
pass | |
try: | |
f2 = open(filename, 'wb') | |
f2.write(curfile) | |
f2.close() | |
except: | |
pass | |
def main(): | |
for fzip in sys.argv[1:]: | |
if os.path.exists(fzip): | |
os.chdir(os.path.dirname(os.path.abspath(fzip))) | |
if zipr(fzip) > 0: | |
input() | |
if __name__ == '__main__': | |
try: | |
main() | |
except KeyboardInterrupt: | |
pass | |
except: | |
import traceback | |
print("Unhandled exception:\n") | |
traceback.print_exc() | |
input('\nPress any key...') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment