Struct File
pub struct File { /* private fields */ }Expand description
Provides access to low-level file and memory parsing utilities.
The crate::Parser type is used for decoding CIL bytecode and metadata streams.
§Usage Examples
use dotscope::{Parser, disassembler::decode_instruction};
let code = [0x2A]; // ret
let mut parser = Parser::new(&code);
let instr = decode_instruction(&mut parser, 0x1000)?;
assert_eq!(instr.mnemonic, "ret");The self-referencing struct.
Implementations§
§impl File
impl File
pub fn from_file(file: &Path) -> Result<File>
pub fn from_file(file: &Path) -> Result<File>
Loads a PE file from the given path.
This method opens a file from disk and parses it as a .NET PE file. The file is memory-mapped for efficient access.
§Arguments
file- Path to the PE file on disk.
§Errors
Returns an error if:
- The file cannot be read or opened
- The file is not a valid PE format
- The PE file does not contain .NET metadata (missing CLR runtime header)
- The file is empty
§Examples
use dotscope::File;
use std::path::Path;
let file = File::from_file(Path::new("tests/samples/WindowsBase.dll"))?;
println!("Loaded {} bytes with {} sections",
file.len(), file.sections().count());
// Access assembly metadata
let (clr_rva, clr_size) = file.clr();
println!("CLR runtime header: RVA=0x{:x}, size={}", clr_rva, clr_size);pub fn from_mem(data: Vec<u8>) -> Result<File>
pub fn from_mem(data: Vec<u8>) -> Result<File>
Loads a PE file from a memory buffer.
This method parses a PE file that’s already loaded into memory. Useful when working with embedded resources or downloaded files.
§Arguments
data- The bytes of the PE file.
§Errors
Returns an error if:
- The buffer is empty
- The data is not a valid PE format
- The PE file does not contain .NET metadata (missing CLR runtime header)
§Examples
use dotscope::File;
use std::fs;
// Load from downloaded or embedded data
let data = fs::read("tests/samples/WindowsBase.dll")?;
let file = File::from_mem(data)?;
// Inspect the assembly
println!("Assembly size: {} bytes", file.len());
println!("Image base: 0x{:x}", file.imagebase());
// Find specific sections
for section in file.sections() {
let name = std::str::from_utf8(§ion.name)
.unwrap_or("<invalid>")
.trim_end_matches('\0');
if name == ".text" {
println!("Code section at RVA 0x{:x}", section.virtual_address);
break;
}
}pub fn len(&self) -> usize
pub fn len(&self) -> usize
Returns the total size of the loaded file in bytes.
§Examples
use dotscope::File;
use std::path::Path;
let file = File::from_file(Path::new("tests/samples/WindowsBase.dll"))?;
println!("File size: {} bytes", file.len());pub fn is_empty(&self) -> bool
pub fn is_empty(&self) -> bool
Returns true if the file has a length of zero.
§Examples
use dotscope::File;
use std::path::Path;
let file = File::from_file(Path::new("tests/samples/WindowsBase.dll"))?;
assert!(!file.is_empty()); // Valid PE files are never emptypub fn imagebase(&self) -> u64
pub fn imagebase(&self) -> u64
Returns the image base address of the loaded PE file.
The image base is the preferred virtual address where the PE file should be loaded in memory. This is used for calculating virtual addresses.
§Examples
use dotscope::File;
use std::path::Path;
let file = File::from_file(Path::new("tests/samples/WindowsBase.dll"))?;
let base = file.imagebase();
println!("Image base: 0x{:x}", base);pub fn header(&self) -> &Header<'_>
pub fn header(&self) -> &Header<'_>
Returns a reference to the PE header.
The PE header contains essential metadata about the executable, including the machine type, number of sections, and timestamp.
§Examples
use dotscope::File;
use std::path::Path;
let file = File::from_file(Path::new("tests/samples/WindowsBase.dll"))?;
let header = file.header();
println!("Machine type: 0x{:x}", header.coff_header.machine);
println!("Number of sections: {}", header.coff_header.number_of_sections);pub fn header_dos(&self) -> &DosHeader
pub fn header_dos(&self) -> &DosHeader
Returns a reference to the DOS header.
The DOS header is the first part of a PE file and contains the DOS stub that displays the “This program cannot be run in DOS mode” message.
§Examples
use dotscope::File;
use std::path::Path;
let file = File::from_file(Path::new("tests/samples/WindowsBase.dll"))?;
let dos_header = file.header_dos();
println!("DOS signature: 0x{:x}", dos_header.signature);
println!("Number of bytes on last page: {}", dos_header.bytes_on_last_page);pub fn header_optional(&self) -> &Option<OptionalHeader>
pub fn header_optional(&self) -> &Option<OptionalHeader>
Returns a reference to the optional header, if present.
This is always Some for valid .NET assemblies since they require
an optional header to define data directories and other metadata.
§Examples
use dotscope::File;
use std::path::Path;
let file = File::from_file(Path::new("tests/samples/WindowsBase.dll"))?;
let optional_header = file.header_optional().unwrap();
println!("Entry point: 0x{:x}", optional_header.standard_fields.address_of_entry_point);
println!("Subsystem: {:?}", optional_header.windows_fields.subsystem);pub fn clr(&self) -> (usize, usize)
pub fn clr(&self) -> (usize, usize)
Returns the RVA and size (in bytes) of the CLR runtime header.
The CLR runtime header contains metadata about the .NET runtime, including pointers to metadata tables and other runtime structures.
§Returns
A tuple containing (rva, size) where:
rvais the relative virtual address of the CLR headersizeis the size of the CLR header in bytes
§Examples
use dotscope::File;
use std::path::Path;
let file = File::from_file(Path::new("tests/samples/WindowsBase.dll"))?;
let (clr_rva, clr_size) = file.clr();
println!("CLR header at RVA: 0x{:x}, size: {} bytes", clr_rva, clr_size);§Panics
Panics if the CLR runtime header is missing (should not happen for valid .NET assemblies).
pub fn sections(&self) -> impl Iterator<Item = &SectionTable>
pub fn sections(&self) -> impl Iterator<Item = &SectionTable>
Returns an iterator over the section headers of the PE file.
Sections contain the actual code and data of the PE file, such as
.text (executable code), .data (initialized data), and .rsrc (resources).
§Examples
use dotscope::File;
use std::path::Path;
let file = File::from_file(Path::new("tests/samples/WindowsBase.dll"))?;
for section in file.sections() {
let name = std::str::from_utf8(§ion.name)
.unwrap_or("<invalid>")
.trim_end_matches('\0');
println!("Section: {} at RVA 0x{:x}, size: {} bytes",
name, section.virtual_address, section.virtual_size);
}pub fn directories(&self) -> Vec<(DataDirectoryType, DataDirectory)>
pub fn directories(&self) -> Vec<(DataDirectoryType, DataDirectory)>
Returns the data directories of the PE file.
§Examples
use dotscope::File;
use std::path::Path;
let file = File::from_file(Path::new("tests/samples/WindowsBase.dll"))?;
for (dir_type, directory) in file.directories() {
println!("Directory: {:?}, RVA: 0x{:x}", dir_type, directory.virtual_address);
}§Panics
Panics if the optional header is missing (should not happen for valid .NET assemblies).
pub fn data(&self) -> &[u8] ⓘ
pub fn data(&self) -> &[u8] ⓘ
Returns the raw data of the loaded file.
This provides access to the entire PE file contents as a byte slice. Useful for reading specific offsets or when you need direct access to the binary data.
§Examples
use dotscope::File;
use std::path::Path;
let file = File::from_file(Path::new("tests/samples/WindowsBase.dll"))?;
let data = file.data();
// Check DOS signature (MZ)
assert_eq!(&data[0..2], b"MZ");
// Access PE signature offset
let pe_offset = u32::from_le_bytes([data[60], data[61], data[62], data[63]]) as usize;
assert_eq!(&data[pe_offset..pe_offset + 4], b"PE\0\0");pub fn data_slice(&self, offset: usize, len: usize) -> Result<&[u8]>
pub fn data_slice(&self, offset: usize, len: usize) -> Result<&[u8]>
Returns a slice of the file data at the given offset and length.
This is a safe way to access specific portions of the PE file data with bounds checking to prevent buffer overflows.
§Arguments
offset- The offset to start the slice from.len- The length of the slice.
§Errors
Returns an error if the requested range is out of bounds.
§Examples
use dotscope::File;
use std::path::Path;
let file = File::from_file(Path::new("tests/samples/WindowsBase.dll"))?;
// Read the DOS header (first 64 bytes)
let dos_header = file.data_slice(0, 64)?;
assert_eq!(&dos_header[0..2], b"MZ");
// Read PE signature
let pe_offset = u32::from_le_bytes([dos_header[60], dos_header[61],
dos_header[62], dos_header[63]]) as usize;
let pe_sig = file.data_slice(pe_offset, 4)?;
assert_eq!(pe_sig, b"PE\0\0");pub fn va_to_offset(&self, va: usize) -> Result<usize>
pub fn va_to_offset(&self, va: usize) -> Result<usize>
Converts a virtual address (VA) to a file offset.
Virtual addresses are absolute addresses where the PE file would be loaded in memory. This method converts them to file offsets for reading data from the actual file.
§Arguments
va- The virtual address to convert.
§Errors
Returns an error if the VA is out of bounds or cannot be mapped.
§Examples
use dotscope::File;
use std::path::Path;
let file = File::from_file(Path::new("tests/samples/WindowsBase.dll"))?;
// Convert entry point VA to file offset
let entry_point_va = file.header_optional().unwrap().standard_fields.address_of_entry_point as usize;
let image_base = file.imagebase() as usize;
let full_va = image_base + entry_point_va;
let offset = file.va_to_offset(full_va)?;
println!("Entry point at file offset: 0x{:x}", offset);pub fn rva_to_offset(&self, rva: usize) -> Result<usize>
pub fn rva_to_offset(&self, rva: usize) -> Result<usize>
Converts a relative virtual address (RVA) to a file offset.
RVAs are addresses relative to the image base. This is the most common address format used within PE files for referencing data and code.
§Arguments
rva- The RVA to convert.
§Errors
Returns an error if the RVA cannot be mapped to a file offset.
§Examples
use dotscope::File;
use std::path::Path;
let file = File::from_file(Path::new("tests/samples/WindowsBase.dll"))?;
// Convert CLR header RVA to file offset
let (clr_rva, _) = file.clr();
let clr_offset = file.rva_to_offset(clr_rva)?;
// Read CLR header data
let clr_data = file.data_slice(clr_offset, 72)?; // CLR header is 72 bytes
println!("CLR header starts with: {:02x?}", &clr_data[0..8]);pub fn offset_to_rva(&self, offset: usize) -> Result<usize>
pub fn offset_to_rva(&self, offset: usize) -> Result<usize>
Converts a file offset to a relative virtual address (RVA).
This is the inverse of rva_to_offset(). Given a file offset,
it calculates what RVA that offset corresponds to when the
PE file is loaded in memory.
§Arguments
offset- The file offset to convert.
§Errors
Returns an error if the offset cannot be mapped to an RVA.
§Examples
use dotscope::File;
use std::path::Path;
let file = File::from_file(Path::new("tests/samples/WindowsBase.dll"))?;
// Find what RVA corresponds to file offset 0x1000
let rva = file.offset_to_rva(0x1000)?;
println!("File offset 0x1000 maps to RVA 0x{:x}", rva);
// Verify round-trip conversion
let back_to_offset = file.rva_to_offset(rva)?;
assert_eq!(back_to_offset, 0x1000);Trait Implementations§
Auto Trait Implementations§
impl Freeze for File
impl !RefUnwindSafe for File
impl Send for File
impl Sync for File
impl Unpin for File
impl !UnwindSafe for File
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more