Line data Source code
1 : use lief_ffi as ffi;
2 : use bitflags::bitflags;
3 : use crate::{to_slice, declare_fwd_iterator};
4 : use crate::common::{into_optional, FromFFI};
5 : use crate::assembly::Instructions;
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 1948824 : fn name(&self) -> String {
19 1948824 : self.as_generic().name().to_string()
20 1948824 : }
21 : /// Symbol's value whose interpretation depends on the symbol's kind.
22 : /// Usually this is the address of the symbol though.
23 1018404 : fn value(&self) -> u64 {
24 1018404 : self.as_generic().value()
25 1018404 : }
26 : /// Size of the symbol (can be 0)
27 1018404 : fn size(&self) -> u64 {
28 1018404 : self.as_generic().size()
29 1018404 : }
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 1009080 : fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
46 1009080 : f.debug_struct("Symbol")
47 1009080 : .field("name", &self.name())
48 1009080 : .field("value", &self.value())
49 1009080 : .field("size", &self.size())
50 1009080 : .finish()
51 1009080 : }
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 303000 : fn name(&self) -> String {
61 303000 : self.as_generic().name().to_string()
62 303000 : }
63 :
64 : /// Size of the section **in the file**
65 289512 : fn size(&self) -> u64 {
66 289512 : self.as_generic().size()
67 289512 : }
68 :
69 : /// Offset of the section **in the file**
70 289428 : fn offset(&self) -> u64 {
71 289428 : self.as_generic().offset()
72 289428 : }
73 :
74 : /// Address of the section **in memory**
75 289428 : fn virtual_address(&self) -> u64 {
76 289428 : self.as_generic().virtual_address()
77 289428 : }
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 287040 : fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
87 287040 : f.debug_struct("Section")
88 287040 : .field("name", &self.name())
89 287040 : .field("size", &self.size())
90 287040 : .field("offset", &self.offset())
91 287040 : .field("virtual_address", &self.virtual_address())
92 287040 : .finish()
93 287040 : }
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 : pub trait Binary {
121 : #[doc(hidden)]
122 : fn as_generic(&self) -> &ffi::AbstractBinary;
123 :
124 : #[doc(hidden)]
125 : fn as_pin_mut_generic(&mut self) -> Pin<&mut ffi::AbstractBinary>;
126 :
127 : /// Binary's entrypoint
128 35 : fn entrypoint(&self) -> u64 {
129 35 : self.as_generic().entrypoint()
130 35 : }
131 :
132 : /// Default base address where the binary should be mapped
133 8 : fn imagebase(&self) -> u64 {
134 8 : self.as_generic().imagebase()
135 8 : }
136 :
137 : /// Whether the current binary is **an executable** and **position independent**
138 8 : fn is_pie(&self) -> bool {
139 8 : self.as_generic().is_pie()
140 8 : }
141 :
142 : /// Whether the binary defines a non-executable stack
143 8 : fn has_nx(&self) -> bool {
144 8 : self.as_generic().has_nx()
145 8 : }
146 :
147 : /// Original file size of the binary
148 8 : fn original_size(&self) -> u64 {
149 8 : self.as_generic().original_size()
150 8 : }
151 :
152 : /// Return the debug info if present. It can be either a
153 : /// [`crate::pdb::DebugInfo`] or [`crate::dwarf::DebugInfo`].
154 : ///
155 : /// For ELF and Mach-O binaries, it returns the given DebugInfo object **only**
156 : /// if the binary embeds the DWARF debug info in the binary itself.
157 : ///
158 : /// For PE file, this function tries to find the **external** PDB using
159 : /// the [`crate::pe::debug::CodeViewPDB::filename`] output (if present). One can also
160 : /// use [`crate::pdb::load`] or [`crate::pdb::DebugInfo::from`] to get PDB debug
161 : /// info.
162 : ///
163 : /// <div class="warning">
164 : /// This function requires LIEF's extended version otherwise it always return `None`
165 : /// </div>
166 0 : fn debug_info(&self) -> Option<crate::DebugInfo> {
167 0 : into_optional(self.as_generic().debug_info())
168 0 : }
169 :
170 : /// Disassemble code starting a the given virtual address and with the given
171 : /// size.
172 : ///
173 : /// ```
174 : /// let insts = binary.disassemble(0xacde, 100);
175 : /// for inst in insts {
176 : /// println!("{}", inst.to_string());
177 : /// }
178 : /// ```
179 : ///
180 : /// See also [`crate::assembly::Instruction`] and [`crate::assembly::Instructions`]
181 0 : fn disassemble(&self, address: u64, size: u64) -> InstructionsIt {
182 0 : InstructionsIt::new(self.as_generic().disassemble(address, size))
183 0 : }
184 :
185 : /// Disassemble code for the given symbol name
186 : ///
187 : /// ```
188 : /// let insts = binary.disassemble_symbol("__libc_start_main");
189 : /// for inst in insts {
190 : /// println!("{}", inst.to_string());
191 : /// }
192 : /// ```
193 : ///
194 : /// See also [`crate::assembly::Instruction`] and [`crate::assembly::Instructions`]
195 0 : fn disassemble_symbol(&self, name: &str) -> InstructionsIt {
196 0 : InstructionsIt::new(self.as_generic().disassemble_function(name.to_string()))
197 0 : }
198 :
199 : /// Disassemble code at the given virtual address
200 : ///
201 : /// ```
202 : /// let insts = binary.disassemble_address(0xacde);
203 : /// for inst in insts {
204 : /// println!("{}", inst.to_string());
205 : /// }
206 : /// ```
207 : ///
208 : /// See also [`crate::assembly::Instruction`] and [`crate::assembly::Instructions`]
209 0 : fn disassemble_address(&self, address: u64) -> InstructionsIt {
210 0 : InstructionsIt::new(self.as_generic().disassemble_address(address))
211 0 : }
212 :
213 : /// Disassemble code provided by the given slice at the specified `address` parameter.
214 : ///
215 : /// See also [`crate::assembly::Instruction`] and [`crate::assembly::Instructions`]
216 0 : fn disassemble_slice(&self, slice: &[u8], address: u64) -> InstructionsIt {
217 0 : unsafe {
218 0 : InstructionsIt::new(self.as_generic().disassemble_buffer(
219 0 : slice.as_ptr(), slice.len().try_into().unwrap(),
220 0 : address))
221 0 : }
222 0 : }
223 :
224 : /// Assemble **and patch** the provided assembly code at the specified address.
225 : ///
226 : /// The generated assembly is returned by the function
227 : ///
228 : /// ```
229 : /// let mut bin = get_binary();
230 : ///
231 : /// let Vec<u8> bytes = bin.assemble(0x12000440, r#"
232 : /// xor rax, rbx;
233 : /// mov rcx, rax;
234 : /// "#);
235 : /// ```
236 0 : fn assemble(&mut self, address: u64, asm: &str) -> Vec<u8> {
237 0 : Vec::from(self.as_pin_mut_generic().assemble(address, asm).as_slice())
238 0 : }
239 :
240 : /// Get the default memory page size according to the architecture and the format of the
241 : /// current binary
242 0 : fn page_size(&self) -> u64 {
243 0 : self.as_generic().page_size()
244 0 : }
245 : }
246 :
247 : pub trait DebugInfo {
248 : #[doc(hidden)]
249 : fn as_generic(&self) -> &ffi::AbstracDebugInfo;
250 : }
251 :
252 :
253 0 : bitflags! {
254 0 : /// Flags used to characterize the semantics of the function
255 868740 : #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
256 0 : pub struct FunctionFlags: u32 {
257 0 : const NONE = 0x0;
258 0 : /// The function acts as constructor.
259 0 : ///
260 0 : /// Usually this flag is associated with functions
261 0 : /// that are located in the `.init_array`, `__mod_init_func` or `.tls` sections
262 0 : const CONSTRUCTOR = 0x1;
263 0 :
264 0 : /// The function acts as a destructor.
265 0 : ///
266 0 : /// Usually this flag is associated with functions
267 0 : /// that are located in the `.fini_array` or `__mod_term_func` sections
268 0 : const DESTRUCTOR = 0x2;
269 0 :
270 0 : /// The function is associated with Debug information
271 0 : const DEBUG_INFO = 0x4;
272 0 :
273 0 : /// The function is exported by the binary and the [`Function::address`]
274 0 : /// returns its virtual address in the binary
275 0 : const EXPORTED = 0x8;
276 0 :
277 0 : /// The function is **imported** by the binary and the [`Function::address`]
278 0 : /// should return 0
279 0 : const IMPORTED = 0x10;
280 0 : }
281 0 : }
282 :
283 :
284 : impl From<u32> for FunctionFlags {
285 868740 : fn from(value: u32) -> Self {
286 868740 : FunctionFlags::from_bits_truncate(value)
287 868740 : }
288 : }
289 :
290 : impl From<FunctionFlags> for u32 {
291 0 : fn from(value: FunctionFlags) -> Self {
292 0 : value.bits()
293 0 : }
294 : }
295 :
296 : impl std::fmt::Display for FunctionFlags {
297 0 : fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
298 0 : bitflags::parser::to_writer(self, f)
299 0 : }
300 : }
301 :
302 : /// Structure that represents a binary's function
303 : pub struct Function {
304 : ptr: cxx::UniquePtr<ffi::AbstractFunction>,
305 : }
306 :
307 : impl FromFFI<ffi::AbstractFunction> for Function {
308 868740 : fn from_ffi(ptr: cxx::UniquePtr<ffi::AbstractFunction>) -> Self {
309 868740 : Self {
310 868740 : ptr,
311 868740 : }
312 868740 : }
313 : }
314 :
315 : impl Symbol for Function {
316 868740 : fn as_generic(&self) -> &lief_ffi::AbstractSymbol {
317 868740 : self.ptr.as_ref().unwrap().as_ref()
318 868740 : }
319 :
320 0 : fn as_pin_mut_generic(&mut self) -> Pin<&mut ffi::AbstractSymbol> {
321 0 : unsafe {
322 0 : Pin::new_unchecked({
323 0 : (self.ptr.as_ref().unwrap().as_ref() as *const ffi::AbstractSymbol
324 0 : as *mut ffi::AbstractSymbol)
325 0 : .as_mut()
326 0 : .unwrap()
327 0 : })
328 0 : }
329 0 : }
330 : }
331 :
332 : impl Function {
333 : /// Flags characterizing the semantics of the function
334 868740 : pub fn flags(&self) -> FunctionFlags {
335 868740 : FunctionFlags::from(self.ptr.flags())
336 868740 : }
337 :
338 : /// Address of the function (if not imported)
339 868740 : pub fn address(&self) -> u64 {
340 868740 : self.ptr.address()
341 868740 : }
342 : }
343 :
344 : impl std::fmt::Debug for Function {
345 868740 : fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
346 868740 : f.debug_struct("Function")
347 868740 : .field("name", &self.name())
348 868740 : .field("address", &self.address())
349 868740 : .field("flags", &self.flags())
350 868740 : .finish()
351 868740 : }
352 : }
353 :
354 868740 : declare_fwd_iterator!(
355 868740 : Functions,
356 868740 : Function,
357 868740 : ffi::AbstractFunction,
358 868740 : ffi::AbstractBinary,
359 868740 : ffi::AbstractBinary_it_functions
360 868740 : );
361 :
362 0 : declare_fwd_iterator!(
363 0 : InstructionsIt,
364 0 : Instructions,
365 0 : ffi::asm_Instruction,
366 0 : ffi::AbstractBinary,
367 0 : ffi::AbstractBinary_it_instructions
368 0 : );
|