rustdllproxy
Installation
Compatibility
This crate currently only supports the standard DLL PE format. .NET DLLs are not supported.
Use Cases
This crate serves two main purposes:
- Single DLL Proxying - Proxy a single DLL to modify or better understand its behavior
- DLL Consolidation - Collect several DLLs into one unified proxy, which can be used alongside custom applications or techniques
Current Limitations
- Only supports exports from the standard PE DLL format (.NET DLLs are not compatible)
- When hooking functions with custom code, the function signature must be known
- This can be found using disassemblers and reverse engineering tools like Ghidra
Commands
Rustdllproxy ships two subcommands:
| Command | Purpose |
|---|---|
rustdllproxy new |
Generate a new proxy cdylib crate from one or more existing DLLs. |
rustdllproxy build |
Sync the .def file with src/lib.rs and build the crate. |
Creating a New Crate
Tip: Use
-pmultiple times to unify several DLLs into one proxy.
Tip: The
-aflag can be used to optionally compile for 32 bit.
Important: Proxy Strategy
Before creating your crate, decide how the proxy DLL will interact with the original(s). A typical pattern is to append an underscore to the original DLL name.
⚠️ THIS MUST BE DONE BEFORE GENERATING THE CRATE - the generated .def file will reference this name for forwarding behavior.
Writing Hooks
The macro library supports 3 main hook types: prehook, posthook, and fullhook.
Hook Implementation Steps
-
Replace the
#[no_mangle]directive with the hook macro (leave the//<dllname>.dlltrailing comment in place —rustdllproxy builduses it to recover the original DLL name)://dllbeingproxied.dll -
Fill out the function signature (declare inputs as
mutto modify them) -
Build with
rustdllproxy build.
Previously, step 3 required hand-editing the
.deffile (function_name = dll.function_name @N→function_name @N) and then forcing a Cargo rebuild because Cargo doesn't fingerprint.defchanges. Thebuildsubcommand handles both.
Hook Types
In this section, target.dll is commonly used. Remember in most cases this would be target_.dll
prehook
Executes code before the original function. Allows you to add functionality or modify input variables.
//target.dll
posthook
Executes code after the original function. View and edit the return value using the magic ret variable.
//target.dll
Note: The
retvariable is automatically defined as mutable. You don't need to reference it if not needed.
fullhook
Provides complete control over function execution. Manually manage the return value and function calling.
//target.dll
Building the Crate
Run from the proxy crate directory (or pass it as the first argument):
| Flag | Default | Effect |
|---|---|---|
PATH |
. |
Path to the proxy crate root. |
--profile <name> |
release |
Cargo build profile (release, dev, custom). |
--no-build |
off | Regenerate the .def file but skip cargo build. |
-- <args> |
— | Forwarded verbatim to cargo build. |
How It Works
- Reads
[package].namefromCargo.tomlto locate<name>.def. - Walks
src/lib.rsto classify every exported function as either hooked (#[prehook]/#[posthook]/#[fullhook]) or forwarded (#[no_mangle]). - For each function, the original DLL name is recovered from, in order:
- the first string literal of the hook macro (hooked functions only),
- the trailing
//<dllname>.dllcomment on the attribute line, - the existing forwarding entry already in the
.deffile.
- Rewrites
<name>.defso hooked functions readname @Nand forwarded functions readname = origdll.name @N. Existing ordinals are preserved. - Bumps
src/lib.rs's mtime to force a relink (Cargo doesn't fingerprint.defchanges), then invokescargo build.
Caveats
- The
.deffile is fully regenerated on every run — manual edits to it (extra directives, custom ordinals) will be overwritten. - If an
#[no_mangle]function loses both its//<dllname>.dllcomment and its forwarding entry in the.deffile, the build aborts with an error explaining how to restore one of them.
Example Workflow
Let's say you want to modify office.dll used in office software via DLL search order hijacking:
Step 1: Prepare the Original DLL
# Rename the original DLL
Step 2: Generate Proxy Crate
Step 3: Implement Hooks
Leave the //office_.dll trailing comment that the generator emitted — the build step reads it.
//office_.dll
Step 4: Build and Deploy
# Rename the built DLL back to office.dll
# Place in the target directory
DLL Bundling Considerations
Important: Proxying several DLLs together is typically useful for reverse engineering and custom software development, not process modification.
When bundling multiple DLLs:
- Function ordinals may change due to export ordering
- This is rarely problematic since modern software uses export names for compatibility
- Primarily useful for analysis and custom application development
Changelog
Release notes live in CHANGELOG.md.
Contributing
Contributions are welcome! Please feel free to submit issues and pull requests.