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 : /// Whether the current binary is **an executable** and **position independent**
144 8 : fn is_pie(&self) -> bool {
145 8 : self.as_generic().is_pie()
146 8 : }
147 :
148 : /// Whether the binary defines a non-executable stack
149 8 : fn has_nx(&self) -> bool {
150 8 : self.as_generic().has_nx()
151 8 : }
152 :
153 : /// Original file size of the binary
154 8 : fn original_size(&self) -> u64 {
155 8 : self.as_generic().original_size()
156 8 : }
157 :
158 : /// Return the debug info if present. It can be either a
159 : /// [`crate::pdb::DebugInfo`] or [`crate::dwarf::DebugInfo`].
160 : ///
161 : /// For ELF and Mach-O binaries, it returns the given DebugInfo object **only**
162 : /// if the binary embeds the DWARF debug info in the binary itself.
163 : ///
164 : /// For PE file, this function tries to find the **external** PDB using
165 : /// the [`crate::pe::debug::CodeViewPDB::filename`] output (if present). One can also
166 : /// use [`crate::pdb::load`] or [`crate::pdb::DebugInfo::from`] to get PDB debug
167 : /// info.
168 : ///
169 : /// <div class="warning">
170 : /// This function requires LIEF's extended version otherwise it always return `None`
171 : /// </div>
172 0 : fn debug_info(&self) -> Option<crate::DebugInfo> {
173 0 : into_optional(self.as_generic().debug_info())
174 0 : }
175 :
176 : /// Disassemble code starting at the given virtual address and with the given
177 : /// size.
178 : ///
179 : /// ```
180 : /// let insts = binary.disassemble(0xacde, 100);
181 : /// for inst in insts {
182 : /// println!("{}", inst.to_string());
183 : /// }
184 : /// ```
185 : ///
186 : /// See also [`crate::assembly::Instruction`] and [`crate::assembly::Instructions`]
187 0 : fn disassemble(&self, address: u64, size: u64) -> InstructionsIt {
188 0 : InstructionsIt::new(self.as_generic().disassemble(address, size))
189 0 : }
190 :
191 : /// Disassemble code for the given symbol name
192 : ///
193 : /// ```
194 : /// let insts = binary.disassemble_symbol("__libc_start_main");
195 : /// for inst in insts {
196 : /// println!("{}", inst.to_string());
197 : /// }
198 : /// ```
199 : ///
200 : /// See also [`crate::assembly::Instruction`] and [`crate::assembly::Instructions`]
201 0 : fn disassemble_symbol(&self, name: &str) -> InstructionsIt {
202 0 : InstructionsIt::new(self.as_generic().disassemble_function(name.to_string()))
203 0 : }
204 :
205 : /// Disassemble code at the given virtual address
206 : ///
207 : /// ```
208 : /// let insts = binary.disassemble_address(0xacde);
209 : /// for inst in insts {
210 : /// println!("{}", inst.to_string());
211 : /// }
212 : /// ```
213 : ///
214 : /// See also [`crate::assembly::Instruction`] and [`crate::assembly::Instructions`]
215 0 : fn disassemble_address(&self, address: u64) -> InstructionsIt {
216 0 : InstructionsIt::new(self.as_generic().disassemble_address(address))
217 0 : }
218 :
219 : /// Disassemble code provided by the given slice at the specified `address` parameter.
220 : ///
221 : /// See also [`crate::assembly::Instruction`] and [`crate::assembly::Instructions`]
222 0 : fn disassemble_slice(&self, slice: &[u8], address: u64) -> InstructionsIt {
223 0 : unsafe {
224 0 : InstructionsIt::new(self.as_generic().disassemble_buffer(
225 0 : slice.as_ptr(), slice.len().try_into().unwrap(),
226 0 : address))
227 0 : }
228 0 : }
229 :
230 : /// Assemble **and patch** the provided assembly code at the specified address.
231 : ///
232 : /// The generated assembly is returned by the function
233 : ///
234 : /// ```
235 : /// let mut bin = get_binary();
236 : ///
237 : /// let Vec<u8> bytes = bin.assemble(0x12000440, r#"
238 : /// xor rax, rbx;
239 : /// mov rcx, rax;
240 : /// "#);
241 : /// ```
242 0 : fn assemble(&mut self, address: u64, asm: &str) -> Vec<u8> {
243 0 : Vec::from(self.as_pin_mut_generic().assemble(address, asm).as_slice())
244 0 : }
245 :
246 : /// Same as [`Binary::assemble`] but this function takes an extra [`AssemblerConfig`] that
247 : /// is used to configure the assembly engine: dialect, symbols definitions.
248 0 : fn assemble_with_config(&mut self, address: u64, asm: &str, config: &AssemblerConfig) -> Vec<u8> {
249 0 : let ffi_config = config.into_ffi();
250 0 : Vec::from(self.as_pin_mut_generic().assemble_with_config(address, asm, ffi_config.as_ref()).as_slice())
251 0 : }
252 :
253 : /// Get the default memory page size according to the architecture and the format of the
254 : /// current binary
255 0 : fn page_size(&self) -> u64 {
256 0 : self.as_generic().page_size()
257 0 : }
258 :
259 : /// Load and associate an external debug file (e.g., DWARF or PDB) with this binary.
260 : ///
261 : /// This method attempts to load the debug information from the file located at the given path,
262 : /// and binds it to the current binary instance. If successful, it returns the
263 : /// loaded [`crate::DebugInfo`] object.
264 : ///
265 : /// <div class="warning">
266 : /// It is the caller's responsibility to ensure that the debug file is
267 : /// compatible with the binary. Incorrect associations may lead to
268 : /// inconsistent or invalid results.
269 : /// </div>
270 : ///
271 : /// <div class="note">
272 : /// This function does not verify that the debug file matches the binary's unique
273 : /// identifier (e.g., build ID, GUID).
274 : /// </div>
275 0 : fn load_debug_info(&mut self, path: &std::path::Path) -> Option<crate::DebugInfo> {
276 0 : into_optional(self.as_pin_mut_generic().load_debug_info(path.to_str().unwrap()))
277 0 : }
278 : }
279 :
280 : /// This class provides a generic interface for accessing debug information
281 : /// from different formats such as DWARF and PDB.
282 : ///
283 : /// Users can use this interface to access high-level debug features like
284 : /// resolving function addresses.
285 : ///
286 : /// See: [`crate::pdb::DebugInfo`], [`crate::dwarf::DebugInfo`]
287 : pub trait DebugInfo {
288 : #[doc(hidden)]
289 : fn as_generic(&self) -> &ffi::AbstracDebugInfo;
290 :
291 : /// Attempt to resolve the address of the function specified by `name`.
292 0 : fn find_function_address(&self, name: &str) -> Option<u64> {
293 0 : to_opt_trait!(
294 0 : &lief_ffi::AbstracDebugInfo::find_function_address,
295 0 : self.as_generic(),
296 0 : name
297 0 : );
298 0 : }
299 : }
300 :
301 0 : bitflags! {
302 0 : /// Flags used to characterize the semantics of the function
303 868788 : #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
304 0 : pub struct FunctionFlags: u32 {
305 0 : const NONE = 0x0;
306 0 : /// The function acts as constructor.
307 0 : ///
308 0 : /// Usually this flag is associated with functions
309 0 : /// that are located in the `.init_array`, `__mod_init_func` or `.tls` sections
310 0 : const CONSTRUCTOR = 0x1;
311 0 :
312 0 : /// The function acts as a destructor.
313 0 : ///
314 0 : /// Usually this flag is associated with functions
315 0 : /// that are located in the `.fini_array` or `__mod_term_func` sections
316 0 : const DESTRUCTOR = 0x2;
317 0 :
318 0 : /// The function is associated with Debug information
319 0 : const DEBUG_INFO = 0x4;
320 0 :
321 0 : /// The function is exported by the binary and the [`Function::address`]
322 0 : /// returns its virtual address in the binary
323 0 : const EXPORTED = 0x8;
324 0 :
325 0 : /// The function is **imported** by the binary and the [`Function::address`]
326 0 : /// should return 0
327 0 : const IMPORTED = 0x10;
328 0 : }
329 0 : }
330 :
331 :
332 : impl From<u32> for FunctionFlags {
333 868788 : fn from(value: u32) -> Self {
334 868788 : FunctionFlags::from_bits_truncate(value)
335 868788 : }
336 : }
337 :
338 : impl From<FunctionFlags> for u32 {
339 0 : fn from(value: FunctionFlags) -> Self {
340 0 : value.bits()
341 0 : }
342 : }
343 :
344 : impl std::fmt::Display for FunctionFlags {
345 0 : fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
346 0 : bitflags::parser::to_writer(self, f)
347 0 : }
348 : }
349 :
350 : /// Structure that represents a binary's function
351 : pub struct Function {
352 : ptr: cxx::UniquePtr<ffi::AbstractFunction>,
353 : }
354 :
355 : impl FromFFI<ffi::AbstractFunction> for Function {
356 868788 : fn from_ffi(ptr: cxx::UniquePtr<ffi::AbstractFunction>) -> Self {
357 868788 : Self {
358 868788 : ptr,
359 868788 : }
360 868788 : }
361 : }
362 :
363 : impl Symbol for Function {
364 868788 : fn as_generic(&self) -> &lief_ffi::AbstractSymbol {
365 868788 : self.ptr.as_ref().unwrap().as_ref()
366 868788 : }
367 :
368 0 : fn as_pin_mut_generic(&mut self) -> Pin<&mut ffi::AbstractSymbol> {
369 0 : unsafe {
370 0 : Pin::new_unchecked({
371 0 : (self.ptr.as_ref().unwrap().as_ref() as *const ffi::AbstractSymbol
372 0 : as *mut ffi::AbstractSymbol)
373 0 : .as_mut()
374 0 : .unwrap()
375 0 : })
376 0 : }
377 0 : }
378 : }
379 :
380 : impl Function {
381 : /// Flags characterizing the semantics of the function
382 868788 : pub fn flags(&self) -> FunctionFlags {
383 868788 : FunctionFlags::from(self.ptr.flags())
384 868788 : }
385 :
386 : /// Address of the function (if not imported)
387 868788 : pub fn address(&self) -> u64 {
388 868788 : self.ptr.address()
389 868788 : }
390 : }
391 :
392 : impl std::fmt::Debug for Function {
393 868788 : fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
394 868788 : f.debug_struct("Function")
395 868788 : .field("name", &self.name())
396 868788 : .field("address", &self.address())
397 868788 : .field("flags", &self.flags())
398 868788 : .finish()
399 868788 : }
400 : }
401 :
402 868788 : declare_fwd_iterator!(
403 868788 : Functions,
404 868788 : Function,
405 868788 : ffi::AbstractFunction,
406 868788 : ffi::AbstractBinary,
407 868788 : ffi::AbstractBinary_it_functions
408 868788 : );
409 :
410 0 : declare_fwd_iterator!(
411 0 : InstructionsIt,
412 0 : Instructions,
413 0 : ffi::asm_Instruction,
414 0 : ffi::AbstractBinary,
415 0 : ffi::AbstractBinary_it_instructions
416 0 : );
|