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