1 /* ldid - (Mach-O) Link-Loader Identity Editor 
   2  * Copyright (C) 2007-2012  Jay Freeman (saurik) 
   5 /* GNU Affero General Public License, Version 3 {{{ */ 
   7  * This program is free software: you can redistribute it and/or modify 
   8  * it under the terms of the GNU Affero General Public License as published by 
   9  * the Free Software Foundation, either version 3 of the License, or 
  10  * (at your option) any later version. 
  12  * This program is distributed in the hope that it will be useful, 
  13  * but WITHOUT ANY WARRANTY; without even the implied warranty of 
  14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
  15  * GNU Affero General Public License for more details. 
  17  * You should have received a copy of the GNU Affero General Public License 
  18  * along with this program.  If not, see <http://www.gnu.org/licenses/>. 
  22 #include "minimal/stdlib.h" 
  23 #include "minimal/string.h" 
  24 #include "minimal/mapping.h" 
  33 #include <sys/types.h> 
  41 #define FAT_MAGIC 0xcafebabe 
  42 #define FAT_CIGAM 0xbebafeca 
  62 #define MH_MAGIC 0xfeedface 
  63 #define MH_CIGAM 0xcefaedfe 
  65 #define MH_MAGIC_64 0xfeedfacf 
  66 #define MH_CIGAM_64 0xcffaedfe 
  68 #define MH_DYLDLINK   0x4 
  70 #define MH_EXECUTE    0x2 
  73 #define MH_DYLIB_STUB 0x9 
  80 #define LC_REQ_DYLD           uint32_t(0x80000000) 
  82 #define LC_SEGMENT            uint32_t(0x01) 
  83 #define LC_SYMTAB             uint32_t(0x02) 
  84 #define LC_DYSYMTAB           uint32_t(0x0b) 
  85 #define LC_LOAD_DYLIB         uint32_t(0x0c) 
  86 #define LC_ID_DYLIB           uint32_t(0x0d) 
  87 #define LC_SEGMENT_64         uint32_t(0x19) 
  88 #define LC_UUID               uint32_t(0x1b) 
  89 #define LC_CODE_SIGNATURE     uint32_t(0x1d) 
  90 #define LC_SEGMENT_SPLIT_INFO uint32_t(0x1e) 
  91 #define LC_REEXPORT_DYLIB     uint32_t(0x1f | LC_REQ_DYLD) 
  92 #define LC_ENCRYPTION_INFO    uint32_t(0x21) 
  93 #define LC_DYLD_INFO          uint32_t(0x22) 
  94 #define LC_DYLD_INFO_ONLY     uint32_t(0x22 | LC_REQ_DYLD) 
  99     uint32_t current_version
; 
 100     uint32_t compatibility_version
; 
 103 struct dylib_command 
{ 
 109 struct uuid_command 
{ 
 115 struct symtab_command 
{ 
 124 struct dyld_info_command 
{ 
 128     uint32_t rebase_size
; 
 131     uint32_t weak_bind_off
; 
 132     uint32_t weak_bind_size
; 
 133     uint32_t lazy_bind_off
; 
 134     uint32_t lazy_bind_size
; 
 136     uint32_t export_size
; 
 139 struct dysymtab_command 
{ 
 152     uint32_t extrefsymoff
; 
 153     uint32_t nextrefsyms
; 
 154     uint32_t indirectsymoff
; 
 155     uint32_t nindirectsyms
; 
 162 struct dylib_table_of_contents 
{ 
 163     uint32_t symbol_index
; 
 164     uint32_t module_index
; 
 167 struct dylib_module 
{ 
 168     uint32_t module_name
; 
 177     uint32_t iinit_iterm
; 
 178     uint32_t ninit_nterm
; 
 179     uint32_t objc_module_info_addr
; 
 180     uint32_t objc_module_info_size
; 
 183 struct dylib_reference 
{ 
 188 struct relocation_info 
{ 
 190     uint32_t r_symbolnum
:24; 
 209 struct segment_command 
{ 
 223 struct segment_command_64 
{ 
 265 struct linkedit_data_command 
{ 
 272 struct encryption_info_command 
{ 
 280 uint16_t Swap_(uint16_t value
) { 
 282         ((value 
>>  8) & 0x00ff) | 
 283         ((value 
<<  8) & 0xff00); 
 286 uint32_t Swap_(uint32_t value
) { 
 287     value 
= ((value 
>>  8) & 0x00ff00ff) | 
 288             ((value 
<<  8) & 0xff00ff00); 
 289     value 
= ((value 
>> 16) & 0x0000ffff) | 
 290             ((value 
<< 16) & 0xffff0000); 
 294 int16_t Swap_(int16_t value
) { 
 295     return Swap_(static_cast<uint16_t>(value
)); 
 298 int32_t Swap_(int32_t value
) { 
 299     return Swap_(static_cast<uint32_t>(value
)); 
 304 uint16_t Swap(uint16_t value
) { 
 305     return little_ 
? Swap_(value
) : value
; 
 308 uint32_t Swap(uint32_t value
) { 
 309     return little_ 
? Swap_(value
) : value
; 
 312 int16_t Swap(int16_t value
) { 
 313     return Swap(static_cast<uint16_t>(value
)); 
 316 int32_t Swap(int32_t value
) { 
 317     return Swap(static_cast<uint32_t>(value
)); 
 320 template <typename Target_
> 
 332     Data(void *base
, size_t size
) : 
 339     uint16_t Swap(uint16_t value
) const { 
 340         return swapped_ 
? Swap_(value
) : value
; 
 343     uint32_t Swap(uint32_t value
) const { 
 344         return swapped_ 
? Swap_(value
) : value
; 
 347     int16_t Swap(int16_t value
) const { 
 348         return Swap(static_cast<uint16_t>(value
)); 
 351     int32_t Swap(int32_t value
) const { 
 352         return Swap(static_cast<uint32_t>(value
)); 
 355     void *GetBase() const { 
 359     size_t GetSize() const { 
 370     struct mach_header 
*mach_header_
; 
 371     struct load_command 
*load_command_
; 
 374     MachHeader(void *base
, size_t size
) : 
 377         mach_header_ 
= (mach_header 
*) base
; 
 379         switch (Swap(mach_header_
->magic
)) { 
 381                 swapped_ 
= !swapped_
; 
 387                 swapped_ 
= !swapped_
; 
 396         void *post 
= mach_header_ 
+ 1; 
 398             post 
= (uint32_t *) post 
+ 1; 
 399         load_command_ 
= (struct load_command 
*) post
; 
 402             Swap(mach_header_
->filetype
) == MH_EXECUTE 
|| 
 403             Swap(mach_header_
->filetype
) == MH_DYLIB 
|| 
 404             Swap(mach_header_
->filetype
) == MH_BUNDLE
 
 408     struct mach_header 
*operator ->() const { 
 412     uint32_t GetCPUType() const { 
 413         return Swap(mach_header_
->cputype
); 
 416     uint16_t GetCPUSubtype() const { 
 417         return Swap(mach_header_
->cpusubtype
) & 0xff; 
 420     std::vector
<struct load_command 
*> GetLoadCommands() const { 
 421         std::vector
<struct load_command 
*> load_commands
; 
 423         struct load_command 
*load_command 
= load_command_
; 
 424         for (uint32_t cmd 
= 0; cmd 
!= Swap(mach_header_
->ncmds
); ++cmd
) { 
 425             load_commands
.push_back(load_command
); 
 426             load_command 
= (struct load_command 
*) ((uint8_t *) load_command 
+ Swap(load_command
->cmdsize
)); 
 429         return load_commands
; 
 432     std::vector
<segment_command 
*> GetSegments(const char *segment_name
) const { 
 433         std::vector
<struct segment_command 
*> segment_commands
; 
 435         _foreach (load_command
, GetLoadCommands()) { 
 436             if (Swap(load_command
->cmd
) == LC_SEGMENT
) { 
 437                 segment_command 
*segment_command 
= reinterpret_cast<struct segment_command 
*>(load_command
); 
 438                 if (strncmp(segment_command
->segname
, segment_name
, 16) == 0) 
 439                     segment_commands
.push_back(segment_command
); 
 443         return segment_commands
; 
 446     std::vector
<segment_command_64 
*> GetSegments64(const char *segment_name
) { 
 447         std::vector
<struct segment_command_64 
*> segment_commands
; 
 449         _foreach (load_command
, GetLoadCommands()) { 
 450             if (Swap(load_command
->cmd
) == LC_SEGMENT_64
) { 
 451                 segment_command_64 
*segment_command 
= reinterpret_cast<struct segment_command_64 
*>(load_command
); 
 452                 if (strncmp(segment_command
->segname
, segment_name
, 16) == 0) 
 453                     segment_commands
.push_back(segment_command
); 
 457         return segment_commands
; 
 460     std::vector
<section 
*> GetSections(const char *segment_name
, const char *section_name
) const { 
 461         std::vector
<section 
*> sections
; 
 463         _foreach (segment
, GetSegments(segment_name
)) { 
 464             section 
*section 
= (struct section 
*) (segment 
+ 1); 
 467             for (sect 
= 0; sect 
!= Swap(segment
->nsects
); ++sect
) { 
 468                 if (strncmp(section
->sectname
, section_name
, 16) == 0) 
 469                     sections
.push_back(section
); 
 477     template <typename Target_
> 
 478     Pointer
<Target_
> GetPointer(uint32_t address
, const char *segment_name 
= NULL
) const { 
 479         load_command 
*load_command 
= (struct load_command 
*) (mach_header_ 
+ 1); 
 482         for (cmd 
= 0; cmd 
!= Swap(mach_header_
->ncmds
); ++cmd
) { 
 483             if (Swap(load_command
->cmd
) == LC_SEGMENT
) { 
 484                 segment_command 
*segment_command 
= (struct segment_command 
*) load_command
; 
 485                 if (segment_name 
!= NULL 
&& strncmp(segment_command
->segname
, segment_name
, 16) != 0) 
 488                 section 
*sections 
= (struct section 
*) (segment_command 
+ 1); 
 491                 for (sect 
= 0; sect 
!= Swap(segment_command
->nsects
); ++sect
) { 
 492                     section 
*section 
= §ions
[sect
]; 
 493                     //printf("%s %u %p %p %u\n", segment_command->segname, sect, address, section->addr, section->size); 
 494                     if (address 
>= Swap(section
->addr
) && address 
< Swap(section
->addr
) + Swap(section
->size
)) { 
 495                         //printf("0x%.8x %s\n", address, segment_command->segname); 
 496                         return Pointer
<Target_
>(this, reinterpret_cast<Target_ 
*>(address 
- Swap(section
->addr
) + Swap(section
->offset
) + (char *) mach_header_
)); 
 502             load_command 
= (struct load_command 
*) ((char *) load_command 
+ Swap(load_command
->cmdsize
)); 
 505         return Pointer
<Target_
>(this); 
 508     template <typename Target_
> 
 509     Pointer
<Target_
> GetOffset(uint32_t offset
) { 
 510         return Pointer
<Target_
>(this, reinterpret_cast<Target_ 
*>(offset 
+ (uint8_t *) mach_header_
)); 
 514 class FatMachHeader 
: 
 521     FatMachHeader(void *base
, size_t size
, fat_arch 
*fat_arch
) : 
 522         MachHeader(base
, size
), 
 527     fat_arch 
*GetFatArch() const { 
 536     fat_header 
*fat_header_
; 
 537     std::vector
<FatMachHeader
> mach_headers_
; 
 540     FatHeader(void *base
, size_t size
) : 
 543         fat_header_ 
= reinterpret_cast<struct fat_header 
*>(base
); 
 545         if (Swap(fat_header_
->magic
) == FAT_CIGAM
) { 
 546             swapped_ 
= !swapped_
; 
 548         } else if (Swap(fat_header_
->magic
) != FAT_MAGIC
) { 
 550             mach_headers_
.push_back(FatMachHeader(base
, size
, NULL
)); 
 552             size_t fat_narch 
= Swap(fat_header_
->nfat_arch
); 
 553             fat_arch 
*fat_arch 
= reinterpret_cast<struct fat_arch 
*>(fat_header_ 
+ 1); 
 555             for (arch 
= 0; arch 
!= fat_narch
; ++arch
) { 
 556                 uint32_t arch_offset 
= Swap(fat_arch
->offset
); 
 557                 uint32_t arch_size 
= Swap(fat_arch
->size
); 
 558                 mach_headers_
.push_back(FatMachHeader((uint8_t *) base 
+ arch_offset
, arch_size
, fat_arch
)); 
 564     std::vector
<FatMachHeader
> &GetMachHeaders() { 
 565         return mach_headers_
; 
 569         return fat_header_ 
!= NULL
; 
 572     struct fat_header 
*operator ->() const { 
 577 FatHeader 
Map(const char *path
, bool ro 
= false) { 
 579     void *base(map(path
, 0, _not(size_t), &size
, ro
)); 
 580     return FatHeader(base
, size
); 
 583 template <typename Target_
> 
 586     const MachHeader 
*framework_
; 
 587     const Target_ 
*pointer_
; 
 590     Pointer(const MachHeader 
*framework 
= NULL
, const Target_ 
*pointer 
= NULL
) : 
 591         framework_(framework
), 
 596     operator const Target_ 
*() const { 
 600     const Target_ 
*operator ->() const { 
 604     Pointer
<Target_
> &operator ++() { 
 609     template <typename Value_
> 
 610     Value_ 
Swap(Value_ value
) { 
 611         return framework_
->Swap(value
); 
 615 #define CSMAGIC_CODEDIRECTORY      uint32_t(0xfade0c02) 
 616 #define CSMAGIC_EMBEDDED_SIGNATURE uint32_t(0xfade0cc0) 
 617 #define CSMAGIC_ENTITLEMENTS       uint32_t(0xfade7171) 
 619 #define CSSLOT_CODEDIRECTORY uint32_t(0) 
 620 #define CSSLOT_REQUIREMENTS  uint32_t(2) 
 621 #define CSSLOT_ENTITLEMENTS  uint32_t(5) 
 636     struct BlobIndex index
[]; 
 639 struct CodeDirectory 
{ 
 644     uint32_t identOffset
; 
 645     uint32_t nSpecialSlots
; 
 655 extern "C" uint32_t hash(uint8_t *k
, uint32_t length
, uint32_t initval
); 
 657 void sha1(uint8_t *hash
, uint8_t *data
, size_t size
) { 
 660     SHA1Input(&context
, data
, size
); 
 661     SHA1Result(&context
, hash
); 
 664 struct CodesignAllocation 
{ 
 669     CodesignAllocation(uint32_t type
, uint16_t subtype
, size_t size
) : 
 677 int main(int argc
, const char *argv
[]) { 
 683     little_ 
= endian
.byte
[0]; 
 706     uint32_t flag_CPUType(_not(uint32_t)); 
 707     uint32_t flag_CPUSubtype(_not(uint32_t)); 
 712     const void *xmld(NULL
); 
 715     uintptr_t noffset(_not(uintptr_t)); 
 716     uintptr_t woffset(_not(uintptr_t)); 
 718     std::vector
<std::string
> files
; 
 721         fprintf(stderr
, "usage: %s -S[entitlements.xml] <binary>\n", argv
[0]); 
 722         fprintf(stderr
, "   %s -e MobileSafari\n", argv
[0]); 
 723         fprintf(stderr
, "   %s -S cat\n", argv
[0]); 
 724         fprintf(stderr
, "   %s -Stfp.xml gdb\n", argv
[0]); 
 728     for (int argi(1); argi 
!= argc
; ++argi
) 
 729         if (argv
[argi
][0] != '-') 
 730             files
.push_back(argv
[argi
]); 
 731         else switch (argv
[argi
][1]) { 
 732             case 'R': flag_R 
= true; break; 
 733             case 'r': flag_r 
= true; break; 
 735             case 't': flag_t 
= true; break; 
 736             case 'u': flag_u 
= true; break; 
 737             case 'p': flag_p 
= true; break; 
 738             case 'e': flag_e 
= true; break; 
 739             case 'O': flag_O 
= true; break; 
 741             case 'D': flag_D 
= true; break; 
 742             case 'd': flag_d 
= true; break; 
 744             case 'a': flag_a 
= true; break; 
 748                 if (argv
[argi
][2] != '\0') { 
 749                     const char *cpu 
= argv
[argi
] + 2; 
 750                     const char *colon 
= strchr(cpu
, ':'); 
 751                     _assert(colon 
!= NULL
); 
 753                     flag_CPUType 
= strtoul(cpu
, &arge
, 0); 
 754                     _assert(arge 
== colon
); 
 755                     flag_CPUSubtype 
= strtoul(colon 
+ 1, &arge
, 0); 
 756                     _assert(arge 
== argv
[argi
] + strlen(argv
[argi
])); 
 768                 if (argv
[argi
][2] != '\0') { 
 769                     const char *xml 
= argv
[argi
] + 2; 
 770                     xmld 
= map(xml
, 0, _not(size_t), &xmls
, true); 
 776                 if (argv
[argi
][2] == '-') 
 780                     timev 
= strtoul(argv
[argi
] + 2, &arge
, 0); 
 781                     _assert(arge 
== argv
[argi
] + strlen(argv
[argi
])); 
 787                 noffset 
= strtoul(argv
[argi
] + 2, &arge
, 0); 
 788                 _assert(arge 
== argv
[argi
] + strlen(argv
[argi
])); 
 793                 woffset 
= strtoul(argv
[argi
] + 2, &arge
, 0); 
 794                 _assert(arge 
== argv
[argi
] + strlen(argv
[argi
])); 
 802     if (files
.empty()) usage
: { 
 806     size_t filei(0), filee(0); 
 807     _foreach (file
, files
) try { 
 808         const char *path(file
.c_str()); 
 809         const char *base 
= strrchr(path
, '/'); 
 810         char *temp(NULL
), *dir
; 
 813             dir 
= strndup_(path
, base
++ - path 
+ 1); 
 821                 FatHeader 
fat_header(Map(path
)); 
 822                 _foreach (mach_header
, fat_header
.GetMachHeaders()) { 
 824                         if (mach_header
.GetCPUType() != flag_CPUType
) 
 826                         if (mach_header
.GetCPUSubtype() != flag_CPUSubtype
) 
 830                     mach_header
->flags 
= mach_header
.Swap(mach_header
.Swap(mach_header
->flags
) | MH_DYLDLINK
); 
 832                     uint32_t size(_not(uint32_t)); { 
 833                         _foreach (load_command
, mach_header
.GetLoadCommands()) { 
 834                             switch (mach_header
.Swap(load_command
->cmd
)) { 
 835                                 case LC_CODE_SIGNATURE
: { 
 836                                     struct linkedit_data_command 
*signature 
= reinterpret_cast<struct linkedit_data_command 
*>(load_command
); 
 837                                     memset(reinterpret_cast<uint8_t *>(mach_header
.GetBase()) + mach_header
.Swap(signature
->dataoff
), 0, mach_header
.Swap(signature
->datasize
)); 
 838                                     memset(signature
, 0, sizeof(struct linkedit_data_command
)); 
 840                                     mach_header
->ncmds 
= mach_header
.Swap(mach_header
.Swap(mach_header
->ncmds
) - 1); 
 841                                     mach_header
->sizeofcmds 
= mach_header
.Swap(uint32_t(mach_header
.Swap(mach_header
->sizeofcmds
) - sizeof(struct linkedit_data_command
))); 
 845                                     struct symtab_command 
*symtab 
= reinterpret_cast<struct symtab_command 
*>(load_command
); 
 846                                     size 
= mach_header
.Swap(symtab
->stroff
) + mach_header
.Swap(symtab
->strsize
); 
 852                     _assert(size 
!= _not(uint32_t)); 
 854                     _foreach (segment
, const_cast<FatMachHeader 
&>(mach_header
).GetSegments("__LINKEDIT")) { 
 855                         segment
->filesize 
-= mach_header
.GetSize() - size
; 
 857                         if (fat_arch 
*fat_arch 
= mach_header
.GetFatArch()) { 
 858                             fat_arch
->size 
= fat_header
.Swap(size
); 
 859                             clip 
= std::max(clip
, fat_header
.Swap(fat_arch
->offset
) + size
); 
 861                             clip 
= std::max(clip
, size
); 
 864                     _foreach (segment
, const_cast<FatMachHeader 
&>(mach_header
).GetSegments64("__LINKEDIT")) { 
 865                         segment
->filesize 
-= mach_header
.GetSize() - size
; 
 867                         if (fat_arch 
*fat_arch 
= mach_header
.GetFatArch()) { 
 868                             fat_arch
->size 
= fat_header
.Swap(size
); 
 869                             clip 
= std::max(clip
, fat_header
.Swap(fat_arch
->offset
) + size
); 
 871                             clip 
= std::max(clip
, size
); 
 877                 _syscall(truncate(path
, clip
)); 
 881             asprintf(&temp
, "%s.%s.cs", dir
, base
); 
 882             const char *allocate 
= getenv("CODESIGN_ALLOCATE"); 
 883             if (allocate 
== NULL
) 
 884                 allocate 
= "codesign_allocate"; 
 886             std::vector
<CodesignAllocation
> allocations
; { 
 887                 FatHeader 
fat_header(Map(path
)); 
 888                 _foreach (mach_header
, fat_header
.GetMachHeaders()) { 
 890                         if (mach_header
.GetCPUType() != flag_CPUType
) 
 892                         if (mach_header
.GetCPUSubtype() != flag_CPUSubtype
) 
 896                     mach_header
->flags 
= mach_header
.Swap(mach_header
.Swap(mach_header
->flags
) | MH_DYLDLINK
); 
 898                     size_t size(_not(size_t)); { 
 899                         _foreach (load_command
, mach_header
.GetLoadCommands()) { 
 900                             uint32_t cmd(mach_header
.Swap(load_command
->cmd
)); 
 901                             if (cmd 
== LC_CODE_SIGNATURE
) { 
 902                                 struct linkedit_data_command 
*signature 
= reinterpret_cast<struct linkedit_data_command 
*>(load_command
); 
 903                                 size 
= mach_header
.Swap(signature
->dataoff
); 
 904                                 _assert(size 
< mach_header
.GetSize()); 
 909                         if (size 
== _not(size_t)) 
 910                             size 
= mach_header
.GetSize(); 
 913                     allocations
.push_back(CodesignAllocation(mach_header
.GetCPUType(), mach_header
.GetCPUSubtype(), size
)); 
 917             if (!allocations
.empty()) { 
 922                 // XXX: this leaks memory, but it doesn't really matter 
 923                 std::vector
<const char *> args
; 
 926                 args
.push_back(allocate
); 
 928                 args
.push_back("-i"); 
 929                 args
.push_back(path
); 
 931                 _foreach (allocation
, allocations
) { 
 932                     args
.push_back("-A"); 
 934                     asprintf(&arg
, "%u", allocation
.type_
); 
 937                     asprintf(&arg
, "%u", allocation
.subtype_
); 
 941                     alloc 
+= sizeof(struct SuperBlob
); 
 944                     special 
= std::max(special
, CSSLOT_CODEDIRECTORY
); 
 945                     alloc 
+= sizeof(struct BlobIndex
); 
 946                     alloc 
+= sizeof(struct CodeDirectory
); 
 947                     alloc 
+= strlen(base
) + 1; 
 949                     special 
= std::max(special
, CSSLOT_REQUIREMENTS
); 
 950                     alloc 
+= sizeof(struct BlobIndex
); 
 954                         special 
= std::max(special
, CSSLOT_ENTITLEMENTS
); 
 955                         alloc 
+= sizeof(struct BlobIndex
); 
 956                         alloc 
+= sizeof(struct Blob
); 
 960                     size_t normal((allocation
.size_ 
+ 0x1000 - 1) / 0x1000); 
 961                     alloc 
+= (special 
+ normal
) * 0x14; 
 967                     asprintf(&arg
, "%zu", alloc
); 
 971                 args
.push_back("-o"); 
 972                 args
.push_back(temp
); 
 974                 args
.push_back(NULL
); 
 983                 execvp(allocate
, (char **) &args
[0]); 
 988             _syscall(waitpid(pid
, &status
, 0)); 
 989             _assert(WIFEXITED(status
)); 
 990             _assert(WEXITSTATUS(status
) == 0); 
 996             printf("path%zu='%s'\n", filei
, file
.c_str()); 
 998         FatHeader 
fat_header(Map(temp 
== NULL 
? path 
: temp
, !(flag_R 
| flag_T 
| flag_s 
| flag_S 
| flag_O 
| flag_D
))); 
 999         struct linkedit_data_command 
*signature(NULL
); 
1001         _foreach (mach_header
, fat_header
.GetMachHeaders()) { 
1003                 if (mach_header
.GetCPUType() != flag_CPUType
) 
1005                 if (mach_header
.GetCPUSubtype() != flag_CPUSubtype
) 
1010                 printf("cpu=0x%x:0x%x\n", mach_header
.GetCPUType(), mach_header
.GetCPUSubtype()); 
1013                 if (struct fat_arch 
*fat_arch 
= mach_header
.GetFatArch()) 
1014                     printf("offset=0x%x\n", Swap(fat_arch
->offset
)); 
1016                     printf("offset=0x0\n"); 
1019             if (woffset 
!= _not(uintptr_t)) { 
1020                 Pointer
<uint32_t> wvalue(mach_header
.GetPointer
<uint32_t>(woffset
)); 
1022                     printf("(null) %p\n", reinterpret_cast<void *>(woffset
)); 
1024                     printf("0x%.08x\n", *wvalue
); 
1027             if (noffset 
!= _not(uintptr_t)) 
1028                 printf("%s\n", &*mach_header
.GetPointer
<char>(noffset
)); 
1031                 _foreach(segment
, mach_header
.GetSegments("__TEXT")) { 
1032                     printf("vmaddr=0x%x\n", mach_header
.Swap(segment
->vmaddr
)); 
1033                     printf("fileoff=0x%x\n", mach_header
.Swap(segment
->fileoff
)); 
1037                 _foreach(section
, mach_header
.GetSections("__TEXT", "__text")) 
1038                     section
->addr 
= mach_header
.Swap(0); 
1041             _foreach (load_command
, mach_header
.GetLoadCommands()) { 
1042                 uint32_t cmd(mach_header
.Swap(load_command
->cmd
)); 
1044                 if (flag_R 
&& cmd 
== LC_REEXPORT_DYLIB
) 
1045                     load_command
->cmd 
= mach_header
.Swap(LC_LOAD_DYLIB
); 
1046                 else if (cmd 
== LC_CODE_SIGNATURE
) 
1047                     signature 
= reinterpret_cast<struct linkedit_data_command 
*>(load_command
); 
1048                 else if (cmd 
== LC_UUID
) { 
1049                     volatile struct uuid_command 
*uuid_command(reinterpret_cast<struct uuid_command 
*>(load_command
)); 
1052                         printf("uuid%zu=%.2x%.2x%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x%.2x%.2x%.2x%.2x\n", filei
, 
1053                             uuid_command
->uuid
[ 0], uuid_command
->uuid
[ 1], uuid_command
->uuid
[ 2], uuid_command
->uuid
[ 3], 
1054                             uuid_command
->uuid
[ 4], uuid_command
->uuid
[ 5], uuid_command
->uuid
[ 6], uuid_command
->uuid
[ 7], 
1055                             uuid_command
->uuid
[ 8], uuid_command
->uuid
[ 9], uuid_command
->uuid
[10], uuid_command
->uuid
[11], 
1056                             uuid_command
->uuid
[12], uuid_command
->uuid
[13], uuid_command
->uuid
[14], uuid_command
->uuid
[15] 
1059                 } else if (cmd 
== LC_ID_DYLIB
) { 
1060                     volatile struct dylib_command 
*dylib_command(reinterpret_cast<struct dylib_command 
*>(load_command
)); 
1063                         printf("time%zu=0x%.8x\n", filei
, mach_header
.Swap(dylib_command
->dylib
.timestamp
)); 
1071                             dylib_command
->dylib
.timestamp 
= 0; 
1072                             timed 
= hash(reinterpret_cast<uint8_t *>(mach_header
.GetBase()), mach_header
.GetSize(), timev
); 
1075                         dylib_command
->dylib
.timestamp 
= mach_header
.Swap(timed
); 
1077                 } else if (cmd 
== LC_ENCRYPTION_INFO
) { 
1078                     volatile struct encryption_info_command 
*encryption_info_command(reinterpret_cast<struct encryption_info_command 
*>(load_command
)); 
1081                         encryption_info_command
->cryptid 
= mach_header
.Swap(0); 
1084                         printf("cryptoff=0x%x\n", mach_header
.Swap(encryption_info_command
->cryptoff
)); 
1085                         printf("cryptsize=0x%x\n", mach_header
.Swap(encryption_info_command
->cryptsize
)); 
1086                         printf("cryptid=0x%x\n", mach_header
.Swap(encryption_info_command
->cryptid
)); 
1092                 _assert(signature 
!= NULL
); 
1094                 uint32_t data 
= mach_header
.Swap(signature
->dataoff
); 
1096                 uint8_t *top 
= reinterpret_cast<uint8_t *>(mach_header
.GetBase()); 
1097                 uint8_t *blob 
= top 
+ data
; 
1098                 struct SuperBlob 
*super 
= reinterpret_cast<struct SuperBlob 
*>(blob
); 
1100                 for (size_t index(0); index 
!= Swap(super
->count
); ++index
) 
1101                     if (Swap(super
->index
[index
].type
) == CSSLOT_ENTITLEMENTS
) { 
1102                         uint32_t begin 
= Swap(super
->index
[index
].offset
); 
1103                         struct Blob 
*entitlements 
= reinterpret_cast<struct Blob 
*>(blob 
+ begin
); 
1104                         fwrite(entitlements 
+ 1, 1, Swap(entitlements
->length
) - sizeof(struct Blob
), stdout
); 
1109                 _assert(signature 
!= NULL
); 
1111                 uint32_t data 
= mach_header
.Swap(signature
->dataoff
); 
1113                 uint8_t *top 
= reinterpret_cast<uint8_t *>(mach_header
.GetBase()); 
1114                 uint8_t *blob 
= top 
+ data
; 
1115                 struct SuperBlob 
*super 
= reinterpret_cast<struct SuperBlob 
*>(blob
); 
1117                 for (size_t index(0); index 
!= Swap(super
->count
); ++index
) 
1118                     if (Swap(super
->index
[index
].type
) == CSSLOT_CODEDIRECTORY
) { 
1119                         uint32_t begin 
= Swap(super
->index
[index
].offset
); 
1120                         struct CodeDirectory 
*directory 
= reinterpret_cast<struct CodeDirectory 
*>(blob 
+ begin
); 
1122                         uint8_t (*hashes
)[20] = reinterpret_cast<uint8_t (*)[20]>(blob 
+ begin 
+ Swap(directory
->hashOffset
)); 
1123                         uint32_t pages 
= Swap(directory
->nCodeSlots
); 
1126                             for (size_t i 
= 0; i 
!= pages 
- 1; ++i
) 
1127                                 sha1(hashes
[i
], top 
+ 0x1000 * i
, 0x1000); 
1129                             sha1(hashes
[pages 
- 1], top 
+ 0x1000 * (pages 
- 1), ((data 
- 1) % 0x1000) + 1); 
1134                 _assert(signature 
!= NULL
); 
1136                 uint32_t data 
= mach_header
.Swap(signature
->dataoff
); 
1137                 uint32_t size 
= mach_header
.Swap(signature
->datasize
); 
1139                 uint8_t *top 
= reinterpret_cast<uint8_t *>(mach_header
.GetBase()); 
1140                 uint8_t *blob 
= top 
+ data
; 
1141                 struct SuperBlob 
*super 
= reinterpret_cast<struct SuperBlob 
*>(blob
); 
1142                 super
->blob
.magic 
= Swap(CSMAGIC_EMBEDDED_SIGNATURE
); 
1144                 uint32_t count 
= xmld 
== NULL 
? 2 : 3; 
1145                 uint32_t offset 
= sizeof(struct SuperBlob
) + count 
* sizeof(struct BlobIndex
); 
1147                 super
->index
[0].type 
= Swap(CSSLOT_CODEDIRECTORY
); 
1148                 super
->index
[0].offset 
= Swap(offset
); 
1150                 uint32_t begin 
= offset
; 
1151                 struct CodeDirectory 
*directory 
= reinterpret_cast<struct CodeDirectory 
*>(blob 
+ begin
); 
1152                 offset 
+= sizeof(struct CodeDirectory
); 
1154                 directory
->blob
.magic 
= Swap(CSMAGIC_CODEDIRECTORY
); 
1155                 directory
->version 
= Swap(uint32_t(0x00020001)); 
1156                 directory
->flags 
= Swap(uint32_t(0)); 
1157                 directory
->codeLimit 
= Swap(data
); 
1158                 directory
->hashSize 
= 0x14; 
1159                 directory
->hashType 
= 0x01; 
1160                 directory
->spare1 
= 0x00; 
1161                 directory
->pageSize 
= 0x0c; 
1162                 directory
->spare2 
= Swap(uint32_t(0)); 
1164                 directory
->identOffset 
= Swap(offset 
- begin
); 
1165                 strcpy(reinterpret_cast<char *>(blob 
+ offset
), base
); 
1166                 offset 
+= strlen(base
) + 1; 
1168                 uint32_t special 
= xmld 
== NULL 
? CSSLOT_REQUIREMENTS 
: CSSLOT_ENTITLEMENTS
; 
1169                 directory
->nSpecialSlots 
= Swap(special
); 
1171                 uint8_t (*hashes
)[20] = reinterpret_cast<uint8_t (*)[20]>(blob 
+ offset
); 
1172                 memset(hashes
, 0, sizeof(*hashes
) * special
); 
1174                 offset 
+= sizeof(*hashes
) * special
; 
1177                 uint32_t pages 
= (data 
+ 0x1000 - 1) / 0x1000; 
1178                 directory
->nCodeSlots 
= Swap(pages
); 
1181                     for (size_t i 
= 0; i 
!= pages 
- 1; ++i
) 
1182                         sha1(hashes
[i
], top 
+ 0x1000 * i
, 0x1000); 
1184                     sha1(hashes
[pages 
- 1], top 
+ 0x1000 * (pages 
- 1), ((data 
- 1) % 0x1000) + 1); 
1186                 directory
->hashOffset 
= Swap(offset 
- begin
); 
1187                 offset 
+= sizeof(*hashes
) * pages
; 
1188                 directory
->blob
.length 
= Swap(offset 
- begin
); 
1190                 super
->index
[1].type 
= Swap(CSSLOT_REQUIREMENTS
); 
1191                 super
->index
[1].offset 
= Swap(offset
); 
1193                 memcpy(blob 
+ offset
, "\xfa\xde\x0c\x01\x00\x00\x00\x0c\x00\x00\x00\x00", 0xc); 
1197                     super
->index
[2].type 
= Swap(CSSLOT_ENTITLEMENTS
); 
1198                     super
->index
[2].offset 
= Swap(offset
); 
1200                     uint32_t begin 
= offset
; 
1201                     struct Blob 
*entitlements 
= reinterpret_cast<struct Blob 
*>(blob 
+ begin
); 
1202                     offset 
+= sizeof(struct Blob
); 
1204                     memcpy(blob 
+ offset
, xmld
, xmls
); 
1207                     entitlements
->magic 
= Swap(CSMAGIC_ENTITLEMENTS
); 
1208                     entitlements
->length 
= Swap(offset 
- begin
); 
1211                 for (size_t index(0); index 
!= count
; ++index
) { 
1212                     uint32_t type 
= Swap(super
->index
[index
].type
); 
1213                     if (type 
!= 0 && type 
<= special
) { 
1214                         uint32_t offset 
= Swap(super
->index
[index
].offset
); 
1215                         struct Blob 
*local 
= (struct Blob 
*) (blob 
+ offset
); 
1216                         sha1((uint8_t *) (hashes 
- type
), (uint8_t *) local
, Swap(local
->length
)); 
1220                 super
->count 
= Swap(count
); 
1221                 super
->blob
.length 
= Swap(offset
); 
1223                 if (offset 
> size
) { 
1224                     fprintf(stderr
, "offset (%u) > size (%u)\n", offset
, size
); 
1226                 } //else fprintf(stderr, "offset (%zu) <= size (%zu)\n", offset, size); 
1228                 memset(blob 
+ offset
, 0, size 
- offset
); 
1233             uint8_t *top 
= reinterpret_cast<uint8_t *>(fat_header
.GetBase()); 
1234             size_t size 
= fat_header
.GetSize(); 
1237             asprintf(©
, "%s.%s.cp", dir
, base
); 
1238             FILE *file 
= fopen(copy
, "w+"); 
1239             size_t writ 
= fwrite(top
, 1, size
, file
); 
1240             _assert(writ 
== size
); 
1243             _syscall(unlink(temp
)); 
1250             _syscall(stat(path
, &info
)); 
1251             _syscall(chown(temp
, info
.st_uid
, info
.st_gid
)); 
1252             _syscall(chmod(temp
, info
.st_mode
)); 
1253             _syscall(unlink(path
)); 
1254             _syscall(rename(temp
, path
)); 
1260     } catch (const char *) {