DiskAnalyzer 0.0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- diskanalyzer-0.0.1/DiskAnalyzer/DiskAnalyzer.py +485 -0
- diskanalyzer-0.0.1/DiskAnalyzer/MftAnalyzer.py +934 -0
- diskanalyzer-0.0.1/DiskAnalyzer/NtfsAnalyzer.py +159 -0
- diskanalyzer-0.0.1/DiskAnalyzer/__init__.py +58 -0
- diskanalyzer-0.0.1/DiskAnalyzer/__main__.py +64 -0
- diskanalyzer-0.0.1/DiskAnalyzer.egg-info/PKG-INFO +149 -0
- diskanalyzer-0.0.1/DiskAnalyzer.egg-info/SOURCES.txt +16 -0
- diskanalyzer-0.0.1/DiskAnalyzer.egg-info/dependency_links.txt +1 -0
- diskanalyzer-0.0.1/DiskAnalyzer.egg-info/entry_points.txt +4 -0
- diskanalyzer-0.0.1/DiskAnalyzer.egg-info/top_level.txt +1 -0
- diskanalyzer-0.0.1/LICENSE.txt +674 -0
- diskanalyzer-0.0.1/MANIFEST.in +4 -0
- diskanalyzer-0.0.1/PKG-INFO +149 -0
- diskanalyzer-0.0.1/README.md +110 -0
- diskanalyzer-0.0.1/pyproject.toml +60 -0
- diskanalyzer-0.0.1/setup.cfg +53 -0
- diskanalyzer-0.0.1/setup.py +56 -0
|
@@ -0,0 +1,485 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
###################
|
|
5
|
+
# This package implements multiples libraries and tools to parse, analyze
|
|
6
|
+
# and extract informations from disk on the live system.
|
|
7
|
+
# Copyright (C) 2025 DiskAnalyzer
|
|
8
|
+
|
|
9
|
+
# This program is free software: you can redistribute it and/or modify
|
|
10
|
+
# it under the terms of the GNU General Public License as published by
|
|
11
|
+
# the Free Software Foundation, either version 3 of the License, or
|
|
12
|
+
# (at your option) any later version.
|
|
13
|
+
|
|
14
|
+
# This program is distributed in the hope that it will be useful,
|
|
15
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
16
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
17
|
+
# GNU General Public License for more details.
|
|
18
|
+
|
|
19
|
+
# You should have received a copy of the GNU General Public License
|
|
20
|
+
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
21
|
+
###################
|
|
22
|
+
|
|
23
|
+
"""
|
|
24
|
+
This package implements multiples libraries and tools to parse, analyze
|
|
25
|
+
and extract informations from disk on the live system.
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
__version__ = "0.0.1"
|
|
29
|
+
__author__ = "Maurice Lambert"
|
|
30
|
+
__author_email__ = "mauricelambert434@gmail.com"
|
|
31
|
+
__maintainer__ = "Maurice Lambert"
|
|
32
|
+
__maintainer_email__ = "mauricelambert434@gmail.com"
|
|
33
|
+
__description__ = """
|
|
34
|
+
This package implements multiples libraries and tools to parse, analyze
|
|
35
|
+
and extract informations from disk on the live system.
|
|
36
|
+
"""
|
|
37
|
+
__url__ = "https://github.com/mauricelambert/DiskAnalyzer"
|
|
38
|
+
|
|
39
|
+
__all__ = ["GPTHeader", "GPTPartitionEntry", "MBRHeader", "MBRPartitionEntry", "Partition", "disk_parsing", "get_main_partition"]
|
|
40
|
+
|
|
41
|
+
__license__ = "GPL-3.0 License"
|
|
42
|
+
__copyright__ = """
|
|
43
|
+
DiskAnalyzer Copyright (C) 2025 Maurice Lambert
|
|
44
|
+
This program comes with ABSOLUTELY NO WARRANTY.
|
|
45
|
+
This is free software, and you are welcome to redistribute it
|
|
46
|
+
under certain conditions.
|
|
47
|
+
"""
|
|
48
|
+
copyright = __copyright__
|
|
49
|
+
license = __license__
|
|
50
|
+
|
|
51
|
+
print(copyright)
|
|
52
|
+
|
|
53
|
+
from ctypes import (
|
|
54
|
+
LittleEndianStructure,
|
|
55
|
+
c_uint8,
|
|
56
|
+
c_uint32,
|
|
57
|
+
c_char,
|
|
58
|
+
c_uint64,
|
|
59
|
+
c_ubyte,
|
|
60
|
+
c_wchar,
|
|
61
|
+
)
|
|
62
|
+
from typing import Tuple, List, Union
|
|
63
|
+
from dataclasses import dataclass
|
|
64
|
+
from _io import BufferedReader
|
|
65
|
+
from enum import Enum
|
|
66
|
+
from sys import exit
|
|
67
|
+
|
|
68
|
+
SECTOR_SIZE = 512
|
|
69
|
+
DRIVE_PATH = r"\\.\PhysicalDrive0"
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
class PartitionStatus(Enum):
|
|
73
|
+
"""
|
|
74
|
+
Enum for disk partitions status (bootable or not bootable).
|
|
75
|
+
"""
|
|
76
|
+
|
|
77
|
+
ACTIVE = 0x80
|
|
78
|
+
INACTIVE = 0x00
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class MbrPartitionType(Enum):
|
|
82
|
+
"""
|
|
83
|
+
Enum for disk partitions type.
|
|
84
|
+
"""
|
|
85
|
+
|
|
86
|
+
EMPTY = 0x00
|
|
87
|
+
FAT12 = 0x01
|
|
88
|
+
FAT16 = 0x04
|
|
89
|
+
FAT32 = 0x0B
|
|
90
|
+
FAT32_LBA = 0x0C
|
|
91
|
+
NTFS = 0x07
|
|
92
|
+
LINUX_SWAP = 0x82
|
|
93
|
+
EXT2 = 0x83
|
|
94
|
+
EXT3 = 0x83
|
|
95
|
+
EXT4 = 0x83
|
|
96
|
+
LINUX_LVM = 0x8E
|
|
97
|
+
WINDOWS_RE = 0x27
|
|
98
|
+
GPT_PROTECTIVE = 0xEE
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
class GptPartitionType(Enum):
|
|
102
|
+
"""
|
|
103
|
+
Enum for disk partitions type.
|
|
104
|
+
"""
|
|
105
|
+
|
|
106
|
+
EMPTY = "00000000-0000-0000-0000-000000000000"
|
|
107
|
+
PARTITION_SYSTEM_GUID = "C12A7328-F81F-11D2-BA4B-00A0C93EC93B"
|
|
108
|
+
LEGACY_MBR_PARTITION_GUID = "024DEE41-33E7-11D3-9D69-0008C781F39F"
|
|
109
|
+
PARTITION_MSFT_RESERVED_GUID = "E3C9E316-0B5C-4DB8-817D-F92DF00215AE"
|
|
110
|
+
PARTITION_BASIC_DATA_GUID = "EBD0A0A2-B9E5-4433-87C0-68B6B72699C7"
|
|
111
|
+
PARTITION_LINUX_FILE_SYSTEM_DATA_GUID = (
|
|
112
|
+
"0FC63DAF-8483-4772-8E79-3D69D8477DE4"
|
|
113
|
+
)
|
|
114
|
+
PARTITION_LINUX_RAID_GUID = "A19D880F-05FC-4D3B-A006-743F0F84911E"
|
|
115
|
+
PARTITION_LINUX_SWAP_GUID = "0657FD6D-A4AB-43C4-84E5-0933C84B4F4F"
|
|
116
|
+
PARTITION_LINUX_LVM_GUID = "E6D6D379-F507-44C2-A23C-238F2A3DF928"
|
|
117
|
+
PARTITION_U_BOOT_ENVIRONMENT = "3DE21764-95BD-54BD-A5C3-4ABE786F38A8"
|
|
118
|
+
WINDOWS_RECOVERY_TOOLS = "DE94BBA4-06D1-4D40-A16A-BFD50179D6AC"
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
status_dict = {status.value: status.name for status in PartitionStatus}
|
|
122
|
+
mbr_type_dict = {
|
|
123
|
+
part_type.value: part_type.name for part_type in MbrPartitionType
|
|
124
|
+
}
|
|
125
|
+
gpt_type_dict = {
|
|
126
|
+
part_type.value: part_type.name for part_type in GptPartitionType
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
gpt_attributes = {
|
|
130
|
+
0x0000000000000001: "Platform required",
|
|
131
|
+
0x0000000000000002: "EFI firmware ignore partition",
|
|
132
|
+
0x0000000000000004: "Legacy BIOS bootable",
|
|
133
|
+
0x0000000000000008: "Reserved for future use",
|
|
134
|
+
0x0100000000000000: "Successful boot flag",
|
|
135
|
+
0x0010000000000000: "Tries remaining",
|
|
136
|
+
0x0020000000000000: "Tries remaining",
|
|
137
|
+
0x0040000000000000: "Tries remaining",
|
|
138
|
+
0x0001000000000000: "Priority low",
|
|
139
|
+
0x0002000000000000: "Priority medium",
|
|
140
|
+
0x0004000000000000: "Priority high",
|
|
141
|
+
0x0008000000000000: "Priority highest",
|
|
142
|
+
0x0100000000000000: "Successful boot flag",
|
|
143
|
+
0x1000000000000000: "Read-only",
|
|
144
|
+
0x2000000000000000: "Shadow copy",
|
|
145
|
+
0x4000000000000000: "Hidden",
|
|
146
|
+
0x8000000000000000: "No drive letter",
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
@dataclass
|
|
151
|
+
class Partition:
|
|
152
|
+
start_sector: int
|
|
153
|
+
end_sector: int
|
|
154
|
+
size: int # In sectors
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
class MBRPartitionEntry(LittleEndianStructure):
|
|
158
|
+
"""
|
|
159
|
+
This class defines the MBR partition structure.
|
|
160
|
+
"""
|
|
161
|
+
|
|
162
|
+
_pack_ = 1
|
|
163
|
+
_fields_ = [
|
|
164
|
+
("status", c_uint8),
|
|
165
|
+
("chs_first", c_uint8 * 3),
|
|
166
|
+
("type", c_uint8),
|
|
167
|
+
("chs_last", c_uint8 * 3),
|
|
168
|
+
("lba_start", c_uint32),
|
|
169
|
+
("total_sectors", c_uint32),
|
|
170
|
+
]
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
class MBRHeader(LittleEndianStructure):
|
|
174
|
+
"""
|
|
175
|
+
This class defines the MBR structure.
|
|
176
|
+
"""
|
|
177
|
+
|
|
178
|
+
_pack_ = 1
|
|
179
|
+
_fields_ = [
|
|
180
|
+
("bootloader", c_ubyte * 446),
|
|
181
|
+
("partitions", MBRPartitionEntry * 4),
|
|
182
|
+
("signature", c_ubyte * 2),
|
|
183
|
+
]
|
|
184
|
+
|
|
185
|
+
def to_partition(self) -> Union[Partition, None]:
|
|
186
|
+
"""
|
|
187
|
+
This function makes partition from MBR.
|
|
188
|
+
"""
|
|
189
|
+
|
|
190
|
+
for entry in self.partitions:
|
|
191
|
+
if (
|
|
192
|
+
entry.type != 0x00
|
|
193
|
+
and entry.type != 0x05
|
|
194
|
+
and entry.type != 0x0F
|
|
195
|
+
):
|
|
196
|
+
start = entry.lba_start
|
|
197
|
+
size = entry.total_sectors
|
|
198
|
+
end = start + size - 1
|
|
199
|
+
if size > 2097152:
|
|
200
|
+
return Partition(
|
|
201
|
+
start_sector=start, end_sector=end, size=size
|
|
202
|
+
)
|
|
203
|
+
return None
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
class GPTHeader(LittleEndianStructure):
|
|
207
|
+
"""
|
|
208
|
+
This class defines the GPT structure.
|
|
209
|
+
"""
|
|
210
|
+
|
|
211
|
+
_pack_ = 1
|
|
212
|
+
_fields_ = [
|
|
213
|
+
("signature", c_char * 8),
|
|
214
|
+
("revision", c_uint32),
|
|
215
|
+
("header_size", c_uint32),
|
|
216
|
+
("header_crc32", c_uint32),
|
|
217
|
+
("reserved", c_uint32),
|
|
218
|
+
("current_lba", c_uint64),
|
|
219
|
+
("backup_lba", c_uint64),
|
|
220
|
+
("first_usable_lba", c_uint64),
|
|
221
|
+
("last_usable_lba", c_uint64),
|
|
222
|
+
("disk_guid", c_ubyte * 16),
|
|
223
|
+
("partition_entry_lba", c_uint64),
|
|
224
|
+
("num_part_entries", c_uint32),
|
|
225
|
+
("part_entry_size", c_uint32),
|
|
226
|
+
("part_array_crc32", c_uint32),
|
|
227
|
+
]
|
|
228
|
+
|
|
229
|
+
def to_partition(self) -> Union[Partition, None]:
|
|
230
|
+
"""
|
|
231
|
+
This function makes partition from GPT.
|
|
232
|
+
"""
|
|
233
|
+
|
|
234
|
+
for entry in self.partitions:
|
|
235
|
+
guid_type = format_guid(entry.part_type_guid).upper()
|
|
236
|
+
if (
|
|
237
|
+
guid_type == "EBD0A0A2-B9E5-4433-87C0-68B6B72699C7"
|
|
238
|
+
or guid_type == "0FC63DAF-8483-4772-8E79-3D69D8477DE4"
|
|
239
|
+
):
|
|
240
|
+
start = entry.start_lba
|
|
241
|
+
end = entry.end_lba
|
|
242
|
+
size = end - start + 1
|
|
243
|
+
return Partition(start_sector=start, end_sector=end, size=size)
|
|
244
|
+
return None
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
class GPTPartitionEntry(LittleEndianStructure):
|
|
248
|
+
"""
|
|
249
|
+
This class defines the GPT partition structure.
|
|
250
|
+
"""
|
|
251
|
+
|
|
252
|
+
_pack_ = 1
|
|
253
|
+
_fields_ = [
|
|
254
|
+
("part_type_guid", c_ubyte * 16),
|
|
255
|
+
("unique_part_guid", c_ubyte * 16),
|
|
256
|
+
("start_lba", c_uint64),
|
|
257
|
+
("end_lba", c_uint64),
|
|
258
|
+
("attributes", c_uint64),
|
|
259
|
+
("part_name", c_wchar * 36), # 72 bytes, UTF-16 encoded
|
|
260
|
+
]
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
data_type = type(c_ubyte * 16)
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
def format_guid(guid_bytes: data_type) -> str:
|
|
267
|
+
"""
|
|
268
|
+
This function returns a GUID string from data.
|
|
269
|
+
"""
|
|
270
|
+
|
|
271
|
+
data = bytes(guid_bytes)
|
|
272
|
+
return (
|
|
273
|
+
f"{int.from_bytes(data[0:4], 'little'):08X}-"
|
|
274
|
+
f"{int.from_bytes(data[4:6], 'little'):04X}-"
|
|
275
|
+
f"{int.from_bytes(data[6:8], 'little'):04X}-"
|
|
276
|
+
f"{data[8:10].hex()}-{data[10:].hex()}"
|
|
277
|
+
)
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
def is_gpt_signature(mbr: MBRHeader, sector_data: bytes) -> bool:
|
|
281
|
+
"""
|
|
282
|
+
This function checks the GPT magic bytes
|
|
283
|
+
to detect the start sector structure.
|
|
284
|
+
"""
|
|
285
|
+
|
|
286
|
+
return any(
|
|
287
|
+
entry.type == 0xEE for entry in mbr.partitions
|
|
288
|
+
) and sector_data.startswith(b"EFI PART")
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
def parse_mbr(mbr_data: bytes) -> MBRHeader:
|
|
292
|
+
"""
|
|
293
|
+
This function parses the MBR data.
|
|
294
|
+
"""
|
|
295
|
+
|
|
296
|
+
return MBRHeader.from_buffer_copy(mbr_data)
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
def print_mbr_analysis(mbr: MBRHeader) -> None:
|
|
300
|
+
"""
|
|
301
|
+
This function prints informations about MBR.
|
|
302
|
+
"""
|
|
303
|
+
|
|
304
|
+
if bytes(mbr.signature) != b"\x55\xaa":
|
|
305
|
+
print("[-] Invalid MBR signature")
|
|
306
|
+
return None
|
|
307
|
+
|
|
308
|
+
print("[+] MBR Detected")
|
|
309
|
+
|
|
310
|
+
line_length = 40
|
|
311
|
+
bootloader = memoryview(bytes(mbr.bootloader))
|
|
312
|
+
|
|
313
|
+
print(" Bootloader")
|
|
314
|
+
for index in range(0, len(bootloader), line_length):
|
|
315
|
+
print(" ", bootloader[index : index + line_length].hex())
|
|
316
|
+
|
|
317
|
+
for index, entry in enumerate(mbr.partitions):
|
|
318
|
+
if entry.type != 0:
|
|
319
|
+
print(f" Partition {index + 1}:")
|
|
320
|
+
print(
|
|
321
|
+
f" Status : 0x{entry.status:02X} ({status_dict[entry.status]})"
|
|
322
|
+
)
|
|
323
|
+
print(
|
|
324
|
+
f" Type : 0x{entry.type:02X} ({mbr_type_dict[entry.type]})"
|
|
325
|
+
)
|
|
326
|
+
print(f" Start LBA : {entry.lba_start}")
|
|
327
|
+
print(
|
|
328
|
+
f" Total Sectors: {entry.total_sectors} B ({(entry.total_sectors * 512) / (1024 ** 2):.2f} MB)"
|
|
329
|
+
)
|
|
330
|
+
|
|
331
|
+
print(" Boot Signature")
|
|
332
|
+
print(" ", bytes(mbr.signature).hex())
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
def gpt_partitions_size(partition: GPTPartitionEntry) -> float:
|
|
336
|
+
"""
|
|
337
|
+
This function returns the size in MB for a GPT partition
|
|
338
|
+
"""
|
|
339
|
+
|
|
340
|
+
return (
|
|
341
|
+
(partition.end_lba - partition.start_lba) * SECTOR_SIZE / (1024 * 1024)
|
|
342
|
+
)
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
def parse_gpt(file: BufferedReader, gpt_data: bytes) -> GPTHeader:
|
|
346
|
+
"""
|
|
347
|
+
This function parses the GPT data.
|
|
348
|
+
"""
|
|
349
|
+
|
|
350
|
+
gpt_header = GPTHeader.from_buffer_copy(gpt_data)
|
|
351
|
+
|
|
352
|
+
gpt_header.partitions = []
|
|
353
|
+
file.seek(gpt_header.partition_entry_lba * SECTOR_SIZE)
|
|
354
|
+
for _ in range(gpt_header.num_part_entries):
|
|
355
|
+
entry_data = file.read(128)
|
|
356
|
+
if len(entry_data) == 128 and entry_data != b"\0" * 128:
|
|
357
|
+
entry = GPTPartitionEntry.from_buffer_copy(entry_data)
|
|
358
|
+
gpt_header.partitions.append(entry)
|
|
359
|
+
entry.flags = [
|
|
360
|
+
attr
|
|
361
|
+
for value, attr in gpt_attributes.items()
|
|
362
|
+
if entry.attributes & value
|
|
363
|
+
]
|
|
364
|
+
|
|
365
|
+
return gpt_header
|
|
366
|
+
|
|
367
|
+
|
|
368
|
+
def print_gpt_analysis(gpt_header: GPTHeader) -> None:
|
|
369
|
+
"""
|
|
370
|
+
This function prints informations about GPT headers and partitions.
|
|
371
|
+
"""
|
|
372
|
+
|
|
373
|
+
if gpt_header.signature != b"EFI PART":
|
|
374
|
+
print("[-] Invalid GPT signature")
|
|
375
|
+
return None
|
|
376
|
+
|
|
377
|
+
print("[+] GPT Detected")
|
|
378
|
+
print(f" GPT Signature : {gpt_header.signature.decode()}")
|
|
379
|
+
print(f" GPT Disk GUID : {format_guid(gpt_header.disk_guid)}")
|
|
380
|
+
print(f" Partition Count : {gpt_header.num_part_entries}")
|
|
381
|
+
print(f" Partition Entry Size: {gpt_header.part_entry_size}")
|
|
382
|
+
print(f" Partition Table LBA : {gpt_header.partition_entry_lba}")
|
|
383
|
+
|
|
384
|
+
print("\n[+] Partition Entries:")
|
|
385
|
+
for index, entry in enumerate(gpt_header.partitions):
|
|
386
|
+
part_name = entry.part_name.strip() if entry.part_name else "No Name"
|
|
387
|
+
part_guid = format_guid(entry.unique_part_guid)
|
|
388
|
+
type_guid = format_guid(entry.part_type_guid).upper()
|
|
389
|
+
print(f" Partition {index+1}:")
|
|
390
|
+
print(f" Type GUID : {type_guid} ({gpt_type_dict[type_guid]})")
|
|
391
|
+
print(f" Unique GUID : {part_guid}")
|
|
392
|
+
print(f" Start LBA : {entry.start_lba}")
|
|
393
|
+
print(f" End LBA : {entry.end_lba}")
|
|
394
|
+
print(f" Size in MB : {gpt_partitions_size(entry):.2f} MB")
|
|
395
|
+
print(
|
|
396
|
+
f" Attributes : {hex(entry.attributes)} ({entry.attributes})"
|
|
397
|
+
)
|
|
398
|
+
if entry.attributes:
|
|
399
|
+
print(f" {', '.join(entry.flags)}")
|
|
400
|
+
print(f" Partition Name: {part_name}")
|
|
401
|
+
|
|
402
|
+
|
|
403
|
+
def disk_parsing(
|
|
404
|
+
keep_open: bool = False,
|
|
405
|
+
) -> Union[
|
|
406
|
+
Tuple[
|
|
407
|
+
Union[PermissionError, Exception, MBRHeader, GPTHeader], BufferedReader
|
|
408
|
+
],
|
|
409
|
+
PermissionError,
|
|
410
|
+
Exception,
|
|
411
|
+
MBRHeader,
|
|
412
|
+
GPTHeader,
|
|
413
|
+
]:
|
|
414
|
+
"""
|
|
415
|
+
This function returns the parsed structure or error and opened file if keep_open is True.
|
|
416
|
+
"""
|
|
417
|
+
|
|
418
|
+
try:
|
|
419
|
+
file = open(DRIVE_PATH, "rb")
|
|
420
|
+
except PermissionError:
|
|
421
|
+
print("[-] Permission denied. Run as Administrator.")
|
|
422
|
+
return 1
|
|
423
|
+
except Exception as e:
|
|
424
|
+
print(f"[-] Error: {e}")
|
|
425
|
+
return 127
|
|
426
|
+
|
|
427
|
+
first_sector = file.read(SECTOR_SIZE)
|
|
428
|
+
second_sector = file.read(SECTOR_SIZE)
|
|
429
|
+
|
|
430
|
+
mbr = parse_mbr(first_sector)
|
|
431
|
+
|
|
432
|
+
if is_gpt_signature(mbr, second_sector):
|
|
433
|
+
return_value = parse_gpt(file, second_sector)
|
|
434
|
+
else:
|
|
435
|
+
return_value = parse_mbr(mbr)
|
|
436
|
+
|
|
437
|
+
if keep_open:
|
|
438
|
+
return return_value, file
|
|
439
|
+
|
|
440
|
+
file.close()
|
|
441
|
+
return return_value
|
|
442
|
+
|
|
443
|
+
|
|
444
|
+
def get_main_partition(
|
|
445
|
+
*args, **kwargs
|
|
446
|
+
) -> Tuple[Partition, Union[None, BufferedReader]]:
|
|
447
|
+
"""
|
|
448
|
+
This function returns the main partition.
|
|
449
|
+
"""
|
|
450
|
+
|
|
451
|
+
file = None
|
|
452
|
+
data = disk_parsing(*args, **kwargs)
|
|
453
|
+
|
|
454
|
+
if isinstance(data, tuple) and isinstance(data[1], BufferedReader):
|
|
455
|
+
file = data[1]
|
|
456
|
+
data = data[0]
|
|
457
|
+
|
|
458
|
+
return data.to_partition(), file
|
|
459
|
+
|
|
460
|
+
|
|
461
|
+
def main() -> int:
|
|
462
|
+
"""
|
|
463
|
+
The main function to starts the script from the command line.
|
|
464
|
+
"""
|
|
465
|
+
|
|
466
|
+
value = disk_parsing()
|
|
467
|
+
|
|
468
|
+
if isinstance(value, PermissionError):
|
|
469
|
+
print("[-] Permission denied. Run as Administrator.")
|
|
470
|
+
return 1
|
|
471
|
+
elif isinstance(value, Exception):
|
|
472
|
+
print(f"[-] Error: {value}")
|
|
473
|
+
return 127
|
|
474
|
+
elif isinstance(value, GPTHeader):
|
|
475
|
+
print_gpt_analysis(value)
|
|
476
|
+
elif isinstance(value, MBRHeader):
|
|
477
|
+
print_mbr_analysis(value)
|
|
478
|
+
else:
|
|
479
|
+
return 127
|
|
480
|
+
|
|
481
|
+
return 0
|
|
482
|
+
|
|
483
|
+
|
|
484
|
+
if __name__ == "__main__":
|
|
485
|
+
exit(main())
|