1use std::path::Path;
2use std::fs;
3
4use crate::Section;
5use crate::symbols::Symbol;
6use crate::functions::Function;
7use crate::tables::{Table,TableView,StringItem, SymbolTable, SymbolTableMut, StringTable};
8use crate::headers::FileHeader;
9use crate::errors::{Error,Result};
10use crate::common::{
11 Layout,
12 Width,
13 SectionType,
14 Updateable,
15 Update,
16 All
17};
18
19pub struct Binary {
21 header: FileHeader,
22 sections: Vec<Section>,
23}
24
25impl Binary {
26
27 fn empty() -> Self {
28 Self {
29 header: FileHeader::new(),
30 sections: Vec::new()
31 }
32 }
33
34 fn new(header: FileHeader, sections: Vec<Section>) -> Self {
35 Self { header, sections }
36 }
37
38 pub fn read(&mut self, data: &[u8]) -> Result<usize> {
39 self.header = FileHeader::parse(&data)?;
40
41 let count = self.header.shnum();
42 let offset = self.header.shoff();
43 let size = self.header.shentsize();
44 let layout = self.header.layout();
45 let width = self.header.width();
46
47 self.sections = Section::read_all(
48 &data,
49 count,
50 offset,
51 size,
52 layout,
53 width
54 )?;
55
56 self.process()?;
57 Ok(self.size())
58 }
59
60 pub fn write(&self, data: &mut [u8]) -> Result<usize> {
61 self.header.write(data)?;
62 let offset = self.header.shoff();
63
64 for (index,section) in self.sections.iter().enumerate() {
65 section.write(
66 data,
67 offset,
68 index,
69 )?;
70 }
71
72 Ok(self.size())
73 }
74
75 pub fn load<T: AsRef<Path>>(path: T) -> Result<Self> {
76 let data = fs::read(path.as_ref())?;
77 let mut binary = Binary::empty();
78 binary.read(&data)?;
79 Ok(binary)
80 }
81
82 pub fn save<T: AsRef<Path>>(&self, path: T) -> Result<usize> {
83 let size = self.size();
84 let mut data = vec![0;size];
85 self.write(&mut data)?;
86 fs::write(path, data)?;
87 Ok(size)
88 }
89
90 pub fn process(&mut self) -> Result<()> {
91
92 let str_section = self.section(self.header.shstrndx())?.clone();
93 let str_table = StringTable::try_from(&str_section)?;
94
95 for section in self.sections.iter_mut() {
96 let offset = section.name_index();
97 let name = str_table
98 .at_offset(offset)
99 .and_then(|e| e.string())
100 .unwrap_or("".into());
101
102 section.set_name(name);
103 }
104
105 Ok(())
106 }
107
108 pub fn size(&self) -> usize {
109 self.header.size() +
110 self.sections
111 .iter()
112 .fold(0,|a,s| a + s.size())
113 }
114
115 pub fn section(&self, index: usize) -> Result<&Section> {
116 self.sections
117 .get(index)
118 .ok_or(Error::NotFound)
119 }
120
121 pub fn section_for_address(&self, address: usize) -> Result<&Section> {
122 self.sections
123 .iter()
124 .find(|s| s.start() <= address && s.end() > address)
125 .ok_or(Error::NotFound)
126 }
127
128 pub fn section_mut(&mut self, index: usize) -> Result<&mut Section> {
129 self.sections
130 .get_mut(index)
131 .ok_or(Error::NotFound)
132 }
133
134 pub fn sections(&self, kind: SectionType) -> Vec<&Section> {
135 self.sections
136 .iter()
137 .filter(|s| s.is_kind(kind))
138 .collect()
139 }
140
141 pub fn sections_mut(&mut self, kind: SectionType) -> Vec<&mut Section> {
142 self.sections
143 .iter_mut()
144 .filter(|s| s.is_kind(kind))
145 .collect()
146 }
147
148 pub fn section_name(&self, offset: usize) -> Result<String> {
149 self.section(self.header.shstrndx())
150 .and_then(Table::<StringItem>::try_from)
151 .and_then(|t| t
152 .at_offset(offset)
153 .and_then(|e| e.string()))
154 }
155
156 pub fn section_names(&self) -> Result<Vec<String>> {
157 self.section(self.header.shstrndx())
158 .and_then(StringTable::try_from)
159 .and_then(|t| t
160 .items())
161 .and_then(|v| v
162 .iter()
163 .map(|e| e.string())
164 .collect())
165 }
166
167 pub fn string_tables(&self) -> Vec<StringTable> {
169 let k = self.header.shstrndx();
170 self.sections
171 .iter()
172 .enumerate()
173 .filter(|(i,_)| *i != k)
174 .map(|(_,t)| t)
175 .flat_map(StringTable::try_from)
176 .collect()
177 }
178
179 pub fn symbol_tables(&self) -> Vec<SymbolTable> {
180 self.sections
181 .iter()
182 .flat_map(SymbolTable::try_from)
183 .collect()
184 }
185
186 pub fn symbol_tables_mut(&mut self) -> Vec<SymbolTableMut> {
187 self.sections
188 .iter_mut()
189 .flat_map(SymbolTableMut::try_from)
190 .collect()
191 }
192
193 pub fn symbol_name(&self, offset: usize) -> Result<String> {
194 self.string_tables()
195 .iter()
196 .find_map(|t| t
197 .at_offset(offset)
198 .and_then(|s| s.string())
199 .ok())
200 .ok_or(Error::NotFound)
201 }
202
203 pub fn symbols(&self) -> Result<Vec<Symbol>> {
204
205 let mut symbols = self
206 .symbol_tables()
207 .iter()
208 .flat_map(SymbolTable::items)
209 .flatten()
210 .collect::<Vec<Symbol>>();
211
212 for symbol in symbols.iter_mut() {
213
214 if (symbol.is_object() ||
215 symbol.is_function() ||
216 symbol.is_section()) &&
217 !symbol.is_weak() &&
218 symbol.has_section()
219 {
220 let section = symbol.section(self)?;
221
222 let offset = symbol
224 .value()
225 .saturating_sub(section
226 .address() as u64);
227
228 let data = section
230 .slice(
231 offset as usize,
232 symbol.size() as usize)?;
233
234 symbol.set_data(data);
236
237 }
238 }
239
240 Ok(symbols)
241 }
242
243 pub fn functions(&self) -> Result<Vec<Function>> {
244
245 let mut functions = self
246 .symbols()?
247 .into_iter()
248 .filter_map(|s| Function::try_from(s).ok())
249 .collect::<Vec<Function>>();
250
251 for function in functions.iter_mut() {
252
253 let index = function.symbol().name();
255 let name = self.symbol_name(index)?;
256
257 function.set_name(name)
259
260 }
261
262 Ok(functions)
263 }
264
265 pub fn data(&self, address: usize, size: usize) -> Vec<u8> {
266 self.section_for_address(address)
267 .and_then(|s| s.slice(s.offset().saturating_sub(address), size))
268 .and_then(|d| Ok(d.to_vec()))
269 .unwrap_or(Vec::new())
270 }
271
272 pub fn shnum(&self) -> usize {
274 self.header.shnum()
275 }
276
277 pub fn shoff(&self) -> usize {
279 self.header.shoff()
280 }
281
282 pub fn shentsize(&self) -> usize {
284 self.header.shentsize()
285 }
286
287 pub fn phnum(&self) -> usize {
289 self.header.phnum()
290 }
291
292 pub fn phoff(&self) -> usize {
294 self.header.phoff()
295 }
296
297 pub fn phentsize(&self) -> usize {
299 self.header.phentsize()
300 }
301
302 pub fn shstrndx(&self) -> usize {
303 self.header.shstrndx()
304 }
305
306 pub fn layout(&self) -> Layout {
308 self.header.data()
309 }
310
311 pub fn width(&self) -> Width {
313 self.header.class()
314 }
315
316}
317
318impl Updateable for Binary {
319 fn update(&mut self) {
320 self.header.update();
321 self.sections.update();
322 Update::<All>::clear();
323 }
324}
325
326#[cfg(test)]
327mod tests {
328 use super::*;
329
330 #[test]
331 fn test_read_string_table() {
332 let binary = Binary::load("assets/libjpeg/libjpeg.so.9").unwrap();
333
334 let names = binary
335 .sections(SectionType::Strings)
336 .iter()
337 .map(|s| s.name_index())
338 .map(|i| binary.section_name(i))
339 .collect::<Result<Vec<String>>>()
340 .unwrap();
341
342 assert_eq!(names[0].as_str(),".dynstr");
343 assert_eq!(names[1].as_str(),".shstrtab");
344 assert_eq!(names[2].as_str(),".strtab");
345 }
346
347 #[test]
348 fn test_get_symbol_tables() {
349 let path = "assets/libvpf/libvpf.so.4.1";
350 let binary = Binary::load(path).unwrap();
351
352 let tables = binary.symbol_tables();
353 assert_eq!(tables.len(),1);
354
355 let index = tables[0].name_index();
356 assert_eq!(index,59);
357
358 let result = binary.section_name(index);
359 assert!(result.is_ok());
360
361 let name = result.unwrap();
362 assert_eq!(name, ".dynsym".to_string());
363 }
364
365 #[test]
366 fn test_get_symbols() {
367 let path = "assets/libvpf/libvpf.so.4.1";
368 let binary = Binary::load(path).unwrap();
369
370 let result = binary.symbols();
371 assert!(result.is_ok());
372
373 let symbols = result.unwrap();
374 assert_eq!(symbols.len(),294);
375
376 let index = symbols[1].name();
377 let result = binary.symbol_name(index);
378 assert!(result.is_ok());
379
380 let name = result.unwrap();
381 assert_eq!(name, "__ctype_toupper_loc".to_string());
382
383 let index = symbols[78].name();
384 let result = binary.symbol_name(index);
385 assert!(result.is_ok());
386
387 let name = result.unwrap();
388 assert_eq!(name, "NOPROJ".to_string());
389 }
390
391 #[test]
392 fn test_get_functions() {
393 let path = "assets/libvpf/libvpf.so.4.1";
394 let binary = Binary::load(path).unwrap();
395
396 let result = binary.functions();
397
398 assert!(result.is_ok());
399
400 let functions = result.unwrap();
401 assert_eq!(functions.len(),280);
402
403 let function1 = &functions[80];
404 let function2 = &functions[171];
405 let function3 = &functions[238];
406
407 assert_eq!(function1.address(),0x15df0);
408 assert_eq!(function2.address(),0x06250);
409 assert_eq!(function3.address(),0x256a0);
410
411 assert_eq!(function1.name(),"table_in_list".to_string());
412 assert_eq!(function2.name(),"swap_two".to_string());
413 assert_eq!(function3.name(),"leftjust".to_string());
414 }
415
416 #[test]
417 fn test_get_sections_for_address() {
418 let path = "assets/libvpf/libvpf.so.4.1";
419 let binary = Binary::load(path).unwrap();
420
421 let result = binary.section_for_address(0x2d5);
422 assert!(result.is_ok());
423
424 let section = result.unwrap();
425 assert_eq!(section.name(),".note.gnu.build-id");
426
427 let result = binary.section_for_address(0x2f0);
428 assert!(result.is_ok());
429
430 let section = result.unwrap();
431 assert_eq!(section.name(),".gnu.hash");
432
433 let result = binary.section_for_address(0x5740);
434 assert!(result.is_ok());
435
436 let section = result.unwrap();
437 assert_eq!(section.name(),".text");
438
439 let result = binary.section_for_address(0x33f40);
440 assert!(result.is_ok());
441
442 let section = result.unwrap();
443 assert_eq!(section.name(),".fini");
444
445 let result = binary.section_for_address(0x33f39);
446 assert!(result.is_ok());
447
448 let section = result.unwrap();
449 assert_eq!(section.name(),".text");
450 }
451
452
453 }