Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 | /* * Copyright (c) 2017-2021 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */ #ifndef mach_o_Header_h #define mach_o_Header_h #include <array> #include <span> #include <string_view> #include <stdio.h> #include <limits.h> #include <mach-o/loader.h> #include <mach-o/fat.h> #include <uuid/uuid.h> #include "Platform.h" #include "Architecture.h" #include "Version32.h" #include "Version64.h" #include "Error.h" #include "Policy.h" #ifndef LC_ATOM_INFO #define LC_ATOM_INFO 0x36 #endif #ifndef LC_FUNCTION_VARIANTS #define LC_FUNCTION_VARIANTS 0x37 #endif #ifndef LC_FUNCTION_VARIANT_FIXUPS #define LC_FUNCTION_VARIANT_FIXUPS 0x38 #endif #ifndef EXPORT_SYMBOL_FLAGS_FUNCTION_VARIANT #define EXPORT_SYMBOL_FLAGS_FUNCTION_VARIANT 0x20 #endif #ifndef VM_PROT_READ #define VM_PROT_READ 0x01 #endif #ifndef VM_PROT_WRITE #define VM_PROT_WRITE 0x02 #endif #ifndef VM_PROT_EXECUTE #define VM_PROT_EXECUTE 0x04 #endif #ifndef LC_TARGET_TRIPLE #define LC_TARGET_TRIPLE 0x39 struct target_triple_command { uint32_t cmd; /* LC_TARGET_TRIPLE */ uint32_t cmdsize; /* including string */ union lc_str triple; /* target triple string */ }; #endif #ifndef DYLIB_USE_WEAK_LINK struct dylib_use_command { uint32_t cmd; /* LC_LOAD_DYLIB or LC_LOAD_WEAK_DYLIB */ uint32_t cmdsize; /* overall size, including path */ uint32_t nameoff; /* == 16, dylibs's path offset */ uint32_t marker; /* == 0x1a741800 */ uint32_t current_version; /* dylib's current version number */ uint32_t compat_version; /* == 0x00010000 */ uint32_t flags; /* DYLIB_USE_... flags */ }; #define DYLIB_USE_WEAK_LINK 0x01 #define DYLIB_USE_REEXPORT 0x02 #define DYLIB_USE_UPWARD 0x04 #define DYLIB_USE_DELAYED_INIT 0x08 #endif #ifndef MH_NO_DYNAMIC_ACCESS #define MH_NO_DYNAMIC_ACCESS 0x400 // cannot be dlopen()ed or dlsym()ed #endif namespace mach_o { /*! * @struct LinkedDylibAttributes * * @abstract * Attributes of how a dylib can be linked */ struct VIS_HIDDEN LinkedDylibAttributes { constexpr LinkedDylibAttributes() : raw(0) {} union { struct { bool weakLink : 1 = false; bool reExport : 1 = false; bool upward : 1 = false; bool delayInit : 1 = false; uint8_t padding : 4 = 0; }; uint8_t raw; }; void toString(char buf[64]) const; static const LinkedDylibAttributes regular; static const LinkedDylibAttributes justWeakLink; static const LinkedDylibAttributes justUpward; static const LinkedDylibAttributes justReExport; static const LinkedDylibAttributes justDelayInit; private: constexpr LinkedDylibAttributes(uint8_t v) : raw(v) {} }; static_assert(sizeof(LinkedDylibAttributes) == 1); VIS_HIDDEN inline bool operator==(const LinkedDylibAttributes& a, LinkedDylibAttributes b) { return (a.raw == b.raw); } /*! * @class Header * * @abstract * A mapped mach-o file can be cast to a Header*, then these methods used to parse/validate it. * The Header constructor can be used to build a mach-o file dynamically for unit tests */ struct VIS_HIDDEN Header { static bool isSharedCacheEligiblePath(const char* path); static const Header* isMachO(std::span<const uint8_t> content); Error valid(uint64_t fileSize) const; // methods that look at mach_header bool hasMachOMagic() const; const char* archName() const; Architecture arch() const; uint32_t pointerSize() const; uint32_t ncmds() const; bool uses16KPages() const; bool is64() const; bool isDyldManaged() const; bool isDylib() const; bool isDylibStub() const; bool isDylibOrStub() const; bool isBundle() const; bool isMainExecutable() const; bool isDynamicExecutable() const; bool isStaticExecutable() const; bool isDylinker() const; bool isKextBundle() const; bool isObjectFile() const; bool isFileSet() const; bool isPreload() const; bool isPIE() const; bool usesTwoLevelNamespace() const; bool isArch(const char* archName) const; bool inDyldCache() const; bool hasThreadLocalVariables() const; bool hasWeakDefs() const; bool usesWeakDefs() const; uint32_t machHeaderSize() const; bool mayHaveTextFixups() const; bool hasSubsectionsViaSymbols() const; bool noReexportedDylibs() const; bool isAppExtensionSafe() const; bool isSimSupport() const; bool noDynamicAccess() const; // methods that look for load commands Error validStructureLoadCommands(uint64_t fileSize) const; Error forEachLoadCommand(void (^callback)(const load_command* cmd, bool& stop)) const; void forEachLoadCommandSafe(void (^callback)(const load_command* cmd, bool& stop)) const; //asserts if error void forDyldEnv(void (^callback)(const char* envVar, bool& stop)) const; void forEachRPath(void (^callback)(const char* rPath, bool& stop)) const; void forEachLinkerOption(void (^callback)(const char* opt, bool& stop)) const; void forAllowableClient(void (^callback)(const char* clientName, bool& stop)) const; PlatformAndVersions platformAndVersions() const; bool builtForPlatform(Platform, bool onlyOnePlatform=false) const; bool builtForSimulator() const; void forEachBuildTool(void (^handler)(Platform platform, uint32_t tool, uint32_t version)) const; bool getUuid(uuid_t uuid) const; bool sourceVersion(Version64& version) const; bool getDylibInstallName(const char** installName, Version32* compatVersion, Version32* currentVersion) const; const char* installName() const; // returns nullptr is no install name const char* umbrellaName() const; // returns nullptr if dylib is not in an umbrella void forEachLinkedDylib(void (^callback)(const char* loadPath, LinkedDylibAttributes kind, Version32 compatVersion, Version32 curVersion, bool synthesizedLink, bool& stop)) const; const char* linkedDylibLoadPath(uint32_t depIndex) const; uint32_t linkedDylibCount(bool* allDepsAreRegular = nullptr) const; bool canBeFairPlayEncrypted() const; bool hasEncryptionInfo(uint32_t& cryptId, uint32_t& textOffset, uint32_t& size) const; bool isFairPlayEncrypted(uint32_t& textOffset, uint32_t& size) const; bool hasChainedFixups() const; bool hasChainedFixupsLoadCommand() const; bool hasOpcodeFixups() const; bool hasCodeSignature(uint32_t& fileOffset, uint32_t& size) const; bool hasLinkerOptimizationHints(uint32_t& offset, uint32_t& size) const; bool getEntry(uint64_t& offset, bool& usesCRT) const; bool hasIndirectSymbolTable(uint32_t& fileOffset, uint32_t& count) const; bool hasClassicRelocations(uint32_t& nLocRel, uint32_t& nExtRel) const; bool hasSplitSegInfo(bool& isMarker) const; bool hasAtomInfo(uint32_t& fileOffset, uint32_t& count) const; CString libOrdinalName(int libOrdinal) const; const load_command* findLoadCommand(uint32_t& index, bool (^predicate)(const load_command* lc)) const; void findLoadCommandRange(uint32_t& startIndex, uint32_t& endIndex, bool (^predicate)(const load_command* lc)) const; void printLoadCommands(FILE* out=stdout, unsigned indentLevel=0) const; bool hasFunctionVariantFixups() const; bool loadableIntoProcess(Platform processPlatform, CString path, bool internalInstall=false) const; bool hasPlusLoadMethod() const; void forEachSingletonPatch(void (^handler)(uint64_t runtimeOffset)) const; bool hasObjCMessageReferences() const; bool findObjCDataSection(CString sectionName, uint64_t& sectionRuntimeOffset, uint64_t& sectionSize) const; CString targetTriple() const; // returns empty string if no triple specified bool hasFunctionsVariantTable(uint64_t& runtimeOffset) const; // load command helpers static const dylib_command* isDylibLoadCommand(const load_command* lc); const thread_command* unixThreadLoadCommand() const; uint32_t sizeForLinkedDylibCommand(const char* path, LinkedDylibAttributes depAttrs, uint32_t& traditionalCmd) const; // methods that look for segments/sections uint32_t segmentCount() const; uint32_t loadCommandsFreeSpace() const; bool allowsAlternatePlatform() const; bool hasInterposingTuples() const; bool isRestricted() const; uint64_t preferredLoadAddress() const; int64_t getSlide() const; bool hasObjC() const; bool hasDataConst() const; bool hasDiscontiguousSegments() const; std::string_view segmentName(uint32_t segIndex) const; uint64_t segmentVmAddr(uint32_t segIndex) const; uint64_t segmentVmSize(uint32_t segIndex) const; uint32_t segmentFileOffset(uint32_t segIndex) const; struct SegmentInfo { std::string_view segmentName; uint64_t vmaddr = 0; uint64_t vmsize = 0; uint32_t fileOffset = 0; uint32_t fileSize = 0; uint32_t flags = 0; uint16_t segmentIndex = 0; uint8_t maxProt = 0; uint8_t initProt = 0; bool readOnlyData() const { return flags & SG_READ_ONLY; } bool isProtected() const { return flags & SG_PROTECTED_VERSION_1; } bool executable() const { return initProt & VM_PROT_EXECUTE; } bool writable() const { return initProt & VM_PROT_WRITE; } bool readable() const { return initProt & VM_PROT_READ; } bool hasZeroFill() const { return (initProt == 3) && (fileSize < vmsize); } }; void forEachSegment(void (^callback)(const SegmentInfo& info, bool& stop)) const; void forEachSegment(void (^callback)(const SegmentInfo& info, uint64_t sizeOfSections, uint32_t maxAlignOfSections, bool& stop)) const; struct SectionInfo { std::string_view sectionName; std::string_view segmentName; uint32_t segIndex = 0; uint32_t segMaxProt = 0; uint32_t segInitProt = 0; uint32_t flags = 0; uint32_t alignment = 0; uint64_t address = 0; uint64_t size = 0; uint32_t fileOffset = 0; uint32_t relocsOffset = 0; uint32_t relocsCount = 0; uint32_t reserved1 = 0; uint32_t reserved2 = 0; }; void forEachSection(void (^callback)(const SectionInfo&, bool& stop)) const; void forEachSection(void (^callback)(const SegmentInfo&, const SectionInfo&, bool& stop)) const; void forEachInterposingSection(void (^callback)(const SectionInfo&, bool& stop)) const; std::span<const uint8_t> findSectionContent(CString segName, CString sectName, bool useVmOffset) const; bool hasSection(CString segName, CString sectName, bool segNamePrefix=false) const; static uint32_t threadLoadCommandsSize(const Architecture& arch); uint32_t threadLoadCommandsSize() const; uint32_t headerAndLoadCommandsSize() const; static uint32_t pointerAligned(bool is64, uint32_t value); uint32_t pointerAligned(uint32_t value) const; uint32_t fileSize() const; const uint8_t* computeLinkEditBias(bool zeroFillExpanded) const; bool hasZerofillExpansion() const; uint64_t zerofillExpansionAmount() const; bool hasCustomStackSize(uint64_t& size) const; bool hasFirmwareChainStarts(uint16_t* pointerFormat=nullptr, uint32_t* startsCount=nullptr, const uint32_t** starts=nullptr) const; bool hasFirmwareRebaseRuns() const; bool forEachFirmwareRebaseRuns(void (^callback)(uint32_t offset, bool& stop)) const; static const char* protectionString(uint32_t flags, char str[8]); private: friend class Image; friend class RebaseOpcodes; friend class BindOpcodes; friend class LazyBindOpcodes; friend class ChainedFixups; bool entryAddrFromThreadCmd(const thread_command* cmd, uint64_t& addr) const; bool hasLoadCommand(uint32_t lc) const; void forEachPlatformLoadCommand(void (^callback)(Platform platform, Version32 minOS, Version32 sdk)) const; Error validSemanticsPlatform() const; Error validSemanticsInstallName(const Policy& policy) const; Error validSemanticsLinkedDylibs(const Policy& policy) const; Error validSemanticsLinkerOptions(const Policy& policy) const; Error validSemanticsUUID(const Policy& policy) const; Error validSemanticsRPath(const Policy& policy) const; Error validSemanticsSegments(const Policy& policy, uint64_t fileSize) const; Error validSemanticsSegmentInIsolation(const Policy& policy, uint64_t wholeFileSize, const segment_command_64* segLC) const; Error validSemanticsMain(const Policy& policy) const; template <typename SG, typename SC> Error validSegment(const Policy& policy, uint64_t wholeFileSize, const SG* seg) const; static std::string_view name16(const char name[16]); const encryption_info_command* findFairPlayEncryptionLoadCommand() const; static LinkedDylibAttributes loadCommandToDylibKind(const dylib_command* dylibCmd); protected: bool hasMachOBigEndianMagic() const; protected: mach_header mh; }; } // namespace mach_o #endif /* mach_o_Header_h */ |