Module refinery.units.formats.archive.xtiss
Expand source code Browse git
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from typing import Optional
from itertools import cycle, islice
import zlib
from refinery.units.formats.archive import ArchiveUnit
from refinery.lib.structures import StructReader
class ISSReader(StructReader[bytearray]):
MAGIC = {
b'InstallShield\0': 1,
b'ISSetupStream\0': 2,
}
def iss_archive_header(self):
signature = bytes(self.read(14))
try:
self.__version = self.MAGIC[signature]
except KeyError:
raise ValueError('invalid signature for ISS archive')
file_count = self.u16()
self.seekrel(0x04)
self.seekrel(0x08)
self.seekrel(0x02)
self.seekrel(0x10)
return file_count
def iss_file_header(self):
if self.__version == 1:
name = self.read(260).rstrip(B'\0').decode('utf8')
flags = self.u32()
self.seekrel(4)
size = self.u32()
self.seekrel(8)
is_unicode = self.u16()
self.seekrel(30)
else:
name_length = self.u32()
flags = self.u32()
self.seekrel(2)
size = self.u32()
self.seekrel(8)
is_unicode = self.u16()
name = self.read(name_length).decode('utf-16le')
return name, size, flags, is_unicode
def iss_file(self):
name, size, flags, is_unicode = self.iss_file_header()
def _data(
data: bytearray = self.read(size),
seed: bytes = name.encode('utf8'),
_is4: bool = flags & 4 == 4,
_isu: bool = is_unicode
):
key = bytes(x ^ k for x, k in zip(seed, cycle(B'\x13\x35\x86\x07')))
if _is4:
key = bytes(islice(cycle(key), 0, 1024))
for (i, b), k in zip(enumerate(data), cycle(key)):
data[i] = ~(k ^ (b << 4 | b >> 4)) & 0xFF
if _isu:
data = zlib.decompress(data)
return data
return name, _data
class xtiss(ArchiveUnit):
"""
Extracts files from Install Shield Setup files.
"""
def unpack(self, data: bytearray):
offset = max(data.rfind(magic) for magic in ISSReader.MAGIC)
if offset < 0:
raise ValueError('ISS magic not found.')
data[:offset] = []
reader = ISSReader(data)
count = reader.iss_archive_header()
self.log_info(F'archive contains {count} files according to header')
for _ in range(count):
name, data = reader.iss_file()
yield self._pack(name, None, data)
@classmethod
def handles(cls, data: bytearray) -> Optional[bool]:
return data.startswith(B'MZ') and any(data.find(m) > 0 for m in ISSReader.MAGIC)
Classes
class ISSReader (data, bigendian=False)
-
An extension of a
MemoryFile
which provides methods to read structured data.Expand source code Browse git
class ISSReader(StructReader[bytearray]): MAGIC = { b'InstallShield\0': 1, b'ISSetupStream\0': 2, } def iss_archive_header(self): signature = bytes(self.read(14)) try: self.__version = self.MAGIC[signature] except KeyError: raise ValueError('invalid signature for ISS archive') file_count = self.u16() self.seekrel(0x04) self.seekrel(0x08) self.seekrel(0x02) self.seekrel(0x10) return file_count def iss_file_header(self): if self.__version == 1: name = self.read(260).rstrip(B'\0').decode('utf8') flags = self.u32() self.seekrel(4) size = self.u32() self.seekrel(8) is_unicode = self.u16() self.seekrel(30) else: name_length = self.u32() flags = self.u32() self.seekrel(2) size = self.u32() self.seekrel(8) is_unicode = self.u16() name = self.read(name_length).decode('utf-16le') return name, size, flags, is_unicode def iss_file(self): name, size, flags, is_unicode = self.iss_file_header() def _data( data: bytearray = self.read(size), seed: bytes = name.encode('utf8'), _is4: bool = flags & 4 == 4, _isu: bool = is_unicode ): key = bytes(x ^ k for x, k in zip(seed, cycle(B'\x13\x35\x86\x07'))) if _is4: key = bytes(islice(cycle(key), 0, 1024)) for (i, b), k in zip(enumerate(data), cycle(key)): data[i] = ~(k ^ (b << 4 | b >> 4)) & 0xFF if _isu: data = zlib.decompress(data) return data return name, _data
Ancestors
- StructReader
- MemoryFile
- MemoryFileMethods
- typing.Generic
- _io.BytesIO
- _io._BufferedIOBase
- _io._IOBase
Class variables
var read_as_bytes
var MAGIC
Instance variables
var closed
-
Expand source code Browse git
@property def closed(self) -> bool: return self._closed
Methods
def iss_archive_header(self)
-
Expand source code Browse git
def iss_archive_header(self): signature = bytes(self.read(14)) try: self.__version = self.MAGIC[signature] except KeyError: raise ValueError('invalid signature for ISS archive') file_count = self.u16() self.seekrel(0x04) self.seekrel(0x08) self.seekrel(0x02) self.seekrel(0x10) return file_count
def iss_file_header(self)
-
Expand source code Browse git
def iss_file_header(self): if self.__version == 1: name = self.read(260).rstrip(B'\0').decode('utf8') flags = self.u32() self.seekrel(4) size = self.u32() self.seekrel(8) is_unicode = self.u16() self.seekrel(30) else: name_length = self.u32() flags = self.u32() self.seekrel(2) size = self.u32() self.seekrel(8) is_unicode = self.u16() name = self.read(name_length).decode('utf-16le') return name, size, flags, is_unicode
def iss_file(self)
-
Expand source code Browse git
def iss_file(self): name, size, flags, is_unicode = self.iss_file_header() def _data( data: bytearray = self.read(size), seed: bytes = name.encode('utf8'), _is4: bool = flags & 4 == 4, _isu: bool = is_unicode ): key = bytes(x ^ k for x, k in zip(seed, cycle(B'\x13\x35\x86\x07'))) if _is4: key = bytes(islice(cycle(key), 0, 1024)) for (i, b), k in zip(enumerate(data), cycle(key)): data[i] = ~(k ^ (b << 4 | b >> 4)) & 0xFF if _isu: data = zlib.decompress(data) return data return name, _data
Inherited members
class xtiss (*paths, list=False, join_path=False, drop_path=False, fuzzy=0, exact=False, regex=False, path=b'path', date=b'date', pwd=b'')
-
Extracts files from Install Shield Setup files.
Expand source code Browse git
class xtiss(ArchiveUnit): """ Extracts files from Install Shield Setup files. """ def unpack(self, data: bytearray): offset = max(data.rfind(magic) for magic in ISSReader.MAGIC) if offset < 0: raise ValueError('ISS magic not found.') data[:offset] = [] reader = ISSReader(data) count = reader.iss_archive_header() self.log_info(F'archive contains {count} files according to header') for _ in range(count): name, data = reader.iss_file() yield self._pack(name, None, data) @classmethod def handles(cls, data: bytearray) -> Optional[bool]: return data.startswith(B'MZ') and any(data.find(m) > 0 for m in ISSReader.MAGIC)
Ancestors
Class variables
var required_dependencies
var optional_dependencies
Methods
def unpack(self, data)
-
Expand source code Browse git
def unpack(self, data: bytearray): offset = max(data.rfind(magic) for magic in ISSReader.MAGIC) if offset < 0: raise ValueError('ISS magic not found.') data[:offset] = [] reader = ISSReader(data) count = reader.iss_archive_header() self.log_info(F'archive contains {count} files according to header') for _ in range(count): name, data = reader.iss_file() yield self._pack(name, None, data)
Inherited members