Expand description
§PeRs
PeRs is a parser for Windows Portable Executable (PE) files. It started as a port of the C#
library PeNet and is tested against PeNet’s test cases and test
binaries. PeRs borrows the file data instead of copying it: fixed layout headers and tables are
referenced in place, variable structures such as imports, version information, .NET tables and
certificates are decoded into small owned values. The API uses typed addresses, real enums and
Result<Option<T>> accessors that tell absent and malformed structures apart. It needs no native
Windows APIs and works in no_std environments with alloc.
§Features
- All native PE headers: DOS, NT, file and optional header (32 and 64 bit), sections, data directories
- Imports, delay imports, exports (including forwarded exports), bound imports, relocations, exception directory with unwind information, debug directory (CodeView PDB info), TLS callbacks, load config, COM descriptor
- Resources: version information and icons as
.icofiles - .NET metadata: metadata header, heaps and all metadata tables
- Hashes: MD5, SHA-1, SHA-256, ImpHash, TypeRefHash, Authenticode hash
- Authenticode: signing certificate, signature validation, signing time stamp, CRL URLs
- Editing with
PeEditor: add and remove sections, add imports
§Usage
use pers::PeFile;
let data = std::fs::read("firefox.exe")?;
let pe = PeFile::parse(&data)?;
let file_header = pe.nt_headers().file_header;
println!("Machine: {}", file_header.machine().description());
println!("SHA-256: {}", hex::encode(pe.sha256()));
for section in pe.section_headers()? {
println!("{} {}", section.name(), section.virtual_address());
}
// Ok(None) if the file has no imports, Err if they are malformed.
if let Some(imports) = pe.imported_functions()? {
for import in imports {
println!("{} {:?}", import.dll, import.name);
}
}
println!("Signed: {}", pe.is_signed());
println!("Valid signature: {}", pe.has_valid_signature());Large files can be memory mapped:
use pers::{MmFile, PeFile};
let file = MmFile::open_read_only("large.dll")?;
let pe = PeFile::parse(&file)?;Edits go through PeEditor, which owns the data:
use pers::editor::PeEditor;
let mut editor = PeEditor::new(std::fs::read("app.exe")?)?;
editor.add_import("gdi32.dll", "StartPage")?;
std::fs::write("app_patched.exe", editor.into_bytes())?;§Cargo Features
| Feature | Default | Content |
|---|---|---|
std | yes | std::error::Error, I/O helpers, thread safe caches |
mmap | yes | MmFile for memory mapped files |
resources | yes | Version information and icons |
dotnet | yes | .NET metadata |
authenticode | yes | Authenticode signatures |
Without std the crate is no_std and needs alloc.
§Comparison
| Crate | Formats | Focus | Compared to PeRs |
|---|---|---|---|
| object | ELF, Mach-O, PE/COFF, Wasm | Unified zero-copy reading and writing | Multi-format and very mature; no .NET metadata or Authenticode validation |
| goblin | ELF, Mach-O, PE | Cross-platform parser and loader | Multi-format; covers the PE basics, no .NET metadata or signature validation |
| pelite | PE | Low allocation PE reader with resources | Similar borrowing design; no .NET metadata or signature validation |
| editpe | PE | Editing resources such as icons and version info | Stronger resource editing; less analysis |
| authenticode | PE | Authenticode signatures, built on object | Signature parsing and hashing; PeRs also verifies signer and counter signer signatures |
| lief | ELF, Mach-O, PE | Bindings to the C++ library LIEF | Very complete, but needs the native library |
PeRs only reads PE files. It combines the native structures with .NET metadata, ImpHash,
TypeRefHash, version information, icons and Authenticode validation in one no_std crate, and is
tested against the cases and binaries of PeNet. For tools that need ELF or Mach-O as well, use
object or goblin.
§Development
nix develop
just test
just clippy
just fmt
just features # build every feature combinationThe tests are ported from PeNet and use its test binaries in tests/Binaries. A fuzz target
lives in fuzz/ (cargo +nightly fuzz run parse).
§License
Licensed under either of
- Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.
§Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
Re-exports§
pub use address::FileOffset;pub use address::Rva;pub use address::Va;
Modules§
- address
- Typed addresses. Mixing a relative virtual address with a file offset is a type error.
- authenticode
authenticode - Authenticode signatures.
- editor
- Editing of PE files: adding and removing sections, adding imports.
- imp_
hash - Import hash (ImpHash) as defined by Mandiant: the MD5 of the normalized import list.
- net
dotnet - .NET (CLR) metadata: the metadata root, its heaps and the metadata tables.
- pe
- Native PE structures.
- resource
resources - Resources: version information and icons.
Structs§
- MmFile
mmap - A memory mapped file, the fastest way to parse large files:
PeFile::parse(&MmFile::open_read_only(path)?). - PeFile
- A parsed Portable Executable file borrowing its data.
Enums§
- Error
- Errors of parsing and editing PE files. The variants carry no heap data, so errors are cheap
to clone and work without
std.