Line data Source code
1 : use std::mem::size_of;
2 : use std::path::Path;
3 : use std::pin::Pin;
4 :
5 : use num_traits::{cast, Num};
6 :
7 : use lief_ffi as ffi;
8 :
9 : use super::builder::Config;
10 : use super::dynamic::{self, DynamicEntries, Library};
11 : use super::hash::{Gnu, Sysv};
12 : use super::header::Header;
13 : use super::note::ItNotes;
14 : use super::parser_config::Config as ParserConfig;
15 : use super::relocation::{
16 : DynamicRelocations, ObjectRelocations, PltGotRelocations, Relocation, Relocations,
17 : };
18 : use super::section::{Section, Sections};
19 : use super::segment::{self, Segments};
20 : use super::symbol::{DynamicSymbols, ExportedSymbols, ImportedSymbols, SymtabSymbols};
21 : use super::symbol_versioning::{SymbolVersion, SymbolVersionDefinition, SymbolVersionRequirement};
22 : use super::{Segment, Symbol};
23 : use crate::elf::dynamic::DynamicEntry;
24 : use crate::Error;
25 :
26 : use crate::common::{into_optional, FromFFI};
27 : use crate::generic;
28 : use crate::{declare_iterator, to_conv_result, to_result, to_slice};
29 :
30 0 : #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
31 : pub enum ElfClass {
32 : Elf32,
33 : Elf64,
34 : Unknown,
35 : }
36 :
37 : impl ElfClass {
38 : const ELF_CLASS32: u32 = 1;
39 : const ELF_CLASS64: u32 = 2;
40 :
41 0 : pub fn from_value(value: u32) -> Self {
42 0 : match value {
43 0 : Self::ELF_CLASS32 => ElfClass::Elf32,
44 0 : Self::ELF_CLASS64 => ElfClass::Elf64,
45 0 : _ => ElfClass::Unknown,
46 : }
47 0 : }
48 : }
49 :
50 : /// This is the main interface to read and write ELF binary attributes.
51 : ///
52 : /// Note that this structure implements the [`generic::Binary`] trait from which other generic
53 : /// functions are exposed
54 : pub struct Binary {
55 : ptr: cxx::UniquePtr<ffi::ELF_Binary>,
56 : }
57 :
58 : impl std::fmt::Debug for Binary {
59 96 : fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
60 96 : f.debug_struct("Binary")
61 96 : .field("header", &self.header())
62 96 : .finish()
63 96 : }
64 : }
65 :
66 : impl FromFFI<ffi::ELF_Binary> for Binary {
67 216 : fn from_ffi(ptr: cxx::UniquePtr<ffi::ELF_Binary>) -> Self {
68 216 : Self { ptr }
69 216 : }
70 : }
71 :
72 : impl Binary {
73 : /// Create a [`Binary`] from the given file path
74 10 : pub fn parse<P: AsRef<Path>>(path: P) -> Option<Self> {
75 10 : let bin = ffi::ELF_Binary::parse(path.as_ref().to_str().unwrap());
76 10 : if bin.is_null() {
77 0 : return None;
78 10 : }
79 10 : Some(Binary::from_ffi(bin))
80 10 : }
81 :
82 : /// Parse from a string file path and with a provided configuration
83 0 : pub fn parse_with_config<P: AsRef<Path>>(path: P, config: &ParserConfig) -> Option<Self> {
84 0 : let ffi_config = config.to_ffi();
85 0 : let ffi = ffi::ELF_Binary::parse_with_config(path.as_ref().to_str().unwrap(), &ffi_config);
86 0 : if ffi.is_null() {
87 0 : return None;
88 0 : }
89 0 : Some(Binary::from_ffi(ffi))
90 0 : }
91 :
92 : /// Return the main ELF header
93 96 : pub fn header(&self) -> Header {
94 96 : Header::from_ffi(self.ptr.header())
95 96 : }
96 :
97 : /// Return the size taken by the binary when loaded (virtual size)
98 96 : pub fn virtual_size(&self) -> u64 {
99 96 : self.ptr.virtual_size()
100 96 : }
101 :
102 : /// Return the path to the ELF interpreter that is used to process the ELF information
103 : /// once loaded by the kernel
104 96 : pub fn interpreter(&self) -> String {
105 96 : self.ptr.interpreter().to_string()
106 96 : }
107 :
108 : /// Return sysv-hash information (if present)
109 96 : pub fn sysv_hash(&self) -> Option<Sysv> {
110 96 : into_optional(self.ptr.sysv_hash())
111 96 : }
112 :
113 : /// Return GNU Hash info (if present)
114 96 : pub fn gnu_hash(&self) -> Option<Gnu> {
115 96 : into_optional(self.ptr.gnu_hash())
116 96 : }
117 :
118 : /// Return an iterator over the [`crate::elf::Section`] of the binary
119 96 : pub fn sections(&self) -> Sections {
120 96 : Sections::new(self.ptr.sections())
121 96 : }
122 :
123 : /// Return an iterator over the [`crate::elf::Segment`] of the binary
124 96 : pub fn segments(&self) -> Segments {
125 96 : Segments::new(self.ptr.segments())
126 96 : }
127 :
128 : /// Return an iterator over the [`crate::elf::DynamicEntries`] of the binary
129 96 : pub fn dynamic_entries(&self) -> DynamicEntries {
130 96 : DynamicEntries::new(self.ptr.dynamic_entries())
131 96 : }
132 :
133 : /// Remove **all** dynamic entries with the given tag
134 0 : pub fn remove_dynamic_entries_by_tag(&mut self, tag: dynamic::Tag) {
135 0 : self.ptr
136 0 : .as_mut()
137 0 : .unwrap()
138 0 : .remove_dynamic_entries_by_tag(tag.into())
139 0 : }
140 :
141 : /// Add the given dynamic entry and return the new entry
142 0 : pub fn add_dynamic_entry(&mut self, entry: &dyn dynamic::DynamicEntry) -> dynamic::Entries {
143 0 : dynamic::Entries::from_ffi(
144 0 : self.ptr
145 0 : .as_mut()
146 0 : .unwrap()
147 0 : .add_dynamic_entry(entry.as_base()),
148 0 : )
149 0 : }
150 :
151 : /// Return an iterator over the dynamic [`crate::elf::Symbol`] of the binary
152 96 : pub fn dynamic_symbols(&self) -> DynamicSymbols {
153 96 : DynamicSymbols::new(self.ptr.dynamic_symbols())
154 96 : }
155 :
156 : /// Return an iterator over the **exported** [`crate::elf::Symbol`] of the binary
157 96 : pub fn exported_symbols(&self) -> ExportedSymbols {
158 96 : ExportedSymbols::new(self.ptr.exported_symbols())
159 96 : }
160 :
161 : /// Return an iterator over the **imported** [`crate::elf::Symbol`] of the binary
162 96 : pub fn imported_symbols(&self) -> ImportedSymbols {
163 96 : ImportedSymbols::new(self.ptr.imported_symbols())
164 96 : }
165 :
166 : /// Return an iterator over the symtab-debug [`crate::elf::Symbol`] of the binary
167 96 : pub fn symtab_symbols(&self) -> SymtabSymbols {
168 96 : SymtabSymbols::new(self.ptr.symtab_symbols())
169 96 : }
170 :
171 : /// Return an iterator over the [`crate::elf::SymbolVersion`] of the binary
172 192 : pub fn symbols_version(&self) -> SymbolsVersion {
173 192 : SymbolsVersion::new(self.ptr.symbols_version())
174 192 : }
175 :
176 : /// Return an iterator over the [`crate::elf::SymbolVersionRequirement`] of the binary
177 96 : pub fn symbols_version_requirement(&self) -> SymbolsVersionRequirement {
178 96 : SymbolsVersionRequirement::new(self.ptr.symbols_version_requirement())
179 96 : }
180 :
181 : /// Return an iterator over the [`crate::elf::SymbolVersionDefinition`] of the binary
182 96 : pub fn symbols_version_definition(&self) -> SymbolsVersionDefinition {
183 96 : SymbolsVersionDefinition::new(self.ptr.symbols_version_definition())
184 96 : }
185 :
186 : /// Return an iterator over the [`crate::elf::Notes`] of the binary
187 96 : pub fn notes(&self) -> ItNotes {
188 96 : ItNotes::new(self.ptr.notes())
189 96 : }
190 :
191 : /// Return an iterator over the `.plt.got` [`crate::elf::Relocation`] of the binary
192 96 : pub fn pltgot_relocations(&self) -> PltGotRelocations {
193 96 : PltGotRelocations::new(self.ptr.pltgot_relocations())
194 96 : }
195 :
196 : /// Return an iterator over the regular [`crate::elf::Relocation`] of the binary
197 96 : pub fn dynamic_relocations(&self) -> DynamicRelocations {
198 96 : DynamicRelocations::new(self.ptr.dynamic_relocations())
199 96 : }
200 :
201 : /// Return an iterator over the object-file (`.o`) [`crate::elf::Relocation`]
202 96 : pub fn object_relocations(&self) -> ObjectRelocations {
203 96 : ObjectRelocations::new(self.ptr.object_relocations())
204 96 : }
205 :
206 : /// Return an iterator over **all** [`crate::elf::Relocation`] of the binary
207 96 : pub fn relocations(&self) -> Relocations {
208 96 : Relocations::new(self.ptr.relocations())
209 96 : }
210 :
211 : /// Try to find the ELF section with the given name
212 96 : pub fn section_by_name(&self, name: &str) -> Option<Section> {
213 96 : into_optional(self.ptr.section_by_name(name))
214 96 : }
215 :
216 : /// Try to find the ELF relocation that takes place at the given address
217 24 : pub fn relocation_by_addr(&self, address: u64) -> Option<Relocation> {
218 24 : into_optional(self.ptr.relocation_by_addr(address))
219 24 : }
220 :
221 : /// Try to find the `.plt.got` relocation for the given symbol name
222 24 : pub fn relocation_for_symbol(&self, sym_name: &str) -> Option<Relocation> {
223 24 : into_optional(self.ptr.relocation_for_symbol(sym_name))
224 24 : }
225 :
226 : /// Try to find the symbol with the given name in the dynamic `.dynsym` table
227 12 : pub fn dynamic_symbol_by_name(&self, sym_name: &str) -> Option<Symbol> {
228 12 : into_optional(self.ptr.get_dynamic_symbol(sym_name))
229 12 : }
230 :
231 : /// Try to find the symbol with the given name in the debug `.symtab` table
232 12 : pub fn symtab_symbol_by_name(&self, sym_name: &str) -> Option<Symbol> {
233 12 : into_optional(self.ptr.get_symtab_symbol(sym_name))
234 12 : }
235 :
236 : /// Try to find the library (`DT_NEEDED`) with the given name
237 24 : pub fn get_library(&self, name: &str) -> Option<dynamic::Library> {
238 24 : into_optional(self.ptr.get_library(name))
239 24 : }
240 :
241 : /// Try to find the section that encompasses the given offset. `skip_nobits` can be used
242 : /// to include (or not) the `SHT_NOTBIT` sections
243 24 : pub fn section_from_offset(&self, offset: u64, skip_nobits: bool) -> Option<Section> {
244 24 : into_optional(self.ptr.section_from_offset(offset, skip_nobits))
245 24 : }
246 :
247 : /// Try to find the section that encompasses the given virtual address. `skip_nobits` can be used
248 : /// to include (or not) the `SHT_NOTBIT` sections
249 24 : pub fn section_from_virtual_address(&self, address: u64, skip_nobits: bool) -> Option<Section> {
250 24 : into_optional(self.ptr.section_from_virtual_address(address, skip_nobits))
251 24 : }
252 :
253 : /// Try to find the segment that encompasses the given virtual address
254 24 : pub fn segment_from_virtual_address(&self, address: u64) -> Option<Segment> {
255 24 : into_optional(self.ptr.segment_from_virtual_address(address))
256 24 : }
257 :
258 : /// Try to find the segment that encompasses the given offset
259 24 : pub fn segment_from_offset(&self, offset: u64) -> Option<Segment> {
260 24 : into_optional(self.ptr.segment_from_offset(offset))
261 24 : }
262 :
263 : /// Get a slice of the content at the given address.
264 12 : pub fn content_from_virtual_address(&self, address: u64, size: u64) -> &[u8] {
265 12 : to_slice!(self.ptr.get_content_from_virtual_address(address, size));
266 12 : }
267 :
268 : /// Convert the given virtual address into an offset
269 24 : pub fn virtual_address_to_offset(&self, address: u64) -> Result<u64, Error> {
270 24 : to_result!(ffi::ELF_Binary::virtual_address_to_offset, &self, address);
271 24 : }
272 :
273 : /// Return the array defined by the given tag (e.g.
274 : /// [`dynamic::Tag::INIT_ARRAY`]) with relocations applied (if any)
275 288 : pub fn get_relocated_dynamic_array(&self, tag: dynamic::Tag) -> Vec<u64> {
276 288 : Vec::from(
277 288 : self.ptr
278 288 : .get_relocated_dynamic_array(u64::from(tag))
279 288 : .as_slice(),
280 288 : )
281 288 : }
282 :
283 : /// True if the current binary is targeting Android
284 0 : pub fn is_targeting_android(&self) -> bool {
285 0 : self.ptr.is_targeting_android()
286 0 : }
287 :
288 : /// Get the integer value at the given virtual address
289 4 : pub fn get_int_from_virtual_address<T>(&self, addr: u64) -> Result<T, Error>
290 4 : where
291 4 : T: Num + cast::FromPrimitive + cast::ToPrimitive,
292 4 : {
293 4 : // Can't be in the generic trait because of:
294 4 : // > for a trait to be "object safe" it needs to allow building a vtable to allow the call
295 4 : // > to be resolvable dynamically; for more information visit
296 4 : // > https://doc.rust-lang.org/reference/items/traits.html#object-safety
297 4 : if size_of::<T>() == size_of::<u8>() {
298 1 : to_conv_result!(
299 1 : ffi::AbstractBinary::get_u8,
300 1 : self.ptr.as_ref().unwrap().as_ref(),
301 1 : |value| {
302 1 : T::from_u8(value).unwrap_or_else(|| panic!("Can't cast value: {value}"))
303 1 : },
304 1 : addr
305 : );
306 3 : }
307 3 :
308 3 : if size_of::<T>() == size_of::<u16>() {
309 1 : to_conv_result!(
310 1 : ffi::AbstractBinary::get_u16,
311 1 : self.ptr.as_ref().unwrap().as_ref(),
312 1 : |value| {
313 1 : T::from_u16(value).unwrap_or_else(|| panic!("Can't cast value: {value}"))
314 1 : },
315 1 : addr
316 : );
317 2 : }
318 2 :
319 2 : if size_of::<T>() == size_of::<u32>() {
320 1 : to_conv_result!(
321 1 : ffi::AbstractBinary::get_u32,
322 1 : self.ptr.as_ref().unwrap().as_ref(),
323 1 : |value| {
324 1 : T::from_u32(value).unwrap_or_else(|| panic!("Can't cast value: {value}"))
325 1 : },
326 1 : addr
327 : );
328 1 : }
329 1 :
330 1 : if size_of::<T>() == size_of::<u64>() {
331 1 : to_conv_result!(
332 1 : ffi::AbstractBinary::get_u64,
333 1 : self.ptr.as_ref().unwrap().as_ref(),
334 1 : |value| {
335 1 : T::from_u64(value).unwrap_or_else(|| panic!("Can't cast value: {value}"))
336 1 : },
337 1 : addr
338 : );
339 0 : }
340 0 :
341 0 : Err(Error::NotSupported)
342 4 : }
343 :
344 : /// Write back the current ELF binary into the file specified in parameter
345 1 : pub fn write<P: AsRef<Path>>(&mut self, output: P) {
346 1 : self.ptr.as_mut().unwrap().write(output.as_ref().to_str().unwrap());
347 1 : }
348 :
349 : /// Write back the current ELF binary into the file specified in parameter with the
350 : /// configuration provided in the second parameter.
351 1 : pub fn write_with_config<P: AsRef<Path>>(&mut self, output: P, config: Config) {
352 1 : self.ptr
353 1 : .as_mut()
354 1 : .unwrap()
355 1 : .write_with_config(output.as_ref().to_str().unwrap(), config.to_ffi());
356 1 : }
357 :
358 : /// Add a library as dependency
359 12 : pub fn add_library<'a>(&'a mut self, library: &str) -> Library<'a> {
360 12 : Library::from_ffi(self.ptr.as_mut().unwrap().add_library(library))
361 12 : }
362 :
363 : /// Iterator over the functions found in this binary
364 96 : pub fn functions(&self) -> generic::Functions {
365 96 : generic::Functions::new(self.ptr.functions())
366 96 : }
367 :
368 : /// Try to find the dynamic entry associated with the given tag
369 0 : pub fn dynamic_entry_by_tag(&self, tag: dynamic::Tag) -> Option<dynamic::Entries> {
370 0 : into_optional(self.ptr.dynamic_entry_by_tag(tag.into()))
371 0 : }
372 :
373 : /// Look for the segment with the given type. If there are multiple segment
374 : /// with the same type, it returns the first one.
375 0 : pub fn segment_by_type(&self, seg_type: segment::Type) -> Option<Segment> {
376 0 : into_optional(self.ptr.segment_by_type(seg_type.into()))
377 0 : }
378 :
379 : /// Remove the given dynamic entry
380 0 : pub fn remove_dynamic_entry(&mut self, entry: impl dynamic::DynamicEntry) {
381 0 : self.ptr.pin_mut().remove_dynamic_entry(entry.as_base());
382 0 : }
383 :
384 : /// Remove the dynamic entries matching the given predicate.
385 : ///
386 : /// The function returns the number of entries that have been deleted.
387 0 : pub fn remove_dynamic_entry_if<P>(&mut self, predicate: P) -> usize
388 0 : where
389 0 : P: Fn(&dynamic::Entries) -> bool,
390 0 : {
391 0 : let entries = self.dynamic_entries()
392 0 : .filter(predicate)
393 0 : .map(|e| e.as_base().raw_ptr() )
394 0 : .collect::<Vec<_>>();
395 0 :
396 0 : let cnt = entries.len();
397 :
398 0 : for ffi_entry in entries {
399 0 : unsafe {
400 0 : self.ptr.pin_mut().remove_dynamic_entry_from_ptr(ffi_entry);
401 0 : }
402 : }
403 0 : cnt
404 0 : }
405 :
406 : /// Remove the `DT_NEEDED` dependency with the given name
407 0 : pub fn remove_library(&mut self, name: &str) {
408 0 : self.ptr.pin_mut().remove_library(name.to_string());
409 0 : }
410 :
411 : /// Add the provided segment to the binary. This function returns the
412 : /// newly added segment which could define additional attributes like the virtual address.
413 0 : pub fn add_segment(&mut self, segment: &Segment) -> Option<Segment> {
414 0 : into_optional(
415 0 : self.ptr
416 0 : .pin_mut()
417 0 : .add_segment(segment.ptr.as_ref().unwrap()),
418 0 : )
419 0 : }
420 :
421 : /// Change the path to the interpreter
422 0 : pub fn set_interpreter<P: AsRef<Path>>(&mut self, interpreter: P) {
423 0 : self.ptr.pin_mut().set_interpreter(interpreter.as_ref().to_str().unwrap());
424 0 : }
425 :
426 : /// Try to find the SymbolVersionRequirement associated with the given library
427 : /// name (e.g. `libc.so.6`)
428 0 : pub fn find_version_requirement(&self, libname: &str) -> Option<SymbolVersionRequirement> {
429 0 : into_optional(self.ptr.find_version_requirement(libname.to_string()))
430 0 : }
431 :
432 : /// Deletes all required symbol versions linked to the specified library name.
433 : /// The function returns true if the operation succeed, false otherwise.
434 : ///
435 : /// <div class='warning'>
436 : /// To maintain consistency, this function also removes versions
437 : /// associated with dynamic symbols that are linked to the specified
438 : /// library name.
439 : /// </div>
440 0 : pub fn remove_version_requirement(&mut self, libname: &str) -> bool {
441 0 : self.ptr
442 0 : .pin_mut()
443 0 : .remove_version_requirement(libname.to_string())
444 0 : }
445 :
446 : /// Remove the given segment. If `clear` is set, the original content of the
447 : /// segment will be filled with zeros before removal.
448 0 : pub fn remove_segment(&mut self, segment: Segment, clear: bool) {
449 0 : self.ptr
450 0 : .pin_mut()
451 0 : .remove_segment(segment.ptr.as_ref().unwrap(), clear)
452 0 : }
453 :
454 : /// Remove all segments associated with the given type.
455 : ///
456 : /// If `clear` is set, the original content of the segments will be filled
457 : /// with zeros before removal.
458 0 : pub fn remove_segments_by_type(&mut self, ty: segment::Type, clear: bool) {
459 0 : self.ptr.pin_mut().remove_segments_by_type(ty.into(), clear)
460 0 : }
461 : }
462 :
463 : impl generic::Binary for Binary {
464 480 : fn as_generic(&self) -> &ffi::AbstractBinary {
465 480 : self.ptr.as_ref().unwrap().as_ref()
466 480 : }
467 :
468 0 : fn as_pin_mut_generic(&mut self) -> Pin<&mut ffi::AbstractBinary> {
469 0 : unsafe {
470 0 : Pin::new_unchecked({
471 0 : (self.ptr.as_ref().unwrap().as_ref() as *const ffi::AbstractBinary
472 0 : as *mut ffi::AbstractBinary)
473 0 : .as_mut()
474 0 : .unwrap()
475 0 : })
476 0 : }
477 0 : }
478 : }
479 :
480 18648 : declare_iterator!(
481 18648 : SymbolsVersion,
482 18648 : SymbolVersion<'a>,
483 18648 : ffi::ELF_SymbolVersion,
484 18648 : ffi::ELF_Binary,
485 18648 : ffi::ELF_Binary_it_symbols_version
486 18648 : );
487 180 : declare_iterator!(
488 180 : SymbolsVersionRequirement,
489 180 : SymbolVersionRequirement<'a>,
490 180 : ffi::ELF_SymbolVersionRequirement,
491 180 : ffi::ELF_Binary,
492 180 : ffi::ELF_Binary_it_symbols_version_requirement
493 180 : );
494 36 : declare_iterator!(
495 36 : SymbolsVersionDefinition,
496 36 : SymbolVersionDefinition<'a>,
497 36 : ffi::ELF_SymbolVersionDefinition,
498 36 : ffi::ELF_Binary,
499 36 : ffi::ELF_Binary_it_symbols_version_definition
500 36 : );
|