Line data Source code
1 : use lief_ffi as ffi;
2 :
3 : use crate::common::{FromFFI, into_optional};
4 : use std::marker::PhantomData;
5 : use crate::macho::Binary;
6 :
7 : /// This structure represents a library embedded in a dyld shared cache.
8 : /// It mirrors the original `dyld_cache_image_info` structure.
9 : pub struct Dylib<'a> {
10 : ptr: cxx::UniquePtr<ffi::dsc_Dylib>,
11 : _owner: PhantomData<&'a ()>,
12 : }
13 :
14 : impl FromFFI<ffi::dsc_Dylib> for Dylib<'_> {
15 0 : fn from_ffi(ptr: cxx::UniquePtr<ffi::dsc_Dylib>) -> Self {
16 0 : Self {
17 0 : ptr,
18 0 : _owner: PhantomData,
19 0 : }
20 0 : }
21 : }
22 :
23 : impl Dylib<'_> {
24 : /// Original path of the library (e.g. `/usr/lib/libcryptex.dylib`)
25 0 : pub fn path(&self) -> String {
26 0 : self.ptr.path().to_string()
27 0 : }
28 :
29 : /// In-memory address of the library
30 0 : pub fn address(&self) -> u64 {
31 0 : self.ptr.address()
32 0 : }
33 :
34 : /// Modification time of the library matching `stat.st_mtime`, or 0
35 0 : pub fn modtime(&self) -> u64 {
36 0 : self.ptr.modtime()
37 0 : }
38 :
39 : /// File serial number matching `stat.st_ino` or 0
40 : ///
41 : /// Note that for shared cache targeting iOS, this value can hold a hash of
42 : /// the path (if modtime is set to 0)
43 0 : pub fn inode(&self) -> u64 {
44 0 : self.ptr.inode()
45 0 : }
46 :
47 : /// Padding alignment value (should be 0)
48 0 : pub fn padding(&self) -> u64 {
49 0 : self.ptr.padding()
50 0 : }
51 :
52 : /// Get a [`Binary`] representation for this Dylib.
53 : ///
54 : /// One can use this function to write back the Mach-O binary on the disk:
55 : ///
56 : /// ```cpp
57 : /// dylib.get().expect("Can't extract").write("liblockdown.dylib");
58 : /// ```
59 0 : pub fn get(&self) -> Option<Binary> {
60 0 : self.get_with_opt(&ExtractOpt::default())
61 0 : }
62 : /// Get a [`Binary`] representation for this Dylib with the provided [`ExtractOpt`] options.
63 0 : pub fn get_with_opt(&self, opt: &ExtractOpt) -> Option<Binary> {
64 0 : into_optional(self.ptr.get_macho(opt.to_ffi()))
65 0 : }
66 : }
67 :
68 : /// This structure is used to tweak the extraction process while calling
69 : /// [`Dylib::get_with_opt`]. These options allow to deoptimize the dylib and get an
70 : /// accurate representation of the origin Mach-O binary.
71 : pub struct ExtractOpt {
72 : /// Whether the segment's offsets should be packed to avoid
73 : /// an in-memory size while writing back the binary.
74 : ///
75 : /// <div class="note">This option does not have an impact on the performances</div>
76 : pub pack: bool,
77 :
78 : /// Fix call instructions that target addresses outside the current dylib
79 : /// virtual space.
80 : ///
81 : /// <div class="warning">
82 : /// Enabling this option can have a significant impact on the performances.
83 : /// Make sure to enable the internal cache mechanism.
84 : /// </div>
85 : ///
86 : /// [`crate::dsc::enable_cache`] or [`crate::dsc::DyldSharedCache::enable_caching`]
87 : pub fix_branches: bool,
88 :
89 : /// Fix memory accesses performed outside the dylib's virtual space
90 : ///
91 : /// <div class="warning">
92 : /// Enabling this option can have a significant impact on the performances.
93 : /// Make sure to enable the internal cache mechanism.
94 : /// </div>
95 : ///
96 : /// [`crate::dsc::enable_cache`] or [`crate::dsc::DyldSharedCache::enable_caching`]
97 : pub fix_memory: bool,
98 :
99 : /// Recover and fix relocations
100 : ///
101 : /// <div class="warning">
102 : /// Enabling this option can have a significant impact on the performances.
103 : /// Make sure to enable the internal cache mechanism.
104 : /// </div>
105 : ///
106 : /// [`crate::dsc::enable_cache`] or [`crate::dsc::DyldSharedCache::enable_caching`]
107 : pub fix_relocations: bool,
108 :
109 : /// Fix Objective-C information
110 : ///
111 : /// <div class="warning">
112 : /// Enabling this option can have a significant impact on the performances.
113 : /// Make sure to enable the internal cache mechanism.
114 : /// </div>
115 : ///
116 : /// [`crate::dsc::enable_cache`] or [`crate::dsc::DyldSharedCache::enable_caching`]
117 : pub fix_objc: bool,
118 :
119 : /// Whether the `LC_DYLD_CHAINED_FIXUPS` command should be (re)created.
120 : ///
121 : /// If this value is not set, LIEF will add the command only if it's
122 : /// meaningful regarding the other options
123 : pub create_dyld_chained_fixup_cmd: Option<bool>,
124 : }
125 :
126 : impl Default for ExtractOpt {
127 0 : fn default() -> ExtractOpt {
128 0 : ExtractOpt {
129 0 : pack: true,
130 0 : fix_branches: false,
131 0 : fix_memory: true,
132 0 : fix_relocations: true,
133 0 : fix_objc: true,
134 0 : create_dyld_chained_fixup_cmd: None,
135 0 : }
136 0 : }
137 : }
138 :
139 : impl ExtractOpt {
140 : #[doc(hidden)]
141 0 : fn to_ffi(&self) -> ffi::dsc_Dylib_extract_opt {
142 0 : ffi::dsc_Dylib_extract_opt {
143 0 : pack: self.pack,
144 0 : fix_branches: self.fix_branches,
145 0 : fix_memory: self.fix_memory,
146 0 : fix_relocations: self.fix_relocations,
147 0 : fix_objc: self.fix_objc,
148 0 : create_dyld_chained_fixup_cmd: self.create_dyld_chained_fixup_cmd.unwrap_or(false),
149 0 : create_dyld_chained_fixup_cmd_set: self.create_dyld_chained_fixup_cmd.is_some()
150 0 : }
151 0 : }
152 : }
153 :
154 : impl std::fmt::Debug for Dylib<'_> {
155 0 : fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
156 0 : f.debug_struct("Dylib")
157 0 : .field("path", &self.path())
158 0 : .field("address", &self.address())
159 0 : .field("modtime", &self.modtime())
160 0 : .field("inode", &self.inode())
161 0 : .field("padding", &self.padding())
162 0 : .finish()
163 0 :
164 0 : }
165 : }
|