Shellcode Development (Windows/Linux/macOS)
Build shellcode as a constrained engineering problem: small PIC code, strict ABI behavior, reliable memory transitions, and reproducible test loops.
This skill is for implementation and validation workflow. It is not a vulnerability discovery skill.
When to activate
- Writing or reviewing shellcode/stagers in ASM/C/Python pipelines
- Building cross-platform syscall-based payloads (Windows/Linux/macOS)
- Porting payloads between
x86_64 and arm64
- Handling bad-byte restrictions with encoder/decoder stages
- Implementing reflective/manual in-memory loading workflows
- Debugging crashes caused by calling-convention or stack-alignment mistakes
- Verifying payload behavior with emulator/disassembler tooling before runtime tests
If the task is specifically about BOFs, prefer bof/c-bof or bof/cpp-bof first. If it is specifically about stack masquerade or syscall gates, combine with offensive-coding/stack-spoofing or offensive-coding/indirect-syscall.
Core workflow
Define execution contract first
- Target OS + architecture + entry assumptions
- Available registers, expected stack alignment, bad-byte set, max size
- Whether network/file APIs are allowed or syscall-only is required
Pick payload shape
- Single-stage (small, immediate execution)
- Two-stage (tiny bootstrap + streamed body)
- Reflective/in-memory loader path (PE/ELF/Mach-O aware)
Implement ABI-correct stub
- Preserve required non-volatiles
- Maintain alignment guarantees
- Use position-independent data access only
Validate in three layers
- Static: disassembly and byte checks
- Emulation: deterministic instruction/memory behavior
- Runtime: target OS debugger + telemetry sanity
Harden incrementally
- Add only required obfuscation/encoding
- Re-test after each hardening change
- Keep a plain debug build to avoid blind debugging
Platform rules that break payloads most often
Windows x64
- Respect Microsoft x64 ABI and shadow space requirements.
- Syscall path expects
mov r10, rcx before syscall.
- If using indirect syscalls, source
syscall;ret from a clean ntdll gadget and keep SSN resolution runtime-based.
- Reflective loading must correctly parse PE exports/imports/relocations and section permissions.
Linux x64/aarch64
mmap/mprotect transitions are part of payload lifecycle; test all return paths.
- For x64 syscalls, syscall number/arg placement must match kernel ABI (
rax + rdi/rsi/rdx/r10/r8/r9).
- For aarch64 syscalls, use
x8 for syscall number and x0-x5 for args.
- Avoid assuming vDSO location or fixed helper addresses.
macOS x64/arm64
- Syscall tables and calling details differ from Linux; validate against XNU sources/current targets.
- Treat Mach-O and dyld assumptions as version-sensitive.
- arm64 stack alignment and calling convention errors fail fast; emulate and runtime-test both.
Encoder and polymorphism guidance
- Use encoding to satisfy transport/bad-byte constraints, not as a default.
- Keep decoder stubs minimal and architecture-appropriate.
- Polymorphism/metamorphism increases implementation risk and detection surface if overused.
- Prefer deterministic transforms you can regression-test over “clever” mutation logic.
- Map evasion assumptions to ATT&CK-style behavior expectations and verify with runtime telemetry.
Python/C integration pattern
- Use Python (pwntools/Keystone/Capstone/Unicorn) for generation, assembly, disassembly, and emulation harnesses.
- Use C/C++ (or Rust/Go) wrappers for runtime loaders/injectors and platform APIs.
- Keep shellcode bytes and loader logic separable so you can swap payload versions quickly.
- Always retain one end-to-end harness that runs:
generate -> inspect -> emulate -> execute test.
Quality gates before shipping
- Byte-level constraints pass (
badchars, size, null/newline policy)
- Stack/register invariants verified at entry/exit
- Memory permissions transitions are reversible and error-checked
- No hardcoded OS-build-specific syscall numbers unless explicitly pinned for research
- At least one emulator run and one real runtime debug pass on target architecture
- Crash artifacts and logs are reproducible with the same payload bytes
Resources
- references/platform-workflows.md — concrete Windows/Linux/macOS build and validation flows, including syscall and memory-transition checkpoints
- references/tooling-and-labs.md — practical usage of pwntools, Capstone, Keystone, Unicorn, debugger loops, and test harness patterns
- references/encoders-and-stagers.md — staged payload patterns, bad-byte encoders, polymorphism trade-offs, and failure modes
- references/evasion-patterns-from-projects.md — transferable shellcode-dev engineering patterns from real implementations (runtime SSN mapping, recycled syscall gates, DESYNC readiness checks, sleep masking pipelines, CFG-aware gadget handling)
- references/loader-core-qualification.md — load when qualifying, porting, or reviewing a raw PIC loader core (extracted
.text/.rdata) or its wrapper: defect taxonomy (thunk-slot placement, SSE/section alignment, decode-cursor vs ABI conflation, kernel-dependent paths), crash-signature triage on Windows, and the per-backend gate recipe
- Upstream methodology:
offensive-techniques/binary-exploitation-technique (where shellcode fits in the chain) and offensive-ctf/pwn-ctf/references/shellcode-filtering.md (byte-blacklist recipes).
- Start with
references/platform-workflows.md; wrong platform assumptions break payloads faster than bad-byte or evasion mistakes.
1---2name: shellcode-dev3description: Auth/lab dev: shellcode-format engineering; PIC, ABI, syscalls, encoders, memory permissions, reflective-loader labs, emulator validation.4license: MIT5---67# Shellcode Development (Windows/Linux/macOS)89Build shellcode as a constrained engineering problem: small PIC code, strict ABI behavior, reliable memory transitions, and reproducible test loops.1011This skill is for **implementation and validation workflow**. It is not a vulnerability discovery skill.1213## When to activate1415- Writing or reviewing shellcode/stagers in ASM/C/Python pipelines16- Building cross-platform syscall-based payloads (Windows/Linux/macOS)17- Porting payloads between `x86_64` and `arm64`18- Handling bad-byte restrictions with encoder/decoder stages19- Implementing reflective/manual in-memory loading workflows20- Debugging crashes caused by calling-convention or stack-alignment mistakes21- Verifying payload behavior with emulator/disassembler tooling before runtime tests2223If the task is specifically about BOFs, prefer `bof/c-bof` or `bof/cpp-bof` first. If it is specifically about stack masquerade or syscall gates, combine with `offensive-coding/stack-spoofing` or `offensive-coding/indirect-syscall`.2425---2627## Core workflow28291. **Define execution contract first**30 - Target OS + architecture + entry assumptions31 - Available registers, expected stack alignment, bad-byte set, max size32 - Whether network/file APIs are allowed or syscall-only is required33342. **Pick payload shape**35 - Single-stage (small, immediate execution)36 - Two-stage (tiny bootstrap + streamed body)37 - Reflective/in-memory loader path (PE/ELF/Mach-O aware)38393. **Implement ABI-correct stub**40 - Preserve required non-volatiles41 - Maintain alignment guarantees42 - Use position-independent data access only43444. **Validate in three layers**45 - Static: disassembly and byte checks46 - Emulation: deterministic instruction/memory behavior47 - Runtime: target OS debugger + telemetry sanity48495. **Harden incrementally**50 - Add only required obfuscation/encoding51 - Re-test after each hardening change52 - Keep a plain debug build to avoid blind debugging5354---5556## Platform rules that break payloads most often5758### Windows x645960- Respect Microsoft x64 ABI and shadow space requirements.61- Syscall path expects `mov r10, rcx` before `syscall`.62- If using indirect syscalls, source `syscall;ret` from a clean `ntdll` gadget and keep SSN resolution runtime-based.63- Reflective loading must correctly parse PE exports/imports/relocations and section permissions.6465### Linux x64/aarch646667- `mmap`/`mprotect` transitions are part of payload lifecycle; test all return paths.68- For x64 syscalls, syscall number/arg placement must match kernel ABI (`rax` + `rdi/rsi/rdx/r10/r8/r9`).69- For aarch64 syscalls, use `x8` for syscall number and `x0-x5` for args.70- Avoid assuming vDSO location or fixed helper addresses.7172### macOS x64/arm647374- Syscall tables and calling details differ from Linux; validate against XNU sources/current targets.75- Treat Mach-O and dyld assumptions as version-sensitive.76- arm64 stack alignment and calling convention errors fail fast; emulate and runtime-test both.7778---7980## Encoder and polymorphism guidance8182- Use encoding to satisfy transport/bad-byte constraints, not as a default.83- Keep decoder stubs minimal and architecture-appropriate.84- Polymorphism/metamorphism increases implementation risk and detection surface if overused.85- Prefer deterministic transforms you can regression-test over “clever” mutation logic.86- Map evasion assumptions to ATT&CK-style behavior expectations and verify with runtime telemetry.8788---8990## Python/C integration pattern9192- Use Python (pwntools/Keystone/Capstone/Unicorn) for generation, assembly, disassembly, and emulation harnesses.93- Use C/C++ (or Rust/Go) wrappers for runtime loaders/injectors and platform APIs.94- Keep shellcode bytes and loader logic separable so you can swap payload versions quickly.95- Always retain one end-to-end harness that runs: `generate -> inspect -> emulate -> execute test`.9697---9899## Quality gates before shipping100101- Byte-level constraints pass (`badchars`, size, null/newline policy)102- Stack/register invariants verified at entry/exit103- Memory permissions transitions are reversible and error-checked104- No hardcoded OS-build-specific syscall numbers unless explicitly pinned for research105- At least one emulator run and one real runtime debug pass on target architecture106- Crash artifacts and logs are reproducible with the same payload bytes107108---109110## Resources111112- [references/platform-workflows.md](references/platform-workflows.md) — concrete Windows/Linux/macOS build and validation flows, including syscall and memory-transition checkpoints113- [references/tooling-and-labs.md](references/tooling-and-labs.md) — practical usage of pwntools, Capstone, Keystone, Unicorn, debugger loops, and test harness patterns114- [references/encoders-and-stagers.md](references/encoders-and-stagers.md) — staged payload patterns, bad-byte encoders, polymorphism trade-offs, and failure modes115- [references/evasion-patterns-from-projects.md](references/evasion-patterns-from-projects.md) — transferable shellcode-dev engineering patterns from real implementations (runtime SSN mapping, recycled syscall gates, DESYNC readiness checks, sleep masking pipelines, CFG-aware gadget handling)116- [references/loader-core-qualification.md](references/loader-core-qualification.md) — load when qualifying, porting, or reviewing a raw PIC loader core (extracted `.text`/`.rdata`) or its wrapper: defect taxonomy (thunk-slot placement, SSE/section alignment, decode-cursor vs ABI conflation, kernel-dependent paths), crash-signature triage on Windows, and the per-backend gate recipe117- Upstream methodology: `offensive-techniques/binary-exploitation-technique` (where shellcode fits in the chain) and `offensive-ctf/pwn-ctf/references/shellcode-filtering.md` (byte-blacklist recipes).118- Start with `references/platform-workflows.md`; wrong platform assumptions break payloads faster than bad-byte or evasion mistakes.