Line data Source code
1 : use std::mem::size_of;
2 : use std::pin::Pin;
3 : use num_traits::{Num, cast};
4 :
5 : use crate::Error;
6 : use super::commands::build_version::{BuildVersion, Platform};
7 : use super::commands::code_signature::CodeSignature;
8 : use super::commands::code_signature_dir::CodeSignatureDir;
9 : use super::commands::data_in_code::DataInCode;
10 : use super::commands::dyld_chained_fixups::DyldChainedFixups;
11 : use super::commands::dyld_environment::DyldEnvironment;
12 : use super::commands::dyld_export_trie::DyldExportsTrie;
13 : use super::commands::dyldinfo::DyldInfo;
14 : use super::commands::dylib::Libraries;
15 : use super::commands::dylinker::Dylinker;
16 : use super::commands::dynamic_symbol_command::DynamicSymbolCommand;
17 : use super::commands::encryption_info::EncryptionInfo;
18 : use super::commands::functionstarts::FunctionStarts;
19 : use super::commands::linker_opt_hint::LinkerOptHint;
20 : use super::commands::main_cmd::Main;
21 : use super::commands::rpath::RPath;
22 : use super::commands::routine::Routine;
23 : use super::commands::segment::Segments;
24 : use super::commands::segment_split_info::SegmentSplitInfo;
25 : use super::commands::source_version::SourceVersion;
26 : use super::commands::sub_framework::SubFramework;
27 : use super::commands::sub_client::SubClients;
28 : use super::commands::symbol_command::SymbolCommand;
29 : use super::commands::thread_command::ThreadCommand;
30 : use super::commands::two_level_hints::TwoLevelHints;
31 : use super::commands::uuid::UUID;
32 : use super::commands::version_min::VersionMin;
33 : use super::commands::CommandsIter;
34 : use super::header::Header;
35 : use super::relocation::Relocations;
36 : use super::section::Sections;
37 : use super::symbol::Symbols;
38 : use super::binding_info::BindingInfo;
39 : use super::stub::Stub;
40 : use lief_ffi as ffi;
41 :
42 : use crate::common::{into_optional, FromFFI};
43 : use crate::{generic, declare_fwd_iterator, declare_iterator, to_conv_result};
44 : use crate::objc::Metadata;
45 :
46 : /// This is the main interface to read and write Mach-O binary attributes.
47 : ///
48 : /// Note that this structure implements the [`generic::Binary`] trait from which other generic
49 : /// functions are exposed
50 : pub struct Binary {
51 : ptr: cxx::UniquePtr<ffi::MachO_Binary>,
52 : }
53 :
54 : impl std::fmt::Debug for Binary {
55 140 : fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
56 140 : f.debug_struct("Binary").finish()
57 140 : }
58 : }
59 :
60 : impl FromFFI<ffi::MachO_Binary> for Binary {
61 140 : fn from_ffi(ptr: cxx::UniquePtr<ffi::MachO_Binary>) -> Self {
62 140 : Binary { ptr }
63 140 : }
64 : }
65 :
66 : impl Binary {
67 : /// Return the main Mach-O header
68 140 : pub fn header(&self) -> Header {
69 140 : Header::from_ffi(self.ptr.header())
70 140 : }
71 :
72 : /// Return an iterator over the different [`crate::macho::Commands`] used by the
73 : /// Mach-O binary
74 140 : pub fn commands(&self) -> CommandsIter {
75 140 : CommandsIter::new(self.ptr.commands())
76 140 : }
77 :
78 : /// Return an iterator over the different [`crate::macho::Section`] of the binary
79 140 : pub fn sections(&self) -> Sections {
80 140 : Sections::new(self.ptr.sections())
81 140 : }
82 :
83 : /// Return an iterator over the different [`crate::macho::commands::Segment`] (`LC_SEGMENT/LC_SIGNATURE`)
84 : /// of the binary.
85 140 : pub fn segments(&self) -> Segments {
86 140 : Segments::new(self.ptr.segments())
87 140 : }
88 :
89 : /// Return an iterator over the [`crate::macho::commands::Dylib`] used by this binary
90 140 : pub fn libraries(&self) -> Libraries {
91 140 : Libraries::new(self.ptr.libraries())
92 140 : }
93 :
94 : /// Return an iterator over the different [`crate::macho::Relocation`] of this binary
95 140 : pub fn relocations(&self) -> Relocations {
96 140 : Relocations::new(self.ptr.relocations())
97 140 : }
98 :
99 : /// Return an iterator over the different [`crate::macho::Symbol`] of this binary
100 140 : pub fn symbols(&self) -> Symbols {
101 140 : Symbols::new(self.ptr.symbols())
102 140 : }
103 :
104 : /// Return the `LC_DYLD_INFO/LC_DYLD_INFO_ONLY` command if present
105 140 : pub fn dyld_info(&self) -> Option<DyldInfo> {
106 140 : into_optional(self.ptr.dyld_info())
107 140 : }
108 :
109 : /// Return the `LC_UUID` command if present
110 140 : pub fn uuid(&self) -> Option<UUID> {
111 140 : into_optional(self.ptr.uuid())
112 140 : }
113 :
114 : /// Return the `LC_MAIN` command if present
115 140 : pub fn main_command(&self) -> Option<Main> {
116 140 : into_optional(self.ptr.main_command())
117 140 : }
118 :
119 : /// Return the `LC_LOAD_DYLINKER/LC_ID_DYLINKER` command if present
120 140 : pub fn dylinker(&self) -> Option<Dylinker> {
121 140 : into_optional(self.ptr.dylinker())
122 140 : }
123 :
124 : /// Return the `LC_FUNCTION_STARTS` command if present
125 140 : pub fn function_starts(&self) -> Option<FunctionStarts> {
126 140 : into_optional(self.ptr.function_starts())
127 140 : }
128 :
129 : /// Return the `LC_SOURCE_VERSION` command if present
130 140 : pub fn source_version(&self) -> Option<SourceVersion> {
131 140 : into_optional(self.ptr.source_version())
132 140 : }
133 :
134 : /// Return the `LC_THREAD/LC_UNIXTHREAD` command if present
135 140 : pub fn thread_command(&self) -> Option<ThreadCommand> {
136 140 : into_optional(self.ptr.thread_command())
137 140 : }
138 :
139 : /// Return the `LC_RPATH` command if present
140 140 : pub fn rpath(&self) -> Option<RPath> {
141 140 : into_optional(self.ptr.rpath())
142 140 : }
143 :
144 : /// Return the `LC_ROUTINE/LC_ROUTINE64` command if present
145 140 : pub fn routine(&self) -> Option<Routine> {
146 140 : into_optional(self.ptr.routine_command())
147 140 : }
148 :
149 : /// Return the `LC_SYMTAB` command if present
150 140 : pub fn symbol_command(&self) -> Option<SymbolCommand> {
151 140 : into_optional(self.ptr.symbol_command())
152 140 : }
153 :
154 : /// Return the `LC_DYSYMTAB` command if present
155 140 : pub fn dynamic_symbol(&self) -> Option<DynamicSymbolCommand> {
156 140 : into_optional(self.ptr.dynamic_symbol_command())
157 140 : }
158 :
159 : /// Return the `LC_CODE_SIGNATURE` command if present
160 140 : pub fn code_signature(&self) -> Option<CodeSignature> {
161 140 : into_optional(self.ptr.code_signature())
162 140 : }
163 :
164 : /// Return the `LC_DYLIB_CODE_SIGN_DRS` command if present
165 140 : pub fn code_signature_dir(&self) -> Option<CodeSignatureDir> {
166 140 : into_optional(self.ptr.code_signature_dir())
167 140 : }
168 :
169 : /// Return the `LC_DATA_IN_CODE` command if present
170 140 : pub fn data_in_code(&self) -> Option<DataInCode> {
171 140 : into_optional(self.ptr.data_in_code())
172 140 : }
173 :
174 : /// Return the `LC_SEGMENT_SPLIT_INFO` command if present
175 140 : pub fn segment_split_info(&self) -> Option<SegmentSplitInfo> {
176 140 : into_optional(self.ptr.segment_split_info())
177 140 : }
178 :
179 : /// Return the `LC_ENCRYPTION_INFO/LC_ENCRYPTION_INFO_64` command if present
180 140 : pub fn encryption_info(&self) -> Option<EncryptionInfo> {
181 140 : into_optional(self.ptr.encryption_info())
182 140 : }
183 :
184 : /// Return the `LC_SUB_FRAMEWORK` command if present
185 140 : pub fn sub_framework(&self) -> Option<SubFramework> {
186 140 : into_optional(self.ptr.sub_framework())
187 140 : }
188 :
189 : /// Return the `LC_SUBCLIENT` command if present
190 140 : pub fn subclients(&self) -> SubClients {
191 140 : SubClients::new(self.ptr.subclients())
192 140 : }
193 :
194 : /// Return the `LC_DYLD_ENVIRONMENT` command if present
195 140 : pub fn dyld_environment(&self) -> Option<DyldEnvironment> {
196 140 : into_optional(self.ptr.dyld_environment())
197 140 : }
198 :
199 : /// Return the `LC_BUILD_VERSION` command if present
200 140 : pub fn build_version(&self) -> Option<BuildVersion> {
201 140 : into_optional(self.ptr.build_version())
202 140 : }
203 :
204 : /// Return the `LC_DYLD_CHAINED_FIXUPS` command if present
205 140 : pub fn dyld_chained_fixups(&self) -> Option<DyldChainedFixups> {
206 140 : into_optional(self.ptr.dyld_chained_fixups())
207 140 : }
208 :
209 : /// Return the `LC_DYLD_EXPORTS_TRIE` command if present
210 140 : pub fn dyld_exports_trie(&self) -> Option<DyldExportsTrie> {
211 140 : into_optional(self.ptr.dyld_exports_trie())
212 140 : }
213 :
214 : /// Return the `LC_TWOLEVEL_HINTS` command if present
215 140 : pub fn two_level_hints(&self) -> Option<TwoLevelHints> {
216 140 : into_optional(self.ptr.two_level_hints())
217 140 : }
218 :
219 : /// Return the `LC_LINKER_OPTIMIZATION_HINT` command if present
220 140 : pub fn linker_opt_hint(&self) -> Option<LinkerOptHint> {
221 140 : into_optional(self.ptr.linker_opt_hint())
222 140 : }
223 :
224 : /// Return the `LC_VERSION_MIN_MACOSX/VERSION_MIN_IPHONEOS` command if present
225 140 : pub fn version_min(&self) -> Option<VersionMin> {
226 140 : into_optional(self.ptr.version_min())
227 140 : }
228 :
229 : /// Check if the binary is supporting ARM64 pointer authentication (arm64e)
230 0 : pub fn support_arm64_ptr_auth(&self) -> bool {
231 0 : self.ptr.support_arm64_ptr_auth()
232 0 : }
233 :
234 : /// Return an iterator over the bindings located in [`DyldInfo`] or [`DyldChainedFixups`]
235 140 : pub fn bindings(&self) -> BindingsInfo {
236 140 : BindingsInfo::new(self.ptr.bindings())
237 140 : }
238 :
239 : /// Return an iterator over the symbol stubs.
240 : ///
241 : /// These stubs are involved when calling an **imported** function and are
242 : /// similar to the ELF's plt/got mechanism.
243 : ///
244 : /// There are located in sections like: `__stubs,__auth_stubs,__symbol_stub,__picsymbolstub4`
245 140 : pub fn symbol_stubs(&self) -> Stubs {
246 140 : Stubs::new(self.ptr.symbol_stubs())
247 140 : }
248 :
249 : /// Return Objective-C metadata if present
250 0 : pub fn objc_metadata(&self) -> Option<Metadata> {
251 0 : into_optional(self.ptr.objc_metadata())
252 0 : }
253 :
254 : /// Return the platform for which this Mach-O has been compiled for
255 140 : pub fn platform(&self) -> Platform {
256 140 : Platform::from(self.ptr.platform())
257 140 : }
258 :
259 : /// True if this binary targets iOS
260 140 : pub fn is_ios(&self) -> bool {
261 140 : self.ptr.is_ios()
262 140 : }
263 :
264 : /// True if this binary targets macOS
265 140 : pub fn is_macos(&self) -> bool {
266 140 : self.ptr.is_macos()
267 140 : }
268 :
269 :
270 : /// Get the integer value at the given virtual address
271 0 : pub fn get_int_from_virtual_address<T>(&self, addr: u64) -> Result<T, Error>
272 0 : where T: Num + cast::FromPrimitive + cast::ToPrimitive
273 0 : {
274 0 : // Can't be in the generic trait because of:
275 0 : // > for a trait to be "object safe" it needs to allow building a vtable to allow the call
276 0 : // > to be resolvable dynamically; for more information visit
277 0 : // > https://doc.rust-lang.org/reference/items/traits.html#object-safety
278 0 : if size_of::<T>() == size_of::<u8>() {
279 0 : to_conv_result!(ffi::AbstractBinary::get_u8,
280 0 : self.ptr.as_ref().unwrap().as_ref(),
281 0 : |value| { T::from_u8(value).expect(format!("Can't cast value: {}", value).as_str()) },
282 0 : addr);
283 0 : }
284 0 :
285 0 : if size_of::<T>() == size_of::<u16>() {
286 0 : to_conv_result!(ffi::AbstractBinary::get_u16,
287 0 : self.ptr.as_ref().unwrap().as_ref(),
288 0 : |value| { T::from_u16(value).expect(format!("Can't cast value: {}", value).as_str()) },
289 0 : addr);
290 0 : }
291 0 :
292 0 : if size_of::<T>() == size_of::<u32>() {
293 0 : to_conv_result!(ffi::AbstractBinary::get_u32,
294 0 : self.ptr.as_ref().unwrap().as_ref(),
295 0 : |value| { T::from_u32(value).expect(format!("Can't cast value: {}", value).as_str()) },
296 0 : addr);
297 0 : }
298 0 :
299 0 : if size_of::<T>() == size_of::<u64>() {
300 0 : to_conv_result!(ffi::AbstractBinary::get_u64,
301 0 : self.ptr.as_ref().unwrap().as_ref(),
302 0 : |value| { T::from_u64(value).expect(format!("Can't cast value: {}", value).as_str()) },
303 0 : addr);
304 0 : }
305 0 :
306 0 : Err(Error::NotSupported)
307 0 : }
308 : }
309 :
310 : impl generic::Binary for Binary {
311 140 : fn as_generic(&self) -> &ffi::AbstractBinary {
312 140 : self.ptr.as_ref().unwrap().as_ref()
313 140 : }
314 :
315 0 : fn as_pin_mut_generic(&mut self) -> Pin<&mut ffi::AbstractBinary> {
316 0 : unsafe {
317 0 : Pin::new_unchecked({
318 0 : (self.ptr.as_ref().unwrap().as_ref()
319 0 : as *const ffi::AbstractBinary
320 0 : as *mut ffi::AbstractBinary).as_mut().unwrap()
321 0 : })
322 0 : }
323 0 : }
324 : }
325 :
326 :
327 65690 : declare_fwd_iterator!(
328 65690 : BindingsInfo,
329 65690 : BindingInfo<'a>,
330 65690 : ffi::MachO_BindingInfo,
331 65690 : ffi::MachO_Binary,
332 65690 : ffi::MachO_Binary_it_bindings_info
333 65690 : );
334 :
335 15200 : declare_iterator!(
336 15200 : Stubs,
337 15200 : Stub<'a>,
338 15200 : ffi::MachO_Stub,
339 15200 : ffi::MachO_Binary,
340 15200 : ffi::MachO_Binary_it_stubs
341 15200 : );
|