Line data Source code
1 : use crate::assembly::{AssemblerConfig, Instructions};
2 : use crate::common::{into_optional, FromFFI};
3 : use crate::{declare_fwd_iterator, declare_lazy_iterator, to_opt_trait, to_slice};
4 : use bitflags::bitflags;
5 : use lief_ffi as ffi;
6 :
7 : use std::pin::Pin;
8 :
9 : /// Trait shared by all the symbols in executable formats
10 : pub trait Symbol {
11 : #[doc(hidden)]
12 : fn as_generic(&self) -> &ffi::AbstractSymbol;
13 :
14 : #[doc(hidden)]
15 : fn as_pin_mut_generic(&mut self) -> Pin<&mut ffi::AbstractSymbol>;
16 :
17 : /// Symbol's name
18 2149875 : fn name(&self) -> String {
19 2149875 : self.as_generic().name().to_string()
20 2149875 : }
21 : /// Symbol's value whose interpretation depends on the symbol's kind.
22 : /// Usually this is the address of the symbol though.
23 1129791 : fn value(&self) -> u64 {
24 1129791 : self.as_generic().value()
25 1129791 : }
26 : /// Size of the symbol (can be 0)
27 1129791 : fn size(&self) -> u64 {
28 1129791 : self.as_generic().size()
29 1129791 : }
30 :
31 0 : fn set_name(&mut self, name: &str) {
32 0 : self.as_pin_mut_generic().set_name(name.to_string());
33 0 : }
34 :
35 0 : fn set_value(&mut self, value: u64) {
36 0 : self.as_pin_mut_generic().set_value(value);
37 0 : }
38 :
39 0 : fn set_size(&mut self, size: u64) {
40 0 : self.as_pin_mut_generic().set_size(size);
41 0 : }
42 : }
43 :
44 : impl std::fmt::Debug for &dyn Symbol {
45 1119378 : fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
46 1119378 : f.debug_struct("Symbol")
47 1119378 : .field("name", &self.name())
48 1119378 : .field("value", &self.value())
49 1119378 : .field("size", &self.size())
50 1119378 : .finish()
51 1119378 : }
52 : }
53 :
54 : /// Trait shared by all the sections in executable formats
55 : pub trait Section {
56 : #[doc(hidden)]
57 : fn as_generic(&self) -> &ffi::AbstractSection;
58 :
59 : #[doc(hidden)]
60 : fn as_generic_mut(&mut self) -> Pin<&mut ffi::AbstractSection>;
61 :
62 : /// Name of the section
63 359035 : fn name(&self) -> String {
64 359035 : self.as_generic().name().to_string()
65 359035 : }
66 :
67 : /// Size of the section **in the file**
68 343824 : fn size(&self) -> u64 {
69 343824 : self.as_generic().size()
70 343824 : }
71 :
72 : /// Offset of the section **in the file**
73 343733 : fn offset(&self) -> u64 {
74 343733 : self.as_generic().offset()
75 343733 : }
76 :
77 : /// Address of the section **in memory**
78 343746 : fn virtual_address(&self) -> u64 {
79 343746 : self.as_generic().virtual_address()
80 343746 : }
81 :
82 : /// Content of the section
83 0 : fn content(&self) -> &[u8] {
84 0 : to_slice!(self.as_generic().content());
85 0 : }
86 :
87 : /// Change the section's name
88 0 : fn set_name(&mut self, name: &str) {
89 0 : self.as_generic_mut().set_name(name.to_string());
90 0 : }
91 :
92 : /// Change section content
93 0 : fn set_content(&mut self, data: &[u8]) {
94 0 : unsafe {
95 0 : self.as_generic_mut().set_content(data.as_ptr(), data.len());
96 0 : }
97 0 : }
98 :
99 : /// Change section size
100 0 : fn set_size(&mut self, size: u64) {
101 0 : self.as_generic_mut().set_size(size);
102 0 : }
103 : }
104 :
105 : impl std::fmt::Debug for &dyn Section {
106 340496 : fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
107 340496 : f.debug_struct("Section")
108 340496 : .field("name", &self.name())
109 340496 : .field("size", &self.size())
110 340496 : .field("offset", &self.offset())
111 340496 : .field("virtual_address", &self.virtual_address())
112 340496 : .finish()
113 340496 : }
114 : }
115 :
116 : pub trait Relocation {
117 : #[doc(hidden)]
118 : fn as_generic(&self) -> &ffi::AbstractRelocation;
119 :
120 : /// Address where the relocation should take place
121 2955914 : fn address(&self) -> u64 {
122 2955914 : self.as_generic().address()
123 2955914 : }
124 :
125 : /// Size of the relocation
126 2955914 : fn size(&self) -> u64 {
127 2955914 : self.as_generic().size()
128 2955914 : }
129 : }
130 :
131 : impl std::fmt::Debug for &dyn Relocation {
132 2955914 : fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
133 2955914 : f.debug_struct("Relocation")
134 2955914 : .field("address", &self.address())
135 2955914 : .field("size", &self.size())
136 2955914 : .finish()
137 2955914 : }
138 : }
139 :
140 : /// Generic interface representing a binary executable.
141 : ///
142 : /// This trait provides a unified interface across multiple binary formats
143 : /// such as ELF, PE, Mach-O, and others. It enables users to access binary
144 : /// components like headers, sections, symbols, relocations,
145 : /// and functions in a format-agnostic way.
146 : pub trait Binary {
147 : #[doc(hidden)]
148 : fn as_generic(&self) -> &ffi::AbstractBinary;
149 :
150 : #[doc(hidden)]
151 : fn as_pin_mut_generic(&mut self) -> Pin<&mut ffi::AbstractBinary>;
152 :
153 : /// Binary's entrypoint
154 55 : fn entrypoint(&self) -> u64 {
155 55 : self.as_generic().entrypoint()
156 55 : }
157 :
158 : /// Default base address where the binary should be mapped
159 10 : fn imagebase(&self) -> u64 {
160 10 : self.as_generic().imagebase()
161 10 : }
162 :
163 : /// Size of the binary when mapped in memory
164 0 : fn virtual_size(&self) -> u64 {
165 0 : self.as_generic().virtual_size()
166 0 : }
167 :
168 : /// Whether the current binary is **an executable** and **position independent**
169 10 : fn is_pie(&self) -> bool {
170 10 : self.as_generic().is_pie()
171 10 : }
172 :
173 : /// Whether the binary defines a non-executable stack
174 10 : fn has_nx(&self) -> bool {
175 10 : self.as_generic().has_nx()
176 10 : }
177 :
178 : /// Original file size of the binary
179 10 : fn original_size(&self) -> u64 {
180 10 : self.as_generic().original_size()
181 10 : }
182 :
183 : /// Return the debug info if present. It can be either a
184 : /// [`crate::pdb::DebugInfo`] or [`crate::dwarf::DebugInfo`].
185 : ///
186 : /// For ELF and Mach-O binaries, it returns the given DebugInfo object **only**
187 : /// if the binary embeds the DWARF debug info in the binary itself.
188 : ///
189 : /// For PE file, this function tries to find the **external** PDB using
190 : /// the [`crate::pe::debug::CodeViewPDB::filename`] output (if present). One can also
191 : /// use [`crate::pdb::load`] or [`crate::pdb::DebugInfo::from`] to get PDB debug
192 : /// info.
193 : ///
194 : /// <div class="warning">
195 : /// This function requires LIEF's extended version otherwise it always return `None`
196 : /// </div>
197 0 : fn debug_info(&self) -> Option<crate::DebugInfo<'_>> {
198 0 : into_optional(self.as_generic().debug_info())
199 0 : }
200 :
201 : /// Disassemble code starting at the given virtual address and with the given
202 : /// size.
203 : ///
204 : /// ```
205 : /// let insts = binary.disassemble(0xacde, 100);
206 : /// for inst in insts {
207 : /// println!("{}", inst.to_string());
208 : /// }
209 : /// ```
210 : ///
211 : /// See also [`crate::assembly::Instruction`] and [`crate::assembly::Instructions`]
212 0 : fn disassemble(&self, address: u64, size: u64) -> InstructionsIt<'_> {
213 0 : InstructionsIt::new(self.as_generic().disassemble(address, size))
214 0 : }
215 :
216 : /// Disassemble code for the given symbol name
217 : ///
218 : /// ```
219 : /// let insts = binary.disassemble_symbol("__libc_start_main");
220 : /// for inst in insts {
221 : /// println!("{}", inst.to_string());
222 : /// }
223 : /// ```
224 : ///
225 : /// See also [`crate::assembly::Instruction`] and [`crate::assembly::Instructions`]
226 0 : fn disassemble_symbol(&self, name: &str) -> InstructionsIt<'_> {
227 0 : InstructionsIt::new(self.as_generic().disassemble_function(name.to_string()))
228 0 : }
229 :
230 : /// Disassemble code at the given virtual address
231 : ///
232 : /// ```
233 : /// let insts = binary.disassemble_address(0xacde);
234 : /// for inst in insts {
235 : /// println!("{}", inst.to_string());
236 : /// }
237 : /// ```
238 : ///
239 : /// See also [`crate::assembly::Instruction`] and [`crate::assembly::Instructions`]
240 0 : fn disassemble_address(&self, address: u64) -> InstructionsIt<'_> {
241 0 : InstructionsIt::new(self.as_generic().disassemble_address(address))
242 0 : }
243 :
244 : /// Disassemble code provided by the given slice at the specified `address` parameter.
245 : ///
246 : /// See also [`crate::assembly::Instruction`] and [`crate::assembly::Instructions`]
247 0 : fn disassemble_slice(&self, slice: &[u8], address: u64) -> InstructionsIt<'_> {
248 0 : unsafe {
249 0 : InstructionsIt::new(self.as_generic().disassemble_buffer(
250 0 : slice.as_ptr(),
251 0 : slice.len().try_into().unwrap(),
252 0 : address,
253 0 : ))
254 0 : }
255 0 : }
256 :
257 : /// Assemble **and patch** the provided assembly code at the specified address.
258 : ///
259 : /// The generated assembly is returned by the function
260 : ///
261 : /// ```
262 : /// let mut bin = get_binary();
263 : ///
264 : /// let Vec<u8> bytes = bin.assemble(0x12000440, r#"
265 : /// xor rax, rbx;
266 : /// mov rcx, rax;
267 : /// "#);
268 : /// ```
269 0 : fn assemble(&mut self, address: u64, asm: &str) -> Vec<u8> {
270 0 : Vec::from(self.as_pin_mut_generic().assemble(address, asm).as_slice())
271 0 : }
272 :
273 : /// Same as [`Binary::assemble`] but this function takes an extra [`AssemblerConfig`] that
274 : /// is used to configure the assembly engine: dialect, symbols definitions.
275 0 : fn assemble_with_config(
276 0 : &mut self,
277 0 : address: u64,
278 0 : asm: &str,
279 0 : config: &AssemblerConfig,
280 0 : ) -> Vec<u8> {
281 0 : let ffi_config = config.into_ffi();
282 0 : Vec::from(
283 0 : self.as_pin_mut_generic()
284 0 : .assemble_with_config(address, asm, ffi_config.as_ref())
285 0 : .as_slice(),
286 0 : )
287 0 : }
288 :
289 : /// Default memory page size according to the architecture and the format of the
290 : /// current binary
291 0 : fn page_size(&self) -> u64 {
292 0 : self.as_generic().page_size()
293 0 : }
294 :
295 : /// Convert the given offset into a virtual address.
296 : ///
297 : /// If the `slide` parameter is provided (non-zero), it will be used as the base address
298 : /// instead of the binary's imagebase.
299 2 : fn offset_to_virtual_address(&self, offset: u64, slide: u64) -> Result<u64, crate::Error> {
300 2 : let mut err: u32 = 0;
301 2 : let va = self
302 2 : .as_generic()
303 2 : .offset_to_virtual_address(offset, slide, Pin::new(&mut err));
304 2 : if err > 0 {
305 0 : return Err(crate::Error::from(err));
306 2 : }
307 2 : Ok(va)
308 2 : }
309 :
310 : /// Load and associate an external debug file (e.g., DWARF or PDB) with this binary.
311 : ///
312 : /// This method attempts to load the debug information from the file located at the given path,
313 : /// and binds it to the current binary instance. If successful, it returns the
314 : /// loaded [`crate::DebugInfo`] object.
315 : ///
316 : /// <div class="warning">
317 : /// It is the caller's responsibility to ensure that the debug file is
318 : /// compatible with the binary. Incorrect associations may lead to
319 : /// inconsistent or invalid results.
320 : /// </div>
321 : ///
322 : /// <div class="note">
323 : /// This function does not verify that the debug file matches the binary's unique
324 : /// identifier (e.g., build ID, GUID).
325 : /// </div>
326 0 : fn load_debug_info(&mut self, path: &std::path::Path) -> Option<crate::DebugInfo<'_>> {
327 0 : into_optional(
328 0 : self.as_pin_mut_generic()
329 0 : .load_debug_info(path.to_str().unwrap()),
330 0 : )
331 0 : }
332 : }
333 :
334 : /// This class provides a generic interface for accessing debug information
335 : /// from different formats such as DWARF and PDB.
336 : ///
337 : /// Users can use this interface to access high-level debug features like
338 : /// resolving function addresses.
339 : ///
340 : /// See: [`crate::pdb::DebugInfo`], [`crate::dwarf::DebugInfo`]
341 : pub trait DebugInfo {
342 : #[doc(hidden)]
343 : fn as_generic(&self) -> &ffi::AbstracDebugInfo;
344 :
345 : /// Attempt to resolve the address of the function specified by `name`.
346 0 : fn find_function_address(&self, name: &str) -> Option<u64> {
347 0 : to_opt_trait!(
348 0 : &lief_ffi::AbstracDebugInfo::find_function_address,
349 0 : self.as_generic(),
350 0 : name
351 0 : );
352 0 : }
353 : }
354 :
355 0 : bitflags! {
356 0 : /// Flags used to characterize the semantics of the function
357 945698 : #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
358 0 : pub struct FunctionFlags: u32 {
359 0 : const NONE = 0x0;
360 0 : /// The function acts as constructor.
361 0 : ///
362 0 : /// Usually this flag is associated with functions
363 0 : /// that are located in the `.init_array`, `__mod_init_func` or `.tls` sections
364 0 : const CONSTRUCTOR = 0x1;
365 0 :
366 0 : /// The function acts as a destructor.
367 0 : ///
368 0 : /// Usually this flag is associated with functions
369 0 : /// that are located in the `.fini_array` or `__mod_term_func` sections
370 0 : const DESTRUCTOR = 0x2;
371 0 :
372 0 : /// The function is associated with Debug information
373 0 : const DEBUG_INFO = 0x4;
374 0 :
375 0 : /// The function is exported by the binary and the [`Function::address`]
376 0 : /// returns its virtual address in the binary
377 0 : const EXPORTED = 0x8;
378 0 :
379 0 : /// The function is **imported** by the binary and the [`Function::address`]
380 0 : /// should return 0
381 0 : const IMPORTED = 0x10;
382 0 : }
383 0 : }
384 :
385 : impl From<u32> for FunctionFlags {
386 945698 : fn from(value: u32) -> Self {
387 945698 : FunctionFlags::from_bits_truncate(value)
388 945698 : }
389 : }
390 :
391 : impl From<FunctionFlags> for u32 {
392 0 : fn from(value: FunctionFlags) -> Self {
393 0 : value.bits()
394 0 : }
395 : }
396 :
397 : impl std::fmt::Display for FunctionFlags {
398 0 : fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
399 0 : bitflags::parser::to_writer(self, f)
400 0 : }
401 : }
402 :
403 : /// Structure that represents a binary's function
404 : pub struct Function {
405 : ptr: cxx::UniquePtr<ffi::AbstractFunction>,
406 : }
407 :
408 : impl FromFFI<ffi::AbstractFunction> for Function {
409 945698 : fn from_ffi(ptr: cxx::UniquePtr<ffi::AbstractFunction>) -> Self {
410 945698 : Self { ptr }
411 945698 : }
412 : }
413 :
414 : impl Symbol for Function {
415 945698 : fn as_generic(&self) -> &lief_ffi::AbstractSymbol {
416 945698 : self.ptr.as_ref().unwrap().as_ref()
417 945698 : }
418 :
419 0 : fn as_pin_mut_generic(&mut self) -> Pin<&mut ffi::AbstractSymbol> {
420 0 : unsafe {
421 0 : Pin::new_unchecked({
422 0 : (self.ptr.as_ref().unwrap().as_ref() as *const ffi::AbstractSymbol
423 0 : as *mut ffi::AbstractSymbol)
424 0 : .as_mut()
425 0 : .unwrap()
426 0 : })
427 0 : }
428 0 : }
429 : }
430 :
431 : impl Function {
432 : /// Flags characterizing the semantics of the function
433 945698 : pub fn flags(&self) -> FunctionFlags {
434 945698 : FunctionFlags::from(self.ptr.flags())
435 945698 : }
436 :
437 : /// Address of the function (if not imported)
438 945698 : pub fn address(&self) -> u64 {
439 945698 : self.ptr.address()
440 945698 : }
441 : }
442 :
443 : impl std::fmt::Debug for Function {
444 945698 : fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
445 945698 : f.debug_struct("Function")
446 945698 : .field("name", &self.name())
447 945698 : .field("address", &self.address())
448 945698 : .field("flags", &self.flags())
449 945698 : .finish()
450 945698 : }
451 : }
452 :
453 945698 : declare_fwd_iterator!(
454 945698 : Functions,
455 945698 : Function,
456 945698 : ffi::AbstractFunction,
457 945698 : ffi::AbstractBinary,
458 945698 : ffi::AbstractBinary_it_functions
459 945698 : );
460 :
461 0 : declare_lazy_iterator!(
462 0 : InstructionsIt,
463 0 : Instructions,
464 0 : ffi::asm_Instruction,
465 0 : ffi::AbstractBinary,
466 0 : ffi::AbstractBinary_it_instructions
467 0 : );
|