elf_utilities/file/
elf64.rs1use section::Section64;
2use segment::Segment64;
3
4use crate::{
5 header,
6 section::{self, Contents64, StrTabEntry},
7 segment,
8};
9
10const SHSTRTAB_INITIAL_SIZE: usize = 0xb;
11
12#[derive(Clone, Hash, PartialOrd, Ord, PartialEq, Eq)]
13#[repr(C)]
14pub struct ELF64 {
15 pub ehdr: header::Ehdr64,
16 pub sections: Vec<section::Section64>,
17 pub segments: Vec<segment::Segment64>,
18}
19
20impl Default for ELF64 {
21 fn default() -> Self {
22 Self {
23 ehdr: {
24 let mut hdr = header::Ehdr64::default();
25 hdr.e_shnum = 2;
26 hdr.e_shstrndx = 1;
27 hdr.e_shoff += SHSTRTAB_INITIAL_SIZE as u64;
28
29 hdr
30 },
31 sections: {
32 let mut scts = Vec::with_capacity(50);
33 scts.push(section::Section64::new_null_section());
34
35 let shstrtab_contents = Contents64::new_string_table(vec![".shstrtab".to_string()]);
36 scts.push(section::Section64 {
37 name: ".shstrtab".to_string(),
38 header: section::Shdr64 {
39 sh_name: 1,
40 sh_type: section::Type::StrTab.into(),
41 sh_flags: 0,
42 sh_addr: 0,
43 sh_offset: header::Ehdr64::SIZE as u64,
44 sh_size: shstrtab_contents.size() as u64,
45 sh_link: 0,
46 sh_info: 0,
47 sh_addralign: 1,
48 sh_entsize: 0,
49 },
50 contents: shstrtab_contents,
51 });
52 scts
53 },
54 segments: Vec::with_capacity(10),
55 }
56 }
57}
58
59impl ELF64 {
60 pub fn add_section(&mut self, mut sct: Section64) {
62 let last_sct_idx = self.sections.len() - 2;
66
67 self.fill_elf_info(&mut sct, last_sct_idx);
68
69 self.ehdr.e_shoff += sct.header.sh_size;
71 self.ehdr.e_shnum += 1;
72 self.ehdr.e_shstrndx += 1;
73
74 self.sections.insert(self.sections.len() - 1, sct);
75 }
76
77 pub fn add_segment(&mut self, sgt: Segment64) {
78 self.ehdr.e_shoff += segment::Phdr64::SIZE as u64;
80 for sct in self.sections.iter_mut() {
81 sct.header.sh_offset += segment::Phdr64::SIZE as u64;
82 }
83 self.ehdr.e_phnum += 1;
84
85 self.segments.push(sgt);
86 }
87
88 pub fn first_shidx_by<P>(&self, predicate: P) -> Option<usize>
90 where
91 P: Fn(§ion::Section64) -> bool,
92 {
93 for (i, sct) in self.sections.iter().enumerate() {
94 if predicate(sct) {
95 return Some(i);
96 }
97 }
98
99 None
100 }
101
102 pub fn first_section_by<P>(&self, predicate: P) -> Option<§ion::Section64>
104 where
105 P: Fn(§ion::Section64) -> bool,
106 {
107 match self.first_shidx_by(predicate) {
108 Some(idx) => Some(&self.sections[idx]),
109 None => None,
110 }
111 }
112 pub fn first_mut_section_by<P>(&mut self, predicate: P) -> Option<&mut section::Section64>
114 where
115 P: Fn(§ion::Section64) -> bool,
116 {
117 match self.first_shidx_by(predicate) {
118 Some(idx) => Some(&mut self.sections[idx]),
119 None => None,
120 }
121 }
122
123 pub fn to_le_bytes(&self) -> Vec<u8> {
124 let mut file_binary: Vec<u8> = Vec::new();
125
126 let mut header_binary = self.ehdr.to_le_bytes();
127 file_binary.append(&mut header_binary);
128
129 for seg in self.segments.iter() {
130 let mut phdr_binary = seg.header.to_le_bytes();
131 file_binary.append(&mut phdr_binary);
132 }
133
134 let mut sections = self.sections.clone();
135 sections.sort_by_key(|sct| sct.header.sh_offset);
136 for sct in sections.iter() {
137 let mut section_binary = sct.to_le_bytes();
138
139 if sct.header.sh_addralign > 1 && file_binary.len() != sct.header.sh_offset as usize {
140 file_binary.append(&mut vec![0x00; sct.header.sh_offset as usize - file_binary.len()]);
141 }
142
143 file_binary.append(&mut section_binary);
144 }
145
146 if file_binary.len() < self.ehdr.e_shoff as usize {
147 file_binary.append(&mut vec![0x00; self.ehdr.e_shoff as usize - file_binary.len()]);
148 }
149
150 for sct in self.sections.iter() {
151 let mut shdr_binary = sct.header.to_le_bytes();
152 file_binary.append(&mut shdr_binary);
153 }
154 file_binary
155 }
156
157 fn fill_elf_info(&mut self, new_sct: &mut Section64, prev_sct_idx: usize) {
159 let shstrtab_len = self.sections[self.ehdr.e_shstrndx as usize].contents.size() as usize;
160 let prev_offset = self.sections[prev_sct_idx].header.sh_offset;
161 let prev_size = self.sections[prev_sct_idx].header.sh_size;
162
163 new_sct.header.sh_name = shstrtab_len as u32 + 1;
165 if let Contents64::StrTab(ref mut tab) =
167 self.sections[self.ehdr.e_shstrndx as usize].contents
168 {
169 tab.push(StrTabEntry {
170 v: new_sct.name.clone(),
171 idx: shstrtab_len + 1,
172 });
173 }
174
175 if prev_sct_idx == 0 {
179 new_sct.header.sh_offset = header::Ehdr64::SIZE as u64
180 + segment::Phdr64::SIZE as u64 * self.segments.len() as u64
181 + SHSTRTAB_INITIAL_SIZE as u64;
182 } else {
183 new_sct.header.sh_offset = prev_offset + prev_size;
184 }
185
186 new_sct.header.sh_size = new_sct.contents.size() as u64;
187 }
188}