dissect.cobaltstrike.xordecode ============================== .. py:module:: dissect.cobaltstrike.xordecode .. autoapi-nested-parse:: This module is responsible for decoding XorEncoded Cobalt Strike payloads. Not to be confused with the single byte XOR key that is used to obfuscate the beacon configuration block. Attributes ---------- .. autoapisummary:: dissect.cobaltstrike.xordecode.logger Classes ------- .. autoapisummary:: dissect.cobaltstrike.xordecode.XorEncodedFile Functions --------- .. autoapisummary:: dissect.cobaltstrike.xordecode.iter_nonce_offsets dissect.cobaltstrike.xordecode.main Module Contents --------------- .. py:data:: logger .. py:function:: iter_nonce_offsets(fh: BinaryIO, real_size: int = None, maxrange: int = 1024) -> Iterator[int] Returns a generator that yields nonce offset candidates based on encoded real_size. If real_size is None it will automatically determine the size from fh. It tries to find the `nonce offset` using the following structure. ``| nonce (dword) | encoded_size (dword) | encoded MZ + payload |`` Side effects: file handle position due to seeking :param fh: file like object :param real_size: encoded_size to search for, or automatically determined from fh if None. :param maxrange: maximum range to search for :Yields: nonce_offset candidates .. py:class:: XorEncodedFile(fh: BinaryIO, nonce_offset: int = 0) Bases: :py:obj:`io.RawIOBase` A file object providing transparent decoding of XorEncoded files. To verify if a file is a XorEncoded Beacon, use the :meth:`XorEncodedFile.from_file()` constructor which raises ``ValueError`` if it cannot find a nonce candidate or valid MZ header. To skip any validation checks, construct via :meth:`XorEncodedFile` using `nonce_offset`. .. py:attribute:: EOF_SHELLCODE_MARKER :value: b'\xff\xff\xff' .. py:attribute:: fh .. py:attribute:: nonce_offset :value: 0 .. py:attribute:: initial_nonce .. py:attribute:: nonced_filesize .. py:method:: __repr__() -> str Return repr(self). .. py:method:: from_file(fh: BinaryIO, maxrange: int = 1024) -> XorEncodedFile :classmethod: Constructs a XorEncodedFile from file `fh`, raises ValueError if file not determined as a XorEncoded Beacon. This constructor will try to find the correct ``nonce_offset`` by using the following methods: - **end of shellcode offset**: will try to find the end of the shellcode stub. - **real_size**: using :func:`iter_nonce_offsets()` to find candidate offsets based on size. The ``nonce_offset`` candidates are then checked to see if there is a valid MZ header. :param fh: file-like object :param maxrange: how far into the file should be try to find the `nonce_offset` candidates (default 1024) :returns: XorEncodedFile instance :raises ValueError: If it cannot find a `nonce_offset` or valid `MZ header` .. py:method:: from_path(path: Union[str, os.PathLike], maxrange: int = 1024) -> XorEncodedFile :classmethod: Constructs a :class:`XorEncodedFile` from path `path`. This is more of a convenience method as it calls :meth:`XorEncodedFile.from_file` under the hood. :param path: path or path-like to xorencoded file :param maxrange: how far into the file should be try to find the `nonce_offset` candidates (default 1024) :returns: XorEncodedFile instance :raises ValueError: If it cannot find a `nonce_offset` or valid `MZ header` .. py:method:: read_nonce() Return nonce for current file position or 0 if it cannot be read .. py:method:: tell() Return current stream position. .. py:method:: seek(offset, whence=io.SEEK_SET) Change stream position. Change the stream position to the given byte offset. The offset is interpreted relative to the position indicated by whence. Values for whence are: * 0 -- start of stream (the default); offset should be zero or positive * 1 -- current stream position; offset may be negative * 2 -- end of stream; offset is usually negative Return the new absolute position. .. py:method:: read(n=-1) .. py:function:: main() Entrypoint for :doc:`/tools/beacon-xordecode`