1 /* ldid - (Mach-O) Link-Loader Identity Editor 
   2  * Copyright (C) 2007-2010  Jay Freeman (saurik) 
   6  *        Redistribution and use in source and binary 
   7  * forms, with or without modification, are permitted 
   8  * provided that the following conditions are met: 
  10  * 1. Redistributions of source code must retain the 
  11  *    above copyright notice, this list of conditions 
  12  *    and the following disclaimer. 
  13  * 2. Redistributions in binary form must reproduce the 
  14  *    above copyright notice, this list of conditions 
  15  *    and the following disclaimer in the documentation 
  16  *    and/or other materials provided with the 
  18  * 3. The name of the author may not be used to endorse 
  19  *    or promote products derived from this software 
  20  *    without specific prior written permission. 
  22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' 
  23  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, 
  24  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
  25  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
  26  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE 
  27  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
  28  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 
  29  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
  30  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
  31  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
  32  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 
  33  * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
  34  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
  35  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
  38 #include "minimal/stdlib.h" 
  39 #include "minimal/string.h" 
  40 #include "minimal/mapping.h" 
  49 #include <sys/types.h> 
  57 #define FAT_MAGIC 0xcafebabe 
  58 #define FAT_CIGAM 0xbebafeca 
  78 #define MH_MAGIC 0xfeedface 
  79 #define MH_CIGAM 0xcefaedfe 
  81 #define MH_MAGIC_64 0xfeedfacf 
  82 #define MH_CIGAM_64 0xcffaedfe 
  84 #define MH_DYLDLINK   0x4 
  86 #define MH_EXECUTE    0x2 
  89 #define MH_DYLIB_STUB 0x9 
  96 #define LC_REQ_DYLD           uint32_t(0x80000000) 
  98 #define LC_SEGMENT            uint32_t(0x01) 
  99 #define LC_SYMTAB             uint32_t(0x02) 
 100 #define LC_DYSYMTAB           uint32_t(0x0b) 
 101 #define LC_LOAD_DYLIB         uint32_t(0x0c) 
 102 #define LC_ID_DYLIB           uint32_t(0x0d) 
 103 #define LC_UUID               uint32_t(0x1b) 
 104 #define LC_CODE_SIGNATURE     uint32_t(0x1d) 
 105 #define LC_SEGMENT_SPLIT_INFO uint32_t(0x1e) 
 106 #define LC_REEXPORT_DYLIB     uint32_t(0x1f | LC_REQ_DYLD) 
 107 #define LC_DYLD_INFO          uint32_t(0x22) 
 108 #define LC_DYLD_INFO_ONLY     uint32_t(0x22 | LC_REQ_DYLD) 
 113     uint32_t current_version
; 
 114     uint32_t compatibility_version
; 
 117 struct dylib_command 
{ 
 123 struct uuid_command 
{ 
 129 struct symtab_command 
{ 
 138 struct dyld_info_command 
{ 
 142     uint32_t rebase_size
; 
 145     uint32_t weak_bind_off
; 
 146     uint32_t weak_bind_size
; 
 147     uint32_t lazy_bind_off
; 
 148     uint32_t lazy_bind_size
; 
 150     uint32_t export_size
; 
 153 struct dysymtab_command 
{ 
 166     uint32_t extrefsymoff
; 
 167     uint32_t nextrefsyms
; 
 168     uint32_t indirectsymoff
; 
 169     uint32_t nindirectsyms
; 
 176 struct dylib_table_of_contents 
{ 
 177     uint32_t symbol_index
; 
 178     uint32_t module_index
; 
 181 struct dylib_module 
{ 
 182     uint32_t module_name
; 
 191     uint32_t iinit_iterm
; 
 192     uint32_t ninit_nterm
; 
 193     uint32_t objc_module_info_addr
; 
 194     uint32_t objc_module_info_size
; 
 197 struct dylib_reference 
{ 
 202 struct relocation_info 
{ 
 204     uint32_t r_symbolnum
:24; 
 223 struct segment_command 
{ 
 251 struct linkedit_data_command 
{ 
 258 uint16_t Swap_(uint16_t value
) { 
 260         ((value 
>>  8) & 0x00ff) | 
 261         ((value 
<<  8) & 0xff00); 
 264 uint32_t Swap_(uint32_t value
) { 
 265     value 
= ((value 
>>  8) & 0x00ff00ff) | 
 266             ((value 
<<  8) & 0xff00ff00); 
 267     value 
= ((value 
>> 16) & 0x0000ffff) | 
 268             ((value 
<< 16) & 0xffff0000); 
 272 int16_t Swap_(int16_t value
) { 
 273     return Swap_(static_cast<uint16_t>(value
)); 
 276 int32_t Swap_(int32_t value
) { 
 277     return Swap_(static_cast<uint32_t>(value
)); 
 282 uint16_t Swap(uint16_t value
) { 
 283     return little_ 
? Swap_(value
) : value
; 
 286 uint32_t Swap(uint32_t value
) { 
 287     return little_ 
? Swap_(value
) : value
; 
 290 int16_t Swap(int16_t value
) { 
 291     return Swap(static_cast<uint16_t>(value
)); 
 294 int32_t Swap(int32_t value
) { 
 295     return Swap(static_cast<uint32_t>(value
)); 
 298 template <typename Target_
> 
 310     Data(void *base
, size_t size
) : 
 317     uint16_t Swap(uint16_t value
) const { 
 318         return swapped_ 
? Swap_(value
) : value
; 
 321     uint32_t Swap(uint32_t value
) const { 
 322         return swapped_ 
? Swap_(value
) : value
; 
 325     int16_t Swap(int16_t value
) const { 
 326         return Swap(static_cast<uint16_t>(value
)); 
 329     int32_t Swap(int32_t value
) const { 
 330         return Swap(static_cast<uint32_t>(value
)); 
 333     void *GetBase() const { 
 337     size_t GetSize() const { 
 348     struct mach_header 
*mach_header_
; 
 349     struct load_command 
*load_command_
; 
 352     MachHeader(void *base
, size_t size
) : 
 355         mach_header_ 
= (mach_header 
*) base
; 
 357         switch (Swap(mach_header_
->magic
)) { 
 359                 swapped_ 
= !swapped_
; 
 365                 swapped_ 
= !swapped_
; 
 374         void *post 
= mach_header_ 
+ 1; 
 376             post 
= (uint32_t *) post 
+ 1; 
 377         load_command_ 
= (struct load_command 
*) post
; 
 380             Swap(mach_header_
->filetype
) == MH_EXECUTE 
|| 
 381             Swap(mach_header_
->filetype
) == MH_DYLIB 
|| 
 382             Swap(mach_header_
->filetype
) == MH_BUNDLE
 
 386     struct mach_header 
*operator ->() const { 
 390     uint32_t GetCPUType() const { 
 391         return Swap(mach_header_
->cputype
); 
 394     uint16_t GetCPUSubtype() const { 
 395         return Swap(mach_header_
->cpusubtype
) & 0xff; 
 398     std::vector
<struct load_command 
*> GetLoadCommands() const { 
 399         std::vector
<struct load_command 
*> load_commands
; 
 401         struct load_command 
*load_command 
= load_command_
; 
 402         for (uint32_t cmd 
= 0; cmd 
!= Swap(mach_header_
->ncmds
); ++cmd
) { 
 403             load_commands
.push_back(load_command
); 
 404             load_command 
= (struct load_command 
*) ((uint8_t *) load_command 
+ Swap(load_command
->cmdsize
)); 
 407         return load_commands
; 
 410     std::vector
<segment_command 
*> GetSegments(const char *segment_name
) { 
 411         std::vector
<struct segment_command 
*> segment_commands
; 
 413         _foreach (load_command
, GetLoadCommands()) 
 414             if (Swap(load_command
->cmd
) == LC_SEGMENT
) { 
 415                 segment_command 
*segment_command 
= reinterpret_cast<struct segment_command 
*>(load_command
); 
 416                 if (strncmp(segment_command
->segname
, segment_name
, 16) == 0) 
 417                     segment_commands
.push_back(segment_command
); 
 420         return segment_commands
; 
 423     std::vector
<section 
*> GetSections(const char *segment_name
, const char *section_name
) { 
 424         std::vector
<section 
*> sections
; 
 426         _foreach (segment
, GetSegments(segment_name
)) { 
 427             section 
*section 
= (struct section 
*) (segment 
+ 1); 
 430             for (sect 
= 0; sect 
!= Swap(segment
->nsects
); ++sect
) { 
 431                 if (strncmp(section
->sectname
, section_name
, 16) == 0) 
 432                     sections
.push_back(section
); 
 440     template <typename Target_
> 
 441     Pointer
<Target_
> GetPointer(uint32_t address
, const char *segment_name 
= NULL
) const { 
 442         load_command 
*load_command 
= (struct load_command 
*) (mach_header_ 
+ 1); 
 445         for (cmd 
= 0; cmd 
!= Swap(mach_header_
->ncmds
); ++cmd
) { 
 446             if (Swap(load_command
->cmd
) == LC_SEGMENT
) { 
 447                 segment_command 
*segment_command 
= (struct segment_command 
*) load_command
; 
 448                 if (segment_name 
!= NULL 
&& strncmp(segment_command
->segname
, segment_name
, 16) != 0) 
 451                 section 
*sections 
= (struct section 
*) (segment_command 
+ 1); 
 454                 for (sect 
= 0; sect 
!= Swap(segment_command
->nsects
); ++sect
) { 
 455                     section 
*section 
= §ions
[sect
]; 
 456                     //printf("%s %u %p %p %u\n", segment_command->segname, sect, address, section->addr, section->size); 
 457                     if (address 
>= Swap(section
->addr
) && address 
< Swap(section
->addr
) + Swap(section
->size
)) { 
 458                         //printf("0x%.8x %s\n", address, segment_command->segname); 
 459                         return Pointer
<Target_
>(this, reinterpret_cast<Target_ 
*>(address 
- Swap(section
->addr
) + Swap(section
->offset
) + (char *) mach_header_
)); 
 465             load_command 
= (struct load_command 
*) ((char *) load_command 
+ Swap(load_command
->cmdsize
)); 
 468         return Pointer
<Target_
>(this); 
 471     template <typename Target_
> 
 472     Pointer
<Target_
> GetOffset(uint32_t offset
) { 
 473         return Pointer
<Target_
>(this, reinterpret_cast<Target_ 
*>(offset 
+ (uint8_t *) mach_header_
)); 
 481     fat_header 
*fat_header_
; 
 482     std::vector
<MachHeader
> mach_headers_
; 
 485     FatHeader(void *base
, size_t size
) : 
 488         fat_header_ 
= reinterpret_cast<struct fat_header 
*>(base
); 
 490         if (Swap(fat_header_
->magic
) == FAT_CIGAM
) { 
 491             swapped_ 
= !swapped_
; 
 493         } else if (Swap(fat_header_
->magic
) != FAT_MAGIC
) { 
 495             mach_headers_
.push_back(MachHeader(base
, size
)); 
 497             size_t fat_narch 
= Swap(fat_header_
->nfat_arch
); 
 498             fat_arch 
*fat_arch 
= reinterpret_cast<struct fat_arch 
*>(fat_header_ 
+ 1); 
 500             for (arch 
= 0; arch 
!= fat_narch
; ++arch
) { 
 501                 uint32_t arch_offset 
= Swap(fat_arch
->offset
); 
 502                 uint32_t arch_size 
= Swap(fat_arch
->size
); 
 503                 mach_headers_
.push_back(MachHeader((uint8_t *) base 
+ arch_offset
, size
)); 
 509     std::vector
<MachHeader
> &GetMachHeaders() { 
 510         return mach_headers_
; 
 514         return fat_header_ 
!= NULL
; 
 518 FatHeader 
Map(const char *path
) { 
 520     void *base(map(path
, 0, _not(size_t), &size
, false)); 
 521     return FatHeader(base
, size
); 
 524 template <typename Target_
> 
 527     const MachHeader 
*framework_
; 
 528     const Target_ 
*pointer_
; 
 531     Pointer(const MachHeader 
*framework 
= NULL
, const Target_ 
*pointer 
= NULL
) : 
 532         framework_(framework
), 
 537     operator const Target_ 
*() const { 
 541     const Target_ 
*operator ->() const { 
 545     Pointer
<Target_
> &operator ++() { 
 550     template <typename Value_
> 
 551     Value_ 
Swap(Value_ value
) { 
 552         return framework_
->Swap(value
); 
 556 #define CSMAGIC_CODEDIRECTORY      uint32_t(0xfade0c02) 
 557 #define CSMAGIC_EMBEDDED_SIGNATURE uint32_t(0xfade0cc0) 
 558 #define CSMAGIC_ENTITLEMENTS       uint32_t(0xfade7171) 
 560 #define CSSLOT_CODEDIRECTORY uint32_t(0) 
 561 #define CSSLOT_REQUIREMENTS  uint32_t(2) 
 562 #define CSSLOT_ENTITLEMENTS  uint32_t(5) 
 577     struct BlobIndex index
[]; 
 580 struct CodeDirectory 
{ 
 585     uint32_t identOffset
; 
 586     uint32_t nSpecialSlots
; 
 596 extern "C" uint32_t hash(uint8_t *k
, uint32_t length
, uint32_t initval
); 
 598 void sha1(uint8_t *hash
, uint8_t *data
, size_t size
) { 
 601     SHA1Input(&context
, data
, size
); 
 602     SHA1Result(&context
, hash
); 
 605 struct CodesignAllocation 
{ 
 610     CodesignAllocation(uint32_t type
, uint16_t subtype
, size_t size
) : 
 618 int main(int argc
, const char *argv
[]) { 
 624     little_ 
= endian
.byte
[0]; 
 642     const void *xmld(NULL
); 
 645     uintptr_t noffset(_not(uintptr_t)); 
 646     uintptr_t woffset(_not(uintptr_t)); 
 648     std::vector
<std::string
> files
; 
 651         fprintf(stderr
, "usage: %s -S[entitlements.xml] <binary>\n", argv
[0]); 
 652         fprintf(stderr
, "   %s -e MobileSafari\n", argv
[0]); 
 653         fprintf(stderr
, "   %s -S cat\n", argv
[0]); 
 654         fprintf(stderr
, "   %s -Stfp.xml gdb\n", argv
[0]); 
 658     for (int argi(1); argi 
!= argc
; ++argi
) 
 659         if (argv
[argi
][0] != '-') 
 660             files
.push_back(argv
[argi
]); 
 661         else switch (argv
[argi
][1]) { 
 662             case 'R': flag_R 
= true; break; 
 663             case 'r': flag_r 
= true; break; 
 665             case 't': flag_t 
= true; break; 
 666             case 'u': flag_u 
= true; break; 
 667             case 'p': flag_p 
= true; break; 
 668             case 'e': flag_e 
= true; break; 
 678                 if (argv
[argi
][2] != '\0') { 
 679                     const char *xml 
= argv
[argi
] + 2; 
 680                     xmld 
= map(xml
, 0, _not(size_t), &xmls
, true); 
 686                 if (argv
[argi
][2] == '-') 
 690                     timev 
= strtoul(argv
[argi
] + 2, &arge
, 0); 
 691                     _assert(arge 
== argv
[argi
] + strlen(argv
[argi
])); 
 697                 noffset 
= strtoul(argv
[argi
] + 2, &arge
, 0); 
 698                 _assert(arge 
== argv
[argi
] + strlen(argv
[argi
])); 
 703                 woffset 
= strtoul(argv
[argi
] + 2, &arge
, 0); 
 704                 _assert(arge 
== argv
[argi
] + strlen(argv
[argi
])); 
 712     if (files
.empty()) usage
: { 
 716     size_t filei(0), filee(0); 
 717     _foreach (file
, files
) try { 
 718         const char *path(file
.c_str()); 
 719         const char *base 
= strrchr(path
, '/'); 
 720         char *temp(NULL
), *dir
; 
 723             dir 
= strndup_(path
, base
++ - path 
+ 1); 
 730             size_t clip(_not(size_t)); { 
 731                 FatHeader 
fat_header(Map(path
)); 
 732                 _foreach (mach_header
, fat_header
.GetMachHeaders()) { 
 733                     mach_header
->flags 
= mach_header
.Swap(mach_header
.Swap(mach_header
->flags
) | MH_DYLDLINK
); 
 735                     size_t size(_not(size_t)); { 
 736                         _foreach (load_command
, mach_header
.GetLoadCommands()) { 
 737                             switch (mach_header
.Swap(load_command
->cmd
)) { 
 738                                 case LC_CODE_SIGNATURE
: { 
 739                                     struct linkedit_data_command 
*signature 
= reinterpret_cast<struct linkedit_data_command 
*>(load_command
); 
 740                                     memset(signature
, 0, sizeof(struct linkedit_data_command
)); 
 742                                     mach_header
->ncmds 
-= 1; 
 743                                     mach_header
->sizeofcmds 
-= sizeof(struct linkedit_data_command
); 
 747                                     struct symtab_command 
*symtab 
= reinterpret_cast<struct symtab_command 
*>(load_command
); 
 748                                     size 
= symtab
->stroff 
+ symtab
->strsize
; 
 753                         _foreach (segment
, const_cast<MachHeader 
&>(mach_header
).GetSegments("__LINKEDIT")) { 
 754                             segment
->filesize 
-= mach_header
.GetSize() - size
; 
 756                             if (!fat_header
.IsFat()) 
 765             if (clip 
!= _not(size_t)) 
 766                 _syscall(truncate(path
, clip
)); 
 770             asprintf(&temp
, "%s.%s.cs", dir
, base
); 
 771             const char *allocate 
= getenv("CODESIGN_ALLOCATE"); 
 772             if (allocate 
== NULL
) 
 773                 allocate 
= "codesign_allocate"; 
 775             std::vector
<CodesignAllocation
> allocations
; { 
 776                 FatHeader 
fat_header(Map(path
)); 
 777                 _foreach (mach_header
, fat_header
.GetMachHeaders()) { 
 778                     mach_header
->flags 
= mach_header
.Swap(mach_header
.Swap(mach_header
->flags
) | MH_DYLDLINK
); 
 780                     size_t size(_not(size_t)); { 
 781                         _foreach (load_command
, mach_header
.GetLoadCommands()) { 
 782                             uint32_t cmd(mach_header
.Swap(load_command
->cmd
)); 
 783                             if (cmd 
== LC_CODE_SIGNATURE
) { 
 784                                 struct linkedit_data_command 
*signature 
= reinterpret_cast<struct linkedit_data_command 
*>(load_command
); 
 785                                 size 
= mach_header
.Swap(signature
->dataoff
); 
 786                                 _assert(size 
< mach_header
.GetSize()); 
 791                         if (size 
== _not(size_t)) 
 792                             size 
= mach_header
.GetSize(); 
 795                     allocations
.push_back(CodesignAllocation(mach_header
.GetCPUType(), mach_header
.GetCPUSubtype(), size
)); 
 802                 // XXX: this leaks memory, but it doesn't really matter 
 803                 std::vector
<const char *> args
; 
 806                 args
.push_back(allocate
); 
 808                 args
.push_back("-i"); 
 809                 args
.push_back(path
); 
 811                 _foreach (allocation
, allocations
) { 
 812                     args
.push_back("-A"); 
 814                     asprintf(&arg
, "%u", allocation
.type_
); 
 817                     asprintf(&arg
, "%u", allocation
.subtype_
); 
 821                     alloc 
+= sizeof(struct SuperBlob
); 
 824                     special 
= std::max(special
, CSSLOT_CODEDIRECTORY
); 
 825                     alloc 
+= sizeof(struct BlobIndex
); 
 826                     alloc 
+= sizeof(struct CodeDirectory
); 
 827                     alloc 
+= strlen(base
) + 1; 
 829                     special 
= std::max(special
, CSSLOT_REQUIREMENTS
); 
 830                     alloc 
+= sizeof(struct BlobIndex
); 
 834                         special 
= std::max(special
, CSSLOT_ENTITLEMENTS
); 
 835                         alloc 
+= sizeof(struct BlobIndex
); 
 836                         alloc 
+= sizeof(struct Blob
); 
 840                     size_t normal((allocation
.size_ 
+ 0x1000 - 1) / 0x1000); 
 841                     alloc 
+= (special 
+ normal
) * 0x14; 
 847                     asprintf(&arg
, "%u", alloc
); 
 851                 args
.push_back("-o"); 
 852                 args
.push_back(temp
); 
 854                 args
.push_back(NULL
); 
 863                 execvp(allocate
, (char **) &args
[0]); 
 868             _syscall(waitpid(pid
, &status
, 0)); 
 869             _assert(WIFEXITED(status
)); 
 870             _assert(WEXITSTATUS(status
) == 0); 
 874             printf("path%zu='%s'\n", filei
, file
.c_str()); 
 876         FatHeader 
fat_header(Map(temp 
== NULL 
? path 
: temp
)); 
 877         struct linkedit_data_command 
*signature(NULL
); 
 879         _foreach (mach_header
, fat_header
.GetMachHeaders()) { 
 880             if (woffset 
!= _not(uintptr_t)) { 
 881                 Pointer
<uint32_t> wvalue(mach_header
.GetPointer
<uint32_t>(woffset
)); 
 883                     printf("(null) %p\n", reinterpret_cast<void *>(woffset
)); 
 885                     printf("0x%.08x\n", *wvalue
); 
 888             if (noffset 
!= _not(uintptr_t)) 
 889                 printf("%s\n", &*mach_header
.GetPointer
<char>(noffset
)); 
 891             _foreach (load_command
, mach_header
.GetLoadCommands()) { 
 892                 uint32_t cmd(mach_header
.Swap(load_command
->cmd
)); 
 894                 if (flag_R 
&& cmd 
== LC_REEXPORT_DYLIB
) 
 895                     load_command
->cmd 
= mach_header
.Swap(LC_LOAD_DYLIB
); 
 896                 else if (cmd 
== LC_CODE_SIGNATURE
) 
 897                     signature 
= reinterpret_cast<struct linkedit_data_command 
*>(load_command
); 
 898                 else if (cmd 
== LC_UUID
) { 
 899                     volatile struct uuid_command 
*uuid_command(reinterpret_cast<struct uuid_command 
*>(load_command
)); 
 902                         printf("uuid%zu=%.2x%.2x%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x%.2x%.2x%.2x%.2x\n", filei
, 
 903                             uuid_command
->uuid
[ 0], uuid_command
->uuid
[ 1], uuid_command
->uuid
[ 2], uuid_command
->uuid
[ 3], 
 904                             uuid_command
->uuid
[ 4], uuid_command
->uuid
[ 5], uuid_command
->uuid
[ 6], uuid_command
->uuid
[ 7], 
 905                             uuid_command
->uuid
[ 8], uuid_command
->uuid
[ 9], uuid_command
->uuid
[10], uuid_command
->uuid
[11], 
 906                             uuid_command
->uuid
[12], uuid_command
->uuid
[13], uuid_command
->uuid
[14], uuid_command
->uuid
[15] 
 909                 } else if (cmd 
== LC_ID_DYLIB
) { 
 910                     volatile struct dylib_command 
*dylib_command(reinterpret_cast<struct dylib_command 
*>(load_command
)); 
 913                         printf("time%zu=0x%.8x\n", filei
, mach_header
.Swap(dylib_command
->dylib
.timestamp
)); 
 921                             dylib_command
->dylib
.timestamp 
= 0; 
 922                             timed 
= hash(reinterpret_cast<uint8_t *>(mach_header
.GetBase()), mach_header
.GetSize(), timev
); 
 925                         dylib_command
->dylib
.timestamp 
= mach_header
.Swap(timed
); 
 931                 _assert(signature 
!= NULL
); 
 933                 uint32_t data 
= mach_header
.Swap(signature
->dataoff
); 
 934                 uint32_t size 
= mach_header
.Swap(signature
->datasize
); 
 936                 uint8_t *top 
= reinterpret_cast<uint8_t *>(mach_header
.GetBase()); 
 937                 uint8_t *blob 
= top 
+ data
; 
 938                 struct SuperBlob 
*super 
= reinterpret_cast<struct SuperBlob 
*>(blob
); 
 940                 for (size_t index(0); index 
!= Swap(super
->count
); ++index
) 
 941                     if (Swap(super
->index
[index
].type
) == CSSLOT_ENTITLEMENTS
) { 
 942                         uint32_t begin 
= Swap(super
->index
[index
].offset
); 
 943                         struct Blob 
*entitlements 
= reinterpret_cast<struct Blob 
*>(blob 
+ begin
); 
 944                         fwrite(entitlements 
+ 1, 1, Swap(entitlements
->length
) - sizeof(struct Blob
), stdout
); 
 949                 _assert(signature 
!= NULL
); 
 951                 uint32_t data 
= mach_header
.Swap(signature
->dataoff
); 
 952                 uint32_t size 
= mach_header
.Swap(signature
->datasize
); 
 954                 uint8_t *top 
= reinterpret_cast<uint8_t *>(mach_header
.GetBase()); 
 955                 uint8_t *blob 
= top 
+ data
; 
 956                 struct SuperBlob 
*super 
= reinterpret_cast<struct SuperBlob 
*>(blob
); 
 958                 for (size_t index(0); index 
!= Swap(super
->count
); ++index
) 
 959                     if (Swap(super
->index
[index
].type
) == CSSLOT_CODEDIRECTORY
) { 
 960                         uint32_t begin 
= Swap(super
->index
[index
].offset
); 
 961                         struct CodeDirectory 
*directory 
= reinterpret_cast<struct CodeDirectory 
*>(blob 
+ begin
); 
 963                         uint8_t (*hashes
)[20] = reinterpret_cast<uint8_t (*)[20]>(blob 
+ begin 
+ Swap(directory
->hashOffset
)); 
 964                         uint32_t pages 
= Swap(directory
->nCodeSlots
); 
 967                             for (size_t i 
= 0; i 
!= pages 
- 1; ++i
) 
 968                                 sha1(hashes
[i
], top 
+ 0x1000 * i
, 0x1000); 
 970                             sha1(hashes
[pages 
- 1], top 
+ 0x1000 * (pages 
- 1), ((data 
- 1) % 0x1000) + 1); 
 975                 _assert(signature 
!= NULL
); 
 977                 uint32_t data 
= mach_header
.Swap(signature
->dataoff
); 
 978                 uint32_t size 
= mach_header
.Swap(signature
->datasize
); 
 980                 uint8_t *top 
= reinterpret_cast<uint8_t *>(mach_header
.GetBase()); 
 981                 uint8_t *blob 
= top 
+ data
; 
 982                 struct SuperBlob 
*super 
= reinterpret_cast<struct SuperBlob 
*>(blob
); 
 983                 super
->blob
.magic 
= Swap(CSMAGIC_EMBEDDED_SIGNATURE
); 
 985                 uint32_t count 
= xmld 
== NULL 
? 2 : 3; 
 986                 uint32_t offset 
= sizeof(struct SuperBlob
) + count 
* sizeof(struct BlobIndex
); 
 988                 super
->index
[0].type 
= Swap(CSSLOT_CODEDIRECTORY
); 
 989                 super
->index
[0].offset 
= Swap(offset
); 
 991                 uint32_t begin 
= offset
; 
 992                 struct CodeDirectory 
*directory 
= reinterpret_cast<struct CodeDirectory 
*>(blob 
+ begin
); 
 993                 offset 
+= sizeof(struct CodeDirectory
); 
 995                 directory
->blob
.magic 
= Swap(CSMAGIC_CODEDIRECTORY
); 
 996                 directory
->version 
= Swap(uint32_t(0x00020001)); 
 997                 directory
->flags 
= Swap(uint32_t(0)); 
 998                 directory
->codeLimit 
= Swap(data
); 
 999                 directory
->hashSize 
= 0x14; 
1000                 directory
->hashType 
= 0x01; 
1001                 directory
->spare1 
= 0x00; 
1002                 directory
->pageSize 
= 0x0c; 
1003                 directory
->spare2 
= Swap(uint32_t(0)); 
1005                 directory
->identOffset 
= Swap(offset 
- begin
); 
1006                 strcpy(reinterpret_cast<char *>(blob 
+ offset
), base
); 
1007                 offset 
+= strlen(base
) + 1; 
1009                 uint32_t special 
= xmld 
== NULL 
? CSSLOT_REQUIREMENTS 
: CSSLOT_ENTITLEMENTS
; 
1010                 directory
->nSpecialSlots 
= Swap(special
); 
1012                 uint8_t (*hashes
)[20] = reinterpret_cast<uint8_t (*)[20]>(blob 
+ offset
); 
1013                 memset(hashes
, 0, sizeof(*hashes
) * special
); 
1015                 offset 
+= sizeof(*hashes
) * special
; 
1018                 uint32_t pages 
= (data 
+ 0x1000 - 1) / 0x1000; 
1019                 directory
->nCodeSlots 
= Swap(pages
); 
1022                     for (size_t i 
= 0; i 
!= pages 
- 1; ++i
) 
1023                         sha1(hashes
[i
], top 
+ 0x1000 * i
, 0x1000); 
1025                     sha1(hashes
[pages 
- 1], top 
+ 0x1000 * (pages 
- 1), ((data 
- 1) % 0x1000) + 1); 
1027                 directory
->hashOffset 
= Swap(offset 
- begin
); 
1028                 offset 
+= sizeof(*hashes
) * pages
; 
1029                 directory
->blob
.length 
= Swap(offset 
- begin
); 
1031                 super
->index
[1].type 
= Swap(CSSLOT_REQUIREMENTS
); 
1032                 super
->index
[1].offset 
= Swap(offset
); 
1034                 memcpy(blob 
+ offset
, "\xfa\xde\x0c\x01\x00\x00\x00\x0c\x00\x00\x00\x00", 0xc); 
1038                     super
->index
[2].type 
= Swap(CSSLOT_ENTITLEMENTS
); 
1039                     super
->index
[2].offset 
= Swap(offset
); 
1041                     uint32_t begin 
= offset
; 
1042                     struct Blob 
*entitlements 
= reinterpret_cast<struct Blob 
*>(blob 
+ begin
); 
1043                     offset 
+= sizeof(struct Blob
); 
1045                     memcpy(blob 
+ offset
, xmld
, xmls
); 
1048                     entitlements
->magic 
= Swap(CSMAGIC_ENTITLEMENTS
); 
1049                     entitlements
->length 
= Swap(offset 
- begin
); 
1052                 for (size_t index(0); index 
!= count
; ++index
) { 
1053                     uint32_t type 
= Swap(super
->index
[index
].type
); 
1054                     if (type 
!= 0 && type 
<= special
) { 
1055                         uint32_t offset 
= Swap(super
->index
[index
].offset
); 
1056                         struct Blob 
*local 
= (struct Blob 
*) (blob 
+ offset
); 
1057                         sha1((uint8_t *) (hashes 
- type
), (uint8_t *) local
, Swap(local
->length
)); 
1061                 super
->count 
= Swap(count
); 
1062                 super
->blob
.length 
= Swap(offset
); 
1064                 if (offset 
> size
) { 
1065                     fprintf(stderr
, "offset (%u) > size (%u)\n", offset
, size
); 
1067                 } //else fprintf(stderr, "offset (%zu) <= size (%zu)\n", offset, size); 
1069                 memset(blob 
+ offset
, 0, size 
- offset
); 
1074             uint8_t *top 
= reinterpret_cast<uint8_t *>(fat_header
.GetBase()); 
1075             size_t size 
= fat_header
.GetSize(); 
1078             asprintf(©
, "%s.%s.cp", dir
, base
); 
1079             FILE *file 
= fopen(copy
, "w+"); 
1080             size_t writ 
= fwrite(top
, 1, size
, file
); 
1081             _assert(writ 
== size
); 
1084             _syscall(unlink(temp
)); 
1091             _syscall(stat(path
, &info
)); 
1092             _syscall(chown(temp
, info
.st_uid
, info
.st_gid
)); 
1093             _syscall(chmod(temp
, info
.st_mode
)); 
1094             _syscall(unlink(path
)); 
1095             _syscall(rename(temp
, path
)); 
1101     } catch (const char *) {