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