hexspell/elf/
header.rs

1//! Definitions relating to the ELF file header.
2//!
3//! The file header contains global information about the binary such as
4//! its architecture, entry point and endianness. This module models that
5//! data using [`Field`](crate::field::Field) so the underlying bytes can be
6//! changed safely. Helper methods interpret raw numeric values into more
7//! meaningful enums, reducing boilerplate for consumers of the crate.
8
9use crate::errors;
10use crate::field::Field;
11
12#[derive(Debug, PartialEq, Eq)]
13pub enum ElfType {
14    None,
15    Relocatable,
16    Executable,
17    SharedObject,
18    Core,
19    Other(u16),
20}
21
22impl From<u16> for ElfType {
23    fn from(value: u16) -> Self {
24        match value {
25            0 => Self::None,
26            1 => Self::Relocatable,
27            2 => Self::Executable,
28            3 => Self::SharedObject,
29            4 => Self::Core,
30            _ => Self::Other(value),
31        }
32    }
33}
34
35#[derive(Debug, Clone, Copy)]
36pub enum Endianness {
37    Little,
38    Big,
39}
40
41#[derive(Debug)]
42pub struct ElfHeader {
43    pub ident: Vec<u8>,
44    pub endianness: Endianness,
45    pub elf_type: Field<ElfType>,
46    pub machine: Field<u16>,
47    pub version: Field<u32>,
48    pub entry: Field<u64>,
49    pub ph_off: Field<u64>,
50    pub sh_off: Field<u64>,
51    pub flags: Field<u32>,
52    pub eh_size: Field<u16>,
53    pub ph_ent_size: Field<u16>,
54    pub ph_num: Field<u16>,
55    pub sh_ent_size: Field<u16>,
56    pub sh_num: Field<u16>,
57    pub sh_strndx: Field<u16>,
58}
59
60impl ElfHeader {
61    pub fn parse(buffer: &[u8]) -> Result<Self, errors::FileParseError> {
62        if buffer.len() < 64 {
63            return Err(errors::FileParseError::BufferOverflow);
64        }
65
66        // Check magic bytes
67        if buffer[0..4] != [0x7F, b'E', b'L', b'F'] {
68            return Err(errors::FileParseError::InvalidFileFormat);
69        }
70
71        let ident: Vec<u8> = buffer[0..16].to_vec();
72        let endianness = match buffer[5] {
73            1 => Endianness::Little,
74            2 => Endianness::Big,
75            _ => return Err(errors::FileParseError::InvalidFileFormat),
76        };
77
78        let read_u16 = |offset: usize| -> u16 {
79            let bytes = [buffer[offset], buffer[offset + 1]];
80            match endianness {
81                Endianness::Little => u16::from_le_bytes(bytes),
82                Endianness::Big => u16::from_be_bytes(bytes),
83            }
84        };
85        let read_u32 = |offset: usize| -> u32 {
86            let bytes = [
87                buffer[offset],
88                buffer[offset + 1],
89                buffer[offset + 2],
90                buffer[offset + 3],
91            ];
92            match endianness {
93                Endianness::Little => u32::from_le_bytes(bytes),
94                Endianness::Big => u32::from_be_bytes(bytes),
95            }
96        };
97        let read_u64 = |offset: usize| -> u64 {
98            let bytes = [
99                buffer[offset],
100                buffer[offset + 1],
101                buffer[offset + 2],
102                buffer[offset + 3],
103                buffer[offset + 4],
104                buffer[offset + 5],
105                buffer[offset + 6],
106                buffer[offset + 7],
107            ];
108            match endianness {
109                Endianness::Little => u64::from_le_bytes(bytes),
110                Endianness::Big => u64::from_be_bytes(bytes),
111            }
112        };
113
114        let elf_type: Field<ElfType> = Field::new(ElfType::from(read_u16(16)), 16, 2);
115        let machine: Field<u16> = Field::new(read_u16(18), 18, 2);
116        let version: Field<u32> = Field::new(read_u32(20), 20, 4);
117        let entry: Field<u64> = Field::new(read_u64(24), 24, 8);
118        let ph_off: Field<u64> = Field::new(read_u64(32), 32, 8);
119        let sh_off: Field<u64> = Field::new(read_u64(40), 40, 8);
120        let flags: Field<u32> = Field::new(read_u32(48), 48, 4);
121        let eh_size: Field<u16> = Field::new(read_u16(52), 52, 2);
122        let ph_ent_size: Field<u16> = Field::new(read_u16(54), 54, 2);
123        let ph_num: Field<u16> = Field::new(read_u16(56), 56, 2);
124        let sh_ent_size: Field<u16> = Field::new(read_u16(58), 58, 2);
125        let sh_num: Field<u16> = Field::new(read_u16(60), 60, 2);
126        let sh_strndx: Field<u16> = Field::new(read_u16(62), 62, 2);
127
128        Ok(ElfHeader {
129            ident,
130            endianness,
131            elf_type,
132            machine,
133            version,
134            entry,
135            ph_off,
136            sh_off,
137            flags,
138            eh_size,
139            ph_ent_size,
140            ph_num,
141            sh_ent_size,
142            sh_num,
143            sh_strndx,
144        })
145    }
146}