1import mmap
2import shutil
3from pathlib import Path
4
5from structlog import get_logger
6
7from unblob.file_utils import File
8from unblob.handlers.archive.zip import ZIPHandler
9from unblob.models import Extractor, HandlerDoc, HandlerType, HexString
10
11logger = get_logger()
12
13LOCAL_FILE_HEADER_ZIP = b"\x50\x4b\x03\x04"
14LOCAL_FILE_HEADER_INSTAR = b"\x50\x4b\x03\x07"
15
16EOCD_ZIP = b"\x50\x4b\x05\x06"
17EOCD_INSTAR = b"\x50\x4b\x05\x09"
18
19CD_FILE_HEADER_ZIP = b"\x50\x4b\x01\x02"
20CD_FILE_HEADER_INSTAR = b"\x50\x4b\x01\x08"
21
22
23class InstarHDExtractor(Extractor):
24 def extract(self, inpath: Path, outdir: Path):
25 outfile = outdir / "instar_hd.deobfuscated"
26 shutil.copyfile(inpath, outfile)
27 with File.from_path(outfile, access=mmap.ACCESS_WRITE) as mm:
28 replacements = {
29 LOCAL_FILE_HEADER_INSTAR: LOCAL_FILE_HEADER_ZIP,
30 EOCD_INSTAR: EOCD_ZIP,
31 CD_FILE_HEADER_INSTAR: CD_FILE_HEADER_ZIP,
32 }
33 for pattern, replacement in replacements.items():
34 pos = mm.find(pattern)
35 while pos != -1:
36 mm[pos : pos + len(pattern)] = replacement
37 pos = mm.find(pattern, pos + len(pattern))
38
39
40class InstarHDHandler(ZIPHandler):
41 NAME = "instar_hd"
42
43 PATTERNS = [HexString("50 4b 03 07")] # match on the modified zip header
44
45 EXTRACTOR = InstarHDExtractor()
46
47 EOCD_RECORD_HEADER = 0x9054B50
48
49 DOC = HandlerDoc(
50 name="Instar HD",
51 description="Instar HD firmware files are modified ZIP archives with non-standard local file headers, central directory headers, and end-of-central-directory records. These modifications include custom magic bytes to differentiate them from standard ZIP files.",
52 handler_type=HandlerType.ARCHIVE,
53 vendor="Instar",
54 references=[],
55 limitations=[],
56 )