diff --git a/src/binary.rs b/src/binary.rs index 0f86140..cb0231d 100644 --- a/src/binary.rs +++ b/src/binary.rs @@ -53,7 +53,7 @@ impl Binary { width )?; - self.process(); + self.process()?; Ok(self.size()) } @@ -200,52 +200,61 @@ impl Binary { .ok_or(Error::NotFound) } - pub fn symbols(&self) -> Vec { - self.symbol_tables() + pub fn symbols(&self) -> Result> { + + let mut symbols = self + .symbol_tables() .iter() .flat_map(SymbolTable::items) .flatten() - .collect() - } + .collect::>(); + + for symbol in symbols.iter_mut() { + + if (symbol.is_object() || + symbol.is_function() || + symbol.is_section()) && + !symbol.is_weak() && + symbol.has_section() + { + let section = symbol.section(self)?; + + // get an offset into the section + let offset = symbol + .value() + .saturating_sub(section + .address() as u64); + + // get a slice of bytes the size of the symbol + let data = section + .slice( + offset as usize, + symbol.size() as usize)?; + + // add them to the symbol + symbol.set_data(data); + + } + } - pub fn functions(&self) -> Vec { - self.symbols() - .into_iter() - .flat_map(|f| self - .symbol_name(f.name()) - .map(|s| (f,s))) - .flat_map(|(v,s)| Function::try_from(v) - .map(|f| { - let address = f.address() as usize; - let size = f.size() as usize; - - f - .with_name(s) - .with_body(&self.data(address,size)) - })) - .collect() + Ok(symbols) } - pub fn functions_ex(&self) -> Result> { + pub fn functions(&self) -> Result> { let mut functions = self - .symbols() + .symbols()? .into_iter() .filter_map(|s| Function::try_from(s).ok()) .collect::>(); for function in functions.iter_mut() { - let section_index = function.section(); - let name_index = function.symbol().name(); - - let section = self.section(section_index)?; - let name = self.symbol_name(name_index)?; - - function.set_body_from( - §ion.data(), - section.offset())?; + // get the function name + let index = function.symbol().name(); + let name = self.symbol_name(index)?; + // set the function name function.set_name(name) } @@ -316,8 +325,6 @@ impl Updateable for Binary { #[cfg(test)] mod tests { - use crate::tables::{StringTable, SymbolTable}; - use super::*; #[test] @@ -360,7 +367,10 @@ mod tests { let path = "assets/libvpf/libvpf.so.4.1"; let binary = Binary::load(path).unwrap(); - let symbols = binary.symbols(); + let result = binary.symbols(); + assert!(result.is_ok()); + + let symbols = result.unwrap(); assert_eq!(symbols.len(),294); let index = symbols[1].name(); @@ -369,6 +379,13 @@ mod tests { let name = result.unwrap(); assert_eq!(name, "__ctype_toupper_loc".to_string()); + + let index = symbols[78].name(); + let result = binary.symbol_name(index); + assert!(result.is_ok()); + + let name = result.unwrap(); + assert_eq!(name, "NOPROJ".to_string()); } #[test] @@ -376,7 +393,11 @@ mod tests { let path = "assets/libvpf/libvpf.so.4.1"; let binary = Binary::load(path).unwrap(); - let functions = binary.functions(); + let result = binary.functions(); + + assert!(result.is_ok()); + + let functions = result.unwrap(); assert_eq!(functions.len(),280); let function1 = &functions[80]; diff --git a/src/common/mod.rs b/src/common/mod.rs index 5754f72..184dbe7 100644 --- a/src/common/mod.rs +++ b/src/common/mod.rs @@ -34,6 +34,7 @@ pub use constants::{ PHType, SHType, SHFlags, + SHIndex, STBind, STType, STVisibility, diff --git a/src/functions/function.rs b/src/functions/function.rs index 59ec33b..2059e00 100644 --- a/src/functions/function.rs +++ b/src/functions/function.rs @@ -5,7 +5,6 @@ use crate::symbols::{Symbol,SymbolInfo}; #[derive(Default)] pub struct Function { name: String, - body: Vec, symbol: Symbol } @@ -41,7 +40,7 @@ impl Function { /// Get the function body pub fn body(&self) -> &[u8] { - &self.body + self.symbol.data() } /// Set the function body @@ -49,8 +48,7 @@ impl Function { /// Also updates the size of the symbol to reflect /// the size of the given body. pub fn set_body(&mut self, body: &[u8]) { - self.body = body.into(); - self.set_size(body.len()); + self.symbol.set_data(body); } /// Extract the function body from section data @@ -305,6 +303,7 @@ impl Function { /// Write the symbol entry to the beginning of the given data fn write_symbol(&self, data: &mut [u8]) -> Result<()> { + assert!(self.symbol.is_function()); self.symbol.write(data) } @@ -316,7 +315,8 @@ impl Function { let start = self.start(offset); let end = self.end(offset); if start <= end && end <= data.len() { - data[start..end].copy_from_slice(&self.body); + let body = self.body(); + data[start..end].copy_from_slice(body); Ok(()) } else { @@ -325,11 +325,16 @@ impl Function { } /// Finish and validate the new function - pub fn build(mut self) -> Result { + pub fn build(self) -> Result { // ensure that the symbol is valid self.symbol.validate()?; + // ensure that the symbol is a function + if !self.symbol.is_function() { + return Err(Error::WrongTypeError); + } + Ok(self) } diff --git a/src/section.rs b/src/section.rs index 19889ba..f589b2a 100644 --- a/src/section.rs +++ b/src/section.rs @@ -151,6 +151,10 @@ impl Section { self.body_size() / self.entity_size() } + pub fn address(&self) -> usize { + self.header.address() as usize + } + pub fn offset(&self) -> usize { self.header.offset() } diff --git a/src/symbols/symbol.rs b/src/symbols/symbol.rs index 5fb8d23..9428712 100644 --- a/src/symbols/symbol.rs +++ b/src/symbols/symbol.rs @@ -1,9 +1,12 @@ +use num_enum::TryFromPrimitive; + +use crate::{Binary, Section}; use crate::errors::Result; use crate::common::{ Width, Layout, Item, - ranges::*, STType, STBind, STVisibility + ranges::*, STType, STBind, STVisibility, SHIndex, FromBytes, IntoBytes }; use crate::symbols::SymbolInfo; use crate::tables::TableItem; @@ -17,6 +20,7 @@ pub struct Symbol { st_info: Item, st_other: Item, st_shndx: Item, + data: Vec, } impl Symbol { @@ -30,9 +34,20 @@ impl Symbol { st_info: Item::new(ST_INFO), st_other: Item::new(ST_OTHER), st_shndx: Item::new(ST_SHNDX), + data: Vec::new(), } } + /// Get a section reference for the symbol + pub fn section<'a>(&self, binary: &'a Binary) -> Result<&'a Section> { + binary.section(self.shndx() as usize) + } + + /// Get a mutable section reference for the symbol + pub fn section_mut<'a>(&self, binary: &'a mut Binary) -> Result<&'a mut Section> { + binary.section_mut(self.shndx() as usize) + } + /// Get the 'st_name' field (name *index*) of the symbol pub fn name(&self) -> usize { self.st_name.get() @@ -65,6 +80,33 @@ impl Symbol { self } + /// Get the data of the symbol + pub fn data(&self) -> &[u8] { + &self.data + } + + /// Get the data of the symbol as a value + pub fn data_as(&self) -> Result { + T::from_bytes(self.data(), self.layout()) + } + + /// Get the data of the symbol mutably + pub fn data_mut(&mut self) -> &mut [u8] { + &mut self.data + } + + /// Set the symbol data and update the `st_size` field + pub fn set_data(&mut self, data: &[u8]) { + self.data = data.into(); + self.set_size(data.len() as u64); + } + + /// Builder method to set the function data + pub fn with_data(mut self, data: &[u8]) -> Self { + self.set_data(data); + self + } + /// Get the 'st_size' field of the symbol pub fn size(&self) -> u64 { self.st_size.get() @@ -244,6 +286,63 @@ impl Symbol { Ok(()) } + /// Returns true if the symbol is a function + pub fn is_function(&self) -> bool { + self.kind() == STType::STT_FUNC + } + + /// Returns true if the symbol is an object + pub fn is_object(&self) -> bool { + self.kind() == STType::STT_OBJECT + } + + /// Returns true if the symbol is a section + pub fn is_section(&self) -> bool { + self.kind() == STType::STT_SECTION + } + + /// Returns true if the symbol is a file + pub fn is_file(&self) -> bool { + self.kind() == STType::STT_FILE + } + + /// Returns true if the symbol is common + pub fn is_common(&self) -> bool { + self.kind() == STType::STT_COMMON + } + + /// Returns true if the symbol is TLS + pub fn is_tls(&self) -> bool { + self.kind() == STType::STT_TLS + } + + /// Returns true if the symbol is global + pub fn is_global(&self) -> bool { + self.bind() == STBind::STB_GLOBAL + } + + /// Returns true if the symbol is local + pub fn is_local(&self) -> bool { + self.bind() == STBind::STB_LOCAL + } + + /// Returns true if the symbol is weak + pub fn is_weak(&self) -> bool { + self.bind() == STBind::STB_WEAK + } + + /// Returns true if the section index isn't + /// a reserved value + pub fn has_section(&self) -> bool { + // TODO: handle SHN_XINDEX situation + let v = self.value() as u32; + v != SHIndex::SHN_UNDEF.into() && + v != SHIndex::SHN_BEFORE.into() && + v != SHIndex::SHN_AFTER.into() && + v != SHIndex::SHN_ABS.into() && + v != SHIndex::SHN_COMMON.into() + } + } impl TableItem for Symbol { @@ -636,4 +735,23 @@ mod tests { assert!(result.is_ok()); assert_eq!(symbol.size(),maximum); } + + #[test] + fn test_data_symbol_read() { + let path = "assets/libvpf/libvpf.so.4.1"; + let binary = Binary::load(path).unwrap(); + + let result = binary.symbols(); + assert!(result.is_ok()); + + let symbols = result.unwrap(); + + let result = symbols[78].data_as::(); + assert!(result.is_ok()); + + let string = result.unwrap(); + let value = string.trim_matches(char::from(0)); + assert_eq!(value.trim(), "Decimal Degrees".to_string()); + } + } \ No newline at end of file