dissect.hypervisor 3.16.dev3__py3-none-any.whl → 3.17.dev1__py3-none-any.whl
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.
- dissect/hypervisor/disk/vmdk.py +90 -33
- {dissect.hypervisor-3.16.dev3.dist-info → dissect.hypervisor-3.17.dev1.dist-info}/METADATA +8 -8
- {dissect.hypervisor-3.16.dev3.dist-info → dissect.hypervisor-3.17.dev1.dist-info}/RECORD +8 -8
- {dissect.hypervisor-3.16.dev3.dist-info → dissect.hypervisor-3.17.dev1.dist-info}/WHEEL +1 -1
- {dissect.hypervisor-3.16.dev3.dist-info → dissect.hypervisor-3.17.dev1.dist-info}/COPYRIGHT +0 -0
- {dissect.hypervisor-3.16.dev3.dist-info → dissect.hypervisor-3.17.dev1.dist-info}/LICENSE +0 -0
- {dissect.hypervisor-3.16.dev3.dist-info → dissect.hypervisor-3.17.dev1.dist-info}/entry_points.txt +0 -0
- {dissect.hypervisor-3.16.dev3.dist-info → dissect.hypervisor-3.17.dev1.dist-info}/top_level.txt +0 -0
dissect/hypervisor/disk/vmdk.py
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import ctypes
|
|
2
4
|
import io
|
|
3
5
|
import logging
|
|
4
6
|
import os
|
|
7
|
+
import re
|
|
5
8
|
import textwrap
|
|
6
9
|
import zlib
|
|
7
10
|
from bisect import bisect_right
|
|
11
|
+
from dataclasses import dataclass
|
|
8
12
|
from functools import lru_cache
|
|
9
13
|
from pathlib import Path
|
|
10
14
|
|
|
@@ -59,13 +63,13 @@ class VMDK(AlignedStream):
|
|
|
59
63
|
if self.descriptor.attr["parentCID"] != "ffffffff":
|
|
60
64
|
self.parent = open_parent(path.parent, self.descriptor.attr["parentFileNameHint"])
|
|
61
65
|
|
|
62
|
-
for
|
|
63
|
-
if
|
|
64
|
-
sdisk_fh = path.with_name(filename).open("rb")
|
|
66
|
+
for extent in self.descriptor.extents:
|
|
67
|
+
if extent.type in ["SPARSE", "VMFSSPARSE", "SESPARSE"]:
|
|
68
|
+
sdisk_fh = path.with_name(extent.filename).open("rb")
|
|
65
69
|
self.disks.append(SparseDisk(sdisk_fh, parent=self.parent))
|
|
66
|
-
elif
|
|
67
|
-
rdisk_fh = path.with_name(filename).open("rb")
|
|
68
|
-
self.disks.append(RawDisk(rdisk_fh,
|
|
70
|
+
elif extent.type in ["VMFS", "FLAT"]:
|
|
71
|
+
rdisk_fh = path.with_name(extent.filename).open("rb")
|
|
72
|
+
self.disks.append(RawDisk(rdisk_fh, extent.sectors * SECTOR_SIZE))
|
|
69
73
|
|
|
70
74
|
elif magic in (COWD_MAGIC, VMDK_MAGIC, SESPARSE_MAGIC):
|
|
71
75
|
sparse_disk = SparseDisk(fh)
|
|
@@ -398,8 +402,53 @@ class SparseExtentHeader:
|
|
|
398
402
|
return getattr(self.hdr, attr)
|
|
399
403
|
|
|
400
404
|
|
|
405
|
+
RE_EXTENT_DESCRIPTOR = re.compile(
|
|
406
|
+
r"""
|
|
407
|
+
^
|
|
408
|
+
(?P<access_mode>RW|RDONLY|NOACCESS)\s
|
|
409
|
+
(?P<sectors>\d+)\s
|
|
410
|
+
(?P<type>SPARSE|ZERO|FLAT|VMFS|VMFSSPARSE|VMFSRDM|VMFSRAW)
|
|
411
|
+
(\s(?P<filename>\".+\"))?
|
|
412
|
+
(\s(?P<start_sector>\d+))?
|
|
413
|
+
(\s(?P<partition_uuid>\S+))?
|
|
414
|
+
(\s(?P<device_identifier>\S+))?
|
|
415
|
+
$
|
|
416
|
+
""",
|
|
417
|
+
re.VERBOSE,
|
|
418
|
+
)
|
|
419
|
+
|
|
420
|
+
|
|
421
|
+
@dataclass
|
|
422
|
+
class ExtentDescriptor:
|
|
423
|
+
raw: str
|
|
424
|
+
access_mode: str
|
|
425
|
+
sectors: int
|
|
426
|
+
type: str
|
|
427
|
+
filename: str | None = None
|
|
428
|
+
start_sector: int | None = None
|
|
429
|
+
partition_uuid: str | None = None
|
|
430
|
+
device_identifier: str | None = None
|
|
431
|
+
|
|
432
|
+
def __post_init__(self) -> None:
|
|
433
|
+
self.sectors = int(self.sectors)
|
|
434
|
+
|
|
435
|
+
if self.filename:
|
|
436
|
+
self.filename = self.filename.strip('"')
|
|
437
|
+
|
|
438
|
+
if self.start_sector:
|
|
439
|
+
self.start_sector = int(self.start_sector)
|
|
440
|
+
|
|
441
|
+
def __repr__(self) -> str:
|
|
442
|
+
return f"<ExtentDescriptor {self.raw}>"
|
|
443
|
+
|
|
444
|
+
def __str__(self) -> str:
|
|
445
|
+
return self.raw
|
|
446
|
+
|
|
447
|
+
|
|
401
448
|
class DiskDescriptor:
|
|
402
|
-
def __init__(
|
|
449
|
+
def __init__(
|
|
450
|
+
self, attr: dict, extents: list[ExtentDescriptor], disk_db: dict, sectors: int, raw_config: str | None = None
|
|
451
|
+
):
|
|
403
452
|
self.attr = attr
|
|
404
453
|
self.extents = extents
|
|
405
454
|
self.ddb = disk_db
|
|
@@ -407,9 +456,15 @@ class DiskDescriptor:
|
|
|
407
456
|
self.raw = raw_config
|
|
408
457
|
|
|
409
458
|
@classmethod
|
|
410
|
-
def parse(cls, vmdk_config):
|
|
459
|
+
def parse(cls, vmdk_config: str) -> DiskDescriptor:
|
|
460
|
+
"""Return :class:`DiskDescriptor` based on the provided ``vmdk_config``.
|
|
461
|
+
|
|
462
|
+
Resources:
|
|
463
|
+
- https://github.com/libyal/libvmdk/blob/main/documentation/VMWare%20Virtual%20Disk%20Format%20(VMDK).asciidoc
|
|
464
|
+
""" # noqa: E501
|
|
465
|
+
|
|
411
466
|
descriptor_settings = {}
|
|
412
|
-
extents = []
|
|
467
|
+
extents: list[ExtentDescriptor] = []
|
|
413
468
|
disk_db = {}
|
|
414
469
|
sectors = 0
|
|
415
470
|
|
|
@@ -420,11 +475,15 @@ class DiskDescriptor:
|
|
|
420
475
|
continue
|
|
421
476
|
|
|
422
477
|
if line.startswith("RW ") or line.startswith("RDONLY ") or line.startswith("NOACCESS "):
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
478
|
+
match = RE_EXTENT_DESCRIPTOR.search(line)
|
|
479
|
+
|
|
480
|
+
if not match:
|
|
481
|
+
log.warning("Unexpected ExtentDescriptor format in vmdk config: %s, ignoring", line)
|
|
482
|
+
continue
|
|
483
|
+
|
|
484
|
+
extent = ExtentDescriptor(raw=line, **match.groupdict())
|
|
485
|
+
sectors += extent.sectors
|
|
486
|
+
extents.append(extent)
|
|
428
487
|
continue
|
|
429
488
|
|
|
430
489
|
setting, _, value = line.partition("=")
|
|
@@ -438,35 +497,33 @@ class DiskDescriptor:
|
|
|
438
497
|
|
|
439
498
|
return cls(descriptor_settings, extents, disk_db, sectors, vmdk_config)
|
|
440
499
|
|
|
441
|
-
def __str__(self):
|
|
442
|
-
str_template =
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
500
|
+
def __str__(self) -> str:
|
|
501
|
+
str_template = textwrap.dedent(
|
|
502
|
+
"""\
|
|
503
|
+
# Disk DescriptorFile
|
|
504
|
+
version=1
|
|
505
|
+
{}
|
|
446
506
|
|
|
447
|
-
|
|
448
|
-
|
|
507
|
+
# Extent Description
|
|
508
|
+
{}
|
|
449
509
|
|
|
450
|
-
|
|
451
|
-
|
|
510
|
+
# The Disk Data Base
|
|
511
|
+
#DDB
|
|
512
|
+
|
|
513
|
+
{}"""
|
|
514
|
+
)
|
|
452
515
|
|
|
453
|
-
{}"""
|
|
454
|
-
str_template = textwrap.dedent(str_template)
|
|
455
516
|
descriptor_settings = []
|
|
456
517
|
for setting, value in self.attr.items():
|
|
457
|
-
if setting
|
|
458
|
-
|
|
459
|
-
descriptor_settings.append("{}={}".format(setting, value))
|
|
518
|
+
if setting != "version":
|
|
519
|
+
descriptor_settings.append(f"{setting}={value}")
|
|
460
520
|
descriptor_settings = "\n".join(descriptor_settings)
|
|
461
521
|
|
|
462
|
-
extents =
|
|
463
|
-
for access_type, size, extent_type, filename in self.extents:
|
|
464
|
-
extents.append('{} {} {} "{}"'.format(access_type, size, extent_type, filename))
|
|
465
|
-
extents = "\n".join(extents)
|
|
522
|
+
extents = "\n".join(map(str, self.extents))
|
|
466
523
|
|
|
467
524
|
disk_db = []
|
|
468
525
|
for setting, value in self.ddb.items():
|
|
469
|
-
disk_db.append('{} = "{}"'
|
|
526
|
+
disk_db.append(f'{setting} = "{value}"')
|
|
470
527
|
disk_db = "\n".join(disk_db)
|
|
471
528
|
|
|
472
529
|
return str_template.format(descriptor_settings, extents, disk_db)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: dissect.hypervisor
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.17.dev1
|
|
4
4
|
Summary: A Dissect module implementing parsers for various hypervisor disk, backup and configuration files
|
|
5
5
|
Author-email: Dissect Team <dissect@fox-it.com>
|
|
6
6
|
License: Affero General Public License v3
|
|
@@ -23,14 +23,14 @@ Description-Content-Type: text/markdown
|
|
|
23
23
|
License-File: LICENSE
|
|
24
24
|
License-File: COPYRIGHT
|
|
25
25
|
Requires-Dist: defusedxml
|
|
26
|
-
Requires-Dist: dissect.cstruct
|
|
27
|
-
Requires-Dist: dissect.util
|
|
28
|
-
Provides-Extra: dev
|
|
29
|
-
Requires-Dist: dissect.hypervisor[full] ; extra == 'dev'
|
|
30
|
-
Requires-Dist: dissect.cstruct <5.0.dev,>=4.0.dev ; extra == 'dev'
|
|
31
|
-
Requires-Dist: dissect.util <4.0.dev,>=3.0.dev ; extra == 'dev'
|
|
26
|
+
Requires-Dist: dissect.cstruct<5,>=4
|
|
27
|
+
Requires-Dist: dissect.util<4,>=3
|
|
32
28
|
Provides-Extra: full
|
|
33
|
-
Requires-Dist: pycryptodome
|
|
29
|
+
Requires-Dist: pycryptodome; extra == "full"
|
|
30
|
+
Provides-Extra: dev
|
|
31
|
+
Requires-Dist: dissect.hypervisor[full]; extra == "dev"
|
|
32
|
+
Requires-Dist: dissect.cstruct<5.0.dev,>=4.0.dev; extra == "dev"
|
|
33
|
+
Requires-Dist: dissect.util<4.0.dev,>=3.0.dev; extra == "dev"
|
|
34
34
|
|
|
35
35
|
# dissect.hypervisor
|
|
36
36
|
|
|
@@ -19,16 +19,16 @@ dissect/hypervisor/disk/qcow2.py,sha256=K4zstjte7SxX2psSbAj4YqwGeplfIvfbq5ScP4mz
|
|
|
19
19
|
dissect/hypervisor/disk/vdi.py,sha256=_kX7ZGOVo_98ckMaiaDEmw4VjNgM57cY4YUSYrk2JGs,1851
|
|
20
20
|
dissect/hypervisor/disk/vhd.py,sha256=OqSdEO2NGMI5DjgxWFbtZp8bPjSon7moMJn_5152MbI,3660
|
|
21
21
|
dissect/hypervisor/disk/vhdx.py,sha256=FVGTY5mUKFb7oRNKNiLGd5ngGfaGvERtFCGhAlyZD_k,12631
|
|
22
|
-
dissect/hypervisor/disk/vmdk.py,sha256=
|
|
22
|
+
dissect/hypervisor/disk/vmdk.py,sha256=CNA2zCWZYKl6G3jWF23_ToJCqHkPR_GngtAH5rGWY30,19298
|
|
23
23
|
dissect/hypervisor/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
24
24
|
dissect/hypervisor/tools/envelope.py,sha256=6_RLtKmFnZ69fx8HlvFgsjDjNrfnXD73dgszpG1mYQE,967
|
|
25
25
|
dissect/hypervisor/util/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
26
26
|
dissect/hypervisor/util/envelope.py,sha256=6nEJfgsxj696qxaLOQ2k5MrVWA2uLkbB5zxxRAvboF4,10405
|
|
27
27
|
dissect/hypervisor/util/vmtar.py,sha256=oNJ-qTvQVOl7al_vExpg_T4LnGyE72O9hjOmQBiTKSA,1469
|
|
28
|
-
dissect.hypervisor-3.
|
|
29
|
-
dissect.hypervisor-3.
|
|
30
|
-
dissect.hypervisor-3.
|
|
31
|
-
dissect.hypervisor-3.
|
|
32
|
-
dissect.hypervisor-3.
|
|
33
|
-
dissect.hypervisor-3.
|
|
34
|
-
dissect.hypervisor-3.
|
|
28
|
+
dissect.hypervisor-3.17.dev1.dist-info/COPYRIGHT,sha256=EOOoIwk_inOMUD4c1ylpzMtYLjGzmc-MLEVAEdLLr20,305
|
|
29
|
+
dissect.hypervisor-3.17.dev1.dist-info/LICENSE,sha256=DZak_2itbUtvHzD3E7GNUYSRK6jdOJ-GqncQ2weavLA,34523
|
|
30
|
+
dissect.hypervisor-3.17.dev1.dist-info/METADATA,sha256=eNMw0l3Ej2zgY_n-4RvjtpkMdopxd598cH04W6KvlTw,3412
|
|
31
|
+
dissect.hypervisor-3.17.dev1.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
|
|
32
|
+
dissect.hypervisor-3.17.dev1.dist-info/entry_points.txt,sha256=oM21bFD0YBHKjgCBk-DQ2398PUZdKV2VNR_IWzd1yog,76
|
|
33
|
+
dissect.hypervisor-3.17.dev1.dist-info/top_level.txt,sha256=Mn-CQzEYsAbkxrUI0TnplHuXnGVKzxpDw_po_sXpvv4,8
|
|
34
|
+
dissect.hypervisor-3.17.dev1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
{dissect.hypervisor-3.16.dev3.dist-info → dissect.hypervisor-3.17.dev1.dist-info}/entry_points.txt
RENAMED
|
File without changes
|
{dissect.hypervisor-3.16.dev3.dist-info → dissect.hypervisor-3.17.dev1.dist-info}/top_level.txt
RENAMED
|
File without changes
|