Struct CilObject

pub struct CilObject { /* private fields */ }
Expand description

The self-referencing struct.

Implementations§

§

impl CilObject

pub fn from_file(file: &Path) -> Result<Self>

Creates a new CilObject by loading and parsing a .NET assembly from disk.

This method handles the complete loading process including file I/O, PE header validation, and metadata parsing. The file is memory-mapped for efficient access to large assemblies.

§Arguments
  • file - Path to the .NET assembly file (.dll, .exe, or .netmodule)
§Returns

Returns a fully parsed CilObject or an error if:

  • The file cannot be opened or read
  • The file is not a valid PE format
  • The PE file is not a valid .NET assembly
  • Metadata streams are corrupted or invalid
§Examples
use dotscope::CilObject;
use std::path::Path;

let assembly = CilObject::from_file(Path::new("tests/samples/WindowsBase.dll"))?;
println!("Loaded assembly: {}", assembly.assembly().unwrap().name);
§Errors

Returns an error if the file cannot be read or parsed as a valid .NET assembly.

pub fn from_file_with_validation( file: &Path, validation_config: ValidationConfig, ) -> Result<Self>

Creates a new CilObject by parsing a .NET assembly from a file with custom validation configuration.

This method allows you to control which validation checks are performed during loading. Use this when you need to balance performance vs. validation coverage.

§Arguments
  • file - Path to the .NET assembly file
  • validation_config - Configuration specifying which validation checks to perform
§Examples
use dotscope::{CilObject, ValidationConfig};
use std::path::Path;

// Load with minimal validation for maximum performance
let assembly = CilObject::from_file_with_validation(
    Path::new("tests/samples/WindowsBase.dll"),
    ValidationConfig::minimal()
)?;

// Load with production validation for balance of safety and performance
let assembly = CilObject::from_file_with_validation(
    Path::new("tests/samples/WindowsBase.dll"),
    ValidationConfig::production()
)?;
§Errors

Returns an error if the file cannot be read, parsed as a valid .NET assembly, or if validation checks fail.

pub fn from_mem(data: Vec<u8>) -> Result<Self>

Creates a new CilObject by parsing a .NET assembly from a memory buffer.

This method is useful for analyzing assemblies that are already loaded in memory, downloaded from network sources, or embedded as resources. The data is copied internally to ensure proper lifetime management.

§Arguments
  • data - Raw bytes of the .NET assembly in PE format
§Returns

Returns a fully parsed CilObject or an error if:

  • The data is not a valid PE format
  • The PE data is not a valid .NET assembly
  • Metadata streams are corrupted or invalid
  • Memory allocation fails during processing
§Examples
use dotscope::CilObject;

// Load assembly from network or embedded resource
//let assembly_bytes = download_assembly().await?;
//let assembly = CilObject::from_mem(assembly_bytes)?;

// Or from file for comparison
let file_data = std::fs::read("tests/samples/WindowsBase.dll")?;
let assembly = CilObject::from_mem(file_data)?;
§Errors

Returns an error if the memory buffer cannot be parsed as a valid .NET assembly.

pub fn from_mem_with_validation( data: Vec<u8>, validation_config: ValidationConfig, ) -> Result<Self>

Creates a new CilObject by parsing a .NET assembly from a memory buffer with custom validation configuration.

This method allows you to control which validation checks are performed during loading. Use this when you need to balance performance vs. validation coverage.

§Arguments
  • data - Raw bytes of the .NET assembly in PE format
  • validation_config - Configuration specifying which validation checks to perform
§Examples
use dotscope::{CilObject, ValidationConfig};

let file_data = std::fs::read("tests/samples/WindowsBase.dll")?;

// Load with production validation settings
let assembly = CilObject::from_mem_with_validation(
    file_data.clone(),
    ValidationConfig::production()
)?;
§Errors

Returns an error if the memory buffer cannot be parsed as a valid .NET assembly or if validation checks fail.

pub fn cor20header(&self) -> &Cor20Header

Returns the COR20 header containing .NET-specific PE information.

The COR20 header (also known as CLI header) contains essential information about the .NET assembly including metadata directory location, entry point, and runtime flags. This header is always present in valid .NET assemblies.

§Returns

Reference to the parsed Cor20Header structure containing:

  • Metadata directory RVA and size
  • Entry point token (for executables)
  • Runtime flags (IL_ONLY, 32BIT_REQUIRED, etc.)
  • Resources and strong name signature locations
§Examples
use dotscope::CilObject;

let assembly = CilObject::from_file("tests/samples/WindowsBase.dll".as_ref())?;
let header = assembly.cor20header();

println!("Metadata RVA: 0x{:X}", header.meta_data_rva);
println!("Runtime flags: {:?}", header.flags);

pub fn metadata_root(&self) -> &Root

Returns the metadata root header containing stream directory information.

The metadata root is the entry point to the .NET metadata system, containing the version signature, stream count, and directory of all metadata streams (#~, #Strings, #US, #GUID, #Blob). This structure is always present and provides the foundation for accessing all assembly metadata.

§Returns

Reference to the parsed Root structure containing:

  • Metadata format version and signature
  • Stream directory with names, offsets, and sizes
  • Framework version string
§Examples
use dotscope::CilObject;

let assembly = CilObject::from_file("tests/samples/WindowsBase.dll".as_ref())?;
let root = assembly.metadata_root();

println!("Metadata version: {}", root.version);
println!("Number of streams: {}", root.stream_headers.len());
for stream in &root.stream_headers {
    println!("Stream: {} at offset 0x{:X}", stream.name, stream.offset);
}

pub fn tables(&self) -> Option<&TablesHeader<'_>>

Returns the metadata tables header from the #~ or #- stream.

The tables header contains all metadata tables defined by ECMA-335, including Type definitions, Method definitions, Field definitions, Assembly references, and many others. This is the core of .NET metadata and provides structured access to all assembly information.

§Returns
  • Some(&TablesHeader) if the #~ stream is present (compressed metadata)
  • None if no tables stream is found (invalid or malformed assembly)

The TablesHeader provides access to:

  • All metadata table row counts and data
  • String, GUID, and Blob heap indices
  • Schema version and heap size information
§Examples
use dotscope::{CilObject, metadata::tables::{TypeDefRaw, TableId}};

let assembly = CilObject::from_file("tests/samples/WindowsBase.dll".as_ref())?;

if let Some(tables) = assembly.tables() {
    println!("Schema version: {}.{}", tables.major_version, tables.minor_version);
     
    // Access individual tables
    if let Some(typedef_table) = &tables.table::<TypeDefRaw>(TableId::TypeDef) {
        println!("Number of types: {}", typedef_table.row_count());
    }
}

pub fn strings(&self) -> Option<&Strings<'_>>

Returns the strings heap from the #Strings stream.

The strings heap contains null-terminated UTF-8 strings used throughout the metadata tables for names of types, members, parameters, and other identifiers. String references in tables are indices into this heap.

§Returns
  • Some(&Strings) if the #Strings stream is present
  • None if the stream is missing (malformed assembly)
§Examples
use dotscope::CilObject;

let assembly = CilObject::from_file("tests/samples/WindowsBase.dll".as_ref())?;

if let Some(strings) = assembly.strings() {
    // Look up string by index (from metadata table)
    if let Ok(name) = strings.get(0x123) {
        println!("String at index 0x123: {}", name);
    }
}

pub fn userstrings(&self) -> Option<&UserStrings<'_>>

Returns the user strings heap from the #US stream.

The user strings heap contains length-prefixed Unicode strings that appear as string literals in CIL code (e.g., from C# string literals). These are accessed via the ldstr instruction and are distinct from metadata strings.

§Returns
  • Some(&UserStrings) if the #US stream is present
  • None if the stream is missing (assembly has no string literals)
§Examples
use dotscope::CilObject;

let assembly = CilObject::from_file("tests/samples/WindowsBase.dll".as_ref())?;

if let Some(user_strings) = assembly.userstrings() {
    // Look up user string by token (from ldstr instruction)
    if let Ok(literal) = user_strings.get(0x70000001) {
        println!("String literal: {}", literal.to_string().unwrap());
    }
}

pub fn guids(&self) -> Option<&Guid<'_>>

Returns the GUID heap from the #GUID stream.

The GUID heap contains 16-byte GUIDs referenced by metadata tables, typically used for type library IDs, interface IDs, and other unique identifiers in COM interop scenarios.

§Returns
  • Some(&Guid) if the #GUID stream is present
  • None if the stream is missing (assembly has no GUID references)
§Examples
use dotscope::CilObject;

let assembly = CilObject::from_file("tests/samples/WindowsBase.dll".as_ref())?;

if let Some(guids) = assembly.guids() {
    // Look up GUID by index (from metadata table)
    if let Ok(guid) = guids.get(1) {
        println!("GUID: {}", guid);
    }
}

pub fn blob(&self) -> Option<&Blob<'_>>

Returns the blob heap from the #Blob stream.

The blob heap contains variable-length binary data referenced by metadata tables, including type signatures, method signatures, field signatures, custom attribute values, and marshalling information.

§Returns
  • Some(&Blob) if the #Blob stream is present
  • None if the stream is missing (malformed assembly)
§Examples
use dotscope::CilObject;

let assembly = CilObject::from_file("tests/samples/WindowsBase.dll".as_ref())?;

if let Some(blob) = assembly.blob() {
    // Look up blob by index (from metadata table)
    if let Ok(signature) = blob.get(0x456) {
        println!("Signature bytes: {:02X?}", signature);
    }
}

pub fn refs_assembly(&self) -> &AssemblyRefMap

Returns all assembly references used by this assembly.

Assembly references represent external .NET assemblies that this assembly depends on, including version information, public key tokens, and culture settings. These correspond to entries in the AssemblyRef metadata table.

§Returns

Reference to the AssemblyRefMap containing all external assembly dependencies.

§Examples
use dotscope::CilObject;

let assembly = CilObject::from_file("tests/samples/WindowsBase.dll".as_ref())?;
let refs = assembly.refs_assembly();

for entry in refs.iter() {
    let (token, assembly_ref) = (entry.key(), entry.value());
    println!("Dependency: {} v{}.{}.{}.{}",
        assembly_ref.name,
        assembly_ref.major_version,
        assembly_ref.minor_version,
        assembly_ref.build_number,
        assembly_ref.revision_number
    );
}

pub fn refs_module(&self) -> &ModuleRefMap

Returns all module references used by this assembly.

Module references represent external unmanaged modules (native DLLs) that this assembly imports functions from via P/Invoke declarations. These correspond to entries in the ModuleRef metadata table.

§Returns

Reference to the ModuleRefMap containing all external module dependencies.

§Examples
use dotscope::CilObject;

let assembly = CilObject::from_file("tests/samples/WindowsBase.dll".as_ref())?;
let refs = assembly.refs_module();

for entry in refs.iter() {
    let (token, module_ref) = (entry.key(), entry.value());
    println!("Native module: {}", module_ref.name);
}

pub fn refs_members(&self) -> &MemberRefMap

Returns all member references used by this assembly.

Member references represent external type members (methods, fields, properties) from other assemblies that are referenced by this assembly’s code. These correspond to entries in the MemberRef metadata table.

§Returns

Reference to the MemberRefMap containing all external member references.

§Examples
use dotscope::CilObject;

let assembly = CilObject::from_file("tests/samples/WindowsBase.dll".as_ref())?;
let refs = assembly.refs_members();

for entry in refs.iter() {
    let (token, member_ref) = (entry.key(), entry.value());
    println!("External member: {}", member_ref.name);
}

pub fn module(&self) -> Option<&ModuleRc>

Returns the primary module information for this assembly.

The module represents the main file of the assembly, containing the module’s name, MVID (Module Version Identifier), and generation ID. Multi-file assemblies can have additional modules, but there’s always one primary module.

§Returns
  • Some(&ModuleRc) if module information is present
  • None if no module table entry exists (malformed assembly)
§Examples
use dotscope::CilObject;

let assembly = CilObject::from_file("tests/samples/WindowsBase.dll".as_ref())?;

if let Some(module) = assembly.module() {
    println!("Module name: {}", module.name);
    println!("Module GUID: {}", module.mvid);
}

pub fn assembly(&self) -> Option<&AssemblyRc>

Returns the assembly metadata for this .NET assembly.

The assembly metadata contains the assembly’s identity including name, version, culture, public key information, and security attributes. This corresponds to the Assembly metadata table entry.

§Returns
  • Some(&AssemblyRc) if assembly metadata is present
  • None if this is a module-only file (no Assembly table entry)
§Examples
use dotscope::CilObject;

let assembly = CilObject::from_file("tests/samples/WindowsBase.dll".as_ref())?;

if let Some(assembly_info) = assembly.assembly() {
    println!("Assembly: {}", assembly_info.name);
    println!("Version: {}.{}.{}.{}",
        assembly_info.major_version,
        assembly_info.minor_version,
        assembly_info.build_number,
        assembly_info.revision_number
    );
}

pub fn assembly_os(&self) -> Option<&AssemblyOsRc>

Returns assembly OS information if present.

The AssemblyOS table contains operating system identification information for the assembly. This table is rarely used in modern .NET assemblies and is primarily for legacy compatibility.

§Returns
  • Some(&AssemblyOsRc) if OS information is present
  • None if no AssemblyOS table entry exists (typical for most assemblies)

pub fn assembly_processor(&self) -> Option<&AssemblyProcessorRc>

Returns assembly processor information if present.

The AssemblyProcessor table contains processor architecture identification information for the assembly. This table is rarely used in modern .NET assemblies and is primarily for legacy compatibility.

§Returns
  • Some(&AssemblyProcessorRc) if processor information is present
  • None if no AssemblyProcessor table entry exists (typical for most assemblies)

pub fn imports(&self) -> &Imports

Returns the imports container with all P/Invoke and COM import information.

The imports container provides access to all external function imports including P/Invoke declarations, COM method imports, and related marshalling information. This data comes from ImplMap and related tables.

§Returns

Reference to the Imports container with all import declarations.

§Examples
use dotscope::CilObject;

let assembly = CilObject::from_file("tests/samples/WindowsBase.dll".as_ref())?;
let imports = assembly.imports();

for entry in imports.iter() {
    let (token, import) = (entry.key(), entry.value());
    println!("Import: {}.{} from {:?}", import.namespace, import.name, import.source_id);
}

pub fn exports(&self) -> &Exports

Returns the exports container with all exported function information.

The exports container provides access to all functions that this assembly exports for use by other assemblies or native code. This includes both managed exports and any native exports in mixed-mode assemblies.

§Returns

Reference to the Exports container with all export declarations.

§Examples
use dotscope::CilObject;

let assembly = CilObject::from_file("tests/samples/WindowsBase.dll".as_ref())?;
let exports = assembly.exports();

for entry in exports.iter() {
    let (token, export) = (entry.key(), entry.value());
    println!("Export: {} at offset 0x{:X} - Token 0x{:X}", export.name, export.offset, token.value());
}

pub fn methods(&self) -> &MethodMap

Returns the methods container with all method definitions and metadata.

The methods container provides access to all methods defined in this assembly, including their signatures, IL code, exception handlers, and related metadata. This integrates data from MethodDef, Param, and other method-related tables.

§Returns

Reference to the MethodMap containing all method definitions.

§Examples
use dotscope::CilObject;

let assembly = CilObject::from_file("tests/samples/WindowsBase.dll".as_ref())?;
let methods = assembly.methods();

for entry in methods.iter() {
    let (token, method) = (entry.key(), entry.value());
    println!("Method: {} (Token: 0x{:08X})", method.name, token.value());
    if let Some(rva) = method.rva {
        println!("  RVA: 0x{:X}", rva);
    }
}

pub fn method_specs(&self) -> &MethodSpecMap

Returns the method specifications container with all generic method instantiations.

The method specifications container provides access to all generic method instantiations defined in this assembly. MethodSpec entries represent calls to generic methods with specific type arguments, enabling IL instructions to reference these instantiations.

§Returns

Reference to the MethodSpecMap containing all method specifications.

§Examples
use dotscope::CilObject;

let assembly = CilObject::from_file("tests/samples/WindowsBase.dll".as_ref())?;
let method_specs = assembly.method_specs();

for entry in method_specs.iter() {
    let (token, method_spec) = (entry.key(), entry.value());
    println!("MethodSpec: Token 0x{:08X}", token.value());
    println!("  Generic args count: {}", method_spec.generic_args.count());
}

pub fn resources(&self) -> &Resources

Returns the resources container with all embedded and linked resources.

The resources container provides access to all resources associated with this assembly, including embedded resources, linked files, and resource metadata. This includes both .NET resources and Win32 resources.

§Returns

Reference to the Resources container with all resource information.

§Examples
use dotscope::CilObject;

let assembly = CilObject::from_file("tests/samples/WindowsBase.dll".as_ref())?;
let resources = assembly.resources();

for entry in resources.iter() {
    let (name, resource) = (entry.key(), entry.value());
    println!("Resource: {} (Size: {}, Offset: 0x{:X})", name, resource.data_offset, resource.data_size);
}

pub fn types(&self) -> &TypeRegistry

Returns the type registry containing all type definitions and references.

The type registry provides centralized access to all types defined in and referenced by this assembly. This includes TypeDef entries (types defined in this assembly), TypeRef entries (types referenced from other assemblies), TypeSpec entries (instantiated generic types), and primitive types.

§Returns

Reference to the TypeRegistry containing all type information.

§Examples
use dotscope::CilObject;

let assembly = CilObject::from_file("tests/samples/WindowsBase.dll".as_ref())?;
let types = assembly.types();

println!("Total types: {}", types.len());

// Get all types
for type_info in types.all_types() {
    println!("Type: {}.{} (Token: 0x{:08X})",
        type_info.namespace, type_info.name, type_info.token.value());
}

// Look up specific types
let string_types = types.get_by_name("String");
for string_type in string_types {
    println!("Found String type in namespace: {}", string_type.namespace);
}

pub fn file(&self) -> &Arc<File>

Returns the underlying file representation of this assembly.

The file object provides access to the raw PE file data, headers, and file-level operations such as RVA-to-offset conversion, section access, and memory-mapped or buffered file I/O. This is useful for low-level analysis or when you need direct access to the PE file structure.

§Returns

Reference to the Arc<File> containing the PE file representation.

§Examples
use dotscope::CilObject;

let assembly = CilObject::from_file("tests/samples/WindowsBase.dll".as_ref())?;
let file = assembly.file();

// Access file-level information
println!("File size: {} bytes", file.data().len());

// Access PE headers
let dos_header = file.header_dos();
let nt_headers = file.header();
println!("PE signature: 0x{:X}", nt_headers.signature);

// Convert RVA to file offset
let (clr_rva, _) = file.clr();
let offset = file.rva_to_offset(clr_rva)?;
println!("CLR header at file offset: 0x{:X}", offset);

pub fn validate(&self, config: ValidationConfig) -> Result<()>

Performs comprehensive validation on the loaded assembly.

This method allows you to validate an already-loaded assembly with specific validation settings. This is useful when you want to perform additional validation after loading, or when you loaded with minimal validation initially.

§Arguments
  • config - Validation configuration specifying which validations to perform
§Returns

Returns Ok(()) if all validations pass, or an error describing any validation failures found.

§Examples
use dotscope::{CilObject, ValidationConfig};
use std::path::Path;

// Load assembly with minimal validation for speed
let assembly = CilObject::from_file_with_validation(
    Path::new("tests/samples/WindowsBase.dll"),
    ValidationConfig::minimal()
)?;

// Later, perform comprehensive validation
assembly.validate(ValidationConfig::comprehensive())?;
§Errors

Returns validation errors found during analysis, such as:

  • Circular type nesting
  • Field layout overlaps
  • Invalid generic constraints
  • Type system inconsistencies

Trait Implementations§

§

impl Drop for CilObject

§

fn drop(&mut self)

Executes the destructor for this type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts 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 more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts 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
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.