Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/unblob/handlers/archive/cab.py: 100%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

17 statements  

1from typing import Optional 

2 

3from structlog import get_logger 

4 

5from ...extractors import Command 

6from ...models import ( 

7 File, 

8 HandlerDoc, 

9 HandlerType, 

10 HexString, 

11 Reference, 

12 StructHandler, 

13 ValidChunk, 

14) 

15 

16logger = get_logger() 

17 

18 

19class CABHandler(StructHandler): 

20 NAME = "cab" 

21 

22 PATTERNS = [HexString("4D 53 43 46 00 00 00 00 // MSCF then reserved dword")] 

23 C_DEFINITIONS = r""" 

24 typedef struct cab_header 

25 { 

26 char signature[4]; /* cabinet file signature contains the characters 'M','S','C','F' (bytes 0x4D, 0x53, 0x43, 0x46). */ 

27 /* This field is used to assure that the file is a cabinet file. */ 

28 uint32 reserved1; /* reserved */ 

29 uint32 cbCabinet; /* size of this cabinet file in bytes */ 

30 uint32 reserved2; /* reserved */ 

31 uint32 coffFiles; /* offset of the first CFFILE entry */ 

32 uint32 reserved3; /* reserved */ 

33 uint8 versionMinor; /* cabinet file format version, minor */ 

34 uint8 versionMajor; /* cabinet file format version, major */ 

35 uint16 cFolders; /* number of CFFOLDER entries in this cabinet */ 

36 uint16 cFiles; /* number of CFFILE entries in this cabinet */ 

37 uint16 flags; /* cabinet file option indicators */ 

38 uint16 setID; /* must be the same for all cabinets in a set*/ 

39 uint16 iCabinet; /* number of this cabinet file in a set */ 

40 uint16 cbCFHeader; /* (optional) size of per-cabinet reserved area */ 

41 uint8 cbCFFolder; /* (optional) size of per-folder reserved area */ 

42 uint8 cbCFData; /* (optional) size of per-datablock reserved area */ 

43 uint8 szCabinetPrev[]; /* (optional) name of previous cabinet file */ 

44 uint8 szDiskPrev[]; /* (optional) name of previous disk */ 

45 uint8 szCabinetNext[]; /* (optional) name of next cabinet file */ 

46 uint8 szDiskNext[]; /* (optional) name of next disk */ 

47 } cab_header_t; 

48 """ 

49 HEADER_STRUCT = "cab_header_t" 

50 

51 EXTRACTOR = Command("7z", "x", "-y", "{inpath}", "-o{outdir}") 

52 

53 DOC = HandlerDoc( 

54 name="CAB", 

55 description="Microsoft Cabinet (CAB) archive files are used for compressed file storage and software installation.", 

56 handler_type=HandlerType.ARCHIVE, 

57 vendor="Microsoft", 

58 references=[ 

59 Reference( 

60 title="Microsoft Cabinet File Format Documentation", 

61 url="https://en.wikipedia.org/wiki/Cabinet_(file_format)", 

62 ), 

63 Reference( 

64 title="Ubuntu Manual - cabextract", 

65 url="https://manpages.ubuntu.com/manpages/focal/man1/cabextract.1.html", 

66 ), 

67 ], 

68 limitations=[], 

69 ) 

70 

71 def calculate_chunk(self, file: File, start_offset: int) -> Optional[ValidChunk]: 

72 header = self.parse_header(file) 

73 

74 if header.cbCabinet < len(header): 

75 return None 

76 

77 return ValidChunk( 

78 start_offset=start_offset, 

79 end_offset=start_offset + header.cbCabinet, 

80 )