Line data Source code
1 : use std::mem::size_of;
2 : use std::pin::Pin;
3 :
4 : use num_traits::{Num, cast};
5 :
6 : use lief_ffi as ffi;
7 :
8 : use crate::Error;
9 : use super::hash::{Sysv, Gnu};
10 : use super::dynamic::{self, DynamicEntries};
11 : use super::header::Header;
12 : use super::section::{Sections, Section};
13 : use super::segment::Segments;
14 : use super::symbol::{DynamicSymbols, ExportedSymbols, ImportedSymbols, SymtabSymbols};
15 : use super::note::ItNotes;
16 : use super::relocation::{Relocation, PltGotRelocations, DynamicRelocations, ObjectRelocations, Relocations};
17 : use super::symbol_versioning::{SymbolVersion, SymbolVersionDefinition, SymbolVersionRequirement};
18 : use super::{Segment, Symbol};
19 :
20 : use crate::generic;
21 : use crate::{declare_iterator, to_slice, to_result, to_conv_result};
22 : use crate::common::{into_optional, FromFFI};
23 :
24 0 : #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
25 : pub enum ElfClass {
26 : Elf32,
27 : Elf64,
28 : Unknown,
29 : }
30 :
31 : impl ElfClass {
32 : const ELF_CLASS32: u32 = 1;
33 : const ELF_CLASS64: u32 = 2;
34 :
35 0 : pub fn from_value(value: u32) -> Self {
36 0 : match value {
37 0 : Self::ELF_CLASS32 => ElfClass::Elf32,
38 0 : Self::ELF_CLASS64 => ElfClass::Elf64,
39 0 : _ => ElfClass::Unknown,
40 : }
41 0 : }
42 : }
43 :
44 : /// This is the main interface to read and write ELF binary attributes.
45 : ///
46 : /// Note that this structure implements the [`generic::Binary`] trait from which other generic
47 : /// functions are exposed
48 : pub struct Binary {
49 : ptr: cxx::UniquePtr<ffi::ELF_Binary>,
50 : }
51 :
52 : impl std::fmt::Debug for Binary {
53 80 : fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
54 80 : f.debug_struct("Binary")
55 80 : .field("header", &self.header())
56 80 : .finish()
57 80 : }
58 : }
59 :
60 : impl FromFFI<ffi::ELF_Binary> for Binary {
61 160 : fn from_ffi(ptr: cxx::UniquePtr<ffi::ELF_Binary>) -> Self {
62 160 : Self {
63 160 : ptr,
64 160 : }
65 160 : }
66 : }
67 :
68 : impl Binary {
69 : /// Create a [`Binary`] from the given file path
70 80 : pub fn parse(path: &str) -> Option<Self> {
71 80 : let bin = ffi::ELF_Binary::parse(path);
72 80 : if bin.is_null() {
73 0 : return None;
74 80 : }
75 80 : Some(Binary::from_ffi(bin))
76 80 : }
77 :
78 : /// Return the main ELF header
79 80 : pub fn header(&self) -> Header {
80 80 : Header::from_ffi(self.ptr.header())
81 80 : }
82 :
83 : /// Return the size taken by the binary when loaded (virtual size)
84 80 : pub fn virtual_size(&self) -> u64 {
85 80 : self.ptr.virtual_size()
86 80 : }
87 :
88 : /// Return the path to the ELF interpreter that is used to process the ELF information
89 : /// once loaded by the kernel
90 80 : pub fn interpreter(&self) -> String {
91 80 : self.ptr.interpreter().to_string()
92 80 : }
93 :
94 : /// Return sysv-hash information (if present)
95 80 : pub fn sysv_hash(&self) -> Option<Sysv> {
96 80 : into_optional(self.ptr.sysv_hash())
97 80 : }
98 :
99 : /// Return GNU Hash info (if present)
100 80 : pub fn gnu_hash(&self) -> Option<Gnu> {
101 80 : into_optional(self.ptr.gnu_hash())
102 80 : }
103 :
104 : /// Return an iterator over the [`crate::elf::Section`] of the binary
105 80 : pub fn sections(&self) -> Sections {
106 80 : Sections::new(self.ptr.sections())
107 80 : }
108 :
109 : /// Return an iterator over the [`crate::elf::Segment`] of the binary
110 80 : pub fn segments(&self) -> Segments {
111 80 : Segments::new(self.ptr.segments())
112 80 : }
113 :
114 : /// Return an iterator over the [`crate::elf::DynamicEntries`] of the binary
115 80 : pub fn dynamic_entries(&self) -> DynamicEntries {
116 80 : DynamicEntries::new(self.ptr.dynamic_entries())
117 80 : }
118 :
119 : /// Return an iterator over the dynamic [`crate::elf::Symbol`] of the binary
120 80 : pub fn dynamic_symbols(&self) -> DynamicSymbols {
121 80 : DynamicSymbols::new(self.ptr.dynamic_symbols())
122 80 : }
123 :
124 : /// Return an iterator over the **exported** [`crate::elf::Symbol`] of the binary
125 80 : pub fn exported_symbols(&self) -> ExportedSymbols {
126 80 : ExportedSymbols::new(self.ptr.exported_symbols())
127 80 : }
128 :
129 : /// Return an iterator over the **imported** [`crate::elf::Symbol`] of the binary
130 80 : pub fn imported_symbols(&self) -> ImportedSymbols {
131 80 : ImportedSymbols::new(self.ptr.imported_symbols())
132 80 : }
133 :
134 : /// Return an iterator over the symtab-debug [`crate::elf::Symbol`] of the binary
135 80 : pub fn symtab_symbols(&self) -> SymtabSymbols {
136 80 : SymtabSymbols::new(self.ptr.symtab_symbols())
137 80 : }
138 :
139 : /// Return an iterator over the [`crate::elf::SymbolVersion`] of the binary
140 160 : pub fn symbols_version(&self) -> SymbolsVersion {
141 160 : SymbolsVersion::new(self.ptr.symbols_version())
142 160 : }
143 :
144 : /// Return an iterator over the [`crate::elf::SymbolVersionRequirement`] of the binary
145 80 : pub fn symbols_version_requirement(&self) -> SymbolsVersionRequirement {
146 80 : SymbolsVersionRequirement::new(self.ptr.symbols_version_requirement())
147 80 : }
148 :
149 : /// Return an iterator over the [`crate::elf::SymbolVersionDefinition`] of the binary
150 80 : pub fn symbols_version_definition(&self) -> SymbolsVersionDefinition {
151 80 : SymbolsVersionDefinition::new(self.ptr.symbols_version_definition())
152 80 : }
153 :
154 : /// Return an iterator over the [`crate::elf::Notes`] of the binary
155 80 : pub fn notes(&self) -> ItNotes {
156 80 : ItNotes::new(self.ptr.notes())
157 80 : }
158 :
159 : /// Return an iterator over the `.plt.got` [`crate::elf::Relocation`] of the binary
160 80 : pub fn pltgot_relocations(&self) -> PltGotRelocations {
161 80 : PltGotRelocations::new(self.ptr.pltgot_relocations())
162 80 : }
163 :
164 : /// Return an iterator over the regular [`crate::elf::Relocation`] of the binary
165 80 : pub fn dynamic_relocations(&self) -> DynamicRelocations {
166 80 : DynamicRelocations::new(self.ptr.dynamic_relocations())
167 80 : }
168 :
169 : /// Return an iterator over the object-file (`.o`) [`crate::elf::Relocation`]
170 80 : pub fn object_relocations(&self) -> ObjectRelocations {
171 80 : ObjectRelocations::new(self.ptr.object_relocations())
172 80 : }
173 :
174 : /// Return an iterator over **all** [`crate::elf::Relocation`] of the binary
175 80 : pub fn relocations(&self) -> Relocations {
176 80 : Relocations::new(self.ptr.relocations())
177 80 : }
178 :
179 : /// Try to find the ELF section with the given name
180 80 : pub fn section_by_name(&self, name: &str) -> Option<Section> {
181 80 : into_optional(self.ptr.section_by_name(name))
182 80 : }
183 :
184 : /// Try to find the ELF relocation that takes place at the given address
185 20 : pub fn relocation_by_addr(&self, address: u64) -> Option<Relocation> {
186 20 : into_optional(self.ptr.relocation_by_addr(address))
187 20 : }
188 :
189 : /// Try to find the `.plt.got` relocation for the given symbol name
190 20 : pub fn relocation_for_symbol(&self, sym_name: &str) -> Option<Relocation> {
191 20 : into_optional(self.ptr.relocation_for_symbol(sym_name))
192 20 : }
193 :
194 : /// Try to find the symbol with the given name in the dynamic `.dynsym` table
195 10 : pub fn dynamic_symbol_by_name(&self, sym_name: &str) -> Option<Symbol> {
196 10 : into_optional(self.ptr.get_dynamic_symbol(sym_name))
197 10 : }
198 :
199 : /// Try to find the symbol with the given name in the debug `.symtab` table
200 10 : pub fn symtab_symbol_by_name(&self, sym_name: &str) -> Option<Symbol> {
201 10 : into_optional(self.ptr.get_symtab_symbol(sym_name))
202 10 : }
203 :
204 : /// Try to find the library (`DT_NEEDED`) with the given name
205 20 : pub fn get_library(&self, name: &str) -> Option<dynamic::Library> {
206 20 : into_optional(self.ptr.get_library(name))
207 20 : }
208 :
209 : /// Try to find the section that encompasses the given offset. `skip_nobits` can be used
210 : /// to include (or not) the `SHT_NOTBIT` sections
211 20 : pub fn section_from_offset(&self, offset: u64, skip_nobits: bool) -> Option<Section> {
212 20 : into_optional(self.ptr.section_from_offset(offset, skip_nobits))
213 20 : }
214 :
215 : /// Try to find the section that encompasses the given virtual address. `skip_nobits` can be used
216 : /// to include (or not) the `SHT_NOTBIT` sections
217 20 : pub fn section_from_virtual_address(&self, address: u64, skip_nobits: bool) -> Option<Section> {
218 20 : into_optional(self.ptr.section_from_virtual_address(address, skip_nobits))
219 20 : }
220 :
221 : /// Try to find the segment that encompasses the given virtual address
222 20 : pub fn segment_from_virtual_address(&self, address: u64) -> Option<Segment> {
223 20 : into_optional(self.ptr.segment_from_virtual_address(address))
224 20 : }
225 :
226 : /// Try to find the segment that encompasses the given offset
227 20 : pub fn segment_from_offset(&self, offset: u64) -> Option<Segment> {
228 20 : into_optional(self.ptr.segment_from_offset(offset))
229 20 : }
230 :
231 : /// Get a slice of the content at the given address.
232 10 : pub fn content_from_virtual_address(&self, address: u64, size: u64) -> &[u8] {
233 10 : to_slice!(self.ptr.get_content_from_virtual_address(address, size));
234 10 : }
235 :
236 : /// Convert the given virtual address into an offset
237 20 : pub fn virtual_address_to_offset(&self, address: u64) -> Result<u64, Error> {
238 20 : to_result!(ffi::ELF_Binary::virtual_address_to_offset, &self, address);
239 20 : }
240 :
241 : /// Return the array defined by the given tag (e.g.
242 : /// [`dynamic::Tag::INIT_ARRAY`]) with relocations applied (if any)
243 240 : pub fn get_relocated_dynamic_array(&self, tag: dynamic::Tag) -> Vec<u64> {
244 240 : Vec::from(self.ptr.get_relocated_dynamic_array(u64::from(tag)).as_slice())
245 240 : }
246 :
247 : /// True if the current binary is targeting Android
248 0 : pub fn is_targeting_android(&self) -> bool {
249 0 : self.ptr.is_targeting_android()
250 0 : }
251 :
252 : /// Get the integer value at the given virtual address
253 4 : pub fn get_int_from_virtual_address<T>(&self, addr: u64) -> Result<T, Error>
254 4 : where T: Num + cast::FromPrimitive + cast::ToPrimitive
255 4 : {
256 4 : // Can't be in the generic trait because of:
257 4 : // > for a trait to be "object safe" it needs to allow building a vtable to allow the call
258 4 : // > to be resolvable dynamically; for more information visit
259 4 : // > https://doc.rust-lang.org/reference/items/traits.html#object-safety
260 4 : if size_of::<T>() == size_of::<u8>() {
261 1 : to_conv_result!(ffi::AbstractBinary::get_u8,
262 1 : self.ptr.as_ref().unwrap().as_ref(),
263 1 : |value| { T::from_u8(value).expect(format!("Can't cast value: {}", value).as_str()) },
264 1 : addr);
265 3 : }
266 3 :
267 3 : if size_of::<T>() == size_of::<u16>() {
268 1 : to_conv_result!(ffi::AbstractBinary::get_u16,
269 1 : self.ptr.as_ref().unwrap().as_ref(),
270 1 : |value| { T::from_u16(value).expect(format!("Can't cast value: {}", value).as_str()) },
271 1 : addr);
272 2 : }
273 2 :
274 2 : if size_of::<T>() == size_of::<u32>() {
275 1 : to_conv_result!(ffi::AbstractBinary::get_u32,
276 1 : self.ptr.as_ref().unwrap().as_ref(),
277 1 : |value| { T::from_u32(value).expect(format!("Can't cast value: {}", value).as_str()) },
278 1 : addr);
279 1 : }
280 1 :
281 1 : if size_of::<T>() == size_of::<u64>() {
282 1 : to_conv_result!(ffi::AbstractBinary::get_u64,
283 1 : self.ptr.as_ref().unwrap().as_ref(),
284 1 : |value| { T::from_u64(value).expect(format!("Can't cast value: {}", value).as_str()) },
285 1 : addr);
286 0 : }
287 0 :
288 0 : Err(Error::NotSupported)
289 4 : }
290 : }
291 :
292 : impl generic::Binary for Binary {
293 400 : fn as_generic(&self) -> &ffi::AbstractBinary {
294 400 : self.ptr.as_ref().unwrap().as_ref()
295 400 : }
296 :
297 0 : fn as_pin_mut_generic(&mut self) -> Pin<&mut ffi::AbstractBinary> {
298 0 : unsafe {
299 0 : Pin::new_unchecked({
300 0 : (self.ptr.as_ref().unwrap().as_ref()
301 0 : as *const ffi::AbstractBinary
302 0 : as *mut ffi::AbstractBinary).as_mut().unwrap()
303 0 : })
304 0 : }
305 0 : }
306 : }
307 :
308 :
309 15540 : declare_iterator!(SymbolsVersion, SymbolVersion<'a>, ffi::ELF_SymbolVersion, ffi::ELF_Binary, ffi::ELF_Binary_it_symbols_version);
310 150 : declare_iterator!(SymbolsVersionRequirement, SymbolVersionRequirement<'a>, ffi::ELF_SymbolVersionRequirement, ffi::ELF_Binary, ffi::ELF_Binary_it_symbols_version_requirement);
311 30 : declare_iterator!(SymbolsVersionDefinition, SymbolVersionDefinition<'a>, ffi::ELF_SymbolVersionDefinition, ffi::ELF_Binary, ffi::ELF_Binary_it_symbols_version_definition);
|