mmap_inject
A minimal, robust manual-map DLL injection library for Windows x64, written in Rust.
Features
- Manual Mapping — injects DLLs without
LoadLibrary, evading basic user-mode hooks - Randomized Base Address — ASLR-style allocation in 64-bit user space (3 retries + OS fallback)
- SEH Support — calls
RtlAddFunctionTablefor x64 structured exception handling - PE Header Wiping — overwrites PE headers immediately after injection
- Import Resolution — resolves normal import tables (IAT) and delayed imports
- TLS Callbacks — executes
DLL_PROCESS_ATTACHTLS callbacks - Base Relocations — applies
IMAGE_REL_BASED_DIR64relocations when the DLL isn't loaded at its preferred base - Detailed error diagnostics — unique error codes identify exactly which step failed
- Zero-cost FFI — single dependency on
windows-sys, no heavy runtime
Quick Start
# Cargo.toml
[]
= "0.1"
use inject_dll;
use ;
let dll_bytes = read?;
let h_proc = unsafe ;
unsafe
Architecture
┌──────────────────────────────────────────────────────┐
│ Injector Process │
│ │
│ injector.rs │
│ ├─ validate PE │
│ ├─ VirtualAllocEx (random base) │
│ ├─ write headers + sections │
│ ├─ apply base relocations (injector-side) │
│ ├─ write MappingCtx + shellcode │
│ └─ CreateRemoteThread → WaitForSingleObject │
│ │
│ ▼ │
│ ┌──────────────────────────────────────┐ │
│ │ Target Process │ │
│ │ │ │
│ │ shellcode.rs (minimal, ~2 KB) │ │
│ │ ├─ resolve imports (IAT) │ │
│ │ ├─ resolve delayed imports │ │
│ │ ├─ execute TLS callbacks │ │
│ │ ├─ RtlAddFunctionTable (SEH) │ │
│ │ └─ DllMain(DLL_PROCESS_ATTACH) │ │
│ └──────────────────────────────────────┘ │
└──────────────────────────────────────────────────────┘
API
inject_dll
pub unsafe
Manually maps the raw DLL bytes into the target process. PE headers are wiped immediately; shellcode and context memory are freed. The DLL itself stays loaded in the target until the process exits.
The process handle needs at minimum:
PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATIONPROCESS_CREATE_THREAD
Error
| Variant | Meaning |
|---|---|
InvalidPe |
Not a valid x64 PE file |
Win32(u32) |
A Win32 API returned an error (GetLastError) |
InvalidArgument |
Null handle, empty payload, etc. |
ShellcodeFailed(usize) |
Import resolution failed; code indicates which step |
SehRegistrationFailed |
DLL loaded but RtlAddFunctionTable failed |
ShellcodeCrashed(u32, usize) |
Remote thread crashed; code = NTSTATUS, step = last marker |
Building
Requires Rust 1.85+ (edition 2024). Release mode is required — debug builds are not supported because the compiler emits function calls (stack probes, non-inlined helpers) that fall outside the shellcode section.
cargo build --release
Static CRT
The .cargo/config.toml enables +crt-static (equivalent to MSVC /MT)
so injected DLLs don't depend on VCRUNTIME140.dll. It also enables
/DYNAMICBASE for full .reloc section generation.
Notes for injected DLLs
- Rust heap allocation (
format!,Box,String,Vec) works fine in manually-mapped DLLs — the default Windows allocator wrapsHeapAllocand needs no CRT initialization. - Statically link the CRT (
+crt-static) so your DLL has no external CRT dependency. - Enable
/DYNAMICBASEso the DLL has a.relocsection (the injector applies relocations when loading at a different base).
Testing
All build/run commands require --release — the shellcode lives in a
custom linker section (.sc) and debug builds emit stack probes +
non-inlined helpers that break the section layout.
# Unit tests — PE structs, RVA conversion, shellcode layout
cargo test --release
# Build examples (test_dll.dll + test_injector.exe)
cargo build --examples --release
# Self-injection test — shows a MessageBox
cargo run --example test_injector --release
# Inject into a specific process by PID
cargo run --example test_injector --release -- 12345
Project Structure
| Path | Description |
|---|---|
src/ |
The mmap_inject library — manual-map DLL injection |
examples/test_dll.rs |
Example DLL — MessageBox("Hello from test_dll") |
examples/test_injector.rs |
Injector — self-inject or test_injector <PID> |
License
MIT — see LICENSE.