/// A 32-bit Mach-O object file. /// /// This is a file that starts with [`macho::MachHeader32`], and corresponds /// to [`crate::FileKind::MachO32`]. pubtype MachOFile32<'data, Endian = Endianness, R = &'data [u8]> =
MachOFile<'data, macho::MachHeader32<Endian>, R>; /// A 64-bit Mach-O object file. /// /// This is a file that starts with [`macho::MachHeader64`], and corresponds /// to [`crate::FileKind::MachO64`]. pubtype MachOFile64<'data, Endian = Endianness, R = &'data [u8]> =
MachOFile<'data, macho::MachHeader64<Endian>, R>;
/// A partially parsed Mach-O file. /// /// Most of the functionality of this type is provided by the [`Object`] trait implementation. #[derive(Debug)] pubstruct MachOFile<'data, Mach, R = &'data [u8]> where
Mach: MachHeader,
R: ReadRef<'data>,
{ pub(super) endian: Mach::Endian, pub(super) data: R, pub(super) header_offset: u64, pub(super) header: &'data Mach, pub(super) segments: Vec<MachOSegmentInternal<'data, Mach, R>>, pub(super) sections: Vec<MachOSectionInternal<'data, Mach, R>>, pub(super) symbols: SymbolTable<'data, Mach, R>,
}
impl<'data, Mach, R> MachOFile<'data, Mach, R> where
Mach: MachHeader,
R: ReadRef<'data>,
{ /// Parse the raw Mach-O file data. pubfn parse(data: R) -> Result<Self> { let header = Mach::parse(data, 0)?; let endian = header.endian()?;
// Build a list of segments and sections to make some operations more efficient. letmut segments = Vec::new(); letmut sections = Vec::new(); letmut symbols = SymbolTable::default(); iflet Ok(mut commands) = header.load_commands(endian, data, 0) { whilelet Ok(Some(command)) = commands.next() { iflet Some((segment, section_data)) = Mach::Segment::from_command(command)? {
segments.push(MachOSegmentInternal { segment, data }); for section in segment.sections(endian, section_data)? { let index = SectionIndex(sections.len() + 1);
sections.push(MachOSectionInternal::parse(index, section, data));
}
} elseiflet Some(symtab) = command.symtab()? {
symbols = symtab.symbols(endian, data)?;
}
}
}
/// Parse the Mach-O file for the given image from the dyld shared cache. /// This will read different sections from different subcaches, if necessary. pubfn parse_dyld_cache_image<'cache, E: Endian>(
image: &DyldCacheImage<'data, 'cache, E, R>,
) -> Result<Self> { let (data, header_offset) = image.image_data_and_offset()?; let header = Mach::parse(data, header_offset)?; let endian = header.endian()?;
// Build a list of sections to make some operations more efficient. // Also build a list of segments, because we need to remember which ReadRef // to read each section's data from. Only the DyldCache knows this information, // and we won't have access to it once we've exited this function. letmut segments = Vec::new(); letmut sections = Vec::new(); letmut linkedit_data: Option<R> = None; letmut symtab = None; iflet Ok(mut commands) = header.load_commands(endian, data, header_offset) { whilelet Ok(Some(command)) = commands.next() { iflet Some((segment, section_data)) = Mach::Segment::from_command(command)? { // Each segment can be stored in a different subcache. Get the segment's // address and look it up in the cache mappings, to find the correct cache data. // This was observed for the arm64e __LINKEDIT segment in macOS 12.0.1. let addr = segment.vmaddr(endian).into(); let (data, _offset) = image
.cache
.data_and_offset_for_address(addr)
.read_error("Could not find segment data in dyld shared cache")?; if segment.name() == macho::SEG_LINKEDIT.as_bytes() {
linkedit_data = Some(data);
}
segments.push(MachOSegmentInternal { segment, data });
for section in segment.sections(endian, section_data)? { let index = SectionIndex(sections.len() + 1);
sections.push(MachOSectionInternal::parse(index, section, data));
}
} elseiflet Some(st) = command.symtab()? {
symtab = Some(st);
}
}
}
// The symbols are found in the __LINKEDIT segment, so make sure to read them from the // correct subcache. let symbols = match (symtab, linkedit_data) {
(Some(symtab), Some(linkedit_data)) => symtab.symbols(endian, linkedit_data)?,
_ => SymbolTable::default(),
};
/// Returns the raw data. pubfn data(&self) -> R { self.data
}
/// Returns the raw Mach-O file header. #[deprecated(note = "Use `macho_header` instead")] pubfn raw_header(&self) -> &'data Mach { self.header
}
/// Get the raw Mach-O file header. pubfn macho_header(&self) -> &'data Mach { self.header
}
/// Get the Mach-O load commands. pubfn macho_load_commands(&self) -> Result<LoadCommandIterator<'data, Mach::Endian>> { self.header
.load_commands(self.endian, self.data, self.header_offset)
}
/// Get the Mach-O symbol table. /// /// Returns an empty symbol table if the file has no symbol table. pubfn macho_symbol_table(&self) -> &SymbolTable<'data, Mach, R> {
&self.symbols
}
fn section_by_name_bytes<'file>(
&'file self,
section_name: &[u8],
) -> Option<MachOSection<'data, 'file, Mach, R>> { // Translate the section_name by stripping the query_prefix to construct // a function that matches names starting with name_prefix, taking into // consideration the maximum section name length. let make_prefix_matcher = |query_prefix: &'static [u8], name_prefix: &'static [u8]| { const MAX_SECTION_NAME_LEN: usize = 16; let suffix = section_name.strip_prefix(query_prefix).map(|suffix| { let max_len = MAX_SECTION_NAME_LEN - name_prefix.len();
&suffix[..suffix.len().min(max_len)]
}); move |name: &[u8]| suffix.is_some() && name.strip_prefix(name_prefix) == suffix
}; // Matches "__text" when searching for ".text" and "__debug_str_offs" // when searching for ".debug_str_offsets", as is common in // macOS/Mach-O. let matches_underscores_prefix = make_prefix_matcher(b".", b"__"); // Matches "__zdebug_info" when searching for ".debug_info" and // "__zdebug_str_off" when searching for ".debug_str_offsets", as is // used by Go when using GNU-style compression. let matches_zdebug_prefix = make_prefix_matcher(b".debug_", b"__zdebug_"); self.sections().find(|section| {
section.name_bytes().map_or(false, |name| {
name == section_name
|| matches_underscores_prefix(name)
|| matches_zdebug_prefix(name)
})
})
}
letmut imports = Vec::new(); iflet Some(dysymtab) = dysymtab { let index = dysymtab.iundefsym.get(self.endian) as usize; let number = dysymtab.nundefsym.get(self.endian) as usize; for i in index..(index.wrapping_add(number)) { let symbol = self.symbols.symbol(SymbolIndex(i))?; let name = symbol.name(self.endian, self.symbols.strings())?; let library = if twolevel {
libraries
.get(symbol.library_ordinal(self.endian) as usize)
.copied()
.read_error("Invalid Mach-O symbol library ordinal")?
} else {
&[]
};
imports.push(Import {
name: ByteString(name),
library: ByteString(library),
});
}
}
Ok(imports)
}
letmut exports = Vec::new(); iflet Some(dysymtab) = dysymtab { let index = dysymtab.iextdefsym.get(self.endian) as usize; let number = dysymtab.nextdefsym.get(self.endian) as usize; for i in index..(index.wrapping_add(number)) { let symbol = self.symbols.symbol(SymbolIndex(i))?; let name = symbol.name(self.endian, self.symbols.strings())?; let address = symbol.n_value(self.endian).into();
exports.push(Export {
name: ByteString(name),
address,
});
}
}
Ok(exports)
}
/// An iterator for the COMDAT section groups in a [`MachOFile64`]. pubtype MachOComdatIterator32<'data, 'file, Endian = Endianness, R = &'data [u8]> =
MachOComdatIterator<'data, 'file, macho::MachHeader32<Endian>, R>; /// An iterator for the COMDAT section groups in a [`MachOFile64`]. pubtype MachOComdatIterator64<'data, 'file, Endian = Endianness, R = &'data [u8]> =
MachOComdatIterator<'data, 'file, macho::MachHeader64<Endian>, R>;
/// An iterator for the COMDAT section groups in a [`MachOFile`]. /// /// This is a stub that doesn't implement any functionality. #[derive(Debug)] pubstruct MachOComdatIterator<'data, 'file, Mach, R = &'data [u8]> where
Mach: MachHeader,
R: ReadRef<'data>,
{ #[allow(unused)]
file: &'file MachOFile<'data, Mach, R>,
}
impl<'data, 'file, Mach, R> Iterator for MachOComdatIterator<'data, 'file, Mach, R> where
Mach: MachHeader,
R: ReadRef<'data>,
{ type Item = MachOComdat<'data, 'file, Mach, R>;
/// A COMDAT section group in a [`MachOFile32`]. pubtype MachOComdat32<'data, 'file, Endian = Endianness, R = &'data [u8]> =
MachOComdat<'data, 'file, macho::MachHeader32<Endian>, R>;
/// A COMDAT section group in a [`MachOFile64`]. pubtype MachOComdat64<'data, 'file, Endian = Endianness, R = &'data [u8]> =
MachOComdat<'data, 'file, macho::MachHeader64<Endian>, R>;
/// A COMDAT section group in a [`MachOFile`]. /// /// This is a stub that doesn't implement any functionality. #[derive(Debug)] pubstruct MachOComdat<'data, 'file, Mach, R = &'data [u8]> where
Mach: MachHeader,
R: ReadRef<'data>,
{ #[allow(unused)]
file: &'file MachOFile<'data, Mach, R>,
}
impl<'data, 'file, Mach, R> read::private::Sealed for MachOComdat<'data, 'file, Mach, R> where
Mach: MachHeader,
R: ReadRef<'data>,
{
}
impl<'data, 'file, Mach, R> ObjectComdat<'data> for MachOComdat<'data, 'file, Mach, R> where
Mach: MachHeader,
R: ReadRef<'data>,
{ type SectionIterator = MachOComdatSectionIterator<'data, 'file, Mach, R>;
/// An iterator for the sections in a COMDAT section group in a [`MachOFile32`]. pubtype MachOComdatSectionIterator32<'data, 'file, Endian = Endianness, R = &'data [u8]> =
MachOComdatSectionIterator<'data, 'file, macho::MachHeader32<Endian>, R>; /// An iterator for the sections in a COMDAT section group in a [`MachOFile64`]. pubtype MachOComdatSectionIterator64<'data, 'file, Endian = Endianness, R = &'data [u8]> =
MachOComdatSectionIterator<'data, 'file, macho::MachHeader64<Endian>, R>;
/// An iterator for the sections in a COMDAT section group in a [`MachOFile`]. /// /// This is a stub that doesn't implement any functionality. #[derive(Debug)] pubstruct MachOComdatSectionIterator<'data, 'file, Mach, R = &'data [u8]> where
Mach: MachHeader,
R: ReadRef<'data>,
{ #[allow(unused)]
file: &'file MachOFile<'data, Mach, R>,
}
impl<'data, 'file, Mach, R> Iterator for MachOComdatSectionIterator<'data, 'file, Mach, R> where
Mach: MachHeader,
R: ReadRef<'data>,
{ type Item = SectionIndex;
/// A trait for generic access to [`macho::MachHeader32`] and [`macho::MachHeader64`]. #[allow(missing_docs)] pubtrait MachHeader: Debug + Pod { type Word: Into<u64>; type Endian: endian::Endian; type Segment: Segment<Endian = Self::Endian, Section = Self::Section>; type Section: Section<Endian = Self::Endian>; type Nlist: Nlist<Endian = Self::Endian>;
/// Return true if this type is a 64-bit header. /// /// This is a property of the type, not a value in the header data. fn is_type_64(&self) -> bool;
/// Return true if the `magic` field signifies big-endian. fn is_big_endian(&self) -> bool;
/// Return true if the `magic` field signifies little-endian. fn is_little_endian(&self) -> bool;
/// Read the file header. /// /// Also checks that the magic field in the file header is a supported format. fn parse<'data, R: ReadRef<'data>>(data: R, offset: u64) -> read::Result<&'data Self> { let header = data
.read_at::<Self>(offset)
.read_error("Invalid Mach-O header size or alignment")?; if !header.is_supported() { return Err(Error("Unsupported Mach-O header"));
}
Ok(header)
}
fn load_commands<'data, R: ReadRef<'data>>(
&self,
endian: Self::Endian,
data: R,
header_offset: u64,
) -> Result<LoadCommandIterator<'data, Self::Endian>> { let data = data
.read_bytes_at(
header_offset + mem::size_of::<Self>() as u64, self.sizeofcmds(endian).into(),
)
.read_error("Invalid Mach-O load command table size")?;
Ok(LoadCommandIterator::new(endian, data, self.ncmds(endian)))
}
/// Return the UUID from the `LC_UUID` load command, if one is present. fn uuid<'data, R: ReadRef<'data>>(
&self,
endian: Self::Endian,
data: R,
header_offset: u64,
) -> Result<Option<[u8; 16]>> { letmut commands = self.load_commands(endian, data, header_offset)?; whilelet Some(command) = commands.next()? { iflet Ok(Some(uuid)) = command.uuid() { return Ok(Some(uuid.uuid));
}
}
Ok(None)
}
}
impl<Endian: endian::Endian> MachHeader for macho::MachHeader32<Endian> { type Word = u32; type Endian = Endian; type Segment = macho::SegmentCommand32<Endian>; type Section = macho::Section32<Endian>; type Nlist = macho::Nlist32<Endian>;
impl<Endian: endian::Endian> MachHeader for macho::MachHeader64<Endian> { type Word = u64; type Endian = Endian; type Segment = macho::SegmentCommand64<Endian>; type Section = macho::Section64<Endian>; type Nlist = macho::Nlist64<Endian>;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.