9 releases
Uses new Rust 2024
| 0.1.2 | Feb 2, 2026 |
|---|---|
| 0.1.1 | Jan 9, 2026 |
| 0.1.0 | Dec 31, 2025 |
| 0.0.6 | May 28, 2025 |
| 0.0.1 | Dec 24, 2022 |
#47 in FFI
163 downloads per month
495KB
11K
SLoC
dotnetdll
A Rust library for reading and writing .NET assembly metadata (DLL/EXE files).
Implements the ECMA-335 (CLI) standard for .NET metadata manipulation.
Status: Pre-1.0. Core functionality is complete and tested, but the API may evolve before the 1.0 release.
Features
- Parse .NET PE files into structured metadata
- Generate .NET assemblies from scratch programmatically
- Inspect types, methods, fields, IL bytecode, custom attributes, and resources
- Type-safe navigation using typed indices instead of raw integers
- Ergonomic macros for constructing types, signatures, and IL code
Quick Start
Add this to your Cargo.toml:
[dependencies]
dotnetdll = "0.1"
Reading a DLL
use dotnetdll::prelude::*;
fn main() -> Result<(), DLLError> {
let bytes = std::fs::read("MyLibrary.dll")?;
let res = Resolution::parse(&bytes, ReadOptions::default())?;
for (type_idx, typedef) in res.enumerate_type_definitions() {
println!("Type: {}", typedef.name);
for (method_idx, method) in res.enumerate_methods(type_idx) {
println!(" Method: {}", method.name);
}
}
Ok(())
}
Writing a DLL
use dotnetdll::prelude::*;
fn main() -> Result<(), DLLError> {
let mut res = Resolution::new(Module::new("HelloWorld.dll"));
res.assembly = Some(Assembly::new("HelloWorld"));
// Reference external assemblies and types
let mscorlib = res.push_assembly_reference(
ExternalAssemblyReference::new("mscorlib")
);
let console = res.push_type_reference(
type_ref! { System.Console in #mscorlib }
);
// Create a type and method with IL
let program = res.push_type_definition(
TypeDefinition::new(None, "Program")
);
let console_type = BaseType::class(console).into();
let write_line = res.push_method_reference(
method_ref! { static void #console_type::WriteLine(string) }
);
let main = res.push_method(
program,
Method::new(
Accessibility::Public,
msig! { static void () },
"Main",
Some(body::Method::new(asm! {
load_string "Hello from dotnetdll!";
call write_line;
Return;
})),
),
);
res.set_entry_point(main);
let bytes = res.write(WriteOptions {
is_32_bit: false,
is_executable: true,
})?;
std::fs::write("HelloWorld.exe", bytes)?;
Ok(())
}
Documentation
- API Documentation - Comprehensive API reference
- Examples - Working examples including a DLL dumper and mini-assembler
Architecture
The library is organized into layers:
resolution- High-level API withResolution::parse()andResolution::write()resolved- Semantic types likeTypeDefinition,Method,Instructionbinary- Low-level ECMA-335 binary structuresdll- PE file parsing
Most users only need resolution and resolved.
Examples
The repository includes example projects you can learn from:
bash
# Inspect a DLL
cargo run -p dump-dll -- path/to/Some.dll
# Mini assembler demo
cargo run -p smolasm -- --help
Compatibility
- Rust 1.85.1+ (Rust 2024 edition)
- Supports PE32 and PE64 formats
- Focuses on metadata manipulation, not runtime execution
- Tested against .NET 5+ assemblies
Contributing
Contributions welcome! Areas where help is especially appreciated:
- Documentation improvements
- Additional examples
- Bug reports and fixes
License
GPL-3.0-or-later. See LICENSE.
Dependencies
~8–11MB
~127K SLoC