Concepts and Lifecycle
ExecUnits provide plugin-supplied command or listener behavior alongside the agent core. This page explains the responsibilities and lifetimes you need to distinguish when reading the platform and role-specific pages.
Separate the Main Concepts
An ExecUnit is the executable part of a plugin that runs on the agent side. Its role, binary format, execution context, and communication mechanism describe different aspects of the same component.
On the supported Portable Operating System Interface (POSIX) platforms, local communication uses named, first-in, first-out (FIFO) objects.
| Concept | Question it answers | Examples |
|---|---|---|
| Role | What responsibility does the component have? | Performing a command; providing a listener's transport behavior. |
| Artifact format | What kind of executable code does the agent receive? | A managed assembly, native library, or shellcode artifact. |
| Execution context | Where does that code run? | Within the agent process or, for supported Windows combinations, another process. |
| Local communication | How does the component exchange messages with the agent core? | A Windows named pipe, a pair of POSIX FIFOs, or a no-IPC strategy without a local channel. |
| External transport | How does listener traffic reach another endpoint? | The transport implemented by the selected listener. |
The differences between POSIX FIFOs and Windows named pipes are explained in Local Communication.
A role does not imply a format. Both commands and listeners can have multiple artifact variants. A format does not imply an execution context, and a context does not imply that every artifact is compatible with it. Use Formats and Compatibility for the supported combinations.
Payload Format and ExecUnit Format
The payload is the program or code that becomes the agent. An ExecUnit is a component the agent hosts. The payload's own packaging does not determine which ExecUnits it can accept: a native agent executable can host a different supported binary format.
Similarly, a native command and a native-library ExecUnit are different concepts. A native command is implemented inside the agent core. A native-library ExecUnit is separately supplied plugin code compiled to a platform library. The word native alone does not identify which of these you are discussing.
Native ExecUnit Callout ABI
For native-library ExecUnits, the loader calls a platform-specific, C-compatible entry point. The return type, calling convention, parameter types, and exported symbol are part of the ABI; a library with the wrong callout can load successfully and still fail when invoked.
| Platform | Loader-facing callout prototype | Export and local-channel contract |
|---|---|---|
| Windows | BOOL WINAPI(const char* connectString) |
The configured native-library export receives the one duplex named-pipe connection string. |
| Linux | void run(char* pipeNameRead, char* pipeNameWrite) |
The exported run callout receives the read and write FIFO paths. |
| FreeBSD | void run(char* pipeNameRead, char* pipeNameWrite) |
The exported run callout receives the read and write FIFO paths. |
| macOS | void run(char* pipeNameRead, char* pipeNameWrite) |
The source-level run callout is exported as the Mach-O symbol _run and receives the read and write FIFO paths. |
The default Windows native-DLL wrappers conventionally export extern "C" __declspec(dllexport) void start(const char* pipename). This wrapper convention is distinct from the commercial agent's configured native-method callout, whose BOOL WINAPI return type and calling convention must be preserved. On Linux and FreeBSD, start(std::string, std::string) may remain as an exported implementation helper, but the loader-facing callout is run(char*, char*); macOS export lists expose _run and keep _start hidden.
Responsibilities and Ownership
| Component | Responsibility |
|---|---|
| Command plugin on Command and Control (C2) | Interprets user input and command results, and supplies the command's agent-side component where required. |
| Agent core | Tracks commands and listeners, selects supported execution facilities, manages local communication, and owns command-result handling. |
| Command ExecUnit | Implements the task, interprets its task-specific configuration, and reports output and outcome. |
| Listener ExecUnit | Implements transport-specific behavior and exchanges listener messages with the core. |
| Listener plugin on C2 | Implements the corresponding server-side listener behavior. |
The core provides execution and communication facilities to both roles, but their message meanings and lifetimes differ. A listener-owned command remains a command even when it is distributed with a listener plugin. See Command ExecUnits and Listener ExecUnits.
Lifetimes and Outcomes
A command represents an invocation with an outcome. Its result data, error information, and completion state are separate concepts. A command can emit several pieces of output and still be finite; output arriving does not establish that the command has completed.
A listener represents an ongoing transport responsibility. It may handle many exchanges during its lifetime. A completed network exchange does not finish the listener, and a failed network exchange does not by itself establish that local communication with the core has failed.
The lifetime of executable code is also separate from the lifetime of its resources. Worker activity, communication handles, queued results, and transport connections can remain relevant after a task has stopped doing useful work. In a shared process, a problem in an ExecUnit can affect the hosting agent because they share process resources.
Info
Lifecycle descriptions express component responsibilities. They do not imply that every current platform or ExecUnit provides graceful cancellation, complete cleanup, or recovery after a disconnect. See Limitations and Diagnostics for the current boundaries.
Configuration and Protocol Boundaries
Host configuration describes the execution facilities used by an ExecUnit. Command-specific and listener-specific configuration describes the component's own behavior. Keep these responsibilities separate when interpreting configuration or investigating a failure.
Type-Length-Value (TLV) encoding is shared infrastructure; it does not make the command, listener, and C2 protocols interchangeable. Use the TLV reference for encoding, the command protocol for command messages, and the listener protocol for listener messages. These references own the detailed wire definitions.
Continue with your role's page, then the relevant Windows, Linux, FreeBSD, or macOS page. The Overview provides the complete reading order.