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.
type is the only required top-level property. All other top-level properties are optional;
their effective defaults are documented below. When an execTypeSelf, execTypeNew, or
execTypeExisting object is supplied, its allocMethod is required. When
peStructureElements is supplied, it must contain versionElements with all eleven string
properties shown in the table.
| Attribute | Explanation |
|---|---|
| type | The payload type. Options: DEBUG_EXECUTABLE, EXECUTABLE, SERVICE, DLL, SHELLCODE. |
| confLocation | Where the payload's configuration is stored. Options: Resource, Appended. Default: Resource. Appended is not valid for SHELLCODE payloads. |
| 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. Default: bob; an empty value also uses bob. |
| paddingSize | Number of bytes of NULL-padding appended to the payload. Default: 0 (no padding). |
| randomnessSeed | Seed for random actions used in obfuscation. Default 0 produces a random build; a nonzero fixed seed produces reproducible random actions. |
| startupNopOperationCount | Number of random no-op actions performed at startup. Default: 0. 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, PatchClrPtr. Default: None. |
| startupEtwBypassMethod | ETW bypass method applied at startup. Options: None, PatchEtwEventWrite, PatchEtwEventWriteDelayedThreaded, HwBreakpoint. Default: None. |
| initialWait | Seconds to wait after startup before launching the main payload code. Default: 0. |
| sleepMethod | Method used for sleep intervals between callbacks. Options: Sleep, StdSleep, WaitableTimer, WaitForEvent. Default: Sleep. |
| rweSectionSize | Size of the executable section where shellcodes and BOF files are loaded. By default the reusable section is disabled; set a positive size to enable it. |
| notUseDotNetLoader | Default: false. The payload normally 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 | Default: false. When enabled, attempts to unload the AppDomain after .NET execution. Can be unstable in some scenarios - test before operational use. |
| disableAmsiBypassInShellcodes | Default: true. Disables the automatic AMSI bypass applied inside shellcode when running in the agent's own process. Set to false to keep that automatic bypass enabled. |
| 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 | By default the built-in template is used. Supply a filename or relative path beneath this plugin's configured template directory, or a direct http: or https: URL. Local values require the plugin's custom-payload-template-dir setting. |
| certificateFile | At most one PE code-signing certificate file (.pfx / .p12) may be uploaded in a multipart/form-data request. It must be valid PKCS#12. When set, generated PE payloads are signed with this certificate. SHELLCODE output is not signed. |
| signingCertificatePassword | Password for the certificateFile. |
| signingTimestampProvider | Reachable URL of a trusted timestamping authority used when signing (e.g. http://timestamp.digicert.com). When omitted, the signature has no timestamp. |
| peStructureElements | Optional PE metadata block. If supplied, its versionElements object and every string field below are required. |
| ↳ versionElements.companyName | Company name embedded in the PE version info. |
| ↳ versionElements.fileDescription | File description embedded in the PE version info. |
| ↳ versionElements.fileVersion | File version string embedded in the PE version info. |
| ↳ versionElements.internalName | Internal name embedded in the PE version info. |
| ↳ versionElements.legalCopyright | Copyright notice embedded in the PE version info. |
| ↳ versionElements.legalTrademarks | Trademark notice embedded in the PE version info. |
| ↳ versionElements.originalFilename | Original filename embedded in the PE version info. |
| ↳ versionElements.privateBuild | Private build description embedded in the PE version info. |
| ↳ versionElements.productName | Product name embedded in the PE version info. |
| ↳ versionElements.productVersion | Product version string embedded in the PE version info. |
| ↳ versionElements.specialBuild | Special build description embedded in the PE version info. |
| execUnitTypeOrder | Ordered list of up to four ExecUnit formats the agent advertises as preferred for self-process command execution. Entries can be DOTNET_EXE, DOTNET_DLL, NATIVE_LIB, or SHELLCODE_NATIVE. Default: [DOTNET_EXE, DOTNET_DLL, NATIVE_LIB, SHELLCODE_NATIVE]. |
| pipenameTemplate | Template string for naming the internal named pipes used during command and listener communication, can use same templates as HTTP listener filename. When omitted, a random name is generated. |
| mutex | Optional string-based mutex that prevents the payload from launching multiple concurrent instances with the same mutex value on the same machine. Default: not set. |
| autoDestructDate | ISO-8601 timestamp after which the agent will terminate itself automatically. Default: not set. |
| obfuscationType | Obfuscation strategy applied to the payload binary. Options: NONE, LIGHT_OBFUSCATION, SINGLE_NOP, GARBAGE_CODE. Default: NONE. |
| obfuscationSeed | Used only when obfuscationType is GARBAGE_CODE. Default 0 produces random garbage code; a nonzero fixed seed makes it reproducible. It has no effect with the other obfuscation types. |
| embeddedListener | Optional embedded listener generated into the payload. Options: NONE, HTTP. Default: NONE (no embedded listener). |
| shellcodeDecodingLogic | Custom encoding/decoding logic for SHELLCODE output. It is validated and applied only when type is SHELLCODE; it is ignored for other output types. The decoding stub is automatically prepended. See shellcodeDecodingLogic below. |
| guardrails[ ] | Conditions that must be met before the payload starts execution. Default: empty. At most one guardrail may use EnvSecret. |
| ↳ 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 | Optional settings for allocating and executing shellcode in the agent's own process. If supplied, allocMethod is required. |
| ↳ allocMethod | Required in execTypeSelf. 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 | Optional settings for allocating and executing shellcode in a newly spawned process. If supplied, allocMethod is required. |
| ↳ allocMethod | Required in execTypeNew. 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 | Optional settings for allocating and executing shellcode in an existing remote process. If supplied, allocMethod is required. |
| ↳ allocMethod | Required in execTypeExisting. 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. A payload can contain at most one EnvSecret guardrail. The configured value is normalized to lowercase before the server derives the stored hash and encryption key. Use a non-empty value: empty value leaves the hash unset and the configuration unencrypted, so the guardrail is ineffective.
During payload generation:
- The UTF-16LE encoding of the lowercase
EnvSecretvalue is hashed with SHA-256 and stored in the payload configuration. - The server appends
_to the lowercase value, encodes that string as UTF-16LE, hashes it with SHA-256, and uses the resulting 256-bit digest as the AES key for the rest of the configuration.
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 agent derives the same SHA-256 AES key from the matched lowercase value plus
_, then decrypts the configuration and continues execution. - 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 operations for
SHELLCODE output. During generation, the named operations transform the shellcode in reverse
expression order. The generated runtime stub then applies each operation's inverse in forward
expression order, restoring the original bytes before execution.
Available operations:
| Operation | Description |
|---|---|
ADD(value) |
Generation adds value; the runtime decoder subtracts it. |
SUB(value) |
Generation subtracts value; the runtime decoder adds it. |
XOR(value) |
Generation and the runtime decoder XOR each byte with value. |
RAW(value) |
Inserts a raw byte directly into the runtime decoding stub and does not transform shellcode bytes. |
Operator names are case-sensitive and must be uppercase. Spaces are ignored. Values can be
decimal or hexadecimal and must be between -128 and 255, inclusive; for example, 111 and
0x6F represent the same byte value.
Example 1 - simple multi-step encoding:
During generation, the shellcode is transformed from the last expression to the first:
- Subtract
0x22from each byte. - XOR each byte with
111. - Add
0x11to each byte.
At runtime, the decoder follows the expression from left to right using inverse operations:
- Subtract
0x11from each byte. - XOR each byte with
111. - Add
0x22to each byte.
Example 2 - with raw byte insertion:
Same as above, but two raw 0x90 bytes (NOP instructions) are inserted into the runtime
decoding stub between the XOR and final ADD decoder 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.