Skip to content

Commit

Permalink
Merge pull request #49 from mjhouse/development
Browse files Browse the repository at this point in the history
Development
  • Loading branch information
mjhouse authored Sep 15, 2023
2 parents 9affd48 + a7361e9 commit 8b6a8eb
Show file tree
Hide file tree
Showing 12 changed files with 296 additions and 27 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,11 +107,12 @@ This release is generally aimed at propagating changes to keep the binary useabl

- [x] Add mechanism to update sections globally on local changes
- [x] Make wrapper Table\<TableItem\> structs for sections
- [ ] Make wrapper Array\<ArrayItem\> structs for sections
- [x] Make wrapper Array\<ArrayItem\> structs for sections
- [ ] Turn the Segment struct into a wrapper struct
- [ ] Make a super list of updates and when they should be applied
- [ ] Update section offsets when items are added/removed from tables
- [x] Update section name indices when the section name string table changes
- [ ] Align sections on write when body of the section changes
- [ ] Add getter/setter methods to Binary

### 0.3.0
Expand Down
37 changes: 36 additions & 1 deletion src/binary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,8 @@ impl Updateable for Binary {

#[cfg(test)]
mod tests {
use crate::tables::{StringTable, SymbolTable};

use super::*;

#[test]
Expand All @@ -217,12 +219,45 @@ mod tests {
let binary = Binary::load(path).unwrap();

for (i,section) in binary.sections.iter().enumerate() {
let kind = section.kind();
let kind = section.header().kind();
let index = section.name();
let name = binary.section_name(index).unwrap();

println!("{}: {} (kind={:?})",i,name,kind);
}
}

#[test]
fn test_display_string_table() {
let path = "assets/libjpeg/libjpeg.so.9";
let binary = Binary::load(path).unwrap();

let sections = &binary.sections[36];

let dynstr = StringTable::try_from(sections).unwrap();

for (i,item) in dynstr.items().unwrap().into_iter().enumerate() {
println!("{}: {}",i,item.string_lossy());
}
}

#[test]
fn test_display_symbol_table() {
let path = "assets/libvpf/libvpf.so.4.1";
let binary = Binary::load(path).unwrap();

let strings = &binary.sections[5];
let symbols = &binary.sections[4];

let dynstr = StringTable::try_from(strings).unwrap();
let dynsym = SymbolTable::try_from(symbols).unwrap();

for (i,item) in dynsym.items().unwrap().into_iter().enumerate() {
let name = dynstr
.at_offset(item.name() as usize)
.map(|v| v.string_lossy());
println!("{}: {:?}",i,name);
}
}

}
2 changes: 1 addition & 1 deletion src/common/bytes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ pub trait Convert<A> {

/// Blanket implementation for NOP conversions to self
impl<A> Convert<A> for A {
fn convert(self) -> Result<Self> { Ok(self) }
fn convert(self) -> Result<A> { Ok(self) }
}

macro_rules! from {
Expand Down
10 changes: 10 additions & 0 deletions src/common/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,16 @@ pub enum SHType {
SHT_SYMTAB_SHNDX = 0x00000012,
SHT_NUM = 0x00000013,
SHT_LOOS = 0x60000000,
SHT_GNU_HASH = 0x6ffffff6,
SHT_GNU_LIBLIST = 0x6ffffff7,
SHT_VERDEF = 0x6ffffffd,
SHT_VERNEED = 0x6ffffffe,
SHT_VERSYM = 0x6fffffff,
SHT_ARM_EXIDX = 0x70000001, // ARM unwind info.
SHT_ARM_PREEMPTMAP = 0x70000002, // pre-emption details.
SHT_ARM_ATTRIBUTES = 0x70000003, // attributes.
SHT_ARM_DEBUGOVERLAY = 0x70000004, // overlay debug info.
SHT_ARM_OVERLAYSECTION = 0x70000005, // GDB and overlay integration info.
#[num_enum(catch_all)]
Unknown(u32),
}
Expand Down
8 changes: 7 additions & 1 deletion src/common/enums.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@ pub enum SectionType {
Relocations, // SHT_REL
RelocationsAddend, // SHT_RELA
Hash, // SHT_HASH
GNUHash, // SHT_GNU_HASH
Dynamic, // SHT_DYNAMIC
Notes, // SHT_NOTE
Empty, // SHT_NOBITS
Reserved, // SHT_SHLIB
GNULibList, // SHT_GNU_LIBLIST
InitArray, // SHT_INIT_ARRAY
FiniArray, // SHT_FINI_ARRAY
PreInitArray, // SHT_PREINIT_ARRAY
Expand All @@ -32,11 +34,13 @@ impl From<SHType> for SectionType {
SHType::SHT_STRTAB => SectionType::Strings,
SHType::SHT_RELA => SectionType::RelocationsAddend,
SHType::SHT_HASH => SectionType::Hash,
SHType::SHT_GNU_HASH => SectionType::GNUHash,
SHType::SHT_DYNAMIC => SectionType::Dynamic,
SHType::SHT_NOTE => SectionType::Notes,
SHType::SHT_NOBITS => SectionType::Empty,
SHType::SHT_REL => SectionType::Relocations,
SHType::SHT_SHLIB => SectionType::Reserved,
SHType::SHT_GNU_LIBLIST => SectionType::GNULibList,
SHType::SHT_DYNSYM => SectionType::DynamicSymbols,
SHType::SHT_INIT_ARRAY => SectionType::InitArray,
SHType::SHT_FINI_ARRAY => SectionType::FiniArray,
Expand All @@ -45,7 +49,7 @@ impl From<SHType> for SectionType {
SHType::SHT_SYMTAB_SHNDX => SectionType::ExtendedSymbols,
SHType::SHT_NUM => SectionType::ReservedTypes,
SHType::SHT_LOOS => SectionType::Unknown,
SHType::Unknown(_) => SectionType::Unknown,
_ => SectionType::Unknown,
}
}
}
Expand All @@ -59,11 +63,13 @@ impl From<SectionType> for SHType {
SectionType::Strings => SHType::SHT_STRTAB,
SectionType::RelocationsAddend => SHType::SHT_RELA,
SectionType::Hash => SHType::SHT_HASH,
SectionType::GNUHash => SHType::SHT_GNU_HASH,
SectionType::Dynamic => SHType::SHT_DYNAMIC,
SectionType::Notes => SHType::SHT_NOTE,
SectionType::Empty => SHType::SHT_NOBITS,
SectionType::Relocations => SHType::SHT_REL,
SectionType::Reserved => SHType::SHT_SHLIB,
SectionType::GNULibList => SHType::SHT_GNU_LIBLIST,
SectionType::DynamicSymbols => SHType::SHT_DYNSYM,
SectionType::InitArray => SHType::SHT_INIT_ARRAY,
SectionType::FiniArray => SHType::SHT_FINI_ARRAY,
Expand Down
15 changes: 15 additions & 0 deletions src/common/field.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,21 @@ where
self.layout = layout;
}

/// Set an offset in bytes to read at
pub fn set_offset(&mut self, offset: usize) {
let range = self.ranges.at_mut();
range.start += offset;
range.end += offset;
}

/// Set an index based on field size to read at
pub fn set_index(&mut self, index: usize) {
let size = self.size();
let range = self.ranges.at_mut();
range.start += index * size;
range.end += index * size;
}

/// Get a constrained slice of bytes using the appropriate range
///
/// If the slice is too short, this method will fail, otherwise
Expand Down
49 changes: 39 additions & 10 deletions src/common/item.rs
Original file line number Diff line number Diff line change
@@ -1,26 +1,33 @@
use crate::common::{Width, Layout, FromBytes, IntoBytes, Convert, Ranges, Field};
use crate::errors::Result;

use std::fmt::Debug;

pub trait T32Value<Out>: FromBytes + IntoBytes + Convert<Out> + Clone {}
pub trait T64Value<Out>: FromBytes + IntoBytes + Convert<Out> + Clone {}
pub trait TOutValue<T32,T64>: Convert<T32> + Convert<T64> + Debug + Clone + Default {}

impl<Out, T: FromBytes + IntoBytes + Convert<Out> + Clone> T32Value<Out> for T {}
impl<Out, T: FromBytes + IntoBytes + Convert<Out> + Clone> T64Value<Out> for T {}
impl<T32,T64, T: Convert<T32> + Convert<T64> + Debug + Clone + Default> TOutValue<T32,T64> for T {}

/// An item in a section, table item etc that contains a field
/// and associated value.
#[derive(Debug,Clone)]
pub struct Item<T32 = u8, T64 = T32, Out = T64>
where
T32: FromBytes + IntoBytes + Convert<Out>,
T64: FromBytes + IntoBytes + Convert<Out>,
Out: Convert<T32> + Convert<T64> + Debug + Clone + Default,
T32: T32Value<Out>,
T64: T64Value<Out>,
Out: TOutValue<T32,T64>,
{
field: Field<T32,T64,Out>,
value: Out,
}

impl<T32, T64, Out> Item<T32, T64, Out>
where
T32: FromBytes + IntoBytes + Convert<Out>,
T64: FromBytes + IntoBytes + Convert<Out>,
Out: Convert<T32> + Convert<T64> + Debug + Clone + Default,
T32: T32Value<Out>,
T64: T64Value<Out>,
Out: TOutValue<T32,T64>,
{
/// Create a new item with given ranges
pub fn new(ranges: Ranges) -> Self {
Expand Down Expand Up @@ -55,6 +62,18 @@ where
self
}

/// Builder method to set an offset
pub fn with_offset(mut self, offset: usize) -> Self {
self.set_offset(offset);
self
}

/// Builder method to set an index
pub fn with_index(mut self, index: usize) -> Self {
self.set_index(index);
self
}

/// Builder method to parse a byte buffer
pub fn parse(mut self, bytes: &[u8]) -> Result<Self> {
self.read(bytes)?;
Expand Down Expand Up @@ -107,13 +126,23 @@ where
self.field.set_layout(layout);
}

/// Set an offset in bytes to read at
pub fn set_offset(&mut self, offset: usize) {
self.field.set_offset(offset);
}

/// Set an index based on field size to read at
pub fn set_index(&mut self, index: usize) {
self.field.set_index(index);
}

}

impl<T32, T64, Out> PartialEq for Item<T32, T64, Out>
where
T32: FromBytes + IntoBytes + Convert<Out>,
T64: FromBytes + IntoBytes + Convert<Out>,
Out: Convert<T32> + Convert<T64> + Debug + Clone + Default + PartialEq,
T32: T32Value<Out>,
T64: T64Value<Out>,
Out: TOutValue<T32,T64> + PartialEq,
{
fn eq(&self, other: &Self) -> bool {
self.get().eq(&other.get())
Expand Down
124 changes: 124 additions & 0 deletions src/common/item_array.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
use crate::common::{Width, Layout, Ranges};
use crate::common::{ByteIter,Item,T32Value,T64Value,TOutValue};
use crate::errors::Result;

#[derive(Clone)]
pub struct ItemArray<T32, T64 = T32, Out = T64>
where
T32: T32Value<Out>,
T64: T64Value<Out>,
Out: TOutValue<T32,T64>,
{
offsets: Vec<usize>,
item: Item<T32,T64,Out>
}

impl<T32,T64,Out> ItemArray<T32, T64, Out>
where
T32: T32Value<Out>,
T64: T64Value<Out>,
Out: TOutValue<T32,T64>,
{

/// Create a new item array with given ranges
pub fn new(ranges: Ranges) -> Self {
Self {
offsets: Vec::new(),
item: Item::new(ranges)
}
}

/// Create a new item array with given ranges, layout, and width
pub fn make(ranges: Ranges, width: Width, layout: Layout) -> Self {
Self::new(ranges)
.with_layout(layout)
.with_width(width)
}

/// Builder method to set the initial width
pub fn with_width(mut self, width: Width) -> Self {
self.set_width(width);
self
}

/// Builder method to set the initial layout
pub fn with_layout(mut self, layout: Layout) -> Self {
self.set_layout(layout);
self
}

/// Builder method to add an array offset
pub fn with_offset(mut self, offset: usize) -> Self {
self.add_offset(offset);
self
}

/// Builder method to set the last offset for the array
pub fn with_last_offset(mut self, offset: usize) -> Self {
self.offsets.pop();
self.add_offset(offset);
self
}

/// Get an iterator over slices of the data
pub fn iterator<'a>(&'a self, bytes: &'a [u8]) -> ByteIter {
ByteIter::length(bytes,self.item_size())
}

/// Read a value at a particular index in the data
pub fn read(&self, bytes: &[u8], index: usize) -> Result<Out> {
self.item
.clone()
.with_layout(self.layout())
.with_width(self.width())
.with_offset(self.offset())
.with_index(index)
.read(bytes)
}

/// Get the offset of a particular index in the array
pub fn item_offset(&self, index: usize) -> usize {
self.item_size() * index
}

/// Get the size of the item for the current width
pub fn item_size(&self) -> usize {
self.item.size()
}

/// Get the length of the array, given the item count
pub fn length(&self, count: usize) -> usize {
self.item_offset(count)
}

/// Get the width (32- or 64-bit) of the item
pub fn width(&self) -> Width {
self.item.width()
}

/// Set the width (32- or 64-bit) of the item
pub fn set_width(&mut self, width: Width) {
self.item.set_width(width);
}

/// Get the layout (little- or big-endian) of the item
pub fn layout(&self) -> Layout {
self.item.layout()
}

/// Set the layout (little- or big-endian) of the item
pub fn set_layout(&mut self, layout: Layout) {
self.item.set_layout(layout);
}

/// Get the total offset at which the array will read
pub fn offset(&self) -> usize {
self.offsets.iter().sum()
}

/// Set the offset of the array in the parsed data
pub fn add_offset(&mut self, offset: usize) {
self.offsets.push(offset);
}

}
Loading

0 comments on commit 8b6a8eb

Please sign in to comment.