45 lines
1.6 KiB
Python
45 lines
1.6 KiB
Python
|
import io
|
||
|
from .matcher import SignatureMatcher, Match
|
||
|
|
||
|
class Zip(SignatureMatcher):
|
||
|
"""
|
||
|
Zip files are read from the bottom
|
||
|
The signature PK is the local file header
|
||
|
|
||
|
https://medium.com/@felixstridsberg/the-zip-file-format-6c8a160d1c34
|
||
|
"""
|
||
|
def __init__(self, file):
|
||
|
self.name = "Zip"
|
||
|
self.signature = b'PK\x03\x04'
|
||
|
super().__init__(file)
|
||
|
|
||
|
def is_valid(self):
|
||
|
for match in self.search():
|
||
|
start = match
|
||
|
header = io.BytesIO(self.file[start:start+4*4 + 2*7])
|
||
|
magic = header.read(4)
|
||
|
min_version = header.read(2)
|
||
|
bitflag = header.read(2)
|
||
|
compression_method = header.read(2)
|
||
|
last_modification_time = header.read(2)
|
||
|
last_modification_data = header.read(2)
|
||
|
crc = header.read(4)
|
||
|
compressed_size = header.read(4)
|
||
|
uncompressed_size = header.read(4)
|
||
|
file_name_length = header.read(2)
|
||
|
extra_field_length = header.read(2)
|
||
|
|
||
|
file_name_length = int.from_bytes(file_name_length, 'little')
|
||
|
extra_field_length = int.from_bytes(extra_field_length, 'little')
|
||
|
compressed_size = int.from_bytes(compressed_size, 'little')
|
||
|
|
||
|
header_size = 4*4 + 2*7
|
||
|
data = {
|
||
|
'name': self.file[start+header_size:start+header_size+file_name_length]
|
||
|
}
|
||
|
|
||
|
size = 4*4 + 2*7 + file_name_length + extra_field_length + compressed_size
|
||
|
self.matches += [Match(start, size, data)]
|
||
|
|
||
|
return len(self.matches) != 0
|