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:
- The
EnvSecretvalue is hashed with SHA-256 and stored in the payload configuration. - The rest of the configuration is encrypted with AES using
<EnvSecret>_as the key.
During payload execution:
- The payload iterates over all environment variable names and values, hashing each with SHA-256.
- Each hash is compared against the stored hash in the configuration.
- If a match is found, the configuration is decrypted using
<EnvSecret>_as the key and execution continues. - 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:
At runtime, the decoding stub will:
- Add
0x11to each byte - XOR each byte with
111 - Subtract
0x22from 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:
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.