dnfile
A Rust crate for parsing .NET executable files — PE files containing CLR (Common Language Runtime) metadata, streams, tables, and CIL (Common Intermediate Language) bytecode.
It is a Rust port of malwarefrank/dnfile, the Python library used by tools like Mandiant capa for static analysis of .NET malware.
What it does
Given a .NET PE file (an executable, DLL, or assembly compiled to MSIL), dnfile lets you:
- Parse the CLR header and verify .NET flags (IL-only, 32-bit-required, strong-named, etc.).
- Walk the #~ / #- metadata stream and access its ~50 ECMA-335 tables (
Module,TypeDef,MethodDef,MemberRef,Assembly,ManifestResource, etc.) by name or index. - Read #Strings, #US, #GUID, #Blob heaps.
- Resolve coded indexes (TypeDefOrRef, MemberRefParent, HasCustomAttribute, …) into typed table rows.
- Decode every CIL instruction in every method body, including operand types, branch targets, switch tables, and tokens.
- Detect mixed-mode (managed + native) and P/Invoke functions.
Quick start
Add to your Cargo.toml:
[]
= "0.4"
Then:
use DnPe;
For very large binaries, back the buffer with memmap2::Mmap instead of std::fs::read:
let file = open?;
let mmap = unsafe ;
let pe = parse?;
# Ok::
Command-line tool: dndump
dndump is a Mandiant capa-style inspector for .NET binaries. It prints the CLR header, metadata streams, populated tables, and the first methods discovered. Pre-built binaries for Linux / macOS / Windows are attached to each GitHub release.
Install from source:
Or build locally:
Other useful invocations:
A minimal library-usage example lives in examples/dnfile.rs:
Feature coverage
Metadata tables supported (with full parse implementations):
Module, TypeRef, TypeDef, Field, MethodDef, Param, InterfaceImpl, MemberRef, Constant, CustomAttribute, FieldMarshal, DeclSecurity, ClassLayout, FieldLayout, StandAloneSig, EventMap, Event, PropertyMap, Property, MethodSemantics, MethodImpl, ModuleRef, TypeSpec, ImplMap, FieldRva, EncLog, EncMap, Assembly, AssemblyProcessor, AssemblyOS, AssemblyRef, AssemblyRefProcessor, AssemblyRefOS, File, ExportedType, ManifestResource, NestedClass, GenericParam, GenericMethod, GenericParamConstraint, FieldPtr, MethodPtr, ParamPtr.
Stubbed (returns NotImplementedError, does not panic): EventPtr, PropertyPtr, Unused, MaxTable. These appear only in uncompressed #- streams or are reserved by ECMA-335.
CIL: all one- and two-byte opcodes from ECMA-335 §III.
Not currently implemented: managed-resource (ResourceSet) parsing — only the ManifestResource metadata-table entry is exposed; the resource blob itself is not parsed.
Requirements
- Rust 1.85 or newer (2024 edition).
Why a Rust port?
dnfile-rs was originally written to power capa-rs, the Rust port of Mandiant's capability extractor. It is suitable for any Rust-side static analysis of .NET binaries that does not require executing the IL.
Used by
- capa-rs — static capability extractor for PE / ELF / shellcode / .NET binaries.
License
Licensed under the Apache License, Version 2.0.
Acknowledgements
- malwarefrank/dnfile — the original Python implementation that this port is modelled on.
- ECMA-335 — Common Language Infrastructure (CLI) specification.