hexspell 0.0.5

A open source lib to parse executables in Rust
Documentation
//! Utilities for parsing and rewriting ELF binaries.
//!
//! The [`ELF`] type encapsulates a binary loaded from disk and provides
//! access to its file header, program headers, and section headers. Each
//! part of the format is parsed lazily into strongly typed structures so
//! that values can be inspected or modified before being written back.
//!
//! While HexSpell only supports a subset of the ELF specification, the
//! API is intentionally designed to mirror the standard and remain easy
//! to extend. This makes it suitable for experiments, teaching purposes,
//! or light-weight patching tasks.

pub mod header;
pub mod program;
pub mod section;

use crate::errors;
use std::fs;
use std::io::{self, Read, Write};

use header::ElfHeader;
use program::ProgramHeader;
use section::SectionHeader;

pub struct ELF {
    pub buffer: Vec<u8>,
    pub header: ElfHeader,
    pub program_headers: Vec<ProgramHeader>,
    pub section_headers: Vec<SectionHeader>,
}

impl ELF {
    /// Write `self.buffer` to disk.
    pub fn write_file(&self, output_path: &str) -> io::Result<()> {
        let mut file = fs::File::create(output_path)?;
        file.write_all(&self.buffer)?;
        Ok(())
    }

    /// Parses a ELF file from a specified file path.
    ///
    /// # Arguments
    /// * `path` - A string slice that holds the path to the ELF file.
    ///
    /// # Returns
    /// A `Result` that is either a `ELF` on success, or a `FileParseError` on failure.
    ///
    /// # Example
    /// ```
    /// use hexspell::elf::ELF;
    /// let elf_file = ELF::from_file("tests/samples/linux").unwrap();
    /// ```
    pub fn from_file(path: &str) -> Result<Self, errors::FileParseError> {
        let mut file = fs::File::open(path)?;
        let mut buffer = Vec::new();
        file.read_to_end(&mut buffer)?;
        Self::from_buffer(buffer)
    }

    /// Parses a ELF file from a byte vector.
    ///
    /// # Arguments
    /// * `buffer` - A byte vector containing the ELF file data.
    ///
    /// # Returns
    /// A `Result` that is either a `ELF` on success, or a `FileParseError` on failure.
    ///
    /// # Example
    /// ```
    /// use hexspell::elf::ELF;
    /// let data = std::fs::read("tests/samples/linux").expect("Failed to read file");
    /// let elf_file = ELF::from_buffer(data).unwrap();
    /// ```
    pub fn from_buffer(buffer: Vec<u8>) -> Result<Self, errors::FileParseError> {
        if buffer.len() < 64 {
            return Err(errors::FileParseError::BufferOverflow);
        }

        let header = ElfHeader::parse(&buffer)?;
        let program_headers = ProgramHeader::parse_program_headers(
            &buffer,
            header.ph_off.value,
            header.ph_ent_size.value,
            header.ph_num.value,
            header.endianness,
        )?;
        let section_headers = SectionHeader::parse_section_headers(
            &buffer,
            header.sh_off.value,
            header.sh_ent_size.value,
            header.sh_num.value,
            header.endianness,
        )?;

        Ok(ELF {
            buffer,
            header,
            program_headers,
            section_headers,
        })
    }
}