]>
Commit | Line | Data |
---|---|---|
b1ab9ed8 | 1 | /* |
d8f41ccd | 2 | * Copyright (c) 2006,2011-2014 Apple Inc. All Rights Reserved. |
b1ab9ed8 A |
3 | * |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * This file contains Original Code and/or Modifications of Original Code | |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. Please obtain a copy of the License at | |
10 | * http://www.opensource.apple.com/apsl/ and read it before using this | |
11 | * file. | |
12 | * | |
13 | * The Original Code and all software distributed under the License are | |
14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
18 | * Please see the License for the specific language governing rights and | |
19 | * limitations under the License. | |
20 | * | |
21 | * @APPLE_LICENSE_HEADER_END@ | |
22 | */ | |
23 | ||
24 | // | |
25 | // macho++ - Mach-O object file helpers | |
26 | // | |
27 | #ifndef _H_MACHOPLUSPLUS | |
28 | #define _H_MACHOPLUSPLUS | |
29 | ||
30 | #include <mach-o/loader.h> | |
31 | #include <mach-o/fat.h> | |
32 | #include <mach-o/arch.h> | |
33 | #include <security_utilities/globalizer.h> | |
34 | #include <security_utilities/endian.h> | |
35 | #include <security_utilities/unix++.h> | |
36 | #include <security_utilities/cfutilities.h> | |
80e23899 | 37 | #include <map> |
b1ab9ed8 A |
38 | |
39 | namespace Security { | |
40 | ||
41 | ||
42 | // | |
43 | // An architecture specification. | |
44 | // Simply a pair or (cpu type, cpu subtype), really. | |
45 | // | |
46 | class Architecture : public std::pair<cpu_type_t, cpu_subtype_t> { | |
47 | typedef std::pair<cpu_type_t, cpu_subtype_t> _Pair; | |
48 | public: | |
49 | Architecture() { } | |
50 | explicit Architecture(cpu_type_t type, cpu_subtype_t sub = CPU_SUBTYPE_MULTIPLE) | |
51 | : std::pair<cpu_type_t, cpu_subtype_t>(type, sub) { } | |
52 | Architecture(const fat_arch &archInFile); | |
53 | Architecture(const char *name); | |
54 | ||
55 | cpu_type_t cpuType() const { return this->first; } | |
56 | cpu_subtype_t cpuSubtype() const { return this->second; } | |
57 | const char *name() const; // NULL if unknown | |
58 | std::string displayName() const; // always display-able | |
59 | ||
60 | static const cpu_type_t none = 0; | |
61 | operator bool () const { return cpuType() != none; } | |
62 | bool operator ! () const { return cpuType() == none; } | |
63 | ||
64 | public: | |
65 | friend bool operator == (const Architecture &a1, const Architecture &a2) | |
66 | { return _Pair(a1) == _Pair(a2); } | |
67 | ||
68 | friend bool operator < (const Architecture &a1, const Architecture &a2) | |
69 | { return _Pair(a1) < _Pair(a2); } | |
70 | ||
71 | bool matches(const Architecture &templ) const; | |
72 | ||
73 | public: | |
74 | static Architecture local(); | |
75 | }; | |
76 | ||
77 | ||
78 | // | |
79 | // Common features of Mach-O object images. | |
80 | // MachOBase does not define where we get this from. | |
81 | // | |
82 | class MachOBase { | |
83 | protected: | |
84 | virtual ~MachOBase(); | |
85 | ||
86 | public: | |
87 | template <class T> | |
88 | T flip(T value) const | |
89 | { return mFlip ? Security::flip(value) : value; } | |
90 | ||
91 | bool isFlipped() const { return mFlip; } | |
92 | bool is64() const { return m64; } | |
93 | ||
94 | const mach_header &header() const { return *mHeader; } | |
95 | Architecture architecture() const; | |
96 | uint32_t type() const; | |
97 | uint32_t flags() const; | |
98 | ||
99 | const load_command *loadCommands() const { return mCommands; } | |
100 | const load_command *nextCommand(const load_command *command) const; | |
101 | size_t commandLength() const { return flip(mHeader->sizeofcmds); } | |
102 | ||
103 | const load_command *findCommand(uint32_t cmd) const; | |
104 | const segment_command *findSegment(const char *segname) const; | |
105 | const section *findSection(const char *segname, const char *sectname) const; | |
106 | ||
107 | const char *string(const load_command *cmd, const lc_str &str) const; | |
108 | ||
109 | const linkedit_data_command *findCodeSignature() const; | |
110 | const linkedit_data_command *findLibraryDependencies() const; | |
e3d460c9 | 111 | const version_min_command *findMinVersion() const; |
b1ab9ed8 A |
112 | |
113 | size_t signingOffset() const; // starting offset of CS section, or 0 if none | |
114 | size_t signingLength() const; // length of CS section, or 0 if none | |
115 | ||
116 | protected: | |
117 | void initHeader(const mach_header *address); | |
118 | void initCommands(const load_command *commands); | |
119 | ||
120 | size_t headerSize() const; // size of header | |
121 | size_t commandSize() const; // size of commands area | |
122 | ||
123 | private: | |
124 | const mach_header *mHeader; // Mach-O header | |
125 | const load_command *mCommands; // load commands | |
126 | const load_command *mEndCommands; // end of load commands | |
127 | ||
128 | bool m64; // is 64-bit | |
129 | bool mFlip; // wrong byte order (flip all integers) | |
130 | }; | |
131 | ||
132 | ||
133 | // | |
134 | // A Mach-O object image that resides on disk. | |
135 | // We only read small parts of the contents into (discontinuous) memory. | |
136 | // | |
137 | class MachO : public MachOBase, public UnixPlusPlus::FileDesc { | |
138 | public: | |
139 | MachO(FileDesc fd, size_t offset = 0, size_t length = 0); | |
140 | ~MachO(); | |
141 | ||
142 | size_t offset() const { return mOffset; } | |
143 | size_t length() const { return mLength; } | |
144 | size_t signingExtent() const; // signingOffset, or file length if none | |
145 | ||
146 | void seek(size_t offset); // relative to start of image | |
147 | CFDataRef dataAt(size_t offset, size_t size); | |
80e23899 A |
148 | void validateStructure(); // is the structure of the mach-o sane |
149 | ||
150 | bool isSuspicious() const { return mSuspicious; } | |
b1ab9ed8 A |
151 | |
152 | private: | |
153 | size_t mOffset; // starting file offset | |
154 | size_t mLength; // Mach-O file length | |
155 | ||
156 | mach_header mHeaderBuffer; // read-in Mach-O header | |
157 | load_command *mCommandBuffer; // read-in (malloc'ed) Mach-O load commands | |
80e23899 A |
158 | |
159 | bool mSuspicious; // strict validation failed | |
b1ab9ed8 A |
160 | }; |
161 | ||
162 | ||
163 | // | |
164 | // A Mach-O object image that was mapped into memory. | |
165 | // We expect the entire image to be contiguously mapped starting at the | |
166 | // address given. No particular alignment is required (beyond native | |
167 | // alignment constraints on member variables). | |
168 | // | |
169 | class MachOImage : public MachOBase { | |
170 | public: | |
171 | MachOImage(const void *address); | |
172 | ||
173 | const void *address() { return &this->header(); } | |
174 | }; | |
175 | ||
176 | class MainMachOImage : public MachOImage { | |
177 | public: | |
178 | MainMachOImage(); | |
179 | ||
180 | static const void *mainImageAddress(); | |
181 | }; | |
182 | ||
183 | ||
184 | // | |
185 | // A Universal object represents a Mach-O binary image (whole) file. | |
186 | // It can represent a true Universal (aka "Fat") file with multiple | |
187 | // architectures; but it will also represent a single Mach-O ("thin") | |
188 | // binary and make you believe it's a Universal with just one architecture. | |
189 | // | |
190 | class Universal : public UnixPlusPlus::FileDesc { | |
191 | public: | |
80e23899 | 192 | Universal(FileDesc fd, size_t offset = 0, size_t length = 0); |
b1ab9ed8 A |
193 | ~Universal(); |
194 | ||
195 | // return a genuine MachO object for the given architecture | |
196 | MachO *architecture() const; // native | |
197 | MachO *architecture(const Architecture &arch) const; // given | |
427c49bc | 198 | MachO *architecture(size_t offset) const; // given by file offset |
b1ab9ed8 A |
199 | |
200 | // return (just) the starting offset of an architecture | |
201 | size_t archOffset() const; // native | |
202 | size_t archOffset(const Architecture &arch) const; // given | |
80e23899 | 203 | size_t archLength(const Architecture &arch) const; // given |
427c49bc | 204 | bool narrowed() const { return mBase != 0; } // part of a fat file |
b1ab9ed8 A |
205 | |
206 | // return a set of architectures contained | |
207 | typedef std::set<Architecture> Architectures; | |
80e23899 | 208 | void architectures(Architectures &archs) const; |
d8f41ccd | 209 | |
b1ab9ed8 A |
210 | bool isUniversal() const { return mArchList != NULL; } |
211 | Architecture bestNativeArch() const; | |
80e23899 | 212 | const size_t lengthOfSlice(size_t offset) const; |
d8f41ccd | 213 | |
e3d3b979 | 214 | size_t offset() const { return mBase; } |
80e23899 | 215 | size_t length() const { return mLength; } |
d8f41ccd | 216 | |
80e23899 | 217 | bool isSuspicious() const; |
e3d3b979 | 218 | |
b1ab9ed8 A |
219 | public: |
220 | static uint32_t typeOf(FileDesc fd); | |
221 | ||
222 | private: | |
223 | const fat_arch *findArch(const Architecture &arch) const; | |
224 | MachO *findImage(const Architecture &arch) const; | |
5c19dc3a | 225 | MachO *make(MachO* macho) const; |
b1ab9ed8 A |
226 | |
227 | private: | |
228 | fat_arch *mArchList; // architectures (NULL if thin file) | |
229 | unsigned mArchCount; // number of architectures (if fat) | |
230 | Architecture mThinArch; // single architecture (if thin) | |
427c49bc | 231 | size_t mBase; // overriding offset in file (all types) |
80e23899 A |
232 | size_t mLength; // length of the architecture if thin file |
233 | typedef std::map<size_t, size_t> OffsetsToLength; | |
234 | OffsetsToLength mSizes; // the length for the slice at a given offset | |
5c19dc3a | 235 | mutable uint32_t mMachType; // canonical Mach-O type (0 if not yet set) |
80e23899 | 236 | bool mSuspicious; // strict validation failed |
b1ab9ed8 A |
237 | }; |
238 | ||
239 | ||
240 | } // end namespace Security | |
241 | ||
242 | #endif // !_H_MACHOPLUSPLUS |