Skip to content

Commercial payload

The commercial payload is the full-featured Windows agent, supporting both x64 and x86 architectures. It covers all common payload types - debug executable, executable, service, DLL, and shellcode - with significantly more configuration options than the open-source payload.

Plugin ID: shelldot.payload.commercial

Template ID (x64): shelldot.payload.commercial-windows-x64

Template ID (x86): shelldot.payload.commercial-windows-x86

Supported types: DEBUG_EXECUTABLE, EXECUTABLE, SERVICE, DLL, SHELLCODE

Configuration

Use the table below to customize how the Commercial Payload behaves. Some attributes apply universally; others come into play only when certain methods or payload types are selected.

Attribute Explanation
type The payload type. Options: DEBUG_EXECUTABLE, EXECUTABLE, SERVICE, DLL, SHELLCODE.
confLocation Where the payload's configuration is stored. Options: Resource, Appended.
dllInternalName For DLL-type payloads, this value appears in the export table header (under filename).
dllMethodName The exported method name used by DLL-type payloads.
paddingSize Number of bytes of NULL-padding appended to the payload. Useful for inflating file size to bypass size-based heuristics.
randomnessSeed Seed for random actions used in obfuscation. A fixed seed produces reproducible builds; leave at 0 for random.
startupNopOperationCount Number of random no-op actions performed at startup. These are not literal CPU NOP instructions but functionally equivalent operations that add junk execution before the real payload logic runs.
startupAmsiBypassMethod AMSI bypass method applied at startup. Options: None, PatchAmsiScanBuffer, PatchAmsiScanBufferDelayedThreaded, HwBreakpoint.
startupEtwBypassMethod ETW bypass method applied at startup. Options: None, PatchEtwEventWrite, PatchEtwEventWriteDelayedThreaded, HwBreakpoint.
initialWait Seconds to wait after startup before launching the main payload code.
sleepMethod Method used for sleep intervals between callbacks. Options: Sleep, StdSleep, WaitableTimer, WaitForEvent.
rweSectionSize Size of the executable section where shellcodes and BOF files are loaded. The agent reuses this section as long as the content fits.
notUseDotNetLoader By default, the payload uses a COM-based .NET execution method when it detects .NET shellcode. Set to true to disable this and use the standard loader instead.
unloadAppDomain Attempts to unload the AppDomain after .NET execution. Can be unstable in some scenarios - test before operational use.
disableAmsiBypassInShellcodes Disables the automatic AMSI bypass applied inside shellcode when running in the agent's own process.
importTableRandomizationSeed Controls Import Address Table (IAT) randomization. Default 0 produces a fully random IAT on each generation. A fixed seed produces identical IAT layouts across builds.
customTemplate Filename, relative path, or URL to a custom agent template used during payload generation.
mutex A string-based mutex that prevents the payload from launching multiple concurrent instances with the same mutex value on the same machine.
autoDestructDate ISO-8601 timestamp after which the agent will terminate itself automatically.
obfuscationType Obfuscation strategy applied to the payload binary. Options: NONE, LIGHT_OBFUSCATION, SINGLE_NOP, GARBAGE_CODE.
obfuscationSeed Seed for the obfuscation randomization. A fixed seed produces reproducible obfuscated builds; leave at 0 for random.
shellcodeDecodingLogic Custom encoding/decoding logic applied to shellcode before it is placed into RWE memory. The decoding stub is automatically prepended. See shellcodeDecodingLogic below.
guardrails[ ] Conditions that must be met before the payload starts execution.
  ↳ type Guardrail type. Options: DomainExists, DomainNotExists, TimeBefore, TimeAfter, EnvSecret. See EnvSecret below.
  ↳ value Value for the guardrail. For DomainExists/DomainNotExists: a hostname. For TimeBefore/TimeAfter: an ISO-8601 timestamp. For EnvSecret: see below.
execTypeSelf Settings for allocating and executing shellcode in the agent's own process.
  ↳ allocMethod Memory allocation method. Options: VirtualAlloc, VirtualAllocNuma, NtAllocateVirtualMemory, NtAllocateMapView, NtAllocateDllMap.
  ↳ allocOnOtherThread Perform the allocation on a separate thread.
  ↳ dllName DLL to map when using NtAllocateDllMap as the allocation method.
  ↳ dripAlloc Allocate memory page-by-page instead of in a single call.
  ↳ dripProtectRwRwe When drip allocating, set each page to RWE individually.
  ↳ drippingSize Size in bytes of each chunk when drip-writing shellcode into memory.
  ↳ execMethod Execution method. Currently only Direct is available (jumps to shellcode directly with no intermediate API call).
  ↳ protectOnOtherThread Change memory protection on a separate thread.
  ↳ protectRwRwe Allocate as RW first, then switch to RWE just before execution.
  ↳ shellcodeEncoding Number of times shellcode is recursively encoded and prefixed with a decoding stub.
  ↳ shellcodePadding Bytes of no-op padding prepended to the shellcode (not literal NOP instructions, but functionally inert).
  ↳ sleepBetweenAllocExec Milliseconds to sleep between allocation and execution.
  ↳ sleepBetweenAllocProtect Milliseconds to sleep between allocation and protection change.
  ↳ sleepBetweenAllocWrite Milliseconds to sleep between allocation and writing shellcode.
  ↳ sleepBetweenDrippings Milliseconds to sleep between drip-write chunks.
  ↳ writeOnOtherThread Write shellcode to memory on a separate thread.
execTypeNew Settings for allocating and executing shellcode in a newly spawned process.
  ↳ allocMethod Memory allocation method. Options: VirtualAlloc, VirtualAllocNuma, NtAllocateMapView, NtAllocateVirtualMemory.
  ↳ allocOnOtherThread Perform the allocation on a separate thread.
  ↳ dripAlloc Allocate memory page-by-page instead of in a single call.
  ↳ dripProtectRwRwe When drip allocating, set each page to RWE individually.
  ↳ drippingSize Size in bytes of each chunk when drip-writing shellcode into memory.
  ↳ execMethod Execution method. Options: CreateThreadEx, NtCreateThreadEx, RtlCreateUserThread.
  ↳ protectOnOtherThread Change memory protection on a separate thread.
  ↳ protectRwRwe Allocate as RW first, then switch to RWE just before execution.
  ↳ shellcodeEncoding Number of times shellcode is recursively encoded and prefixed with a decoding stub.
  ↳ shellcodePadding Bytes of no-op padding prepended to the shellcode (not literal NOP instructions, but functionally inert).
  ↳ sleepBetweenAllocExec Milliseconds to sleep between allocation and execution.
  ↳ sleepBetweenAllocProtect Milliseconds to sleep between allocation and protection change.
  ↳ sleepBetweenAllocWrite Milliseconds to sleep between allocation and writing shellcode.
  ↳ sleepBetweenDrippings Milliseconds to sleep between drip-write chunks.
  ↳ writeOnOtherThread Write shellcode to memory on a separate thread.
execTypeExisting Settings for allocating and executing shellcode in an existing remote process.
  ↳ allocMethod Memory allocation method. Options: VirtualAlloc, VirtualAllocNuma, NtAllocateMapView, NtAllocateVirtualMemory.
  ↳ allocOnOtherThread Perform the allocation on a separate thread.
  ↳ dripAlloc Allocate memory page-by-page instead of in a single call.
  ↳ dripProtectRwRwe When drip allocating, set each page to RWE individually.
  ↳ drippingSize Size in bytes of each chunk when drip-writing shellcode into memory.
  ↳ execMethod Execution method. Options: CreateThreadEx, NtCreateThreadEx, RtlCreateUserThread.
  ↳ protectOnOtherThread Change memory protection on a separate thread.
  ↳ protectRwRwe Allocate as RW first, then switch to RWE just before execution.
  ↳ shellcodeEncoding Number of times shellcode is recursively encoded and prefixed with a decoding stub.
  ↳ shellcodePadding Bytes of no-op padding prepended to the shellcode (not literal NOP instructions, but functionally inert).
  ↳ sleepBetweenAllocExec Milliseconds to sleep between allocation and execution.
  ↳ sleepBetweenAllocProtect Milliseconds to sleep between allocation and protection change.
  ↳ sleepBetweenAllocWrite Milliseconds to sleep between allocation and writing shellcode.
  ↳ sleepBetweenDrippings Milliseconds to sleep between drip-write chunks.
  ↳ writeOnOtherThread Write shellcode to memory on a separate thread.

Guardrail: EnvSecret

The EnvSecret guardrail locks agent execution to a specific environment by tying the configuration encryption to an environment variable present on the target machine.

During payload generation:

  1. The EnvSecret value is hashed with SHA-256 and stored in the payload configuration.
  2. The rest of the configuration is encrypted with AES using <EnvSecret>_ as the key.

During payload execution:

  1. The payload iterates over all environment variable names and values, hashing each with SHA-256.
  2. Each hash is compared against the stored hash in the configuration.
  3. If a match is found, the configuration is decrypted using <EnvSecret>_ as the key and execution continues.
  4. If no match is found, execution stops immediately.

Info

Because only the hash is stored in the payload, static analysis of the binary does not reveal which environment variable is required. An analyst would need to reverse the decoding logic to determine the expected value.


How shellcodeDecodingLogic works

The shellcodeDecodingLogic option defines a sequence of byte-level transformations applied to shellcode. At generation time, the shellcode is encoded using the inverse of these operations (applied in reverse order). At runtime, a decoding stub is prepended to the shellcode that applies the operations in forward order, restoring the original bytes before execution.

Available operations:

Operation Description
ADD(value) Adds value to each byte during decoding.
SUB(value) Subtracts value from each byte during decoding.
XOR(value) XORs each byte with value during decoding.
RAW(value) Inserts a raw byte directly into the decoding stub (not applied to shellcode bytes).

Values can be specified in decimal (e.g. 111) or hexadecimal (e.g. 0x6F) format.

Example 1 - simple multi-step encoding:

ADD(0x11) XOR(111) SUB(0x22)

At runtime, the decoding stub will:

  1. Add 0x11 to each byte
  2. XOR each byte with 111
  3. Subtract 0x22 from each byte

The shellcode is encoded in reverse order (SUB inverse, then XOR inverse, then ADD inverse) before being placed into RWE memory.

Example 2 - with raw byte insertion:

ADD(0x11) XOR(111) RAW(0x90) RAW(0x90) SUB(0x22)

Same as above, but two raw 0x90 bytes (NOP instructions) are inserted into the decoding stub between the XOR and SUB steps. These raw bytes become part of the stub’s instruction stream and can be used to alter the stub’s signature or alignment.

Tip

Combining multiple operations with different values produces a unique encoding per payload, making signature-based detection of the encoded shellcode significantly harder. The RAW() operation is useful for inserting junk bytes that change the decoding stub’s hash without affecting the decoded shellcode.