rustdllproxy
Installation
Compatibility
This crate currently only supports the standard DLL PE format.
Current Limitations
- 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
A Quick Note on Strategy
Before generating your crate, decide how you would like your proxy to work. A typical pattern is search order hijacking, where you would first rename your target DLL to something like target_.dll, and then use the compiled proxy as target.dll. This creates a flow resembling binary -> target.dll -> target_.dll
There are multiple paths forward depending on your use case. If however you need to rename the underlying DLL being proxied, update the generated .def file accordingly.
Tip: rustdllproxy is built as a CLI with clap. Run rustdllproxy --help to see all options and flags.
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)//dllbeingproxied.dll -
Fill out the function signature (declare inputs as
mutto modify them) -
Build with
rustdllproxy build.
Hook Types
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. |
Caveats
- The
.deffile is fully regenerated on every build, manual changes will be overwritten. If you need to make manual changes against how rustdllproxy builds, cargo can be used to accomplish this. - The build system relies on generated comments, .def exports, and hook names to retrieve the name of the underlying DLL before building. If there is not enough information, and error will be thrown to explain how this can be recovered.
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
//office_.dll
Step 4: Build and Deploy
Build files are located under
/target
DLL Bundling Considerations
It is possible to proxy several target DLLs with a single crate. This feature is rarely used and comes with some important caveats.
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.