Containers#

Containers in dissect.target are the abstraction layer for anything that looks (or should look) like a raw disk. For example, VMware VMDK or Microsoft Hyper-V VHD(X) files may be custom file formats, but in the end these are merely containers of the raw disk(s) inside.

The container abstraction layer in dissect.target makes working with these different disk containers easy. Once opened, all containers behave as a binary file-like object. This means that there’s no special API for working with containers, if you know how to read from a file in Python, you’ll know how to read from a container.

See also

To see how to open a container in Python, continue reading here.

View all available container implementations at dissect.target.containers.

Writing your own#

There are a few methods of using your own container implementation in dissect.target:

  • Specify the path to your implementation(s) using the DISSECT_PLUGINS environment variable.

  • Specify the path to your implementation(s) using the --plugin-path argument with the various Dissect Tools.

  • Add a new implementation in the dissect.target source tree at dissect/target/containers.

The last method requires you to have a source checkout and working development setup of dissect.target. This is the recommended method if you intend to contribute your container back to the project.

See also

Read more about using your own modules in dissect.target at Loading your own modules.

Interested in developing for Dissect? Read more at Developing for Dissect.

Regardless of which method you use, you can use the boilerplate below. Do keep in mind that the final line is only required if you’re using either of the DISSECT_PLUGINS or --plugin-path options!

import io
from pathlib import Path
from typing import BinaryIO, Union

from dissect.target.container import Container, register


class MyContainer(Container):
    def __init__(self, fh: Union[BinaryIO, Path], *args, **kwargs):
        # Do your initialization here, for example, initialize a parser:
        # self.vmdk = VMDK(fh)
        # Call ``super().__init__`` with the original file-like object(s) and the container size
        super().__init__(fh, size, *args, **kwargs)

    @staticmethod
    def detect_fh(fh: BinaryIO, original: Union[list, BinaryIO]) -> bool:
        # Perform detection for your container from a binary file-like object here
        # For example, check a specific magic header value
        raise NotImplementedError()

    @staticmethod
    def detect_path(path: Path, original: Union[list, BinaryIO]) -> bool:
        # Perform detection for your container from a Path object here
        # For example, check a specific file extension
        raise NotImplementedError()

    def read(self, length: int) -> bytes:
        # Perform a file read for ``length`` amount of bytes
        raise NotImplementedError()

    def seek(self, offset: int, whence: int = io.SEEK_SET) -> int:
        # Perform a file seek here
        raise NotImplementedError()

    def tell(self) -> int:
        # Perform a file tell here
        raise NotImplementedError()

    def close(self) -> None:
        # Perform any close actions here
        pass


# This line is necessary if your container is outside the ``dissect.target`` source tree!
register(__name__, MyContainer.__name__, internal=False)

See also

You can refer to the API documentation of the Container class for more documentation on the methods referenced here.

If you are placing your implementation in the dissect.target source tree, you’ll need to register your implementation. Do this by opening dissect/target/container.py and add your implementation to the bottom by using register():

register("mycontainer", "MyContainer")