A windows dll injection library written in Rust.
| Injector Process | Target Process | Supported? | 
|---|---|---|
| 32-bit | 32-bit | Yes | 
| 32-bit | 64-bit | No | 
| 64-bit | 32-bit | Yes (requires feature into-x86-from-x64) | 
| 64-bit | 64-bit | Yes | 
This crate allows you to inject and eject a DLL into a target process.
The example below will inject and then eject injection_payload.dll into the process called "ExampleProcess".
use dll_syringe::{Syringe, process::OwnedProcess};
// find target process by name
let target_process = OwnedProcess::find_first_by_name("ExampleProcess").unwrap();
// create a new syringe for the target process
let syringe = Syringe::for_process(target_process);
// inject the payload into the target process
let injected_payload = syringe.inject("injection_payload.dll").unwrap();
// do something else
// eject the payload from the target (optional)
syringe.eject(injected_payload).unwrap();This crate supports two mechanisms for rpc. Both only work one-way for calling exported functions in the target process and are only intended for one-time initialization usage. For extended communication a dedicated rpc library should be used.
| RemotePayloadProcedure | RemoteRawProcedure | |
|---|---|---|
| Feature | rpc-payload | rpc-raw | 
| Argument and Return Requirements | Serialize + DeserializeOwned | Copy, Argument size has to be smaller thanusizein target process | 
| Function Definition | Using macro #[payload_procedure] | Any extern "system"orextern "C"with#[no_mangle] | 
A rpc mechanism based on bincode.
The target procedure must be defined using the #[payload_procedure] macro (requires the payload-utils feature).
The definition of an exported add function could look like this:
#[payload_procedure]
fn add(a: f64, b: f64) -> f64 {
    a + b
}The code of the injector/caller could looks like this:
use dll_syringe::{Syringe, process::OwnedProcess};
// find target process by name
let target_process = OwnedProcess::find_first_by_name("ExampleProcess").unwrap();
// create a new syringe for the target process
let syringe = Syringe::for_process(target_process);
// inject the payload into the target process
let injected_payload = syringe.inject("injection_payload.dll").unwrap();
let remote_add = unsafe { syringe.get_payload_procedure::<fn(f64, f64) -> f64>(injected_payload, "add") }.unwrap().unwrap();
let result = remote_add.call(&2.0, &4.0).unwrap();
println!("{}", result); // prints 6
// eject the payload from the target (optional)
syringe.eject(injected_payload).unwrap();This mechanism is based on dynamically generated assembly code.
The target procedure can be any exported function as long as it uses either the system or C calling convention.
This means that even Win32 functions can be called directly.
The definition of an exported add function could look like this:
#[no_mangle]
extern "system" fn add(a: f64, b: f64) -> f64 {
    a + b
}The code of the injector/caller could looks like this:
use dll_syringe::{Syringe, process::OwnedProcess};
// find target process by name
let target_process = OwnedProcess::find_first_by_name("ExampleProcess").unwrap();
// create a new syringe for the target process
let syringe = Syringe::for_process(target_process);
// inject the payload into the target process
let injected_payload = syringe.inject("injection_payload.dll").unwrap();
let remote_add = unsafe { syringe.get_raw_procedure::<extern "system" fn(f64, f64) -> f64>(injected_payload, "add") }.unwrap().unwrap();
let result = remote_add.call(2.0, 4.0).unwrap();
println!("{}", result); // prints 6
// eject the payload from the target (optional)
syringe.eject(injected_payload).unwrap();Licensed under MIT license (LICENSE or http://opensource.org/licenses/MIT)
You will need the nightly toolchains of Rust and Cargo to build/test this project.
rustup target add x86_64-pc-windows-msvc --toolchain nightly
rustup target add i686-pc-windows-msvc --toolchain nightly
Note
Also applies to developing on Linux, you'll need it for your IDE (i.e. rust-analyzer or RustRover) to work properly.
Run the ./scripts/test.ps1 script from PowerShell.
You'll need cargo xwin to build the MSVC targets on Linux:
cargo install cargo-xwin
After that, you can run the tests with ./scripts/test-wine.ps1 PowerShell script.
(As opposed to ./scripts/test.ps1)
Make sure you have Wine installed!
Inspired by Reloaded.Injector from Sewer.