symtool_backend/
object.rs

1//! Apply transformations to an object.
2
3use crate::error::{Error, TransformError, TransformResult};
4use crate::patch::Patch;
5use goblin::elf::Elf;
6use goblin::mach::MachO;
7use std::convert::TryInto;
8
9/// A generic object type
10pub enum Object<'a> {
11    Elf(Box<Elf<'a>>),
12    MachO(Box<MachO<'a>>),
13}
14
15/// The type of a transformation applied to an object.
16///
17/// A transformation is expected to return a set of patches which are applied in order to the
18/// binary.
19pub type ObjectTransform<Error> =
20    dyn for<'a> Fn(&'a [u8], Object) -> std::result::Result<Vec<Patch>, Error>;
21
22/// Apply a transformation to a binary or an archive of binaries.
23///
24/// Objects are parsed from `reader` and stored into `writer`.
25/// This function supports both BSD and GNU style archives.
26pub fn transform_object<E>(
27    object: &mut [u8],
28    transformation: &ObjectTransform<E>,
29) -> TransformResult<(), E>
30where
31    E: std::error::Error,
32{
33    // Determine the location of the object(s) to manipulate
34    let mut objects = Vec::new();
35    if let Ok(archive) = goblin::archive::Archive::parse(object) {
36        for i in 0..archive.len() {
37            let member = archive.get_at(i).unwrap();
38            objects.push((
39                member.offset.try_into().expect("object too large to parse"),
40                member.header.size,
41            ));
42        }
43    } else {
44        objects.push((0, object.len()));
45    }
46
47    // Transform each object
48    for (offset, size) in objects {
49        let buf = &mut object[offset..offset + size];
50        let object = match goblin::Object::parse(&buf)? {
51            goblin::Object::Elf(elf) => Ok(Object::Elf(Box::new(elf))),
52            goblin::Object::Mach(goblin::mach::Mach::Binary(macho)) => {
53                Ok(Object::MachO(Box::new(macho)))
54            }
55            _ => Err(Error::UnknownObject),
56        }?;
57        let patches = transformation(&buf, object).map_err(TransformError::Transform)?;
58        for patch in patches {
59            patch.apply(buf);
60        }
61    }
62    Ok(())
63}