]>
git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_utilities/lib/macho++.cpp
97b2ea6c17a65a9cd00ea7159d7244d47ae35b55
   2  * Copyright (c) 2006-2014 Apple Inc. All Rights Reserved. 
   4  * @APPLE_LICENSE_HEADER_START@ 
   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 
  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. 
  21  * @APPLE_LICENSE_HEADER_END@ 
  25 // macho++ - Mach-O object file helpers 
  28 #include <security_utilities/alloc.h> 
  29 #include <security_utilities/memutils.h> 
  30 #include <security_utilities/endian.h> 
  31 #include <mach-o/dyld.h> 
  38 /* Maximum number of archs a fat binary can have */ 
  39 static const int MAX_ARCH_COUNT 
= 100; 
  40 /* Maximum power of 2 that a mach-o can be aligned by */ 
  41 static const int MAX_ALIGN 
= 30; 
  44 // Architecture values 
  46 Architecture::Architecture(const fat_arch 
&arch
) 
  47         : pair
<cpu_type_t
, cpu_subtype_t
>(arch
.cputype
, arch
.cpusubtype
) 
  51 Architecture::Architecture(const char *name
) 
  53         if (const NXArchInfo 
*nxa 
= NXGetArchInfoFromName(name
)) { 
  54                 this->first 
= nxa
->cputype
; 
  55                 this->second 
= nxa
->cpusubtype
; 
  57                 this->first 
= this->second 
= none
; 
  63 // The local architecture. 
  65 // We take this from ourselves - the architecture of our main program Mach-O binary. 
  66 // There's the NXGetLocalArchInfo API, but it insists on saying "i386" on modern 
  67 // x86_64-centric systems, and lies to ppc (Rosetta) programs claiming they're native ppc. 
  68 // So let's not use that. 
  70 Architecture 
Architecture::local() 
  72         return MainMachOImage().architecture(); 
  77 // Translate between names and numbers 
  79 const char *Architecture::name() const 
  81         if (const NXArchInfo 
*info 
= NXGetArchInfoFromCpuType(cpuType(), cpuSubtype())) 
  87 std::string 
Architecture::displayName() const 
  89         if (const char *s 
= this->name()) 
  92         snprintf(buf
, sizeof(buf
), "(%d:%d)", cpuType(), cpuSubtype()); 
  98 // Compare architectures. 
  99 // This is asymmetrical; the second argument provides for some templating. 
 101 bool Architecture::matches(const Architecture 
&templ
) const 
 103         if (first 
!= templ
.first
) 
 104                 return false;   // main architecture mismatch 
 105         if (templ
.second 
== CPU_SUBTYPE_MULTIPLE
) 
 106                 return true;    // subtype wildcard 
 107         // match subtypes, ignoring feature bits 
 108         return ((second 
^ templ
.second
) & ~CPU_SUBTYPE_MASK
) == 0; 
 113 // MachOBase contains knowledge of the Mach-O object file format, 
 114 // but abstracts from any particular sourcing. It must be subclassed, 
 115 // and the subclass must provide the file header and commands area 
 116 // during its construction. Memory is owned by the subclass. 
 118 MachOBase::~MachOBase() 
 121 // provide the Mach-O file header, somehow 
 122 void MachOBase::initHeader(const mach_header 
*header
) 
 125         switch (mHeader
->magic
) { 
 143                 secdebug("macho", "%p: unrecognized header magic (%x)", this, mHeader
->magic
); 
 144                 UnixError::throwMe(ENOEXEC
); 
 148 // provide the Mach-O commands section, somehow 
 149 void MachOBase::initCommands(const load_command 
*commands
) 
 151         mCommands 
= commands
; 
 152         mEndCommands 
= LowLevelMemoryUtilities::increment
<load_command
>(commands
, flip(mHeader
->sizeofcmds
)); 
 153         if (mCommands 
+ 1 > mEndCommands
)       // ensure initial load command core available 
 154                 UnixError::throwMe(ENOEXEC
); 
 158 size_t MachOBase::headerSize() const 
 160         return m64 
? sizeof(mach_header_64
) : sizeof(mach_header
); 
 163 size_t MachOBase::commandSize() const 
 165         return flip(mHeader
->sizeofcmds
); 
 170 // Create a MachO object from an open file and a starting offset. 
 171 // We load (only) the header and load commands into memory at that time. 
 172 // Note that the offset must be relative to the start of the containing file 
 173 // (not relative to some intermediate container). 
 175 MachO::MachO(FileDesc fd
, size_t offset
, size_t length
) 
 176         : FileDesc(fd
), mOffset(offset
), mLength(length
), mSuspicious(false) 
 179                 mLength 
= fd
.fileSize(); 
 180         size_t size 
= fd
.read(&mHeaderBuffer
, sizeof(mHeaderBuffer
), mOffset
); 
 181         if (size 
!= sizeof(mHeaderBuffer
)) 
 182                 UnixError::throwMe(ENOEXEC
); 
 183         this->initHeader(&mHeaderBuffer
); 
 184         size_t cmdSize 
= this->commandSize(); 
 185         mCommandBuffer 
= (load_command 
*)malloc(cmdSize
); 
 187                 UnixError::throwMe(); 
 188         if (fd
.read(mCommandBuffer
, cmdSize
, this->headerSize() + mOffset
) != cmdSize
) 
 189                 UnixError::throwMe(ENOEXEC
); 
 190         this->initCommands(mCommandBuffer
); 
 191         /* If we do not know the length, we cannot do a verification of the mach-o structure */ 
 193                 this->validateStructure(); 
 196 void MachO::validateStructure() 
 198         bool isValid 
= false; 
 200         /* There should be either an LC_SEGMENT, an LC_SEGMENT_64, or an LC_SYMTAB 
 201          load_command and that + size must be equal to the end of the arch */ 
 202         for (const struct load_command 
*cmd 
= loadCommands(); cmd 
!= NULL
; cmd 
= nextCommand(cmd
)) { 
 203                 uint32_t cmd_type 
= flip(cmd
->cmd
); 
 204                 struct segment_command 
*seg 
= NULL
; 
 205                 struct segment_command_64 
*seg64 
= NULL
; 
 206                 struct symtab_command 
*symtab 
= NULL
; 
 208                 if (cmd_type 
==  LC_SEGMENT
) { 
 209                         seg 
= (struct segment_command 
*)cmd
; 
 210                         if (strcmp(seg
->segname
, SEG_LINKEDIT
) == 0) { 
 211                                 isValid 
= flip(seg
->fileoff
) + flip(seg
->filesize
) == this->length(); 
 214                 } else if (cmd_type 
== LC_SEGMENT_64
) { 
 215                         seg64 
= (struct segment_command_64 
*)cmd
; 
 216                         if (strcmp(seg64
->segname
, SEG_LINKEDIT
) == 0) { 
 217                                 isValid 
= flip(seg64
->fileoff
) + flip(seg64
->filesize
) == this->length(); 
 220                 /* PPC binaries have a SYMTAB section */ 
 221                 } else if (cmd_type 
== LC_SYMTAB
) { 
 222                         symtab 
= (struct symtab_command 
*)cmd
; 
 223                         isValid 
= flip(symtab
->stroff
) + flip(symtab
->strsize
) == this->length(); 
 234         ::free(mCommandBuffer
); 
 239 // Create a MachO object that is (entirely) mapped into memory. 
 240 // The caller must ensire that the underlying mapping persists 
 241 // at least as long as our object. 
 243 MachOImage::MachOImage(const void *address
) 
 245         this->initHeader((const mach_header 
*)address
); 
 246         this->initCommands(LowLevelMemoryUtilities::increment
<const load_command
>(address
, this->headerSize())); 
 251 // Locate the Mach-O image of the main program 
 253 MainMachOImage::MainMachOImage() 
 254         : MachOImage(mainImageAddress()) 
 258 const void *MainMachOImage::mainImageAddress() 
 260         return _dyld_get_image_header(0); 
 265 // Return various header fields 
 267 Architecture 
MachOBase::architecture() const 
 269         return Architecture(flip(mHeader
->cputype
), flip(mHeader
->cpusubtype
)); 
 272 uint32_t MachOBase::type() const 
 274         return flip(mHeader
->filetype
); 
 277 uint32_t MachOBase::flags() const 
 279         return flip(mHeader
->flags
); 
 284 // Iterate through load commands 
 286 const load_command 
*MachOBase::nextCommand(const load_command 
*command
) const 
 288         using LowLevelMemoryUtilities::increment
; 
 289         /* Do not try and increment by 0, or it will loop forever */ 
 290         if (flip(command
->cmdsize
) == 0) 
 291                 UnixError::throwMe(ENOEXEC
); 
 292         command 
= increment
<const load_command
>(command
, flip(command
->cmdsize
)); 
 293         if (command 
>= mEndCommands
)    // end of load commands 
 295         if (increment(command
, sizeof(load_command
)) > mEndCommands
 
 296                 || increment(command
, flip(command
->cmdsize
)) > mEndCommands
) 
 297                 UnixError::throwMe(ENOEXEC
); 
 303 // Find a specific load command, by command number. 
 304 // If there are multiples, returns the first one found. 
 306 const load_command 
*MachOBase::findCommand(uint32_t cmd
) const 
 308         for (const load_command 
*command 
= loadCommands(); command
; command 
= nextCommand(command
)) 
 309                 if (flip(command
->cmd
) == cmd
) 
 316 // Locate a segment command, by name 
 318 const segment_command 
*MachOBase::findSegment(const char *segname
) const 
 320         for (const load_command 
*command 
= loadCommands(); command
; command 
= nextCommand(command
)) { 
 321                 switch (flip(command
->cmd
)) { 
 325                                 const segment_command 
*seg 
= reinterpret_cast<const segment_command 
*>(command
); 
 326                                 if (!strcmp(seg
->segname
, segname
)) 
 337 const section 
*MachOBase::findSection(const char *segname
, const char *sectname
) const 
 339         using LowLevelMemoryUtilities::increment
; 
 340         if (const segment_command 
*seg 
= findSegment(segname
)) { 
 342                         const segment_command_64 
*seg64 
= reinterpret_cast<const segment_command_64 
*>(seg
); 
 343                         // As a sanity check, if the reported number of sections is not consistent 
 344                         // with the reported size, return NULL 
 345                         if (sizeof(*seg64
) + (seg64
->nsects 
* sizeof(section_64
)) > seg64
->cmdsize
) 
 347                         const section_64 
*sect 
= increment
<const section_64
>(seg64 
+ 1, 0); 
 348                         for (unsigned n 
= flip(seg64
->nsects
); n 
> 0; n
--, sect
++) { 
 349                                 if (!strcmp(sect
->sectname
, sectname
)) 
 350                                         return reinterpret_cast<const section 
*>(sect
); 
 353                         const section 
*sect 
= increment
<const section
>(seg 
+ 1, 0); 
 354                         for (unsigned n 
= flip(seg
->nsects
); n 
> 0; n
--, sect
++) { 
 355                                 if (!strcmp(sect
->sectname
, sectname
)) 
 365 // Translate a union lc_str into the string it denotes. 
 366 // Returns NULL (no exceptions) if the entry is corrupt. 
 368 const char *MachOBase::string(const load_command 
*cmd
, const lc_str 
&str
) const 
 370         size_t offset 
= flip(str
.offset
); 
 371         const char *sp 
= LowLevelMemoryUtilities::increment
<const char>(cmd
, offset
); 
 372         if (offset 
+ strlen(sp
) + 1 > flip(cmd
->cmdsize
))       // corrupt string reference 
 379 // Figure out where the Code Signing information starts in the Mach-O binary image. 
 380 // The code signature is at the end of the file, and identified 
 381 // by a specially-named section. So its starting offset is also the end 
 382 // of the signable part. 
 383 // Note that the offset returned is relative to the start of the Mach-O image. 
 384 // Returns zero if not found (usually indicating that the binary was not signed). 
 386 const linkedit_data_command 
*MachOBase::findCodeSignature() const 
 388         if (const load_command 
*cmd 
= findCommand(LC_CODE_SIGNATURE
)) 
 389                 return reinterpret_cast<const linkedit_data_command 
*>(cmd
); 
 390         return NULL
;            // not found 
 393 size_t MachOBase::signingOffset() const 
 395         if (const linkedit_data_command 
*lec 
= findCodeSignature()) 
 396                 return flip(lec
->dataoff
); 
 401 size_t MachOBase::signingLength() const 
 403         if (const linkedit_data_command 
*lec 
= findCodeSignature()) 
 404                 return flip(lec
->datasize
); 
 409 const linkedit_data_command 
*MachOBase::findLibraryDependencies() const 
 411         if (const load_command 
*cmd 
= findCommand(LC_DYLIB_CODE_SIGN_DRS
)) 
 412                 return reinterpret_cast<const linkedit_data_command 
*>(cmd
); 
 413         return NULL
;            // not found 
 418 // Return the signing-limit length for this Mach-O binary image. 
 419 // This is the signingOffset if present, or the full length if not. 
 421 size_t MachO::signingExtent() const 
 423         if (size_t offset 
= signingOffset()) 
 433 void MachO::seek(size_t offset
) 
 435         FileDesc::seek(mOffset 
+ offset
); 
 438 CFDataRef 
MachO::dataAt(size_t offset
, size_t size
) 
 440         CFMallocData 
buffer(size
); 
 441         if (this->read(buffer
, size
, mOffset 
+ offset
) != size
) 
 442                 UnixError::throwMe(); 
 447 // Fat (aka universal) file wrappers. 
 448 // The offset is relative to the start of the containing file. 
 450 Universal::Universal(FileDesc fd
, size_t offset 
/* = 0 */, size_t length 
/* = 0 */) 
 451         : FileDesc(fd
), mBase(offset
), mLength(length
), mMachType(0), mSuspicious(false) 
 454                 fat_header header
;              // if this is a fat file 
 455                 mach_header mheader
;    // if this is a thin file 
 457         const size_t size 
= max(sizeof(header
), sizeof(mheader
)); 
 458         if (fd
.read(&header
, size
, offset
) != size
) 
 459                 UnixError::throwMe(ENOEXEC
); 
 460         switch (header
.magic
) { 
 466                         // Under certain circumstances (15001604), mArchCount under-counts the architectures 
 467                         // by one, and special testing is required to validate the extra-curricular entry. 
 468                         // We always read an extra entry; in the situations where this might hit end-of-file, 
 469                         // we are content to fail. 
 471                         mArchCount 
= ntohl(header
.nfat_arch
); 
 473                         if (mArchCount 
> MAX_ARCH_COUNT
) 
 474                                 UnixError::throwMe(ENOEXEC
); 
 476                         size_t archSize 
= sizeof(fat_arch
) * (mArchCount 
+ 1); 
 477                         mArchList 
= (fat_arch 
*)malloc(archSize
); 
 479                                 UnixError::throwMe(); 
 480                         if (fd
.read(mArchList
, archSize
, mBase 
+ sizeof(header
)) != archSize
) { 
 482                                 UnixError::throwMe(ENOEXEC
); 
 484                         for (fat_arch 
*arch 
= mArchList
; arch 
<= mArchList 
+ mArchCount
; arch
++) { 
 486                                 n2hi(arch
->cpusubtype
); 
 491                         const fat_arch 
*last_arch 
= mArchList 
+ mArchCount
; 
 492                         if (last_arch
->cputype 
== (CPU_ARCH_ABI64 
| CPU_TYPE_ARM
)) { 
 495                         secdebug("macho", "%p is a fat file with %d architectures", 
 498                         /* A Mach-O universal file has padding of no more than "page size" 
 499                          * between the header and slices. This padding must be zeroed out or the file 
 501                         std::list
<struct fat_arch 
*> sortedList
; 
 502                         for (unsigned i 
= 0; i 
< mArchCount
; i
++) 
 503                                 sortedList
.push_back(mArchList 
+ i
); 
 505                         sortedList
.sort(^ bool (const struct fat_arch 
*arch1
, const struct fat_arch 
*arch2
) { return arch1
->offset 
< arch2
->offset
; }); 
 507                         const size_t universalHeaderEnd 
= mBase 
+ sizeof(header
) + (sizeof(fat_arch
) * mArchCount
); 
 508                         size_t prevHeaderEnd 
= universalHeaderEnd
; 
 509                         size_t prevArchSize 
= 0, prevArchStart 
= 0; 
 511                         for (auto iterator 
= sortedList
.begin(); iterator 
!= sortedList
.end(); ++iterator
) { 
 512                                 auto ret 
= mSizes
.insert(std::pair
<size_t, size_t>((*iterator
)->offset
, (*iterator
)->size
)); 
 513                                 if (ret
.second 
== false) { 
 515                                         MacOSError::throwMe(errSecInternalError
); // Something is wrong if the same size was encountered twice 
 518                                 size_t gapSize 
= (*iterator
)->offset 
- prevHeaderEnd
; 
 520                                 /* The size of the padding after the universal cannot be calculated to a fixed size */ 
 521                                 if (prevHeaderEnd 
!= universalHeaderEnd
) { 
 522                                         if (((*iterator
)->align 
> MAX_ALIGN
) || gapSize 
>= (1 << (*iterator
)->align
)) { 
 528                                 // validate gap bytes in tasty page-sized chunks 
 529                                 CssmAutoPtr
<uint8_t> gapBytes(Allocator::standard().malloc
<uint8_t>(PAGE_SIZE
)); 
 531                                 while (off 
< gapSize
) { 
 532                                         size_t want 
= min(gapSize 
- off
, (size_t)PAGE_SIZE
); 
 533                                         size_t got 
= fd
.read(gapBytes
, want
, prevHeaderEnd 
+ off
); 
 539                                         for (size_t x 
= 0; x 
< got
; x
++) { 
 540                                                 if (gapBytes
[x
] != 0) { 
 553                                 prevHeaderEnd 
= (*iterator
)->offset 
+ (*iterator
)->size
; 
 554                                 prevArchSize 
= (*iterator
)->size
; 
 555                                 prevArchStart 
= (*iterator
)->offset
; 
 558                         /* If there is anything extra at the end of the file, reject this */ 
 559                         if (!mSuspicious 
&& (prevArchStart 
+ prevArchSize 
!= fd
.fileSize())) 
 568                 mThinArch 
= Architecture(mheader
.cputype
, mheader
.cpusubtype
); 
 569                 secdebug("macho", "%p is a thin file (%s)", this, mThinArch
.name()); 
 575                 mThinArch 
= Architecture(flip(mheader
.cputype
), flip(mheader
.cpusubtype
)); 
 576                 secdebug("macho", "%p is a thin file (%s)", this, mThinArch
.name()); 
 579                 UnixError::throwMe(ENOEXEC
); 
 583 Universal::~Universal() 
 588 const size_t Universal::lengthOfSlice(size_t offset
) const 
 590         auto ret 
= mSizes
.find(offset
); 
 591         if (ret 
== mSizes
.end()) 
 592                 MacOSError::throwMe(errSecInternalError
); 
 597 // Get the "local" architecture from the fat file 
 598 // Throws ENOEXEC if not found. 
 600 MachO 
*Universal::architecture() const 
 603                 return findImage(bestNativeArch()); 
 605                 return new MachO(*this, mBase
, mLength
); 
 608 size_t Universal::archOffset() const 
 611                 return mBase 
+ findArch(bestNativeArch())->offset
; 
 618 // Get the specified architecture from the fat file 
 619 // Throws ENOEXEC if not found. 
 621 MachO 
*Universal::architecture(const Architecture 
&arch
) const 
 624                 return findImage(arch
); 
 625         else if (mThinArch
.matches(arch
)) 
 626                 return new MachO(*this, mBase
); 
 628                 UnixError::throwMe(ENOEXEC
); 
 631 size_t Universal::archOffset(const Architecture 
&arch
) const 
 634                 return mBase 
+ findArch(arch
)->offset
; 
 635         else if (mThinArch
.matches(arch
)) 
 638                 UnixError::throwMe(ENOEXEC
); 
 641 size_t Universal::archLength(const Architecture 
&arch
) const 
 644                 return mBase 
+ findArch(arch
)->size
; 
 645         else if (mThinArch
.matches(arch
)) 
 646                 return this->fileSize(); 
 648                 UnixError::throwMe(ENOEXEC
); 
 652 // Get the architecture at a specified offset from the fat file. 
 653 // Throws an exception of the offset does not point at a Mach-O image. 
 655 MachO 
*Universal::architecture(size_t offset
) const 
 658                 return make(new MachO(*this, offset
)); 
 659         else if (offset 
== mBase
) 
 660                 return new MachO(*this); 
 662                 UnixError::throwMe(ENOEXEC
); 
 667 // Locate an architecture from the fat file's list. 
 668 // Throws ENOEXEC if not found. 
 670 const fat_arch 
*Universal::findArch(const Architecture 
&target
) const 
 672         assert(isUniversal()); 
 673         const fat_arch 
*end 
= mArchList 
+ mArchCount
; 
 675         for (const fat_arch 
*arch 
= mArchList
; arch 
< end
; ++arch
) 
 676                 if (arch
->cputype 
== target
.cpuType() 
 677                         && arch
->cpusubtype 
== target
.cpuSubtype()) 
 679         // match for generic model of main architecture 
 680         for (const fat_arch 
*arch 
= mArchList
; arch 
< end
; ++arch
) 
 681                 if (arch
->cputype 
== target
.cpuType() && arch
->cpusubtype 
== 0) 
 683         // match for any subarchitecture of the main architecture (questionable) 
 684         for (const fat_arch 
*arch 
= mArchList
; arch 
< end
; ++arch
) 
 685                 if (arch
->cputype 
== target
.cpuType()) 
 688         UnixError::throwMe(ENOEXEC
);    // not found     
 691 MachO 
*Universal::findImage(const Architecture 
&target
) const 
 693         const fat_arch 
*arch 
= findArch(target
); 
 694         return make(new MachO(*this, mBase 
+ arch
->offset
, arch
->size
)); 
 697 MachO
* Universal::make(MachO
* macho
) const 
 699         auto_ptr
<MachO
> mo(macho
);                              // safe resource 
 700         uint32_t type 
= mo
->type(); 
 701         if (type 
== 0)                                                  // not a recognized Mach-O type 
 702                 UnixError::throwMe(ENOEXEC
); 
 703         if (mMachType 
&& mMachType 
!= type
)             // inconsistent members 
 704                 UnixError::throwMe(ENOEXEC
); 
 705         mMachType 
= type
;                                               // record 
 711 // Find the best-matching architecture for this fat file. 
 712 // We pick the native architecture if it's available. 
 713 // If it contains exactly one architecture, we take that. 
 714 // Otherwise, we throw. 
 716 Architecture 
Universal::bestNativeArch() const 
 719                 // ask the NXArch API for our native architecture 
 720                 const Architecture native 
= Architecture::local(); 
 721                 if (fat_arch 
*match 
= NXFindBestFatArch(native
.cpuType(), native
.cpuSubtype(), mArchList
, mArchCount
)) 
 723                 // if the system can't figure it out, pick (arbitrarily) the first one 
 730 // List all architectures from the fat file's list. 
 732 void Universal::architectures(Architectures 
&archs
) const 
 735                 for (unsigned n 
= 0; n 
< mArchCount
; n
++) 
 736                         archs
.insert(mArchList
[n
]); 
 738                 auto_ptr
<MachO
> macho(architecture()); 
 739                 archs
.insert(macho
->architecture()); 
 744 // Quickly guess the Mach-O type of a file. 
 745 // Returns type zero if the file isn't Mach-O or Universal. 
 746 // Always looks at the start of the file, and does not change the file pointer. 
 748 uint32_t Universal::typeOf(FileDesc fd
) 
 752         if (fd
.read(&header
, sizeof(header
), 0) != sizeof(header
)) 
 754         while (max_tries 
> 0) { 
 755                 switch (header
.magic
) { 
 758                         return header
.filetype
; 
 762                         return flip(header
.filetype
); 
 767                                 const fat_arch 
*arch1 
= 
 768                                         LowLevelMemoryUtilities::increment
<fat_arch
>(&header
, sizeof(fat_header
)); 
 769                                 if (fd
.read(&header
, sizeof(header
), ntohl(arch1
->offset
)) != sizeof(header
)) 
 784 bool Universal::isSuspicious() const 
 788         Universal::Architectures archList
; 
 789         architectures(archList
); 
 790         for (Universal::Architectures::const_iterator it 
= archList
.begin(); it 
!= archList
.end(); ++it
) { 
 791                 auto_ptr
<MachO
> macho(architecture(*it
)); 
 792                 if (macho
->isSuspicious())