1 //! A header contains minimal architecture information, the binary kind, the number of load commands, as well as an endianness hint
2 
3 use core::fmt;
4 use scroll::ctx;
5 use scroll::{Pread, Pwrite, SizeWith};
6 use scroll::ctx::SizeWith;
7 use plain::Plain;
8 
9 use crate::mach::constants::cputype::{CpuType, CpuSubType, CPU_SUBTYPE_MASK};
10 use crate::error;
11 use crate::container::{self, Container};
12 
13 // Constants for the flags field of the mach_header
14 /// the object file has no undefined references
15 pub const MH_NOUNDEFS: u32 = 0x1;
16 /// the object file is the output of an incremental link against a base file and can't be
17 /// link edited again
18 pub const MH_INCRLINK: u32 = 0x2;
19 /// the object file is input for the dynamic linker and can't be staticly link edited again
20 pub const MH_DYLDLINK: u32 = 0x4;
21 /// the object file's undefined references are bound by the dynamic linker when loaded.
22 pub const MH_BINDATLOAD: u32 = 0x8;
23 /// the file has its dynamic undefined references prebound.
24 pub const MH_PREBOUND: u32 = 0x10;
25 /// the file has its read-only and read-write segments split
26 pub const MH_SPLIT_SEGS: u32 = 0x20;
27 /// the shared library init routine is to be run lazily via catching memory faults to its writeable
28 /// segments (obsolete)
29 pub const MH_LAZY_INIT: u32 = 0x40;
30 /// the image is using two-level name space bindings
31 pub const MH_TWOLEVEL: u32 = 0x80;
32 /// the executable is forcing all images to use flat name space bindings
33 pub const MH_FORCE_FLAT: u32 = 0x100;
34 /// this umbrella guarantees no multiple defintions of symbols in its sub-images so the
35 /// two-level namespace hints can always be used.
36 pub const MH_NOMULTIDEFS: u32 = 0x200;
37 /// do not have dyld notify the prebinding agent about this executable
38 pub const MH_NOFIXPREBINDING: u32 = 0x400;
39 /// the binary is not prebound but can have its prebinding redone. only used when MH_PREBOUND is not set.
40 pub const MH_PREBINDABLE: u32 = 0x800;
41 /// indicates that this binary binds to all two-level namespace modules of its dependent libraries.
42 /// Only used when MH_PREBINDABLE and MH_TWOLEVEL are both set.
43 pub const MH_ALLMODSBOUND: u32 = 0x1000;
44 /// safe to divide up the sections into sub-sections via symbols for dead code stripping
45 pub const MH_SUBSECTIONS_VIA_SYMBOLS: u32 = 0x2000;
46 /// the binary has been canonicalized via the unprebind operation
47 pub const MH_CANONICAL: u32 = 0x4000;
48 /// the final linked image contains external weak symbols
49 pub const MH_WEAK_DEFINES: u32 = 0x8000;
50 /// the final linked image uses weak symbols
51 pub const MH_BINDS_TO_WEAK: u32 = 0x10000;
52 /// When this bit is set, all stacks in the task will be given stack execution privilege.
53 /// Only used in MH_EXECUTE filetypes.
54 pub const MH_ALLOW_STACK_EXECUTION: u32 = 0x20000;
55 /// When this bit is set, the binary declares it is safe for use in processes with uid zero
56 pub const MH_ROOT_SAFE: u32 = 0x40000;
57 /// When this bit is set, the binary declares it is safe for use in processes when issetugid() is true
58 pub const MH_SETUID_SAFE: u32 = 0x80000;
59 /// When this bit is set on a dylib,  the static linker does not need to examine dependent dylibs to
60 /// see if any are re-exported
61 pub const MH_NO_REEXPORTED_DYLIBS: u32 = 0x0010_0000;
62 /// When this bit is set, the OS will load the main executable at a random address.
63 /// Only used in MH_EXECUTE filetypes.
64 pub const MH_PIE: u32 = 0x0020_0000;
65 /// Only for use on dylibs.  When linking against a dylib that has this bit set, the static linker
66 /// will automatically not create a LC_LOAD_DYLIB load command to the dylib if no symbols are being
67 /// referenced from the dylib.
68 pub const MH_DEAD_STRIPPABLE_DYLIB: u32 = 0x0040_0000;
69 /// Contains a section of type S_THREAD_LOCAL_VARIABLES
70 pub const MH_HAS_TLV_DESCRIPTORS: u32 = 0x0080_0000;
71 /// When this bit is set, the OS will run the main executable with a non-executable heap even on
72 /// platforms (e.g. i386) that don't require it. Only used in MH_EXECUTE filetypes.
73 pub const MH_NO_HEAP_EXECUTION: u32 = 0x0100_0000;
74 
75 // TODO: verify this number is correct, it was previously 0x02000000 which could indicate a typo/data entry error
76 /// The code was linked for use in an application extension.
77 pub const MH_APP_EXTENSION_SAFE: u32 = 0x0200_0000;
78 
79 #[inline(always)]
flag_to_str(flag: u32) -> &'static str80 pub fn flag_to_str(flag: u32) -> &'static str {
81     match flag {
82         MH_NOUNDEFS => "MH_NOUNDEFS",
83         MH_INCRLINK => "MH_INCRLINK",
84         MH_DYLDLINK => "MH_DYLDLINK",
85         MH_BINDATLOAD => "MH_BINDATLOAD",
86         MH_PREBOUND => "MH_PREBOUND",
87         MH_SPLIT_SEGS => "MH_SPLIT_SEGS",
88         MH_LAZY_INIT => "MH_LAZY_INIT",
89         MH_TWOLEVEL => "MH_TWOLEVEL",
90         MH_FORCE_FLAT => "MH_FORCE_FLAT",
91         MH_NOMULTIDEFS => "MH_NOMULTIDEFS",
92         MH_NOFIXPREBINDING => "MH_NOFIXPREBINDING",
93         MH_PREBINDABLE => "MH_PREBINDABLE ",
94         MH_ALLMODSBOUND => "MH_ALLMODSBOUND",
95         MH_SUBSECTIONS_VIA_SYMBOLS => "MH_SUBSECTIONS_VIA_SYMBOLS",
96         MH_CANONICAL => "MH_CANONICAL",
97         MH_WEAK_DEFINES => "MH_WEAK_DEFINES",
98         MH_BINDS_TO_WEAK => "MH_BINDS_TO_WEAK",
99         MH_ALLOW_STACK_EXECUTION => "MH_ALLOW_STACK_EXECUTION",
100         MH_ROOT_SAFE => "MH_ROOT_SAFE",
101         MH_SETUID_SAFE => "MH_SETUID_SAFE",
102         MH_NO_REEXPORTED_DYLIBS => "MH_NO_REEXPORTED_DYLIBS",
103         MH_PIE => "MH_PIE",
104         MH_DEAD_STRIPPABLE_DYLIB => "MH_DEAD_STRIPPABLE_DYLIB",
105         MH_HAS_TLV_DESCRIPTORS => "MH_HAS_TLV_DESCRIPTORS",
106         MH_NO_HEAP_EXECUTION => "MH_NO_HEAP_EXECUTION",
107         MH_APP_EXTENSION_SAFE => "MH_APP_EXTENSION_SAFE",
108         _ => "UNKNOWN FLAG",
109     }
110 }
111 
112 /// Mach Header magic constant
113 pub const MH_MAGIC: u32 = 0xfeed_face;
114 pub const MH_CIGAM: u32 = 0xcefa_edfe;
115 /// Mach Header magic constant for 64-bit
116 pub const MH_MAGIC_64: u32 = 0xfeed_facf;
117 pub const MH_CIGAM_64: u32 = 0xcffa_edfe;
118 
119 // Constants for the filetype field of the mach_header
120 /// relocatable object file
121 pub const MH_OBJECT: u32 = 0x1;
122 /// demand paged executable file
123 pub const MH_EXECUTE: u32 = 0x2;
124 /// fixed VM shared library file
125 pub const MH_FVMLIB: u32 = 0x3;
126 /// core file
127 pub const MH_CORE: u32 = 0x4;
128 /// preloaded executable file
129 pub const MH_PRELOAD: u32 = 0x5;
130 /// dynamically bound shared library
131 pub const MH_DYLIB: u32 = 0x6;
132 /// dynamic link editor
133 pub const MH_DYLINKER: u32 = 0x7;
134 /// dynamically bound bundle file
135 pub const MH_BUNDLE: u32 = 0x8;
136 /// shared library stub for static linking only, no section contents
137 pub const MH_DYLIB_STUB: u32 = 0x9;
138 /// companion file with only debug sections
139 pub const MH_DSYM: u32 = 0xa;
140 /// x86_64 kexts
141 pub const MH_KEXT_BUNDLE: u32 = 0xb;
142 
filetype_to_str(filetype: u32) -> &'static str143 pub fn filetype_to_str(filetype: u32) -> &'static str {
144     match filetype {
145         MH_OBJECT => "OBJECT",
146         MH_EXECUTE => "EXECUTE",
147         MH_FVMLIB => "FVMLIB",
148         MH_CORE => "CORE",
149         MH_PRELOAD => "PRELOAD",
150         MH_DYLIB => "DYLIB",
151         MH_DYLINKER => "DYLINKER",
152         MH_BUNDLE => "BUNDLE",
153         MH_DYLIB_STUB => "DYLIB_STUB",
154         MH_DSYM => "DSYM",
155         MH_KEXT_BUNDLE => "KEXT_BUNDLE",
156         _ => "UNKNOWN FILETYPE",
157     }
158 }
159 
160 #[repr(C)]
161 #[derive(Clone, Copy, Default, Debug)]
162 #[derive(Pread, Pwrite, SizeWith)]
163 /// A 32-bit Mach-o header
164 pub struct Header32 {
165     /// mach magic number identifier
166     pub magic: u32,
167     /// cpu specifier
168     pub cputype: u32,
169     /// machine specifier
170     pub cpusubtype: u32,
171     /// type of file
172     pub filetype: u32,
173     /// number of load commands
174     pub ncmds: u32,
175     /// the size of all the load commands
176     pub sizeofcmds: u32,
177     /// flags
178     pub flags: u32,
179 }
180 
181 pub const SIZEOF_HEADER_32: usize = 0x1c;
182 
183 unsafe impl Plain for Header32 {}
184 
185 impl Header32 {
186     /// Transmutes the given byte array into the corresponding 32-bit Mach-o header
from_bytes(bytes: &[u8; SIZEOF_HEADER_32]) -> &Self187     pub fn from_bytes(bytes: &[u8; SIZEOF_HEADER_32]) -> &Self {
188         plain::from_bytes(bytes).unwrap()
189     }
size(&self) -> usize190     pub fn size(&self) -> usize {
191         SIZEOF_HEADER_32
192     }
193 }
194 
195 #[repr(C)]
196 #[derive(Clone, Copy, Default, Debug)]
197 #[derive(Pread, Pwrite, SizeWith)]
198 /// A 64-bit Mach-o header
199 pub struct Header64 {
200     /// mach magic number identifier
201     pub magic: u32,
202     /// cpu specifier
203     pub cputype: u32,
204     /// machine specifier
205     pub cpusubtype: u32,
206     /// type of file
207     pub filetype: u32,
208     /// number of load commands
209     pub ncmds: u32,
210     /// the size of all the load commands
211     pub sizeofcmds: u32,
212     /// flags
213     pub flags: u32,
214     pub reserved: u32,
215 }
216 
217 unsafe impl Plain for Header64 {}
218 
219 pub const SIZEOF_HEADER_64: usize = 32;
220 
221 impl Header64 {
222     /// Transmutes the given byte array into the corresponding 64-bit Mach-o header
from_bytes(bytes: &[u8; SIZEOF_HEADER_64]) -> &Self223     pub fn from_bytes(bytes: &[u8; SIZEOF_HEADER_64]) -> &Self {
224         plain::from_bytes(bytes).unwrap()
225     }
size(&self) -> usize226     pub fn size(&self) -> usize {
227         SIZEOF_HEADER_64
228     }
229 }
230 
231 #[repr(C)]
232 #[derive(Clone, Copy, Default)]
233 /// Generic sized header
234 pub struct Header {
235     pub magic: u32,
236     pub cputype: u32,
237     pub cpusubtype: u32,
238     /// type of file
239     pub filetype: u32,
240     /// number of load commands
241     pub ncmds: usize,
242     /// the size of all the load commands
243     pub sizeofcmds: u32,
244     /// flags
245     pub flags: u32,
246     pub reserved: u32,
247 }
248 
249 impl fmt::Debug for Header {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result250     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
251         f.debug_struct("Header")
252             .field("magic", &format_args!("0x{:x}", self.magic))
253             .field("cputype", &self.cputype())
254             .field("cpusubtype", &format_args!("0x{:x}", self.cpusubtype()))
255             .field("filetype", &filetype_to_str(self.filetype))
256             .field("ncmds", &self.ncmds)
257             .field("sizeofcmds", &self.sizeofcmds)
258             .field("flags", &format_args!("0x{:x}", self.flags))
259             .field("reserved", &format_args!("0x{:x}", self.reserved))
260             .finish()
261     }
262 }
263 
264 impl From<Header32> for Header {
from(header: Header32) -> Self265     fn from (header: Header32) -> Self {
266         Header {
267             magic:      header.magic,
268             cputype:    header.cputype,
269             cpusubtype: header.cpusubtype,
270             filetype:   header.filetype,
271             ncmds:      header.ncmds as usize,
272             sizeofcmds: header.sizeofcmds,
273             flags:      header.flags,
274             reserved:   0,
275         }
276     }
277 }
278 
279 impl From<Header> for Header32 {
from(header: Header) -> Self280     fn from (header: Header) -> Self {
281         Header32 {
282             magic:      header.magic,
283             cputype:    header.cputype,
284             cpusubtype: header.cpusubtype,
285             filetype:   header.filetype,
286             ncmds:      header.ncmds as u32,
287             sizeofcmds: header.sizeofcmds,
288             flags:      header.flags,
289         }
290     }
291 }
292 
293 impl From<Header64> for Header {
from(header: Header64) -> Self294     fn from (header: Header64) -> Self {
295         Header {
296             magic:      header.magic,
297             cputype:    header.cputype,
298             cpusubtype: header.cpusubtype,
299             filetype:   header.filetype,
300             ncmds:      header.ncmds as usize,
301             sizeofcmds: header.sizeofcmds,
302             flags:      header.flags,
303             reserved:   header.reserved,
304         }
305     }
306 }
307 
308 impl From<Header> for Header64 {
from(header: Header) -> Self309     fn from (header: Header) -> Self {
310         Header64 {
311             magic:      header.magic,
312             cputype:    header.cputype,
313             cpusubtype: header.cpusubtype,
314             filetype:   header.filetype,
315             ncmds:      header.ncmds as u32,
316             sizeofcmds: header.sizeofcmds,
317             flags:      header.flags,
318             reserved:   header.reserved,
319         }
320     }
321 }
322 
323 impl Header {
new(ctx: container::Ctx) -> Self324     pub fn new(ctx: container::Ctx) -> Self {
325         let mut header = Header::default();
326         header.magic = if ctx.is_big () { MH_MAGIC_64 } else { MH_MAGIC };
327         header
328     }
329     /// Returns the cpu type
cputype(&self) -> CpuType330     pub fn cputype(&self) -> CpuType {
331         self.cputype
332     }
333     /// Returns the cpu subtype with the capabilities removed
cpusubtype(&self) -> CpuSubType334     pub fn cpusubtype(&self) -> CpuSubType {
335         self.cpusubtype & !CPU_SUBTYPE_MASK
336     }
337     /// Returns the capabilities of the CPU
cpu_caps(&self) -> u32338     pub fn cpu_caps(&self) -> u32 {
339         (self.cpusubtype & CPU_SUBTYPE_MASK) >> 24
340     }
341 }
342 
343 impl ctx::SizeWith<container::Ctx> for Header {
344     type Units = usize;
size_with(container: &container::Ctx) -> usize345     fn size_with(container: &container::Ctx) -> usize {
346         match container.container {
347             Container::Little => {
348                 SIZEOF_HEADER_32
349             },
350             Container::Big => {
351                 SIZEOF_HEADER_64
352             },
353         }
354     }
355 }
356 
357 impl ctx::SizeWith<Container> for Header {
358     type Units = usize;
size_with(container: &Container) -> usize359     fn size_with(container: &Container) -> usize {
360         match container {
361             Container::Little => {
362                 SIZEOF_HEADER_32
363             },
364             Container::Big => {
365                 SIZEOF_HEADER_64
366             },
367         }
368     }
369 }
370 
371 impl<'a> ctx::TryFromCtx<'a, container::Ctx> for Header {
372     type Error = crate::error::Error;
373     type Size = usize;
374     fn try_from_ctx(bytes: &'a [u8], container::Ctx { le, container }: container::Ctx) -> error::Result<(Self, Self::Size)> {
375         let size = bytes.len();
376         if size < SIZEOF_HEADER_32 || size < SIZEOF_HEADER_64 {
377             let error = error::Error::Malformed("bytes size is smaller than a Mach-o header".into());
378             Err(error)
379         } else {
380             match container {
381                 Container::Little => {
382                     let header = bytes.pread_with::<Header32>(0, le)?;
383                     Ok((Header::from(header), SIZEOF_HEADER_32))
384                 },
385                 Container::Big => {
386                     let header = bytes.pread_with::<Header64>(0, le)?;
387                     Ok((Header::from(header), SIZEOF_HEADER_64))
388                 },
389             }
390         }
391     }
392 }
393 
394 impl ctx::TryIntoCtx<container::Ctx> for Header {
395     type Error = crate::error::Error;
396     type Size = usize;
try_into_ctx(self, bytes: &mut [u8], ctx: container::Ctx) -> error::Result<Self::Size>397     fn try_into_ctx(self, bytes: &mut [u8], ctx: container::Ctx) -> error::Result<Self::Size> {
398         match ctx.container {
399             Container::Little => {
400                 bytes.pwrite_with(Header32::from(self), 0, ctx.le)?;
401             },
402             Container::Big => {
403                 bytes.pwrite_with(Header64::from(self), 0, ctx.le)?;
404             }
405         };
406         Ok(Header::size_with(&ctx))
407     }
408 }
409 
410 impl ctx::IntoCtx<container::Ctx> for Header {
into_ctx(self, bytes: &mut [u8], ctx: container::Ctx)411     fn into_ctx(self, bytes: &mut [u8], ctx: container::Ctx) {
412         bytes.pwrite_with(self, 0, ctx).unwrap();
413     }
414 }
415 
416 #[cfg(test)]
417 mod tests {
418     use std::mem::size_of;
419     use super::*;
420 
421     #[test]
test_parse_armv7_header()422     fn test_parse_armv7_header() {
423         use crate::mach::constants::cputype::CPU_TYPE_ARM;
424         const CPU_SUBTYPE_ARM_V7: u32 = 9;
425         use super::Header;
426         use crate::container::{Ctx, Container, Endian};
427         use scroll::{Pread};
428         let bytes = b"\xce\xfa\xed\xfe\x0c\x00\x00\x00\t\x00\x00\x00\n\x00\x00\x00\x06\x00\x00\x00\x8c\r\x00\x00\x00\x00\x00\x00\x1b\x00\x00\x00\x18\x00\x00\x00\xe0\xf7B\xbb\x1c\xf50w\xa6\xf7u\xa3\xba(";
429         let header: Header = bytes.pread_with(0, Ctx::new(Container::Little, Endian::Little)).unwrap();
430         assert_eq!(header.cputype, CPU_TYPE_ARM);
431         assert_eq!(header.cpusubtype, CPU_SUBTYPE_ARM_V7);
432     }
433 
434     #[test]
sizeof_header32()435     fn sizeof_header32() {
436         assert_eq!(SIZEOF_HEADER_32, size_of::<Header32>());
437     }
438 
439     #[test]
sizeof_header64()440     fn sizeof_header64() {
441         assert_eq!(SIZEOF_HEADER_64, size_of::<Header64>());
442     }
443 }
444