Line data Source code
1 : use lief_ffi as ffi;
2 :
3 : use bitflags::bitflags;
4 :
5 : use std::{fmt, marker::PhantomData};
6 : use crate::common::FromFFI;
7 :
8 : #[allow(non_camel_case_types)]
9 140 : #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
10 : pub enum FileType {
11 : OBJECT,
12 : EXECUTE,
13 : FVMLIB,
14 : CORE,
15 : PRELOAD,
16 : DYLIB,
17 : DYLINKER,
18 : BUNDLE,
19 : DYLIB_STUB,
20 : DSYM,
21 : KEXT_BUNDLE,
22 : UNKNOWN(u32),
23 : }
24 :
25 : impl From<u32> for FileType {
26 140 : fn from(value: u32) -> Self {
27 140 : match value {
28 10 : 0x00000001 => FileType::OBJECT,
29 40 : 0x00000002 => FileType::EXECUTE,
30 0 : 0x00000003 => FileType::FVMLIB,
31 0 : 0x00000004 => FileType::CORE,
32 0 : 0x00000005 => FileType::PRELOAD,
33 90 : 0x00000006 => FileType::DYLIB,
34 0 : 0x00000007 => FileType::DYLINKER,
35 0 : 0x00000008 => FileType::BUNDLE,
36 0 : 0x00000009 => FileType::DYLIB_STUB,
37 0 : 0x0000000a => FileType::DSYM,
38 0 : 0x0000000b => FileType::KEXT_BUNDLE,
39 0 : _ => FileType::UNKNOWN(value),
40 :
41 : }
42 140 : }
43 : }
44 : impl From<FileType> for u32 {
45 0 : fn from(value: FileType) -> u32 {
46 0 : match value {
47 0 : FileType::OBJECT => 0x00000001,
48 0 : FileType::EXECUTE => 0x00000002,
49 0 : FileType::FVMLIB => 0x00000003,
50 0 : FileType::CORE => 0x00000004,
51 0 : FileType::PRELOAD => 0x00000005,
52 0 : FileType::DYLIB => 0x00000006,
53 0 : FileType::DYLINKER => 0x00000007,
54 0 : FileType::BUNDLE => 0x00000008,
55 0 : FileType::DYLIB_STUB => 0x00000009,
56 0 : FileType::DSYM => 0x0000000a,
57 0 : FileType::KEXT_BUNDLE => 0x0000000b,
58 0 : FileType::UNKNOWN(_) => 0xFF,
59 : }
60 0 : }
61 : }
62 :
63 :
64 : #[allow(non_camel_case_types)]
65 140 : #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
66 : pub enum CpuType {
67 : ANY,
68 : X86,
69 : X86_64,
70 : MIPS,
71 : MC98000,
72 : ARM,
73 : ARM64,
74 : SPARC,
75 : POWERPC,
76 : POWERPC64,
77 : UNKNOWN(i32),
78 : }
79 :
80 : impl From<i32> for CpuType {
81 140 : fn from(value: i32) -> Self {
82 140 : match value {
83 0 : -1 => CpuType::ANY,
84 20 : 0x00000007 => CpuType::X86,
85 40 : 0x01000007 => CpuType::X86_64,
86 0 : 0x00000008 => CpuType::MIPS,
87 0 : 0x0000000a => CpuType::MC98000,
88 20 : 0x0000000c => CpuType::ARM,
89 60 : 0x0100000c => CpuType::ARM64,
90 0 : 0x0000000e => CpuType::SPARC,
91 0 : 0x00000012 => CpuType::POWERPC,
92 0 : 0x01000012 => CpuType::POWERPC64,
93 0 : _ => CpuType::UNKNOWN(value),
94 :
95 : }
96 140 : }
97 : }
98 : impl From<CpuType> for i32 {
99 0 : fn from(value: CpuType) -> i32 {
100 0 : match value {
101 0 : CpuType::ANY => -1,
102 0 : CpuType::X86 => 0x00000007,
103 0 : CpuType::X86_64 => 0x01000007,
104 0 : CpuType::MIPS => 0x00000008,
105 0 : CpuType::MC98000 => 0x0000000a,
106 0 : CpuType::ARM => 0x0000000c,
107 0 : CpuType::ARM64 => 0x0100000c,
108 0 : CpuType::SPARC => 0x0000000e,
109 0 : CpuType::POWERPC => 0x00000012,
110 0 : CpuType::POWERPC64 => 0x01000012,
111 0 : CpuType::UNKNOWN(_) => -1,
112 :
113 : }
114 0 : }
115 : }
116 :
117 :
118 0 : bitflags! {
119 140 : #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
120 0 : pub struct Flags: u32 {
121 0 : const NOUNDEFS = 0x1;
122 0 : const INCRLINK = 0x2;
123 0 : const DYLDLINK = 0x4;
124 0 : const BINDATLOAD = 0x8;
125 0 : const PREBOUND = 0x10;
126 0 : const SPLIT_SEGS = 0x20;
127 0 : const LAZY_INIT = 0x40;
128 0 : const TWOLEVEL = 0x80;
129 0 : const FORCE_FLAT = 0x100;
130 0 : const NOMULTIDEFS = 0x200;
131 0 : const NOFIXPREBINDING = 0x400;
132 0 : const PREBINDABLE = 0x800;
133 0 : const ALLMODSBOUND = 0x1000;
134 0 : const SUBSECTIONS_VIA_SYMBOLS = 0x2000;
135 0 : const CANONICAL = 0x4000;
136 0 : const WEAK_DEFINES = 0x8000;
137 0 : const BINDS_TO_WEAK = 0x10000;
138 0 : const ALLOW_STACK_EXECUTION = 0x20000;
139 0 : const ROOT_SAFE = 0x40000;
140 0 : const SETUID_SAFE = 0x80000;
141 0 : const NO_REEXPORTED_DYLIBS = 0x100000;
142 0 : const PIE = 0x200000;
143 0 : const DEAD_STRIPPABLE_DYLIB = 0x400000;
144 0 : const HAS_TLV_DESCRIPTORS = 0x800000;
145 0 : const NO_HEAP_EXECUTION = 0x1000000;
146 0 : const APP_EXTENSION_SAFE = 0x2000000;
147 0 : }
148 0 : }
149 :
150 :
151 : impl From<u32> for Flags {
152 140 : fn from(value: u32) -> Self {
153 140 : Flags::from_bits_truncate(value)
154 140 : }
155 : }
156 : impl From<Flags> for u32 {
157 0 : fn from(value: Flags) -> Self {
158 0 : value.bits()
159 0 : }
160 : }
161 :
162 : /// Structure that represents the main Mach-O header (at the beginning of the file)
163 : pub struct Header<'a> {
164 : ptr: cxx::UniquePtr<ffi::MachO_Header>,
165 : _owner: PhantomData<&'a ffi::MachO_Binary>
166 : }
167 :
168 : impl FromFFI<ffi::MachO_Header> for Header<'_> {
169 140 : fn from_ffi(hdr: cxx::UniquePtr<ffi::MachO_Header>) -> Self {
170 140 : Self {
171 140 : ptr: hdr,
172 140 : _owner: PhantomData
173 140 : }
174 140 : }
175 : }
176 :
177 : impl Header<'_> {
178 : /// The Mach-O magic bytes. These bytes determine whether it is
179 : /// a 32 bits Mach-O, a 64 bits Mach-O files etc.
180 140 : pub fn magic(&self) -> u32 {
181 140 : self.ptr.magic()
182 140 : }
183 :
184 : /// The CPU architecture targeted by this binary
185 140 : pub fn cpu_type(&self) -> CpuType {
186 140 : CpuType::from(self.ptr.cpu_type())
187 140 : }
188 :
189 : /// Return the CPU subtype supported by the Mach-O binary.
190 : /// For ARM architectures, this value could represent the minimum version
191 : /// for which the Mach-O binary has been compiled for.
192 140 : pub fn cpu_subtype(&self) -> u32 {
193 140 : self.ptr.cpu_subtype()
194 140 : }
195 :
196 : /// Return the type of the Mach-O file (executable, object, shared library, ...)
197 140 : pub fn file_type(&self) -> FileType {
198 140 : FileType::from(self.ptr.file_type())
199 140 : }
200 :
201 : /// Number of [`crate::macho::Commands`] present in the Mach-O binary
202 140 : pub fn nb_cmds(&self) -> u32 {
203 140 : self.ptr.nb_cmds()
204 140 : }
205 :
206 : /// The raw size of **all** the load commands (`LC_xxx`)
207 140 : pub fn sizeof_cmds(&self) -> u32 {
208 140 : self.ptr.sizeof_cmds()
209 140 : }
210 :
211 : /// Header flags
212 140 : pub fn flags(&self) -> Flags {
213 140 : Flags::from(self.ptr.flags())
214 140 : }
215 :
216 : /// According to the official specs, a reserved value
217 140 : pub fn reserved(&self) -> u32 {
218 140 : self.ptr.reserved()
219 140 : }
220 : }
221 :
222 : impl fmt::Debug for Header<'_> {
223 140 : fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
224 140 : f.debug_struct("Header")
225 140 : .field("magic", &self.magic())
226 140 : .field("cpu_type", &self.cpu_type())
227 140 : .field("cpu_subtype", &self.cpu_subtype())
228 140 : .field("file_type", &self.file_type())
229 140 : .field("nb_cmds", &self.nb_cmds())
230 140 : .field("sizeof_cmds", &self.sizeof_cmds())
231 140 : .field("flags", &self.flags())
232 140 : .field("reserved", &self.reserved())
233 140 : .finish()
234 140 : }
235 : }
|