deaf/
binary.rs

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
19/// An ELF formatted binary file
20pub 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    /// Get all string tables except the 'shstrtab'
168    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                // get an offset into the section
223                let offset = symbol
224                    .value()
225                    .saturating_sub(section
226                        .address() as u64);
227
228                // get a slice of bytes the size of the symbol
229                let data = section
230                    .slice(
231                        offset as usize,
232                        symbol.size() as usize)?;
233
234                // add them to the symbol
235                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            // get the function name
254            let index = function.symbol().name();
255            let name = self.symbol_name(index)?;
256
257            // set the function name
258            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    /// Get the number of section headers in the file
273    pub fn shnum(&self) -> usize {
274        self.header.shnum()
275    }
276
277    /// Get the offset of the section header table
278    pub fn shoff(&self) -> usize {
279        self.header.shoff()
280    }
281
282    /// Get the size of section headers
283    pub fn shentsize(&self) -> usize {
284        self.header.shentsize()
285    }
286
287    /// Get the number of program headers in the file
288    pub fn phnum(&self) -> usize {
289        self.header.phnum()
290    }
291
292    /// Get the offset of the program header table
293    pub fn phoff(&self) -> usize {
294        self.header.phoff()
295    }
296
297    /// Get the size of program headers
298    pub fn phentsize(&self) -> usize {
299        self.header.phentsize()
300    }
301
302    pub fn shstrndx(&self) -> usize {
303        self.header.shstrndx()
304    }
305
306    /// Get the layout of the file (little or big endian)
307    pub fn layout(&self) -> Layout {
308        self.header.data()
309    }
310
311    /// Get the addressing width of the file (32, 64 etc)
312    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    // #[test]
454    // fn test_display_sections() {
455    //     let path = "assets/libvpf/libvpf.so.4.1";
456    //     let binary = Binary::load(path).unwrap();
457
458    //     for (i,section) in binary.sections.iter().enumerate() {
459    //         let kind = section.header().kind();
460    //         let index = section.name_index();
461    //         let name = binary.section_name(index).unwrap();
462
463    //         println!("{}: {} (kind={:?})",i,name,kind);
464    //     }
465    // }
466
467    // #[test]
468    // fn test_display_string_table() {
469    //     let path = "assets/libvpf/libvpf.so.4.1";
470    //     let binary = Binary::load(path).unwrap();
471
472    //     let sections = &binary.sections[27];
473
474    //     let dynstr = StringTable::try_from(sections).unwrap();
475        
476    //     for (i,item) in dynstr.items().unwrap().into_iter().enumerate() {
477    //         println!("{}: {}",i,item.string_lossy());
478    //     }
479    // }
480
481    // #[test]
482    // fn test_display_symbol_table() {
483    //     let path = "assets/libvpf/libvpf.so.4.1";
484    //     let binary = Binary::load(path).unwrap();
485
486    //     let strings = &binary.sections[5];
487    //     let symbols = &binary.sections[4];
488
489    //     let dynstr = StringTable::try_from(strings).unwrap();
490    //     let dynsym = SymbolTable::try_from(symbols).unwrap();
491        
492    //     for (i,item) in dynsym.items().unwrap().into_iter().enumerate() {
493    //         let name = dynstr
494    //             .at_offset(item.name() as usize)
495    //             .map(|v| v.string_lossy());
496    //         println!("{}: {:?}",i,name);
497    //     }
498    // }
499
500}