#[repr(C)] #[derive(Copy, Clone, PartialEq, Default)] #[cfg_attr(
feature = "alloc",
derive(scroll::Pread, scroll::Pwrite, scroll::SizeWith)
)] /// An entry in the dynamic array pubstructDyn { /// Dynamic entry type pub d_tag: $size, /// Integer value pub d_val: $size,
}
use plain; unsafeimpl plain::Plain forDyn {}
};
}
// TODO: figure out what's the best, most friendly + safe API choice here - u32s or u64s // remember that DT_TAG is "pointer sized"/used as address sometimes Original rationale: I // decided to use u64 instead of u32 due to pattern matching use case seems safer to cast the // elf32's d_tag from u32 -> u64 at runtime instead of casting the elf64's d_tag from u64 -> // u32 at runtime
/// Marks end of dynamic section pubconst DT_NULL: u64 = 0; /// Name of needed library pubconst DT_NEEDED: u64 = 1; /// Size in bytes of PLT relocs pubconst DT_PLTRELSZ: u64 = 2; /// Processor defined value pubconst DT_PLTGOT: u64 = 3; /// Address of symbol hash table pubconst DT_HASH: u64 = 4; /// Address of string table pubconst DT_STRTAB: u64 = 5; /// Address of symbol table pubconst DT_SYMTAB: u64 = 6; /// Address of Rela relocs pubconst DT_RELA: u64 = 7; /// Total size of Rela relocs pubconst DT_RELASZ: u64 = 8; /// Size of one Rela reloc pubconst DT_RELAENT: u64 = 9; /// Size of string table pubconst DT_STRSZ: u64 = 10; /// Size of one symbol table entry pubconst DT_SYMENT: u64 = 11; /// Address of init function pubconst DT_INIT: u64 = 12; /// Address of termination function pubconst DT_FINI: u64 = 13; /// Name of shared object pubconst DT_SONAME: u64 = 14; /// Library search path (deprecated) pubconst DT_RPATH: u64 = 15; /// Start symbol search here pubconst DT_SYMBOLIC: u64 = 16; /// Address of Rel relocs pubconst DT_REL: u64 = 17; /// Total size of Rel relocs pubconst DT_RELSZ: u64 = 18; /// Size of one Rel reloc pubconst DT_RELENT: u64 = 19; /// Type of reloc in PLT pubconst DT_PLTREL: u64 = 20; /// For debugging; unspecified pubconst DT_DEBUG: u64 = 21; /// Reloc might modify .text pubconst DT_TEXTREL: u64 = 22; /// Address of PLT relocs pubconst DT_JMPREL: u64 = 23; /// Process relocations of object pubconst DT_BIND_NOW: u64 = 24; /// Array with addresses of init fct pubconst DT_INIT_ARRAY: u64 = 25; /// Array with addresses of fini fct pubconst DT_FINI_ARRAY: u64 = 26; /// Size in bytes of DT_INIT_ARRAY pubconst DT_INIT_ARRAYSZ: u64 = 27; /// Size in bytes of DT_FINI_ARRAY pubconst DT_FINI_ARRAYSZ: u64 = 28; /// Library search path pubconst DT_RUNPATH: u64 = 29; /// Flags for the object being loaded pubconst DT_FLAGS: u64 = 30; /// Start of encoded range pubconst DT_ENCODING: u64 = 32; /// Array with addresses of preinit fct pubconst DT_PREINIT_ARRAY: u64 = 32; /// size in bytes of DT_PREINIT_ARRAY pubconst DT_PREINIT_ARRAYSZ: u64 = 33; /// Number used pubconst DT_NUM: u64 = 34; /// Start of OS-specific pubconst DT_LOOS: u64 = 0x6000_000d; /// End of OS-specific pubconst DT_HIOS: u64 = 0x6fff_f000; /// Start of processor-specific pubconst DT_LOPROC: u64 = 0x7000_0000; /// End of processor-specific pubconst DT_HIPROC: u64 = 0x7fff_ffff; // Most used by any processor // pub const DT_PROCNUM: u64 = DT_MIPS_NUM;
/// DT_* entries which fall between DT_ADDRRNGHI & DT_ADDRRNGLO use the /// Dyn.d_un.d_ptr field of the Elf*_Dyn structure. /// /// If any adjustment is made to the ELF object after it has been /// built these entries will need to be adjusted. pubconst DT_ADDRRNGLO: u64 = 0x6fff_fe00; /// GNU-style hash table pubconst DT_GNU_HASH: u64 = 0x6fff_fef5; /// pubconst DT_TLSDESC_PLT: u64 = 0x6fff_fef6; /// pubconst DT_TLSDESC_GOT: u64 = 0x6fff_fef7; /// Start of conflict section pubconst DT_GNU_CONFLICT: u64 = 0x6fff_fef8; /// Library list pubconst DT_GNU_LIBLIST: u64 = 0x6fff_fef9; /// Configuration information pubconst DT_CONFIG: u64 = 0x6fff_fefa; /// Dependency auditing pubconst DT_DEPAUDIT: u64 = 0x6fff_fefb; /// Object auditing pubconst DT_AUDIT: u64 = 0x6fff_fefc; /// PLT padding pubconst DT_PLTPAD: u64 = 0x6fff_fefd; /// Move table pubconst DT_MOVETAB: u64 = 0x6fff_fefe; /// Syminfo table pubconst DT_SYMINFO: u64 = 0x6fff_feff; /// pubconst DT_ADDRRNGHI: u64 = 0x6fff_feff;
/// The versioning entry types. The next are defined as part of the GNU extension pubconst DT_VERSYM: u64 = 0x6fff_fff0; pubconst DT_RELACOUNT: u64 = 0x6fff_fff9; pubconst DT_RELCOUNT: u64 = 0x6fff_fffa; /// State flags, see DF_1_* below pubconst DT_FLAGS_1: u64 = 0x6fff_fffb; /// Address of version definition table pubconst DT_VERDEF: u64 = 0x6fff_fffc; /// Number of version definitions pubconst DT_VERDEFNUM: u64 = 0x6fff_fffd; /// Address of table with needed versions pubconst DT_VERNEED: u64 = 0x6fff_fffe; /// Number of needed versions pubconst DT_VERNEEDNUM: u64 = 0x6fff_ffff;
impl Dynamic { #[cfg(feature = "endian_fd")] /// Returns a vector of dynamic entries from the underlying byte `bytes`, with `endianness`, using the provided `phdrs` pubfn parse(bytes: &[u8], phdrs: &[crate::elf::program_header::ProgramHeader], ctx: Ctx) -> crate::error::Result<Option<Self>> { use scroll::ctx::SizeWith; use scroll::Pread; usecrate::elf::program_header; for phdr in phdrs { if phdr.p_type == program_header::PT_DYNAMIC { let offset = phdr.p_offset as usize; let filesz = phdr.p_filesz as usize; // Ensure offset and filesz are valid. let bytes = if filesz > 0 {
bytes
.pread_with::<&[u8]>(offset, filesz)
.map_err(|_| crate::error::Error::Malformed(format!("Invalid PT_DYNAMIC size (offset {:#x}, filesz {:#x})",
offset, filesz)))?
} else {
&[]
}; let size = Dyn::size_with(&ctx); // the validity of `count` was implicitly checked by reading `bytes`. let count = filesz / size; letmut dyns = Vec::with_capacity(count); letmut offset = 0; for _ in0..count { let dynamic = bytes.gread_with::<Dyn>(&mut offset, ctx)?; let tag = dynamic.d_tag;
dyns.push(dynamic); if tag == DT_NULL { break }
} letmut info = DynamicInfo::default(); for dynamic in &dyns {
info.update(phdrs, dynamic);
} return Ok(Some(Dynamic { dyns: dyns, info: info, }));
}
}
Ok(None)
}
pubfn get_libraries<'a>(&self, strtab: &Strtab<'a>) -> Vec<&'a str> { use log::warn; let count = self.info.needed_count.min(self.dyns.len()); letmut needed = Vec::with_capacity(count); for dynamic in &self.dyns { if dynamic.d_tag as u64 == DT_NEEDED { iflet Some(lib) = strtab.get_at(dynamic.d_val as usize) {
needed.push(lib)
} else {
warn!("Invalid DT_NEEDED {}", dynamic.d_val)
}
}
}
needed
}
}
}
/// Returns a vector of dynamic entries from the given fd and program headers #[cfg(feature = "std")] pubfn from_fd(mut fd: &File, phdrs: &[$phdr]) -> Result<Option<Vec<Dyn>>> { for phdr in phdrs { if phdr.p_type == PT_DYNAMIC { // FIXME: validate filesz before allocating let filesz = phdr.p_filesz as usize; let dync = filesz / SIZEOF_DYN; letmut dyns = vec![Dyn::default(); dync];
fd.seek(Start(u64::from(phdr.p_offset)))?; unsafe {
fd.read_exact(plain::as_mut_bytes(&mut *dyns))?;
}
dyns.dedup(); return Ok(Some(dyns));
}
}
Ok(None)
}
/// Given a bias and a memory address (typically for a _correctly_ mmap'd binary in memory), returns the `_DYNAMIC` array as a slice of that memory pubunsafefn from_raw<'a>(bias: usize, vaddr: usize) -> &'a [Dyn] { let dynp = vaddr.wrapping_add(bias) as *constDyn; letmut idx = 0; while u64::from((*dynp.offset(idx)).d_tag) != DT_NULL {
idx += 1;
}
slice::from_raw_parts(dynp, idx as usize)
}
// TODO: these bare functions have always seemed awkward, but not sure where they should go... /// Maybe gets and returns the dynamic array with the same lifetime as the `phdrs`, using the provided bias with wrapping addition. /// If the bias is wrong, it will either segfault or give you incorrect values, beware pubunsafefn from_phdrs(bias: usize, phdrs: &[$phdr]) -> Option<&[Dyn]> { for phdr in phdrs { // FIXME: change to casting to u64 similar to DT_*? if phdr.p_type as u32 == PT_DYNAMIC { return Some(from_raw(bias, phdr.p_vaddr as usize));
}
}
None
}
/// Gets the needed libraries from the `_DYNAMIC` array, with the str slices lifetime tied to the dynamic array/strtab's lifetime(s) pubunsafefn get_needed<'a>(dyns: &[Dyn], strtab: *const Strtab<'a>, count: usize) -> Vec<&le='color:blue'>'a str> { letmut needed = Vec::with_capacity(count.min(dyns.len())); for dynamic in dyns { if u64::from(dynamic.d_tag) == DT_NEEDED { let lib = &(*strtab)[dynamic.d_val as usize];
needed.push(lib);
}
}
needed
}
}
};
}
macro_rules! elf_dynamic_info_std_impl {
($size:ident, $phdr:ty) => { /// Convert a virtual memory address to a file offset fn vm_to_offset(phdrs: &[$phdr], address: $size) -> Option<$size> { for ph in phdrs { if ph.p_type == crate::elf::program_header::PT_LOAD && address >= ph.p_vaddr { let offset = address - ph.p_vaddr; if offset < ph.p_memsz { return ph.p_offset.checked_add(offset);
}
}
}
None
}
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.