dissect.cobaltstrike.xordecode

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.

Module Contents

Classes

XorEncodedFile

A file object providing transparent decoding of XorEncoded files.

Functions

iter_nonce_offsets(→ Iterator[int])

Returns a generator that yields nonce offset candidates based on encoded real_size.

main()

Entrypoint for beacon-xordecode

Attributes

logger

dissect.cobaltstrike.xordecode.logger[source]
dissect.cobaltstrike.xordecode.iter_nonce_offsets(fh: BinaryIO, real_size: int = None, maxrange: int = 1024) Iterator[int][source]

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

Parameters:
  • fh – file like object

  • real_size – encoded_size to search for, or automatically determined from fh if None.

  • maxrange – maximum range to search for

Yields:

nonce_offset candidates

class dissect.cobaltstrike.xordecode.XorEncodedFile(fh: BinaryIO, nonce_offset: int = 0)[source]

Bases: io.RawIOBase

A file object providing transparent decoding of XorEncoded files.

To verify if a file is a XorEncoded Beacon, use the 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 XorEncodedFile() using nonce_offset.

EOF_SHELLCODE_MARKER = b'\xff\xff\xff'[source]
__repr__() str[source]

Return repr(self).

classmethod from_file(fh: BinaryIO, maxrange: int = 1024) XorEncodedFile[source]

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 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.

Parameters:
  • fh – file-like object

  • 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

classmethod from_path(path: str | os.PathLike, maxrange: int = 1024) XorEncodedFile[source]

Constructs a XorEncodedFile from path path.

This is more of a convenience method as it calls XorEncodedFile.from_file() under the hood.

Parameters:
  • path – path or path-like to xorencoded file

  • 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

read_nonce()[source]

Return nonce for current file position or 0 if it cannot be read

tell()[source]

Return current stream position.

seek(offset, whence=io.SEEK_SET)[source]

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.

read(n=-1)[source]
dissect.cobaltstrike.xordecode.main()[source]

Entrypoint for beacon-xordecode