1/* 2 * Copyright (c) 2006 Apple Computer, Inc. All Rights Reserved. 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> 37#include <map> 38 39namespace Security { 40 41 42// 43// An architecture specification. 44// Simply a pair or (cpu type, cpu subtype), really. 45// 46class Architecture : public std::pair<cpu_type_t, cpu_subtype_t> { 47 typedef std::pair<cpu_type_t, cpu_subtype_t> _Pair; 48public: 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 64public: 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 73public: 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// 82class MachOBase { 83protected: 84 virtual ~MachOBase(); 85 86public: 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; 111 112 size_t signingOffset() const; // starting offset of CS section, or 0 if none 113 size_t signingLength() const; // length of CS section, or 0 if none 114 115protected: 116 void initHeader(const mach_header *address); 117 void initCommands(const load_command *commands); 118 119 size_t headerSize() const; // size of header 120 size_t commandSize() const; // size of commands area 121 122private: 123 const mach_header *mHeader; // Mach-O header 124 const load_command *mCommands; // load commands 125 const load_command *mEndCommands; // end of load commands 126 127 bool m64; // is 64-bit 128 bool mFlip; // wrong byte order (flip all integers) 129}; 130 131 132// 133// A Mach-O object image that resides on disk. 134// We only read small parts of the contents into (discontinuous) memory. 135// 136class MachO : public MachOBase, public UnixPlusPlus::FileDesc { 137public: 138 MachO(FileDesc fd, size_t offset = 0, size_t length = 0); 139 ~MachO(); 140 141 size_t offset() const { return mOffset; } 142 size_t length() const { return mLength; } 143 size_t signingExtent() const; // signingOffset, or file length if none 144 145 void seek(size_t offset); // relative to start of image 146 CFDataRef dataAt(size_t offset, size_t size); 147 void validateStructure(); // is the structure of the mach-o sane 148 149 bool isSuspicious() const { return mSuspicious; } 150 151private: 152 size_t mOffset; // starting file offset 153 size_t mLength; // Mach-O file length 154 155 mach_header mHeaderBuffer; // read-in Mach-O header 156 load_command *mCommandBuffer; // read-in (malloc'ed) Mach-O load commands 157 158 bool mSuspicious; // strict validation failed 159}; 160 161 162// 163// A Mach-O object image that was mapped into memory. 164// We expect the entire image to be contiguously mapped starting at the 165// address given. No particular alignment is required (beyond native 166// alignment constraints on member variables). 167// 168class MachOImage : public MachOBase { 169public: 170 MachOImage(const void *address); 171 172 const void *address() { return &this->header(); } 173}; 174 175class MainMachOImage : public MachOImage { 176public: 177 MainMachOImage(); 178 179 static const void *mainImageAddress(); 180}; 181 182 183// 184// A Universal object represents a Mach-O binary image (whole) file. 185// It can represent a true Universal (aka "Fat") file with multiple 186// architectures; but it will also represent a single Mach-O ("thin") 187// binary and make you believe it's a Universal with just one architecture. 188// 189class Universal : public UnixPlusPlus::FileDesc { 190public: 191 Universal(FileDesc fd, size_t offset = 0, size_t length = 0); 192 ~Universal(); 193 194 // return a genuine MachO object for the given architecture 195 MachO *architecture() const; // native 196 MachO *architecture(const Architecture &arch) const; // given 197 MachO *architecture(size_t offset) const; // given by file offset 198 199 // return (just) the starting offset of an architecture 200 size_t archOffset() const; // native 201 size_t archOffset(const Architecture &arch) const; // given 202 size_t archLength(const Architecture &arch) const; // given 203 bool narrowed() const { return mBase != 0; } // part of a fat file 204 205 // return a set of architectures contained 206 typedef std::set<Architecture> Architectures; 207 void architectures(Architectures &archs) const; 208 209 bool isUniversal() const { return mArchList != NULL; } 210 Architecture bestNativeArch() const; 211 const size_t lengthOfSlice(size_t offset) const; 212 213 size_t offset() const { return mBase; } 214 size_t length() const { return mLength; } 215 216 bool isSuspicious() const; 217 218public: 219 static uint32_t typeOf(FileDesc fd); 220 221private: 222 const fat_arch *findArch(const Architecture &arch) const; 223 MachO *findImage(const Architecture &arch) const; 224 225private: 226 fat_arch *mArchList; // architectures (NULL if thin file) 227 unsigned mArchCount; // number of architectures (if fat) 228 Architecture mThinArch; // single architecture (if thin) 229 size_t mBase; // overriding offset in file (all types) 230 size_t mLength; // length of the architecture if thin file 231 typedef std::map<size_t, size_t> OffsetsToLength; 232 OffsetsToLength mSizes; // the length for the slice at a given offset 233 bool mSuspicious; // strict validation failed 234}; 235 236 237} // end namespace Security 238 239#endif // !_H_MACHOPLUSPLUS 240