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