1from typing import Optional
2
3from structlog import get_logger
4
5from unblob.file_utils import InvalidInputFormat
6
7from ...extractors import Command
8from ...models import (
9 File,
10 HandlerDoc,
11 HandlerType,
12 Reference,
13 Regex,
14 StructHandler,
15 ValidChunk,
16)
17
18logger = get_logger()
19
20
21class NTFSHandler(StructHandler):
22 NAME = "ntfs"
23
24 PATTERNS = [
25 # An initial x86 short jump instruction (EB 52 90)
26 # OEMName (8 bytes) = 'NTFS '
27 # bytes per sector, the rule enforce a non-zero value
28 # 55 AA is the end of sector marker
29 Regex(
30 r"\xEB\x52\x90\x4E\x54\x46\x53\x20\x20\x20\x20[\x00-\xFF][\x01-\xFF][\x00-\xFF]{497}\x55\xAA"
31 )
32 ]
33
34 C_DEFINITIONS = r"""
35 typedef struct ntfs_boot {
36 uint8 jmp_ins[3]; // jump instruction to boot code.
37 char oem_id[8]; // OEM ID, equal "NTFS "
38
39 // BPB
40 uint16 bytes_per_sector;
41 uint8 sectors_per_clusters;
42 uint8 unused1[7];
43 uint8 media_descriptor;
44 uint8 unused2[2];
45 uint16 sectors_per_track;
46 uint16 heads;
47 uint32 hidden_sectors;
48 uint8 unused3[4];
49
50 // EBPB
51 //uint8 bios_drive_num; // 0x24: BIOS drive number =0x80.
52 uint8 unused4[4];
53 uint64 total_sectors;
54 uint64 mft_cluster_number;
55 uint64 mft_mirror_cluster_number;
56 uint8 record_size;
57 uint8 unused5[3];
58 uint8 index_size;
59 uint8 unused6[3];
60 uint64 serial_num;
61 uint32 checksum;
62
63 uint8 bootstrap_code[426];
64 uint16 boot_magic;
65 } ntfs_boot_t;
66 """
67
68 HEADER_STRUCT = "ntfs_boot_t"
69
70 EXTRACTOR = Command("7z", "x", "-x![SYSTEM]", "-y", "{inpath}", "-o{outdir}")
71
72 DOC = HandlerDoc(
73 name="NTFS",
74 description="NTFS (New Technology File System) is a proprietary file system developed by Microsoft, featuring metadata support, advanced data structures, and journaling for reliability. It is commonly used in Windows operating systems for efficient storage and retrieval of files.",
75 handler_type=HandlerType.FILESYSTEM,
76 vendor="Microsoft",
77 references=[
78 Reference(
79 title="NTFS Wikipedia",
80 url="https://en.wikipedia.org/wiki/NTFS",
81 ),
82 ],
83 limitations=[],
84 )
85
86 def calculate_chunk(self, file: File, start_offset: int) -> Optional[ValidChunk]:
87 header = self.parse_header(file)
88
89 fsize = header.total_sectors * header.bytes_per_sector
90 if fsize == 0:
91 raise InvalidInputFormat("NTFS header with null disk size.")
92
93 end_offset = start_offset + len(header) + fsize
94 return ValidChunk(
95 start_offset=start_offset,
96 end_offset=end_offset,
97 )