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 : HPPA,
73 : ARM,
74 : ARM64,
75 : MC88000,
76 : SPARC,
77 : I860,
78 : ALPHA,
79 : POWERPC,
80 : POWERPC64,
81 : UNKNOWN(i32),
82 : }
83 :
84 : impl From<i32> for CpuType {
85 140 : fn from(value: i32) -> Self {
86 140 : match value {
87 0 : -1 => CpuType::ANY,
88 20 : 0x00000007 => CpuType::X86,
89 40 : 0x01000007 => CpuType::X86_64,
90 0 : 0x00000008 => CpuType::MIPS,
91 0 : 0x0000000a => CpuType::MC98000,
92 0 : 0x0000000b => CpuType::HPPA,
93 20 : 0x0000000c => CpuType::ARM,
94 60 : 0x0100000c => CpuType::ARM64,
95 0 : 0x0000000d => CpuType::MC88000,
96 0 : 0x0000000e => CpuType::SPARC,
97 0 : 0x0000000f => CpuType::I860,
98 0 : 0x00000010 => CpuType::ALPHA,
99 0 : 0x00000012 => CpuType::POWERPC,
100 0 : 0x01000012 => CpuType::POWERPC64,
101 0 : _ => CpuType::UNKNOWN(value),
102 :
103 : }
104 140 : }
105 : }
106 : impl From<CpuType> for i32 {
107 0 : fn from(value: CpuType) -> i32 {
108 0 : match value {
109 0 : CpuType::ANY => -1,
110 0 : CpuType::X86 => 0x00000007,
111 0 : CpuType::X86_64 => 0x01000007,
112 0 : CpuType::MIPS => 0x00000008,
113 0 : CpuType::MC98000 => 0x0000000a,
114 0 : CpuType::HPPA => 0x0000000b,
115 0 : CpuType::ARM => 0x0000000c,
116 0 : CpuType::ARM64 => 0x0100000c,
117 0 : CpuType::MC88000 => 0x0000000d,
118 0 : CpuType::SPARC => 0x0000000e,
119 0 : CpuType::I860 => 0x0000000f,
120 0 : CpuType::ALPHA => 0x00000010,
121 0 : CpuType::POWERPC => 0x00000012,
122 0 : CpuType::POWERPC64 => 0x01000012,
123 0 : CpuType::UNKNOWN(_) => -1,
124 : }
125 0 : }
126 : }
127 :
128 :
129 0 : bitflags! {
130 140 : #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
131 0 : pub struct Flags: u32 {
132 0 : const NOUNDEFS = 0x1;
133 0 : const INCRLINK = 0x2;
134 0 : const DYLDLINK = 0x4;
135 0 : const BINDATLOAD = 0x8;
136 0 : const PREBOUND = 0x10;
137 0 : const SPLIT_SEGS = 0x20;
138 0 : const LAZY_INIT = 0x40;
139 0 : const TWOLEVEL = 0x80;
140 0 : const FORCE_FLAT = 0x100;
141 0 : const NOMULTIDEFS = 0x200;
142 0 : const NOFIXPREBINDING = 0x400;
143 0 : const PREBINDABLE = 0x800;
144 0 : const ALLMODSBOUND = 0x1000;
145 0 : const SUBSECTIONS_VIA_SYMBOLS = 0x2000;
146 0 : const CANONICAL = 0x4000;
147 0 : const WEAK_DEFINES = 0x8000;
148 0 : const BINDS_TO_WEAK = 0x10000;
149 0 : const ALLOW_STACK_EXECUTION = 0x20000;
150 0 : const ROOT_SAFE = 0x40000;
151 0 : const SETUID_SAFE = 0x80000;
152 0 : const NO_REEXPORTED_DYLIBS = 0x100000;
153 0 : const PIE = 0x200000;
154 0 : const DEAD_STRIPPABLE_DYLIB = 0x400000;
155 0 : const HAS_TLV_DESCRIPTORS = 0x800000;
156 0 : const NO_HEAP_EXECUTION = 0x1000000;
157 0 : const APP_EXTENSION_SAFE = 0x2000000;
158 0 : }
159 0 : }
160 :
161 :
162 : impl From<u32> for Flags {
163 140 : fn from(value: u32) -> Self {
164 140 : Flags::from_bits_truncate(value)
165 140 : }
166 : }
167 : impl From<Flags> for u32 {
168 0 : fn from(value: Flags) -> Self {
169 0 : value.bits()
170 0 : }
171 : }
172 :
173 : /// Structure that represents the main Mach-O header (at the beginning of the file)
174 : pub struct Header<'a> {
175 : ptr: cxx::UniquePtr<ffi::MachO_Header>,
176 : _owner: PhantomData<&'a ffi::MachO_Binary>
177 : }
178 :
179 : impl FromFFI<ffi::MachO_Header> for Header<'_> {
180 420 : fn from_ffi(hdr: cxx::UniquePtr<ffi::MachO_Header>) -> Self {
181 420 : Self {
182 420 : ptr: hdr,
183 420 : _owner: PhantomData
184 420 : }
185 420 : }
186 : }
187 :
188 : impl Header<'_> {
189 : /// The Mach-O magic bytes. These bytes determine whether it is
190 : /// a 32 bits Mach-O, a 64 bits Mach-O files etc.
191 140 : pub fn magic(&self) -> u32 {
192 140 : self.ptr.magic()
193 140 : }
194 :
195 : /// The CPU architecture targeted by this binary
196 140 : pub fn cpu_type(&self) -> CpuType {
197 140 : CpuType::from(self.ptr.cpu_type())
198 140 : }
199 :
200 : /// Return the CPU subtype supported by the Mach-O binary.
201 : /// For ARM architectures, this value could represent the minimum version
202 : /// for which the Mach-O binary has been compiled for.
203 140 : pub fn cpu_subtype(&self) -> u32 {
204 140 : self.ptr.cpu_subtype()
205 140 : }
206 :
207 : /// Return the type of the Mach-O file (executable, object, shared library, ...)
208 140 : pub fn file_type(&self) -> FileType {
209 140 : FileType::from(self.ptr.file_type())
210 140 : }
211 :
212 : /// Number of [`crate::macho::Commands`] present in the Mach-O binary
213 140 : pub fn nb_cmds(&self) -> u32 {
214 140 : self.ptr.nb_cmds()
215 140 : }
216 :
217 : /// The raw size of **all** the load commands (`LC_xxx`)
218 140 : pub fn sizeof_cmds(&self) -> u32 {
219 140 : self.ptr.sizeof_cmds()
220 140 : }
221 :
222 : /// Header flags
223 140 : pub fn flags(&self) -> Flags {
224 140 : Flags::from(self.ptr.flags())
225 140 : }
226 :
227 : /// According to the official specs, a reserved value
228 140 : pub fn reserved(&self) -> u32 {
229 140 : self.ptr.reserved()
230 140 : }
231 :
232 : /// True if the binary is 32-bit
233 140 : pub fn is_32bit(&self) -> bool {
234 140 : self.ptr.is_32bit()
235 140 : }
236 :
237 : /// True if the binary is 64-bit
238 140 : pub fn is_64bit(&self) -> bool {
239 140 : self.ptr.is_64bit()
240 140 : }
241 : }
242 :
243 : impl fmt::Debug for Header<'_> {
244 140 : fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
245 140 : f.debug_struct("Header")
246 140 : .field("magic", &self.magic())
247 140 : .field("cpu_type", &self.cpu_type())
248 140 : .field("cpu_subtype", &self.cpu_subtype())
249 140 : .field("file_type", &self.file_type())
250 140 : .field("nb_cmds", &self.nb_cmds())
251 140 : .field("sizeof_cmds", &self.sizeof_cmds())
252 140 : .field("flags", &self.flags())
253 140 : .field("reserved", &self.reserved())
254 140 : .finish()
255 140 : }
256 : }
|