diff --git a/dissect/hypervisor/disk/vmdk.py b/dissect/hypervisor/disk/vmdk.py index 5f88a23..173da8a 100644 --- a/dissect/hypervisor/disk/vmdk.py +++ b/dissect/hypervisor/disk/vmdk.py @@ -54,7 +54,7 @@ def __init__(self, fh: BinaryIO | Path | str | list[BinaryIO | Path | str]): if magic == b"# Di" and len(fhs) == 1: # Try reading the disk files from this descriptor # Otherwise we assume that the other file handles are the appropriate disks - self.descriptor = DiskDescriptor.parse(fh.read().decode()) + self.descriptor = DiskDescriptor.parse_bytes(fh.read()) if self.descriptor.attr["parentCID"] != "ffffffff": self.parent = open_parent(path.parent, self.descriptor.attr["parentFileNameHint"]) @@ -175,7 +175,7 @@ def __init__( if self.header.descriptor_size > 0: fh.seek(self.header.descriptor_offset * SECTOR_SIZE) descriptor_buf = fh.read(self.header.descriptor_size * SECTOR_SIZE) - self.descriptor = DiskDescriptor.parse(descriptor_buf.split(b"\x00", 1)[0].decode()) + self.descriptor = DiskDescriptor.parse_bytes(descriptor_buf.split(b"\x00", 1)[0]) elif self.header.magic == COWD_MAGIC: self._grain_directory_size = self.header.num_grain_directory_entries @@ -453,6 +453,16 @@ def __init__( self.sectors = sectors self.raw = raw_config + @classmethod + def parse_bytes(cls, vmdk_config: bytes) -> DiskDescriptor: + descriptor = cls.parse(vmdk_config.decode(errors="replace")) + if encoding := descriptor.attr.get("encoding"): + try: + descriptor = cls.parse(vmdk_config.decode(encoding)) + except (LookupError, UnicodeDecodeError): + pass + return descriptor + @classmethod def parse(cls, vmdk_config: str) -> DiskDescriptor: """Return :class:`DiskDescriptor` based on the provided ``vmdk_config``. diff --git a/tests/disk/test_vmdk.py b/tests/disk/test_vmdk.py index 269aad9..017a8d7 100644 --- a/tests/disk/test_vmdk.py +++ b/tests/disk/test_vmdk.py @@ -30,6 +30,27 @@ def test_vmdk_sesparse() -> None: assert vmdk.read(0x1000000) == b"a" * 0x1000000 +def test_vmdk_descriptor_declared_encoding(tmp_path: Path) -> None: + extent_name = "CentOS 64 副本-flat.vmdk" + descriptor_path = tmp_path / "disk.vmdk" + (tmp_path / extent_name).write_bytes(b"\x00" * 512) + descriptor_path.write_bytes( + ( + "# Disk DescriptorFile\n" + "version=1\n" + 'encoding="GBK"\n' + "CID=369b13fd\n" + "parentCID=ffffffff\n" + f'RW 1 FLAT "{extent_name}" 0\n' + ).encode("gbk") + ) + + vmdk = VMDK(descriptor_path) + + assert vmdk.descriptor.extents[0].filename == extent_name + assert vmdk.size == 512 + + @pytest.mark.parametrize( ("extent_description", "expected_extents"), [