Shellcode
Introduction to Shellcode
Shellcode is machine code that executes specific operations when injected into a target process's memory. It typically serves as the payload in exploits, performing actions like opening a command shell, establishing network connections, or executing arbitrary commands.
Basic Shellcode Concepts
Shellcode Execution Pattern
Shellcode injection follows the "Allocate-Write-Execute" pattern:
Allocate RWX memory with size of shellcode
Write shellcode to allocated memory
Execute the content of allocated memory
Avoid direct
PAGE_EXECUTE_READWRITEallocation as it's easily flagged. Better to:Allocate with
PAGE_READWRITEWrite payload
Change protection to executable
Position-Independent Code Techniques
Shellcode Development Process
API Resolution for Windows Shellcode
identifying kernel32.dll:
get
PEB->Ldr.InMemoryOrderModuleListiterate through
PEB->Ldr.InMemoryOrderModuleList; the first entry is the exe, followed byntdll.dll, and thenkernel32.dll(Win10/11 +). Hash-compare names to locate itparse export address table
loop over export address table to find
GetProcAddressnameget function ordinal and then address ( you have access to
GetProcAddressnow)ensure
GetProcAddressis available before resolvingLoadLibraryA; both can be fetched in the same enumeration loopresolve
LoadLibraryAusingGetProcAddressand call it onWS2_32.dllget and call
WSAStartuplookup
WSASocketAand create a socket with itlookup
WSAConnectand connect to the socketfind the address for
CreateProcessAfromkernel32.dllagainpush
cmd.exeto stack, fillSTARTUPINFOAand callCreateProcessAuse a
nc -nvv -p 443 -lon your own machine and run the shellcode to connect back to itp.s: don't forget to fix the IP and port
Shellcode Execution Flow (Windows)
Shellcode Loaders
Shellcode loaders typically follow this pattern:
Loader Implementation
Meet Shellcode Loader
Takes shellcode as input, verifies environment, injects it if all is good
Responsible for evading sandboxes, proxies, AV, EDR, and safely landing in a machine
Environment verification/keying, careful shellcode decryption
Ends its duties after injecting shellcode
Injection targets:
Self process
Other process
Vulnerable to automated-detonation/sandboxes
Loader might reside in:
Process tree
Process modules list
Recommended languages:
Rust (secure, but larger binaries can stand out)
Nim
Go (runtime signature easily flagged)
Zig (small, no runtime, clean FFI)
Carbon preview (experimental, minimal footprint)
Allocation Phase
Linear, big enough R+X memory region options:
New memory region/section
Code caves
Stack, heap (after adjusting page permissions + disabling DEP)
Keep memory regions small/separate
Typical allocation techniques:
VirtualAllocEx/NtAllocateVirtualMemoryZwCreateSection+NtMapViewOfSection
Best practice - avoid
RWXallocations:Allocate
RWWrite shellcode
Use
VirtualProtectExto switch toRX
Write Phase
Typical write techniques:
WriteProcessMemory/NtWriteVirtualMemorymemcpyto mapped sectionAtom bombing (loud and unreliable)
Evasion strategies:
Prepend shellcode with dummy machine opcodes
Split shellcode into chunks and write in randomized order
Apply delays between consecutive writes
Execute Phase
Most fragile step in the process:
New thread introduced, so EDR closely inspects starting point
EDR might check if starting function is in image-backed memory (e.g.,
ntdll.dll)
Typical execution techniques:
CreateRemoteThread/ZwCreateThreadExNtSetContextThreadNtQueueApcThreadExAPI function hooks / trampolines
Indirect shellcode execution via Windows API:
Some EDRs might spoof Thread Execution Block or
ntdll.dllto detect if the process is attempting to modify them
Exec/DLL to Shellcode Conversion
Embedding shellcode into a shellcode loader executable
Backdooring legitimate PE executables with shellcode
Open-source shellcode loaders:
Polonium (APT implant; useful for studying advanced persistent techniques rather than as a generic open-source loader base)
NullGate – indirect syscalls & junk-write sequencing
Ghost – fiber spoofing & ETW patching
ThreadlessInject – injection without new threads
Direct-syscall helpers (e.g., SysWhispers3, FreshyCalls) are now baseline requirements
Ghost v3.2 – fiber spoofing & ETW patching
ThreadlessInject v1.1 – injection without new threads
ProtectMyTooling - Tool to daisy-chain protections
Cross‑Platform Considerations
Windows on ARM64 (WoA)
Snapdragon X Elite and Surface Pro 10 ship with WoA. Syscalls use
SVC 0and the ARM64 table inntdll!KiServiceTableArm64.Pointer Authentication (PAC) signs the LR value; avoid stack pivots or re‑sign the new target with
PACIASP.Example loader:
examples/woa_loader.s.
Linux 6.9+: eBPF Arena & BPF Tokens
Kernel 6.9 introduces BPF tokens and a shared BPF arena (
BPF_MAP_TYPE_ARENA) that can hold executable memory.Hide shellcode chunks in an arena map and call them via
bpf_prog_run_pin_on_cpu.Demo:
examples/ebpf_arena_loader.c.
macOS Signed System Volume (SSV)
macOS 12+ seals the system partition; unsigned payloads can't live there.
Persistence flow:
Create a sealed‑system snapshot (
bless --mount … --create-snapshot).Mount snapshot read‑write, inject payload, resign with
kmutil, and bless the new snapshot.
User space: use launch agents or dylib hijacks in
/Library/Apple/System/Library/Dyld/.
Shellcode Storage & Hiding Techniques
Storage Options
Hardcoded:
Shellcode stored in code requires recompilation before use
Typically stored in
RW/ROsection
PE Resources:
Can use
RCDATAbinary blobsMost extensively scanned by AV
Additional PE Section:
Stored in additional
R+XsectionUse second-to-last / N-to-last section
Acquired from internet:
Example tool: CSharpShooter
Certificate Table (highly recommended):
Patch the PE file by padding Certificate Table with shellcode bytes and update PE headers
Example: Embed shellcode in
teams.exe, backdoorffmpeg.dllwith shellcode-loaderShellcode loader finds & loads shellcode inside memory
This keeps
teams.exesignature intact and only breaksffmpeg.dllsignatureWhen
teams.exestarts, it loadsffmpeg.dll, which in turn loads the shellcode from teams.exe's certificate table
Legitimate PE backdoored with shellcode & loader
Protection Methods
Shellcode should be protected using:
Compression (
LZMA)Encryption/encoding (
XOR32/RC4/AES)
Evasion Techniques
Progressive Evasion Techniques
For shellcode execution with increasing evasion capability:
Begin with basic shellcode execution
Add encryption/obfuscation
Implement direct syscalls to bypass monitoring
Move to remote process injection when needed
Windows Defender Evasion
Shellcode Evasion Tools
Available at github.com/hackmosphere/DefenderBypass:
myEncoder3.py - Transforms binary files to hex and applies XOR encryption
InjectBasic.cpp - Basic shellcode injector in C++
InjectCryptXOR.cpp - Adds XOR decryption for encrypted shellcode
InjectSyscall-LocalProcess.cpp - Uses direct syscalls to bypass userland hooks, removes suspicious functions from IAT
InjectSyscall-RemoteProcess.cpp - Injects shellcode into remote processes
Windows 11 version 24H2 introduces AMSI heap scanning; allocate with
PAGE_NOACCESS, decrypt in place, then switch toPAGE_EXECUTE_READto avoid live-heap scans
Local vs Remote Injection
Remote injection faces multiple technical challenges:
Enforced defenses (
CFG,CIG)Event tracing in Windows (
ETW)More closely monitored steps: open process handle, allocate, write, execute
Remote injection detection points:
ETW Ti feeds
EDR hooks and sensors
Back-tracing thread's call stack (was
NtOpenProcessinvoked from a trusted thread?)
Advanced Implementations
DripLoader Technique
Code available at github.com/xuanxuan0/DripLoader
Implementation details:
Reserves enough 64KB big chunks with
NO_ACCESSAllocates chunks of
Read+Writememory in that reserved pool, 4KB eachWrites shellcode in chunks in randomized order
Re-protects into
Read+ExecOverwrites prologue of
ntdll!RtlpWow64CtxFromAmd64with aJMPtrampoline to shellcodeUses direct syscalls to call out to
NtAllocateVirtualMemory,NtWriteVirtualMemory,NtCreateThreadEx
Practical Examples
Reverse Shell Shellcode Implementation
[!TIP] Windows 11 23H2 blocks outbound TCP 443/4444 to local subnets (only when Smart App Control policy is set to Block). Choose a non‑standard port or use a named‑pipe payload.
Last updated