1from structlog import get_logger
2
3from ...extractors import Command
4from ...models import (
5 File,
6 HandlerDoc,
7 HandlerType,
8 HexString,
9 Reference,
10 StructHandler,
11 ValidChunk,
12)
13
14logger = get_logger()
15
16
17class CABHandler(StructHandler):
18 NAME = "cab"
19
20 PATTERNS = [HexString("4D 53 43 46 00 00 00 00 // MSCF then reserved dword")]
21 C_DEFINITIONS = r"""
22 typedef struct cab_header
23 {
24 char signature[4]; /* cabinet file signature contains the characters 'M','S','C','F' (bytes 0x4D, 0x53, 0x43, 0x46). */
25 /* This field is used to assure that the file is a cabinet file. */
26 uint32 reserved1; /* reserved */
27 uint32 cbCabinet; /* size of this cabinet file in bytes */
28 uint32 reserved2; /* reserved */
29 uint32 coffFiles; /* offset of the first CFFILE entry */
30 uint32 reserved3; /* reserved */
31 uint8 versionMinor; /* cabinet file format version, minor */
32 uint8 versionMajor; /* cabinet file format version, major */
33 uint16 cFolders; /* number of CFFOLDER entries in this cabinet */
34 uint16 cFiles; /* number of CFFILE entries in this cabinet */
35 uint16 flags; /* cabinet file option indicators */
36 uint16 setID; /* must be the same for all cabinets in a set*/
37 uint16 iCabinet; /* number of this cabinet file in a set */
38 uint16 cbCFHeader; /* (optional) size of per-cabinet reserved area */
39 uint8 cbCFFolder; /* (optional) size of per-folder reserved area */
40 uint8 cbCFData; /* (optional) size of per-datablock reserved area */
41 uint8 szCabinetPrev[]; /* (optional) name of previous cabinet file */
42 uint8 szDiskPrev[]; /* (optional) name of previous disk */
43 uint8 szCabinetNext[]; /* (optional) name of next cabinet file */
44 uint8 szDiskNext[]; /* (optional) name of next disk */
45 } cab_header_t;
46 """
47 HEADER_STRUCT = "cab_header_t"
48
49 EXTRACTOR = Command("7z", "x", "-y", "{inpath}", "-o{outdir}")
50
51 DOC = HandlerDoc(
52 name="CAB",
53 description="Microsoft Cabinet (CAB) archive files are used for compressed file storage and software installation.",
54 handler_type=HandlerType.ARCHIVE,
55 vendor="Microsoft",
56 references=[
57 Reference(
58 title="Microsoft Cabinet File Format Documentation",
59 url="https://en.wikipedia.org/wiki/Cabinet_(file_format)",
60 ),
61 Reference(
62 title="Ubuntu Manual - cabextract",
63 url="https://manpages.ubuntu.com/manpages/focal/man1/cabextract.1.html",
64 ),
65 ],
66 limitations=[],
67 )
68
69 def calculate_chunk(self, file: File, start_offset: int) -> ValidChunk | None:
70 header = self.parse_header(file)
71
72 if header.cbCabinet < len(header):
73 return None
74
75 return ValidChunk(
76 start_offset=start_offset,
77 end_offset=start_offset + header.cbCabinet,
78 )