1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
use crate::{
    header,
    section::{self, Section32},
    segment,
};

#[repr(C)]
#[derive(Default, Clone, Hash, PartialOrd, Ord, PartialEq, Eq)]
pub struct ELF32 {
    pub ehdr: header::Ehdr32,
    pub sections: Vec<section::Section32>,
    pub segments: Vec<segment::Segment32>,
}

impl ELF32 {
    /// add a section with creating new entry of section table and etc.
    pub fn add_section(&mut self, mut sct: section::Section32) {
        // ehdr.e_shstrndxの変更のために計算
        let is_section_name_table = sct.name == ".shstrtab";

        // 新しいセクションのsh_name等を計算する為に
        // 現在の末尾のセクションを取得する
        let last_sct_idx = self.sections.len() - 1;
        self.fill_elf_info(&mut sct, last_sct_idx, &self.sections[last_sct_idx]);

        // セクションの追加 => SHTの開始オフセットが変更される
        self.ehdr.e_shoff += sct.header.sh_size;
        self.ehdr.e_shnum += 1;

        self.sections.push(sct);

        if is_section_name_table {
            self.ehdr.e_shstrndx = self.sections.len() as u16 - 1;
        }
    }

    pub fn add_segment(&mut self, sgt: segment::Segment32) {
        // PHTに追加される => SHTのオフセットと各セクションのオフセットが変更される
        self.ehdr.e_shoff += segment::Phdr32::SIZE as u32;
        for sct in self.sections.iter_mut() {
            sct.header.sh_offset += segment::Phdr32::SIZE as u32;
        }
        self.ehdr.e_phnum += 1;

        self.segments.push(sgt);
    }
    pub fn to_le_bytes(&self) -> Vec<u8> {
        let mut file_binary: Vec<u8> = Vec::new();

        let mut header_binary = self.ehdr.to_le_bytes();
        file_binary.append(&mut header_binary);

        for seg in self.segments.iter() {
            let mut phdr_binary = seg.header.to_le_bytes();
            file_binary.append(&mut phdr_binary);
        }

        for sct in self.sections.iter() {
            // セクションタイプによって処理を変える
            let mut section_binary = sct.to_le_bytes();
            file_binary.append(&mut section_binary);
        }

        for sct in self.sections.iter() {
            let mut shdr_binary = sct.header.to_le_bytes();
            file_binary.append(&mut shdr_binary);
        }
        file_binary
    }

    /// sh_nameやsh_offset等の調整
    fn fill_elf_info(&self, new_sct: &mut Section32, prev_sct_idx: usize, prev_sct: &Section32) {
        let prev_name_idx = prev_sct.header.sh_name;
        let prev_name_len = prev_sct.name.as_bytes().len() as u32;
        let prev_offset = prev_sct.header.sh_offset;
        let prev_size = prev_sct.header.sh_size;

        // <prev_section_name> の後に0x00が入るので,+1
        new_sct.header.sh_name = prev_name_idx + prev_name_len + 1;

        // NULLセクションのすぐ次に挿入する場合,
        // sh_offsetはEhdr32::SIZE + PHT's SIZEという感じになる.
        if prev_sct_idx == 0 {
            new_sct.header.sh_offset = header::Ehdr32::SIZE as u32
                + segment::Phdr32::SIZE as u32 * self.segments.len() as u32;
        } else {
            new_sct.header.sh_offset = prev_offset + prev_size;
        }

        new_sct.header.sh_size = new_sct.contents.size() as u32;
    }
}