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, AsFFI, 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 : /// Strategy used for relocating the PHDR table
51 : #[allow(non_camel_case_types)]
52 0 : #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
53 : pub enum PhdrReloc {
54 : /// Let LIEF choose the best strategy
55 : AUTO,
56 : /// Shift content after the PHDR table (PIE binaries only)
57 : PIE_SHIFT,
58 : /// Relocate the PHDR after the first BSS-like segment
59 : BSS_END,
60 : /// Relocate at the end of the binary
61 : BINARY_END,
62 : /// Relocate between two LOAD segments
63 : SEGMENT_GAP,
64 : UNKNOWN(u32),
65 : }
66 :
67 : impl From<u32> for PhdrReloc {
68 0 : fn from(value: u32) -> Self {
69 0 : match value {
70 0 : 0 => PhdrReloc::AUTO,
71 0 : 1 => PhdrReloc::PIE_SHIFT,
72 0 : 2 => PhdrReloc::BSS_END,
73 0 : 3 => PhdrReloc::BINARY_END,
74 0 : 4 => PhdrReloc::SEGMENT_GAP,
75 0 : _ => PhdrReloc::UNKNOWN(value),
76 : }
77 0 : }
78 : }
79 :
80 : impl From<PhdrReloc> for u32 {
81 0 : fn from(value: PhdrReloc) -> u32 {
82 0 : match value {
83 0 : PhdrReloc::AUTO => 0,
84 0 : PhdrReloc::PIE_SHIFT => 1,
85 0 : PhdrReloc::BSS_END => 2,
86 0 : PhdrReloc::BINARY_END => 3,
87 0 : PhdrReloc::SEGMENT_GAP => 4,
88 0 : PhdrReloc::UNKNOWN(v) => v,
89 : }
90 0 : }
91 : }
92 :
93 : /// Strategy for inserting a new section
94 : #[allow(non_camel_case_types)]
95 0 : #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
96 : pub enum SecInsertPos {
97 : /// Let LIEF choose the best strategy
98 : AUTO,
99 : /// Insert after the last segment offset, before debug info
100 : POST_SEGMENT,
101 : /// Insert after the last section offset, at binary end
102 : POST_SECTION,
103 : UNKNOWN(u32),
104 : }
105 :
106 : impl From<u32> for SecInsertPos {
107 0 : fn from(value: u32) -> Self {
108 0 : match value {
109 0 : 0 => SecInsertPos::AUTO,
110 0 : 1 => SecInsertPos::POST_SEGMENT,
111 0 : 2 => SecInsertPos::POST_SECTION,
112 0 : _ => SecInsertPos::UNKNOWN(value),
113 : }
114 0 : }
115 : }
116 :
117 : impl From<SecInsertPos> for u32 {
118 0 : fn from(value: SecInsertPos) -> u32 {
119 0 : match value {
120 0 : SecInsertPos::AUTO => 0,
121 0 : SecInsertPos::POST_SEGMENT => 1,
122 0 : SecInsertPos::POST_SECTION => 2,
123 0 : SecInsertPos::UNKNOWN(v) => v,
124 : }
125 0 : }
126 : }
127 :
128 : /// This is the main interface to read and write ELF binary attributes.
129 : ///
130 : /// Note that this structure implements the [`generic::Binary`] trait from which other generic
131 : /// functions are exposed
132 : pub struct Binary {
133 : ptr: cxx::UniquePtr<ffi::ELF_Binary>,
134 : }
135 :
136 : impl std::fmt::Debug for Binary {
137 130 : fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
138 130 : f.debug_struct("Binary")
139 130 : .field("header", &self.header())
140 130 : .finish()
141 130 : }
142 : }
143 :
144 : impl FromFFI<ffi::ELF_Binary> for Binary {
145 546 : fn from_ffi(ptr: cxx::UniquePtr<ffi::ELF_Binary>) -> Self {
146 546 : Self { ptr }
147 546 : }
148 : }
149 :
150 : impl Binary {
151 : /// Create a [`Binary`] from the given file path
152 32 : pub fn parse<P: AsRef<Path>>(path: P) -> Option<Self> {
153 32 : let bin = ffi::ELF_Binary::parse(path.as_ref().to_str().unwrap());
154 32 : if bin.is_null() {
155 0 : return None;
156 32 : }
157 32 : Some(Binary::from_ffi(bin))
158 32 : }
159 :
160 : /// Parse from a string file path and with a provided configuration
161 0 : pub fn parse_with_config<P: AsRef<Path>>(path: P, config: &ParserConfig) -> Option<Self> {
162 0 : let ffi_config = config.to_ffi();
163 0 : let ffi = ffi::ELF_Binary::parse_with_config(path.as_ref().to_str().unwrap(), &ffi_config);
164 0 : if ffi.is_null() {
165 0 : return None;
166 0 : }
167 0 : Some(Binary::from_ffi(ffi))
168 0 : }
169 :
170 : /// Return the main ELF header
171 130 : pub fn header(&self) -> Header<'_> {
172 130 : Header::from_ffi(self.ptr.header())
173 130 : }
174 :
175 : /// Return the size taken by the binary when loaded (virtual size)
176 130 : pub fn virtual_size(&self) -> u64 {
177 130 : self.ptr.virtual_size()
178 130 : }
179 :
180 : /// Return the path to the ELF interpreter that is used to process the ELF information
181 : /// once loaded by the kernel
182 130 : pub fn interpreter(&self) -> String {
183 130 : self.ptr.interpreter().to_string()
184 130 : }
185 :
186 : /// Return sysv-hash information (if present)
187 130 : pub fn sysv_hash(&self) -> Option<Sysv<'_>> {
188 130 : into_optional(self.ptr.sysv_hash())
189 130 : }
190 :
191 : /// Return GNU Hash info (if present)
192 130 : pub fn gnu_hash(&self) -> Option<Gnu<'_>> {
193 130 : into_optional(self.ptr.gnu_hash())
194 130 : }
195 :
196 : /// Return an iterator over the [`crate::elf::Section`] of the binary
197 130 : pub fn sections(&self) -> Sections<'_> {
198 130 : Sections::new(self.ptr.sections())
199 130 : }
200 :
201 : /// Return an iterator over the [`crate::elf::Segment`] of the binary
202 130 : pub fn segments(&self) -> Segments<'_> {
203 130 : Segments::new(self.ptr.segments())
204 130 : }
205 :
206 : /// Return an iterator over the [`crate::elf::DynamicEntries`] of the binary
207 130 : pub fn dynamic_entries(&self) -> DynamicEntries<'_> {
208 130 : DynamicEntries::new(self.ptr.dynamic_entries())
209 130 : }
210 :
211 : /// Remove **all** dynamic entries with the given tag
212 0 : pub fn remove_dynamic_entries_by_tag(&mut self, tag: dynamic::Tag) {
213 0 : self.ptr
214 0 : .as_mut()
215 0 : .unwrap()
216 0 : .remove_dynamic_entries_by_tag(tag.into())
217 0 : }
218 :
219 : /// Add the given dynamic entry and return the new entry
220 0 : pub fn add_dynamic_entry(&mut self, entry: &dyn dynamic::DynamicEntry) -> dynamic::Entries<'_> {
221 0 : dynamic::Entries::from_ffi(
222 0 : self.ptr
223 0 : .as_mut()
224 0 : .unwrap()
225 0 : .add_dynamic_entry(entry.as_base()),
226 0 : )
227 0 : }
228 :
229 : /// Return an iterator over the dynamic [`crate::elf::Symbol`] of the binary
230 130 : pub fn dynamic_symbols(&self) -> DynamicSymbols<'_> {
231 130 : DynamicSymbols::new(self.ptr.dynamic_symbols())
232 130 : }
233 :
234 : /// Return an iterator over the **exported** [`crate::elf::Symbol`] of the binary
235 130 : pub fn exported_symbols(&self) -> ExportedSymbols<'_> {
236 130 : ExportedSymbols::new(self.ptr.exported_symbols())
237 130 : }
238 :
239 : /// Return an iterator over the **imported** [`crate::elf::Symbol`] of the binary
240 130 : pub fn imported_symbols(&self) -> ImportedSymbols<'_> {
241 130 : ImportedSymbols::new(self.ptr.imported_symbols())
242 130 : }
243 :
244 : /// Return an iterator over the symtab-debug [`crate::elf::Symbol`] of the binary
245 130 : pub fn symtab_symbols(&self) -> SymtabSymbols<'_> {
246 130 : SymtabSymbols::new(self.ptr.symtab_symbols())
247 130 : }
248 :
249 : /// Return an iterator over the [`crate::elf::SymbolVersion`] of the binary
250 260 : pub fn symbols_version(&self) -> SymbolsVersion<'_> {
251 260 : SymbolsVersion::new(self.ptr.symbols_version())
252 260 : }
253 :
254 : /// Return an iterator over the [`crate::elf::SymbolVersionRequirement`] of the binary
255 130 : pub fn symbols_version_requirement(&self) -> SymbolsVersionRequirement<'_> {
256 130 : SymbolsVersionRequirement::new(self.ptr.symbols_version_requirement())
257 130 : }
258 :
259 : /// Return an iterator over the [`crate::elf::SymbolVersionDefinition`] of the binary
260 130 : pub fn symbols_version_definition(&self) -> SymbolsVersionDefinition<'_> {
261 130 : SymbolsVersionDefinition::new(self.ptr.symbols_version_definition())
262 130 : }
263 :
264 : /// Return an iterator over the [`crate::elf::Notes`] of the binary
265 390 : pub fn notes(&self) -> ItNotes<'_> {
266 390 : ItNotes::new(self.ptr.notes())
267 390 : }
268 :
269 : /// Return an iterator over the `.plt.got` [`crate::elf::Relocation`] of the binary
270 130 : pub fn pltgot_relocations(&self) -> PltGotRelocations<'_> {
271 130 : PltGotRelocations::new(self.ptr.pltgot_relocations())
272 130 : }
273 :
274 : /// Return an iterator over the regular [`crate::elf::Relocation`] of the binary
275 130 : pub fn dynamic_relocations(&self) -> DynamicRelocations<'_> {
276 130 : DynamicRelocations::new(self.ptr.dynamic_relocations())
277 130 : }
278 :
279 : /// Return an iterator over the object-file (`.o`) [`crate::elf::Relocation`]
280 130 : pub fn object_relocations(&self) -> ObjectRelocations<'_> {
281 130 : ObjectRelocations::new(self.ptr.object_relocations())
282 130 : }
283 :
284 : /// Return an iterator over **all** [`crate::elf::Relocation`] of the binary
285 130 : pub fn relocations(&self) -> Relocations<'_> {
286 130 : Relocations::new(self.ptr.relocations())
287 130 : }
288 :
289 : /// Try to find the ELF section with the given name
290 130 : pub fn section_by_name(&self, name: &str) -> Option<Section<'_>> {
291 130 : into_optional(self.ptr.section_by_name(name))
292 130 : }
293 :
294 : /// Try to find the ELF relocation that takes place at the given address
295 26 : pub fn relocation_by_addr(&self, address: u64) -> Option<Relocation<'_>> {
296 26 : into_optional(self.ptr.relocation_by_addr(address))
297 26 : }
298 :
299 : /// Try to find the `.plt.got` relocation for the given symbol name
300 26 : pub fn relocation_for_symbol(&self, sym_name: &str) -> Option<Relocation<'_>> {
301 26 : into_optional(self.ptr.relocation_for_symbol(sym_name))
302 26 : }
303 :
304 : /// Try to find the symbol with the given name in the dynamic `.dynsym` table
305 13 : pub fn dynamic_symbol_by_name(&self, sym_name: &str) -> Option<Symbol<'_>> {
306 13 : into_optional(self.ptr.get_dynamic_symbol(sym_name))
307 13 : }
308 :
309 : /// Try to find the symbol with the given name in the debug `.symtab` table
310 13 : pub fn symtab_symbol_by_name(&self, sym_name: &str) -> Option<Symbol<'_>> {
311 13 : into_optional(self.ptr.get_symtab_symbol(sym_name))
312 13 : }
313 :
314 : /// Try to find the library (`DT_NEEDED`) with the given name
315 26 : pub fn get_library(&self, name: &str) -> Option<dynamic::Library<'_>> {
316 26 : into_optional(self.ptr.get_library(name))
317 26 : }
318 :
319 : /// Try to find the section that encompasses the given offset. `skip_nobits` can be used
320 : /// to include (or not) the `SHT_NOTBIT` sections
321 26 : pub fn section_from_offset(&self, offset: u64, skip_nobits: bool) -> Option<Section<'_>> {
322 26 : into_optional(self.ptr.section_from_offset(offset, skip_nobits))
323 26 : }
324 :
325 : /// Try to find the section that encompasses the given virtual address. `skip_nobits` can be used
326 : /// to include (or not) the `SHT_NOTBIT` sections
327 26 : pub fn section_from_virtual_address(
328 26 : &self,
329 26 : address: u64,
330 26 : skip_nobits: bool,
331 26 : ) -> Option<Section<'_>> {
332 26 : into_optional(self.ptr.section_from_virtual_address(address, skip_nobits))
333 26 : }
334 :
335 : /// Try to find the segment that encompasses the given virtual address
336 26 : pub fn segment_from_virtual_address(&self, address: u64) -> Option<Segment<'_>> {
337 26 : into_optional(self.ptr.segment_from_virtual_address(address))
338 26 : }
339 :
340 : /// Try to find the segment that encompasses the given offset
341 26 : pub fn segment_from_offset(&self, offset: u64) -> Option<Segment<'_>> {
342 26 : into_optional(self.ptr.segment_from_offset(offset))
343 26 : }
344 :
345 : /// Get a slice of the content at the given address.
346 13 : pub fn content_from_virtual_address(&self, address: u64, size: u64) -> &[u8] {
347 13 : to_slice!(self.ptr.get_content_from_virtual_address(address, size));
348 13 : }
349 :
350 : /// Convert the given virtual address into an offset
351 26 : pub fn virtual_address_to_offset(&self, address: u64) -> Result<u64, Error> {
352 26 : to_result!(ffi::ELF_Binary::virtual_address_to_offset, &self, address);
353 26 : }
354 :
355 : /// Return the array defined by the given tag (e.g.
356 : /// [`dynamic::Tag::INIT_ARRAY`]) with relocations applied (if any)
357 390 : pub fn get_relocated_dynamic_array(&self, tag: dynamic::Tag) -> Vec<u64> {
358 390 : Vec::from(
359 390 : self.ptr
360 390 : .get_relocated_dynamic_array(u64::from(tag))
361 390 : .as_slice(),
362 390 : )
363 390 : }
364 :
365 : /// True if the current binary is targeting Android
366 0 : pub fn is_targeting_android(&self) -> bool {
367 0 : self.ptr.is_targeting_android()
368 0 : }
369 :
370 : /// Get the integer value at the given virtual address
371 4 : pub fn get_int_from_virtual_address<T>(&self, addr: u64) -> Result<T, Error>
372 4 : where
373 4 : T: Num + cast::FromPrimitive + cast::ToPrimitive,
374 4 : {
375 4 : // Can't be in the generic trait because of:
376 4 : // > for a trait to be "object safe" it needs to allow building a vtable to allow the call
377 4 : // > to be resolvable dynamically; for more information visit
378 4 : // > https://doc.rust-lang.org/reference/items/traits.html#object-safety
379 4 : if size_of::<T>() == size_of::<u8>() {
380 1 : to_conv_result!(
381 1 : ffi::AbstractBinary::get_u8,
382 1 : self.ptr.as_ref().unwrap().as_ref(),
383 1 : |value| {
384 1 : T::from_u8(value).unwrap_or_else(|| panic!("Can't cast value: {value}"))
385 1 : },
386 1 : addr
387 : );
388 3 : }
389 3 :
390 3 : if size_of::<T>() == size_of::<u16>() {
391 1 : to_conv_result!(
392 1 : ffi::AbstractBinary::get_u16,
393 1 : self.ptr.as_ref().unwrap().as_ref(),
394 1 : |value| {
395 1 : T::from_u16(value).unwrap_or_else(|| panic!("Can't cast value: {value}"))
396 1 : },
397 1 : addr
398 : );
399 2 : }
400 2 :
401 2 : if size_of::<T>() == size_of::<u32>() {
402 1 : to_conv_result!(
403 1 : ffi::AbstractBinary::get_u32,
404 1 : self.ptr.as_ref().unwrap().as_ref(),
405 1 : |value| {
406 1 : T::from_u32(value).unwrap_or_else(|| panic!("Can't cast value: {value}"))
407 1 : },
408 1 : addr
409 : );
410 1 : }
411 1 :
412 1 : if size_of::<T>() == size_of::<u64>() {
413 1 : to_conv_result!(
414 1 : ffi::AbstractBinary::get_u64,
415 1 : self.ptr.as_ref().unwrap().as_ref(),
416 1 : |value| {
417 1 : T::from_u64(value).unwrap_or_else(|| panic!("Can't cast value: {value}"))
418 1 : },
419 1 : addr
420 : );
421 0 : }
422 0 :
423 0 : Err(Error::NotSupported)
424 4 : }
425 :
426 : /// Write back the current ELF binary into the file specified in parameter
427 1 : pub fn write<P: AsRef<Path>>(&mut self, output: P) {
428 1 : self.ptr
429 1 : .as_mut()
430 1 : .unwrap()
431 1 : .write(output.as_ref().to_str().unwrap());
432 1 : }
433 :
434 : /// Write back the current ELF binary into the file specified in parameter with the
435 : /// configuration provided in the second parameter.
436 1 : pub fn write_with_config<P: AsRef<Path>>(&mut self, output: P, config: Config) {
437 1 : self.ptr
438 1 : .as_mut()
439 1 : .unwrap()
440 1 : .write_with_config(output.as_ref().to_str().unwrap(), config.to_ffi());
441 1 : }
442 :
443 : /// Add a library as dependency
444 13 : pub fn add_library<'a>(&'a mut self, library: &str) -> Library<'a> {
445 13 : Library::from_ffi(self.ptr.as_mut().unwrap().add_library(library))
446 13 : }
447 :
448 : /// Iterator over the functions found in this binary
449 130 : pub fn functions(&self) -> generic::Functions<'_> {
450 130 : generic::Functions::new(self.ptr.functions())
451 130 : }
452 :
453 : /// Try to find the dynamic entry associated with the given tag
454 0 : pub fn dynamic_entry_by_tag(&self, tag: dynamic::Tag) -> Option<dynamic::Entries<'_>> {
455 0 : into_optional(self.ptr.dynamic_entry_by_tag(tag.into()))
456 0 : }
457 :
458 : /// Look for the segment with the given type. If there are multiple segment
459 : /// with the same type, it returns the first one.
460 0 : pub fn segment_by_type(&self, seg_type: segment::Type) -> Option<Segment<'_>> {
461 0 : into_optional(self.ptr.segment_by_type(seg_type.into()))
462 0 : }
463 :
464 : /// Remove the given dynamic entry
465 0 : pub fn remove_dynamic_entry(&mut self, entry: impl dynamic::DynamicEntry) {
466 0 : self.ptr.pin_mut().remove_dynamic_entry(entry.as_base());
467 0 : }
468 :
469 : /// Remove the dynamic entries matching the given predicate.
470 : ///
471 : /// The function returns the number of entries that have been deleted.
472 0 : pub fn remove_dynamic_entry_if<P>(&mut self, predicate: P) -> usize
473 0 : where
474 0 : P: Fn(&dynamic::Entries) -> bool,
475 0 : {
476 0 : let entries = self
477 0 : .dynamic_entries()
478 0 : .filter(predicate)
479 0 : .map(|e| e.as_base().raw_ptr())
480 0 : .collect::<Vec<_>>();
481 0 :
482 0 : let cnt = entries.len();
483 :
484 0 : for ffi_entry in entries {
485 0 : unsafe {
486 0 : self.ptr.pin_mut().remove_dynamic_entry_from_ptr(ffi_entry);
487 0 : }
488 : }
489 0 : cnt
490 0 : }
491 :
492 : /// Remove the `DT_NEEDED` dependency with the given name
493 0 : pub fn remove_library(&mut self, name: &str) {
494 0 : self.ptr.pin_mut().remove_library(name.to_string());
495 0 : }
496 :
497 : /// Add the provided segment to the binary. This function returns the
498 : /// newly added segment which could define additional attributes like the virtual address.
499 0 : pub fn add_segment(&mut self, segment: &Segment) -> Option<Segment<'_>> {
500 0 : into_optional(
501 0 : self.ptr
502 0 : .pin_mut()
503 0 : .add_segment(segment.ptr.as_ref().unwrap()),
504 0 : )
505 0 : }
506 :
507 : /// Change the path to the interpreter
508 0 : pub fn set_interpreter<P: AsRef<Path>>(&mut self, interpreter: P) {
509 0 : self.ptr
510 0 : .pin_mut()
511 0 : .set_interpreter(interpreter.as_ref().to_str().unwrap());
512 0 : }
513 :
514 : /// Try to find the SymbolVersionRequirement associated with the given library
515 : /// name (e.g. `libc.so.6`)
516 0 : pub fn find_version_requirement(&self, libname: &str) -> Option<SymbolVersionRequirement<'_>> {
517 0 : into_optional(self.ptr.find_version_requirement(libname.to_string()))
518 0 : }
519 :
520 : /// Deletes all required symbol versions linked to the specified library name.
521 : /// The function returns true if the operation succeed, false otherwise.
522 : ///
523 : /// <div class='warning'>
524 : /// To maintain consistency, this function also removes versions
525 : /// associated with dynamic symbols that are linked to the specified
526 : /// library name.
527 : /// </div>
528 0 : pub fn remove_version_requirement(&mut self, libname: &str) -> bool {
529 0 : self.ptr
530 0 : .pin_mut()
531 0 : .remove_version_requirement(libname.to_string())
532 0 : }
533 :
534 : /// Remove the given segment. If `clear` is set, the original content of the
535 : /// segment will be filled with zeros before removal.
536 0 : pub fn remove_segment(&mut self, segment: Segment, clear: bool) {
537 0 : self.ptr
538 0 : .pin_mut()
539 0 : .remove_segment(segment.ptr.as_ref().unwrap(), clear)
540 0 : }
541 :
542 : /// Remove all segments associated with the given type.
543 : ///
544 : /// If `clear` is set, the original content of the segments will be filled
545 : /// with zeros before removal.
546 0 : pub fn remove_segments_by_type(&mut self, ty: segment::Type, clear: bool) {
547 0 : self.ptr.pin_mut().remove_segments_by_type(ty.into(), clear)
548 0 : }
549 :
550 : /// Return an iterator over all symbols (combined dynamic + symtab)
551 0 : pub fn symbols(&self) -> AllSymbols<'_> {
552 0 : AllSymbols::new(self.ptr.symbols())
553 0 : }
554 :
555 : /// Return all printable strings from the binary with a minimum length
556 0 : pub fn strings(&self, min_size: u64) -> Vec<String> {
557 0 : self.ptr
558 0 : .strings(min_size)
559 0 : .iter()
560 0 : .map(|s| s.to_string())
561 0 : .collect()
562 0 : }
563 :
564 : /// Return the last offset used in binary according to sections table
565 0 : pub fn last_offset_section(&self) -> u64 {
566 0 : self.ptr.last_offset_section()
567 0 : }
568 :
569 : /// Return the last offset used in binary according to segments table
570 0 : pub fn last_offset_segment(&self) -> u64 {
571 0 : self.ptr.last_offset_segment()
572 0 : }
573 :
574 : /// Return the next virtual address available
575 0 : pub fn next_virtual_address(&self) -> u64 {
576 0 : self.ptr.next_virtual_address()
577 0 : }
578 :
579 : /// Return the offset of the end of the binary on disk
580 0 : pub fn eof_offset(&self) -> u64 {
581 0 : self.ptr.eof_offset()
582 0 : }
583 :
584 : /// Return the destructor functions (from `.fini_array`, `.dtors`, etc.)
585 0 : pub fn dtor_functions(&self) -> generic::Functions<'_> {
586 0 : generic::Functions::new(self.ptr.dtor_functions())
587 0 : }
588 :
589 : /// Return the overlay data
590 0 : pub fn overlay(&self) -> &[u8] {
591 0 : to_slice!(self.ptr.get_overlay());
592 0 : }
593 :
594 : /// Set the overlay data
595 0 : pub fn set_overlay(&mut self, data: &[u8]) {
596 0 : unsafe {
597 0 : self.ptr
598 0 : .pin_mut()
599 0 : .set_overlay(data.as_ptr(), data.len() as u64);
600 0 : }
601 0 : }
602 :
603 : /// Check if the binary has a dynamic entry with the given tag
604 0 : pub fn has_dynamic_entry_tag(&self, tag: dynamic::Tag) -> bool {
605 0 : self.ptr.has_dynamic_entry_tag(tag.into())
606 0 : }
607 :
608 : /// Check if the binary has a segment with the given type
609 0 : pub fn has_segment_type(&self, ty: segment::Type) -> bool {
610 0 : self.ptr.has_segment_type(ty.into())
611 0 : }
612 :
613 : /// Check if the binary has a note with the given type
614 0 : pub fn has_note_type(&self, ty: super::note::Type) -> bool {
615 0 : self.ptr.has_note_type(ty.into())
616 0 : }
617 :
618 : /// Check if the binary has a section with the given type
619 0 : pub fn has_section_type(&self, ty: super::section::Type) -> bool {
620 0 : self.ptr.has_section_type(ty.into())
621 0 : }
622 :
623 : /// Try to find a note by its type
624 0 : pub fn note_by_type(&self, ty: super::note::Type) -> Option<super::note::Notes<'_>> {
625 0 : into_optional(self.ptr.get_note_by_type(ty.into()))
626 0 : }
627 :
628 : /// Try to find a section by its type
629 0 : pub fn section_by_type(&self, ty: super::section::Type) -> Option<Section<'_>> {
630 0 : into_optional(self.ptr.get_section_by_type(ty.into()))
631 0 : }
632 :
633 : /// Check if the binary has a section with the given name
634 0 : pub fn has_section(&self, name: &str) -> bool {
635 0 : self.ptr.has_section(name.to_string())
636 0 : }
637 :
638 : /// Check if the binary has a section that spans the given offset
639 0 : pub fn has_section_with_offset(&self, offset: u64) -> bool {
640 0 : self.ptr.has_section_with_offset(offset)
641 0 : }
642 :
643 : /// Check if the binary has a section that spans the given virtual address
644 0 : pub fn has_section_with_va(&self, va: u64) -> bool {
645 0 : self.ptr.has_section_with_va(va)
646 0 : }
647 :
648 : /// Check if the binary has a library dependency with the given name
649 0 : pub fn has_library(&self, name: &str) -> bool {
650 0 : self.ptr.has_library(name.to_string())
651 0 : }
652 :
653 : /// Check if the binary has a dynamic symbol with the given name
654 0 : pub fn has_dynamic_symbol(&self, name: &str) -> bool {
655 0 : self.ptr.has_dynamic_symbol(name.to_string())
656 0 : }
657 :
658 : /// Check if the binary has a symtab symbol with the given name
659 0 : pub fn has_symtab_symbol(&self, name: &str) -> bool {
660 0 : self.ptr.has_symtab_symbol(name.to_string())
661 0 : }
662 :
663 : /// Return the index of the given name in the dynamic symbol table
664 0 : pub fn dynsym_idx(&self, name: &str) -> Option<u64> {
665 0 : let idx = self.ptr.dynsym_idx(name.to_string());
666 0 : if idx < 0 {
667 0 : return None;
668 0 : }
669 0 : Some(idx as u64)
670 0 : }
671 :
672 : /// Return the index of the given name in the symtab symbol table, or -1
673 0 : pub fn symtab_idx(&self, name: &str) -> Option<u64> {
674 0 : let idx = self.ptr.symtab_idx(name.to_string());
675 0 : if idx < 0 {
676 0 : return None;
677 0 : }
678 0 : Some(idx as u64)
679 0 : }
680 :
681 : /// Patch the GOT/PLT entry for the given symbol name
682 0 : pub fn patch_pltgot(&mut self, symbol_name: &str, address: u64) {
683 0 : self.ptr
684 0 : .pin_mut()
685 0 : .patch_pltgot_by_name(symbol_name.to_string(), address);
686 0 : }
687 :
688 : /// Add a section to the binary. If `loaded` is true, the section will be
689 : /// added in a way that it is loaded in memory. `pos` controls where the
690 : /// section is inserted.
691 0 : pub fn add_section(
692 0 : &mut self,
693 0 : section: &Section,
694 0 : loaded: bool,
695 0 : pos: SecInsertPos,
696 0 : ) -> Option<Section<'_>> {
697 0 : into_optional(
698 0 : self.ptr
699 0 : .pin_mut()
700 0 : .add_section(section.as_ffi(), loaded, pos.into()),
701 0 : )
702 0 : }
703 :
704 : /// Add a note to the binary
705 0 : pub fn add_note(&mut self, note: &super::note::Notes) -> super::note::Notes<'_> {
706 0 : super::note::Notes::from_ffi(self.ptr.pin_mut().add_note(note.as_ffi()))
707 0 : }
708 :
709 : /// Add a dynamic relocation
710 0 : pub fn add_dynamic_relocation(&mut self, reloc: &Relocation) -> Relocation<'_> {
711 0 : Relocation::from_ffi(self.ptr.pin_mut().add_dynamic_relocation(reloc.as_ffi()))
712 0 : }
713 :
714 : /// Add a `.plt.got` relocation
715 0 : pub fn add_pltgot_relocation(&mut self, reloc: &Relocation) -> Relocation<'_> {
716 0 : Relocation::from_ffi(self.ptr.pin_mut().add_pltgot_relocation(reloc.as_ffi()))
717 0 : }
718 :
719 : /// Add a symbol to the `.symtab` table
720 0 : pub fn add_symtab_symbol(&mut self, symbol: &Symbol) -> Symbol<'_> {
721 0 : Symbol::from_ffi(self.ptr.pin_mut().add_symtab_symbol(symbol.as_ffi()))
722 0 : }
723 :
724 : /// Add a symbol to the dynamic symbol table (`.dynsym`)
725 0 : pub fn add_dynamic_symbol(&mut self, symbol: &Symbol) -> Symbol<'_> {
726 0 : Symbol::from_ffi(self.ptr.pin_mut().add_dynamic_symbol(symbol.as_ffi()))
727 0 : }
728 :
729 : /// Add an exported function with the given address and name
730 0 : pub fn add_exported_function(&mut self, address: u64, name: &str) -> Symbol<'_> {
731 0 : Symbol::from_ffi(
732 0 : self.ptr
733 0 : .pin_mut()
734 0 : .add_exported_function(address, name.to_string()),
735 0 : )
736 0 : }
737 :
738 : /// Export the symbol with the given name, optionally setting its value (can be 0)
739 0 : pub fn export_symbol_by_name(&mut self, symbol_name: &str, value: u64) -> Symbol<'_> {
740 0 : Symbol::from_ffi(
741 0 : self.ptr
742 0 : .pin_mut()
743 0 : .export_symbol_by_name(symbol_name.to_string(), value),
744 0 : )
745 0 : }
746 :
747 : /// Export an existing symbol
748 0 : pub fn export_symbol(&mut self, symbol: &Symbol) -> Symbol<'_> {
749 0 : Symbol::from_ffi(self.ptr.pin_mut().export_symbol_obj(symbol.as_ffi()))
750 0 : }
751 :
752 : /// Remove the symtab symbol with the given name
753 0 : pub fn remove_symtab_symbol(&mut self, name: &str) {
754 0 : self.ptr
755 0 : .pin_mut()
756 0 : .remove_symtab_symbol_by_name(name.to_string());
757 0 : }
758 :
759 : /// Remove the dynamic symbol with the given name
760 0 : pub fn remove_dynamic_symbol(&mut self, name: &str) {
761 0 : self.ptr
762 0 : .pin_mut()
763 0 : .remove_dynamic_symbol_by_name(name.to_string());
764 0 : }
765 :
766 : /// Remove the given section. If `clear` is set, the section content will be
767 : /// filled with zeros before removal.
768 0 : pub fn remove_section(&mut self, section: &Section, clear: bool) {
769 0 : self.ptr.pin_mut().remove_section(section.as_ffi(), clear);
770 0 : }
771 :
772 : /// Remove the given note
773 0 : pub fn remove_note(&mut self, note: &super::note::Notes) {
774 0 : self.ptr.pin_mut().remove_note(note.as_ffi());
775 0 : }
776 :
777 : /// Extend the given segment by `size` bytes
778 0 : pub fn extend_segment(&mut self, segment: &Segment, size: u64) -> Option<Segment<'_>> {
779 0 : into_optional(
780 0 : self.ptr
781 0 : .pin_mut()
782 0 : .extend_segment(segment.ptr.as_ref().unwrap(), size),
783 0 : )
784 0 : }
785 :
786 : /// Extend the given section by `size` bytes
787 0 : pub fn extend_section(&mut self, section: &Section, size: u64) -> Option<Section<'_>> {
788 0 : into_optional(self.ptr.pin_mut().extend_section(section.as_ffi(), size))
789 0 : }
790 :
791 : /// Strip all debug symbols from the binary
792 0 : pub fn strip(&mut self) {
793 0 : self.ptr.pin_mut().strip();
794 0 : }
795 :
796 : /// Get the index of a section by its name. Returns `None` if not found.
797 0 : pub fn section_idx_by_name(&self, name: &str) -> Option<usize> {
798 0 : let idx = self.ptr.get_section_idx_by_name(name.to_string());
799 0 : if idx < 0 {
800 0 : None
801 : } else {
802 0 : Some(idx as usize)
803 : }
804 0 : }
805 :
806 : /// Get the index of the given section. Returns `None` if not found.
807 0 : pub fn section_idx(&self, section: &Section) -> Option<usize> {
808 0 : let idx = self.ptr.get_section_idx_by_section(section.as_ffi());
809 0 : if idx < 0 {
810 0 : None
811 : } else {
812 0 : Some(idx as usize)
813 : }
814 0 : }
815 :
816 : /// Relocate the PHDR table using the given strategy.
817 : /// Returns the new offset of the PHDR table.
818 0 : pub fn relocate_phdr_table(&mut self, reloc_type: PhdrReloc) -> u64 {
819 0 : self.ptr.pin_mut().relocate_phdr_table(reloc_type.into())
820 0 : }
821 : }
822 :
823 : impl AsFFI<ffi::ELF_Binary> for Binary {
824 0 : fn as_ffi(&self) -> &ffi::ELF_Binary {
825 0 : self.ptr.as_ref().unwrap()
826 0 : }
827 :
828 0 : fn as_mut_ffi(&mut self) -> std::pin::Pin<&mut ffi::ELF_Binary> {
829 0 : self.ptr.pin_mut()
830 0 : }
831 : }
832 :
833 : impl generic::Binary for Binary {
834 650 : fn as_generic(&self) -> &ffi::AbstractBinary {
835 650 : self.ptr.as_ref().unwrap().as_ref()
836 650 : }
837 :
838 0 : fn as_pin_mut_generic(&mut self) -> Pin<&mut ffi::AbstractBinary> {
839 0 : unsafe {
840 0 : Pin::new_unchecked({
841 0 : (self.ptr.as_ref().unwrap().as_ref() as *const ffi::AbstractBinary
842 0 : as *mut ffi::AbstractBinary)
843 0 : .as_mut()
844 0 : .unwrap()
845 0 : })
846 0 : }
847 0 : }
848 : }
849 :
850 20826 : declare_iterator!(
851 20826 : SymbolsVersion,
852 20826 : SymbolVersion<'a>,
853 20826 : ffi::ELF_SymbolVersion,
854 20826 : ffi::ELF_Binary,
855 20826 : ffi::ELF_Binary_it_symbols_version
856 20826 : );
857 221 : declare_iterator!(
858 221 : SymbolsVersionRequirement,
859 221 : SymbolVersionRequirement<'a>,
860 221 : ffi::ELF_SymbolVersionRequirement,
861 221 : ffi::ELF_Binary,
862 221 : ffi::ELF_Binary_it_symbols_version_requirement
863 221 : );
864 39 : declare_iterator!(
865 39 : SymbolsVersionDefinition,
866 39 : SymbolVersionDefinition<'a>,
867 39 : ffi::ELF_SymbolVersionDefinition,
868 39 : ffi::ELF_Binary,
869 39 : ffi::ELF_Binary_it_symbols_version_definition
870 39 : );
871 0 : declare_iterator!(
872 0 : AllSymbols,
873 0 : Symbol<'a>,
874 0 : ffi::ELF_Symbol,
875 0 : ffi::ELF_Binary,
876 0 : ffi::ELF_Binary_it_symbols
877 0 : );
|