1 /* JocStrap - Java/Objective-C Bootstrap 
   2  * Copyright (C) 2007  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_EXECUTE    0x2 
  84 #define MH_DYLIB_STUB 0x9 
  91 #define LC_REQ_DYLD  0x80000000 
  93 #define LC_SEGMENT         0x01 
  94 #define LC_LOAD_DYLIB      0x0c 
  95 #define LC_ID_DYLIB        0x0d 
  97 #define LC_CODE_SIGNATURE  0x1d 
  98 #define LC_REEXPORT_DYLIB (0x1f | LC_REQ_DYLD) 
 103     uint32_t current_version
; 
 104     uint32_t compatibility_version
; 
 107 struct dylib_command 
{ 
 113 struct uuid_command 
{ 
 119 struct segment_command 
{ 
 147 struct linkedit_data_command 
{ 
 154 uint16_t Swap_(uint16_t value
) { 
 156         ((value 
>>  8) & 0x00ff) | 
 157         ((value 
<<  8) & 0xff00); 
 160 uint32_t Swap_(uint32_t value
) { 
 161     value 
= ((value 
>>  8) & 0x00ff00ff) | 
 162             ((value 
<<  8) & 0xff00ff00); 
 163     value 
= ((value 
>> 16) & 0x0000ffff) | 
 164             ((value 
<< 16) & 0xffff0000); 
 168 int16_t Swap_(int16_t value
) { 
 169     return Swap_(static_cast<uint16_t>(value
)); 
 172 int32_t Swap_(int32_t value
) { 
 173     return Swap_(static_cast<uint32_t>(value
)); 
 176 uint16_t Swap(uint16_t value
) { 
 177     return true ? Swap_(value
) : value
; 
 180 uint32_t Swap(uint32_t value
) { 
 181     return true ? Swap_(value
) : value
; 
 184 int16_t Swap(int16_t value
) { 
 185     return Swap(static_cast<uint16_t>(value
)); 
 188 int32_t Swap(int32_t value
) { 
 189     return Swap(static_cast<uint32_t>(value
)); 
 192 template <typename Target_
> 
 199     mach_header 
*mach_header_
; 
 203     uint16_t Swap(uint16_t value
) const { 
 204         return swapped_ 
? Swap_(value
) : value
; 
 207     uint32_t Swap(uint32_t value
) const { 
 208         return swapped_ 
? Swap_(value
) : value
; 
 211     int16_t Swap(int16_t value
) const { 
 212         return Swap(static_cast<uint16_t>(value
)); 
 215     int32_t Swap(int32_t value
) const { 
 216         return Swap(static_cast<uint32_t>(value
)); 
 219     Framework(const char *framework_path
) : 
 222         base_ 
= map(framework_path
, 0, _not(size_t), &size_
, false); 
 223         fat_header 
*fat_header 
= reinterpret_cast<struct fat_header 
*>(base_
); 
 225         if (Swap(fat_header
->magic
) == FAT_CIGAM
) { 
 226             swapped_ 
= !swapped_
; 
 228         } else if (Swap(fat_header
->magic
) != FAT_MAGIC
) 
 229             mach_header_ 
= (mach_header 
*) base_
; 
 231             size_t fat_narch 
= Swap(fat_header
->nfat_arch
); 
 232             fat_arch 
*fat_arch 
= reinterpret_cast<struct fat_arch 
*>(fat_header 
+ 1); 
 234             for (arch 
= 0; arch 
!= fat_narch
; ++arch
) { 
 235                 uint32_t arch_offset 
= Swap(fat_arch
->offset
); 
 236                 mach_header_ 
= (mach_header 
*) ((uint8_t *) base_ 
+ arch_offset
); 
 245         if (Swap(mach_header_
->magic
) == MH_CIGAM
) 
 246             swapped_ 
= !swapped_
; 
 247         else _assert(Swap(mach_header_
->magic
) == MH_MAGIC
); 
 250             Swap(mach_header_
->filetype
) == MH_EXECUTE 
|| 
 251             Swap(mach_header_
->filetype
) == MH_DYLIB 
|| 
 252             Swap(mach_header_
->filetype
) == MH_BUNDLE
 
 256     struct mach_header 
*operator ->() const { 
 268     std::vector
<struct load_command 
*> GetLoadCommands() { 
 269         std::vector
<struct load_command 
*> load_commands
; 
 271         struct load_command 
*load_command 
= reinterpret_cast<struct load_command 
*>(mach_header_ 
+ 1); 
 272         for (uint32_t cmd 
= 0; cmd 
!= Swap(mach_header_
->ncmds
); ++cmd
) { 
 273             load_commands
.push_back(load_command
); 
 274             load_command 
= (struct load_command 
*) ((uint8_t *) load_command 
+ Swap(load_command
->cmdsize
)); 
 277         return load_commands
; 
 280     std::vector
<segment_command 
*> GetSegments(const char *segment_name
) { 
 281         std::vector
<struct segment_command 
*> segment_commands
; 
 283         _foreach (load_command
, GetLoadCommands()) 
 284             if (Swap((*load_command
)->cmd
) == LC_SEGMENT
) { 
 285                 segment_command 
*segment_command 
= reinterpret_cast<struct segment_command 
*>(*load_command
); 
 286                 if (strncmp(segment_command
->segname
, segment_name
, 16) == 0) 
 287                     segment_commands
.push_back(segment_command
); 
 290         return segment_commands
; 
 293     std::vector
<section 
*> GetSections(const char *segment_name
, const char *section_name
) { 
 294         std::vector
<section 
*> sections
; 
 296         _foreach (segment
, GetSegments(segment_name
)) { 
 297             section 
*section 
= (struct section 
*) (*segment 
+ 1); 
 300             for (sect 
= 0; sect 
!= Swap((*segment
)->nsects
); ++sect
) { 
 301                 if (strncmp(section
->sectname
, section_name
, 16) == 0) 
 302                     sections
.push_back(section
); 
 310     template <typename Target_
> 
 311     Pointer
<Target_
> GetPointer(uint32_t address
, const char *segment_name 
= NULL
) { 
 312         load_command 
*load_command 
= (struct load_command 
*) (mach_header_ 
+ 1); 
 315         for (cmd 
= 0; cmd 
!= Swap(mach_header_
->ncmds
); ++cmd
) { 
 316             if (Swap(load_command
->cmd
) == LC_SEGMENT
) { 
 317                 segment_command 
*segment_command 
= (struct segment_command 
*) load_command
; 
 318                 if (segment_name 
!= NULL 
&& strncmp(segment_command
->segname
, segment_name
, 16) != 0) 
 321                 section 
*sections 
= (struct section 
*) (segment_command 
+ 1); 
 324                 for (sect 
= 0; sect 
!= Swap(segment_command
->nsects
); ++sect
) { 
 325                     section 
*section 
= §ions
[sect
]; 
 326                     //printf("%s %u %p %p %u\n", segment_command->segname, sect, address, section->addr, section->size); 
 327                     if (address 
>= Swap(section
->addr
) && address 
< Swap(section
->addr
) + Swap(section
->size
)) { 
 328                         //printf("0x%.8x %s\n", address, segment_command->segname); 
 329                         return Pointer
<Target_
>(this, reinterpret_cast<Target_ 
*>(address 
- Swap(section
->addr
) + Swap(section
->offset
) + (char *) mach_header_
)); 
 335             load_command 
= (struct load_command 
*) ((char *) load_command 
+ Swap(load_command
->cmdsize
)); 
 338         return Pointer
<Target_
>(this); 
 341     template <typename Target_
> 
 342     Pointer
<Target_
> GetOffset(uint32_t offset
) { 
 343         return Pointer
<Target_
>(this, reinterpret_cast<Target_ 
*>(offset 
+ (uint8_t *) mach_header_
)); 
 347 template <typename Target_
> 
 350     const Framework 
*framework_
; 
 351     const Target_ 
*pointer_
; 
 354     Pointer(const Framework 
*framework 
= NULL
, const Target_ 
*pointer 
= NULL
) : 
 355         framework_(framework
), 
 360     operator const Target_ 
*() const { 
 364     const Target_ 
*operator ->() const { 
 368     Pointer
<Target_
> &operator ++() { 
 373     template <typename Value_
> 
 374     Value_ 
Swap(Value_ value
) { 
 375         return framework_
->Swap(value
); 
 379 #define CSMAGIC_CODEDIRECTORY      0xfade0c02 
 380 #define CSMAGIC_EMBEDDED_SIGNATURE 0xfade0cc0 
 381 #define CSMAGIC_ENTITLEMENTS       0xfade7171 
 383 #define CSSLOT_CODEDIRECTORY 0 
 384 #define CSSLOT_REQUIREMENTS  2 
 385 #define CSSLOT_ENTITLEMENTS  5 
 400     struct BlobIndex index
[]; 
 403 struct CodeDirectory 
{ 
 408     uint32_t identOffset
; 
 409     uint32_t nSpecialSlots
; 
 419 extern "C" uint32_t hash(uint8_t *k
, uint32_t length
, uint32_t initval
); 
 421 #define CODESIGN_ALLOCATE "arm-apple-darwin9-codesign_allocate" 
 423 void sha1(uint8_t *hash
, uint8_t *data
, size_t size
) { 
 426     SHA1Input(&context
, data
, size
); 
 427     SHA1Result(&context
, hash
); 
 430 int main(int argc
, const char *argv
[]) { 
 445     const void *xmld(NULL
); 
 448     uintptr_t noffset(_not(uintptr_t)); 
 449     uintptr_t woffset(_not(uintptr_t)); 
 451     std::vector
<std::string
> files
; 
 454         fprintf(stderr
, "usage: %s -S[entitlements.xml] <binary>\n", argv
[0]); 
 455         fprintf(stderr
, "   %s -e MobileSafari\n", argv
[0]); 
 456         fprintf(stderr
, "   %s -S cat\n", argv
[0]); 
 457         fprintf(stderr
, "   %s -Stfp.xml gdb\n", argv
[0]); 
 461     for (int argi(1); argi 
!= argc
; ++argi
) 
 462         if (argv
[argi
][0] != '-') 
 463             files
.push_back(argv
[argi
]); 
 464         else switch (argv
[argi
][1]) { 
 465             case 'R': flag_R 
= true; break; 
 466             case 't': flag_t 
= true; break; 
 467             case 'u': flag_u 
= true; break; 
 468             case 'p': flag_p 
= true; break; 
 469             case 'e': flag_e 
= true; break; 
 479                 if (argv
[argi
][2] != '\0') { 
 480                     const char *xml 
= argv
[argi
] + 2; 
 481                     xmld 
= map(xml
, 0, _not(size_t), &xmls
, true); 
 487                 if (argv
[argi
][2] == '-') 
 491                     timev 
= strtoul(argv
[argi
] + 2, &arge
, 0); 
 492                     _assert(arge 
== argv
[argi
] + strlen(argv
[argi
])); 
 498                 noffset 
= strtoul(argv
[argi
] + 2, &arge
, 0); 
 499                 _assert(arge 
== argv
[argi
] + strlen(argv
[argi
])); 
 504                 woffset 
= strtoul(argv
[argi
] + 2, &arge
, 0); 
 505                 _assert(arge 
== argv
[argi
] + strlen(argv
[argi
])); 
 513     if (files
.empty()) usage
: { 
 517     size_t filei(0), filee(0); 
 518     _foreach (file
, files
) try { 
 519         const char *path(file
->c_str()); 
 520         const char *base 
= strrchr(path
, '/'); 
 521         char *temp(NULL
), *dir
; 
 524             dir 
= strndup_(path
, base
++ - path 
+ 1); 
 531             asprintf(&temp
, "%s.%s.cs", dir
, base
); 
 532             const char *allocate 
= getenv("CODESIGN_ALLOCATE"); 
 533             if (allocate 
== NULL
) 
 534                 allocate 
= "codesign_allocate"; 
 536             size_t size 
= _not(size_t); 
 538                 Framework 
framework(path
); 
 539                 _foreach (load_command
, framework
.GetLoadCommands()) { 
 540                     uint32_t cmd(framework
.Swap((*load_command
)->cmd
)); 
 541                     if (cmd 
== LC_CODE_SIGNATURE
) { 
 542                         struct linkedit_data_command 
*signature 
= reinterpret_cast<struct linkedit_data_command 
*>(*load_command
); 
 543                         size 
= framework
.Swap(signature
->dataoff
); 
 544                         _assert(size 
< framework
.GetSize()); 
 549                 if (size 
== _not(size_t)) 
 550                     size 
= framework
.GetSize(); 
 552                 switch (framework
->cputype
) { 
 553                     case 12: switch (framework
->cpusubtype
) { 
 554                         case 0: arch 
= "arm"; break; 
 555                         case 6: arch 
= "armv6"; break; 
 556                         default: arch 
= NULL
; break; 
 559                     default: arch 
= NULL
; break; 
 563             _assert(arch 
!= NULL
); 
 569                 asprintf(&ssize
, "%u", (sizeof(struct SuperBlob
) + 2 * sizeof(struct BlobIndex
) + sizeof(struct CodeDirectory
) + strlen(base
) + 1 + ((xmld 
== NULL 
? CSSLOT_REQUIREMENTS 
: CSSLOT_ENTITLEMENTS
) + (size 
+ 0x1000 - 1) / 0x1000) * 0x14 + 0xc + (xmld 
== NULL 
? 0 : 0x10 + xmls
) + 15) / 16 * 16); 
 570                 //printf("%s -i %s -a %s %s -o %s\n", allocate, path, arch, ssize, temp); 
 571                 execlp(allocate
, allocate
, "-i", path
, "-a", arch
, ssize
, "-o", temp
, NULL
); 
 576             _syscall(waitpid(pid
, &status
, 0)); 
 577             _assert(WIFEXITED(status
)); 
 578             _assert(WEXITSTATUS(status
) == 0); 
 581         Framework 
framework(temp 
== NULL 
? path 
: temp
); 
 582         struct linkedit_data_command 
*signature(NULL
); 
 585             printf("path%zu='%s'\n", filei
, file
->c_str()); 
 587         if (woffset 
!= _not(uintptr_t)) { 
 588             Pointer
<uint32_t> wvalue(framework
.GetPointer
<uint32_t>(woffset
)); 
 590                 printf("(null) %p\n", woffset
); 
 592                 printf("0x%.08x\n", *wvalue
); 
 595         if (noffset 
!= _not(uintptr_t)) 
 596             printf("%s\n", &*framework
.GetPointer
<char>(noffset
)); 
 598         _foreach (load_command
, framework
.GetLoadCommands()) { 
 599             uint32_t cmd(framework
.Swap((*load_command
)->cmd
)); 
 601             if (flag_R 
&& cmd 
== LC_REEXPORT_DYLIB
) 
 602                 (*load_command
)->cmd 
= framework
.Swap(LC_LOAD_DYLIB
); 
 603             else if (cmd 
== LC_CODE_SIGNATURE
) 
 604                 signature 
= reinterpret_cast<struct linkedit_data_command 
*>(*load_command
); 
 605             else if (cmd 
== LC_UUID
) { 
 606                 volatile struct uuid_command 
*uuid_command(reinterpret_cast<struct uuid_command 
*>(*load_command
)); 
 609                     printf("uuid%zu=%.2x%.2x%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x%.2x%.2x%.2x%.2x\n", filei
, 
 610                         uuid_command
->uuid
[ 0], uuid_command
->uuid
[ 1], uuid_command
->uuid
[ 2], uuid_command
->uuid
[ 3], 
 611                         uuid_command
->uuid
[ 4], uuid_command
->uuid
[ 5], uuid_command
->uuid
[ 6], uuid_command
->uuid
[ 7], 
 612                         uuid_command
->uuid
[ 8], uuid_command
->uuid
[ 9], uuid_command
->uuid
[10], uuid_command
->uuid
[11], 
 613                         uuid_command
->uuid
[12], uuid_command
->uuid
[13], uuid_command
->uuid
[14], uuid_command
->uuid
[15] 
 616             } else if (cmd 
== LC_ID_DYLIB
) { 
 617                 volatile struct dylib_command 
*dylib_command(reinterpret_cast<struct dylib_command 
*>(*load_command
)); 
 620                     printf("time%zu=0x%.8x\n", filei
, framework
.Swap(dylib_command
->dylib
.timestamp
)); 
 628                         dylib_command
->dylib
.timestamp 
= 0; 
 629                         timed 
= hash(reinterpret_cast<uint8_t *>(framework
.GetBase()), framework
.GetSize(), timev
); 
 632                     dylib_command
->dylib
.timestamp 
= framework
.Swap(timed
); 
 638             _assert(signature 
!= NULL
); 
 640             uint32_t data 
= framework
.Swap(signature
->dataoff
); 
 641             uint32_t size 
= framework
.Swap(signature
->datasize
); 
 643             uint8_t *top 
= reinterpret_cast<uint8_t *>(framework
.GetBase()); 
 644             uint8_t *blob 
= top 
+ data
; 
 645             struct SuperBlob 
*super 
= reinterpret_cast<struct SuperBlob 
*>(blob
); 
 647             for (size_t index(0); index 
!= Swap(super
->count
); ++index
) 
 648                 if (Swap(super
->index
[index
].type
) == CSSLOT_ENTITLEMENTS
) { 
 649                     uint32_t begin 
= Swap(super
->index
[index
].offset
); 
 650                     struct Blob 
*entitlements 
= reinterpret_cast<struct Blob 
*>(blob 
+ begin
); 
 651                     fwrite(entitlements 
+ 1, 1, Swap(entitlements
->length
) - sizeof(struct Blob
), stdout
); 
 656             _assert(signature 
!= NULL
); 
 658             uint32_t data 
= framework
.Swap(signature
->dataoff
); 
 659             uint32_t size 
= framework
.Swap(signature
->datasize
); 
 661             uint8_t *top 
= reinterpret_cast<uint8_t *>(framework
.GetBase()); 
 662             uint8_t *blob 
= top 
+ data
; 
 663             struct SuperBlob 
*super 
= reinterpret_cast<struct SuperBlob 
*>(blob
); 
 665             for (size_t index(0); index 
!= Swap(super
->count
); ++index
) 
 666                 if (Swap(super
->index
[index
].type
) == CSSLOT_CODEDIRECTORY
) { 
 667                     uint32_t begin 
= Swap(super
->index
[index
].offset
); 
 668                     struct CodeDirectory 
*directory 
= reinterpret_cast<struct CodeDirectory 
*>(blob 
+ begin
); 
 670                     uint8_t (*hashes
)[20] = reinterpret_cast<uint8_t (*)[20]>(blob 
+ begin 
+ Swap(directory
->hashOffset
)); 
 671                     uint32_t pages 
= Swap(directory
->nCodeSlots
); 
 674                         for (size_t i 
= 0; i 
!= pages 
- 1; ++i
) 
 675                             sha1(hashes
[i
], top 
+ 0x1000 * i
, 0x1000); 
 677                         sha1(hashes
[pages 
- 1], top 
+ 0x1000 * (pages 
- 1), ((data 
- 1) % 0x1000) + 1); 
 682             _assert(signature 
!= NULL
); 
 684             uint32_t data 
= framework
.Swap(signature
->dataoff
); 
 685             uint32_t size 
= framework
.Swap(signature
->datasize
); 
 687             uint8_t *top 
= reinterpret_cast<uint8_t *>(framework
.GetBase()); 
 688             uint8_t *blob 
= top 
+ data
; 
 689             struct SuperBlob 
*super 
= reinterpret_cast<struct SuperBlob 
*>(blob
); 
 690             super
->blob
.magic 
= Swap(CSMAGIC_EMBEDDED_SIGNATURE
); 
 692             uint32_t count 
= xmld 
== NULL 
? 2 : 3; 
 693             uint32_t offset 
= sizeof(struct SuperBlob
) + count 
* sizeof(struct BlobIndex
); 
 695             super
->index
[0].type 
= Swap(CSSLOT_CODEDIRECTORY
); 
 696             super
->index
[0].offset 
= Swap(offset
); 
 698             uint32_t begin 
= offset
; 
 699             struct CodeDirectory 
*directory 
= reinterpret_cast<struct CodeDirectory 
*>(blob 
+ begin
); 
 700             offset 
+= sizeof(struct CodeDirectory
); 
 702             directory
->blob
.magic 
= Swap(CSMAGIC_CODEDIRECTORY
); 
 703             directory
->version 
= Swap(0x00020001); 
 704             directory
->flags 
= Swap(0); 
 705             directory
->codeLimit 
= Swap(data
); 
 706             directory
->hashSize 
= 0x14; 
 707             directory
->hashType 
= 0x01; 
 708             directory
->spare1 
= 0x00; 
 709             directory
->pageSize 
= 0x0c; 
 710             directory
->spare2 
= Swap(0); 
 712             directory
->identOffset 
= Swap(offset 
- begin
); 
 713             strcpy(reinterpret_cast<char *>(blob 
+ offset
), base
); 
 714             offset 
+= strlen(base
) + 1; 
 716             uint32_t special 
= xmld 
== NULL 
? CSSLOT_REQUIREMENTS 
: CSSLOT_ENTITLEMENTS
; 
 717             directory
->nSpecialSlots 
= Swap(special
); 
 719             uint8_t (*hashes
)[20] = reinterpret_cast<uint8_t (*)[20]>(blob 
+ offset
); 
 720             memset(hashes
, 0, sizeof(*hashes
) * special
); 
 722             offset 
+= sizeof(*hashes
) * special
; 
 725             uint32_t pages 
= (data 
+ 0x1000 - 1) / 0x1000; 
 726             directory
->nCodeSlots 
= Swap(pages
); 
 729                 for (size_t i 
= 0; i 
!= pages 
- 1; ++i
) 
 730                     sha1(hashes
[i
], top 
+ 0x1000 * i
, 0x1000); 
 732                 sha1(hashes
[pages 
- 1], top 
+ 0x1000 * (pages 
- 1), ((data 
- 1) % 0x1000) + 1); 
 734             directory
->hashOffset 
= Swap(offset 
- begin
); 
 735             offset 
+= sizeof(*hashes
) * pages
; 
 736             directory
->blob
.length 
= Swap(offset 
- begin
); 
 738             super
->index
[1].type 
= Swap(CSSLOT_REQUIREMENTS
); 
 739             super
->index
[1].offset 
= Swap(offset
); 
 741             memcpy(blob 
+ offset
, "\xfa\xde\x0c\x01\x00\x00\x00\x0c\x00\x00\x00\x00", 0xc); 
 745                 super
->index
[2].type 
= Swap(CSSLOT_ENTITLEMENTS
); 
 746                 super
->index
[2].offset 
= Swap(offset
); 
 748                 uint32_t begin 
= offset
; 
 749                 struct Blob 
*entitlements 
= reinterpret_cast<struct Blob 
*>(blob 
+ begin
); 
 750                 offset 
+= sizeof(struct Blob
); 
 752                 memcpy(blob 
+ offset
, xmld
, xmls
); 
 755                 entitlements
->magic 
= Swap(CSMAGIC_ENTITLEMENTS
); 
 756                 entitlements
->length 
= Swap(offset 
- begin
); 
 759             for (size_t index(0); index 
!= count
; ++index
) { 
 760                 uint32_t type 
= Swap(super
->index
[index
].type
); 
 761                 if (type 
!= 0 && type 
<= special
) { 
 762                     uint32_t offset 
= Swap(super
->index
[index
].offset
); 
 763                     struct Blob 
*local 
= (struct Blob 
*) (blob 
+ offset
); 
 764                     sha1((uint8_t *) (hashes 
- type
), (uint8_t *) local
, Swap(local
->length
)); 
 768             super
->count 
= Swap(count
); 
 769             super
->blob
.length 
= Swap(offset
); 
 772                 fprintf(stderr
, "offset (%u) > size (%u)\n", offset
, size
); 
 774             } //else fprintf(stderr, "offset (%zu) <= size (%zu)\n", offset, size); 
 776             memset(blob 
+ offset
, 0, size 
- offset
); 
 781             _syscall(stat(path
, &info
)); 
 782             _syscall(chown(temp
, info
.st_uid
, info
.st_gid
)); 
 783             _syscall(chmod(temp
, info
.st_mode
)); 
 784             _syscall(unlink(path
)); 
 785             _syscall(rename(temp
, path
)); 
 791     } catch (const char *) {