]> git.saurik.com Git - ldid.git/blame - ldid.cpp
Be a little more explicit about types for Cygwin.
[ldid.git] / ldid.cpp
CommitLineData
a362a82f
JF
1/* JocStrap - Java/Objective-C Bootstrap
2 * Copyright (C) 2007 Jay Freeman (saurik)
3*/
4
5/*
6 * Redistribution and use in source and binary
7 * forms, with or without modification, are permitted
8 * provided that the following conditions are met:
9 *
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
17 * distribution.
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.
21 *
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.
36*/
37
38#include "minimal/stdlib.h"
b8187ac7 39#include "minimal/string.h"
a362a82f
JF
40#include "minimal/mapping.h"
41
fdb119ef
JF
42#include "sha1.h"
43
a362a82f
JF
44#include <cstring>
45#include <string>
46#include <vector>
47
fdb119ef 48#include <sys/wait.h>
31ad673b
JF
49#include <sys/types.h>
50#include <sys/stat.h>
fdb119ef 51
a362a82f
JF
52struct fat_header {
53 uint32_t magic;
54 uint32_t nfat_arch;
c05d9758 55} _packed;
a362a82f
JF
56
57#define FAT_MAGIC 0xcafebabe
58#define FAT_CIGAM 0xbebafeca
59
60struct fat_arch {
61 uint32_t cputype;
62 uint32_t cpusubtype;
63 uint32_t offset;
64 uint32_t size;
65 uint32_t align;
c05d9758 66} _packed;
a362a82f
JF
67
68struct mach_header {
69 uint32_t magic;
70 uint32_t cputype;
71 uint32_t cpusubtype;
72 uint32_t filetype;
73 uint32_t ncmds;
74 uint32_t sizeofcmds;
75 uint32_t flags;
c05d9758 76} _packed;
a362a82f 77
fdb119ef 78#define MH_MAGIC 0xfeedface
a362a82f
JF
79#define MH_CIGAM 0xcefaedfe
80
82813bde
JF
81#define MH_DYLDLINK 0x4
82
efd6cd4a
JF
83#define MH_EXECUTE 0x2
84#define MH_DYLIB 0x6
85#define MH_BUNDLE 0x8
86#define MH_DYLIB_STUB 0x9
a362a82f
JF
87
88struct load_command {
89 uint32_t cmd;
90 uint32_t cmdsize;
c05d9758 91} _packed;
a362a82f 92
645f8f12 93#define LC_REQ_DYLD uint32_t(0x80000000)
a362a82f 94
645f8f12
JF
95#define LC_SEGMENT uint32_t(0x01)
96#define LC_LOAD_DYLIB uint32_t(0x0c)
97#define LC_ID_DYLIB uint32_t(0x0d)
98#define LC_UUID uint32_t(0x1b)
99#define LC_CODE_SIGNATURE uint32_t(0x1d)
100#define LC_REEXPORT_DYLIB uint32_t(0x1f | LC_REQ_DYLD)
a362a82f
JF
101
102struct dylib {
103 uint32_t name;
104 uint32_t timestamp;
105 uint32_t current_version;
106 uint32_t compatibility_version;
c05d9758 107} _packed;
a362a82f
JF
108
109struct dylib_command {
110 uint32_t cmd;
111 uint32_t cmdsize;
112 struct dylib dylib;
c05d9758 113} _packed;
a362a82f
JF
114
115struct uuid_command {
116 uint32_t cmd;
117 uint32_t cmdsize;
118 uint8_t uuid[16];
c05d9758 119} _packed;
a362a82f 120
6e83315b
JF
121struct segment_command {
122 uint32_t cmd;
123 uint32_t cmdsize;
124 char segname[16];
125 uint32_t vmaddr;
126 uint32_t vmsize;
127 uint32_t fileoff;
128 uint32_t filesize;
129 uint32_t maxprot;
130 uint32_t initprot;
131 uint32_t nsects;
132 uint32_t flags;
133};
134
135struct section {
136 char sectname[16];
137 char segname[16];
138 uint32_t addr;
139 uint32_t size;
140 uint32_t offset;
141 uint32_t align;
142 uint32_t reloff;
143 uint32_t nreloc;
144 uint32_t flags;
145 uint32_t reserved1;
146 uint32_t reserved2;
147};
148
fdb119ef
JF
149struct linkedit_data_command {
150 uint32_t cmd;
151 uint32_t cmdsize;
152 uint32_t dataoff;
153 uint32_t datasize;
c05d9758 154} _packed;
fdb119ef
JF
155
156uint16_t Swap_(uint16_t value) {
157 return
158 ((value >> 8) & 0x00ff) |
159 ((value << 8) & 0xff00);
160}
161
162uint32_t Swap_(uint32_t value) {
163 value = ((value >> 8) & 0x00ff00ff) |
164 ((value << 8) & 0xff00ff00);
165 value = ((value >> 16) & 0x0000ffff) |
166 ((value << 16) & 0xffff0000);
167 return value;
168}
169
170int16_t Swap_(int16_t value) {
171 return Swap_(static_cast<uint16_t>(value));
172}
173
174int32_t Swap_(int32_t value) {
175 return Swap_(static_cast<uint32_t>(value));
176}
177
178uint16_t Swap(uint16_t value) {
179 return true ? Swap_(value) : value;
180}
181
182uint32_t Swap(uint32_t value) {
183 return true ? Swap_(value) : value;
184}
185
186int16_t Swap(int16_t value) {
187 return Swap(static_cast<uint16_t>(value));
188}
189
190int32_t Swap(int32_t value) {
191 return Swap(static_cast<uint32_t>(value));
192}
193
6e83315b
JF
194template <typename Target_>
195class Pointer;
196
a362a82f
JF
197class Framework {
198 private:
199 void *base_;
200 size_t size_;
201 mach_header *mach_header_;
202 bool swapped_;
203
204 public:
fdb119ef
JF
205 uint16_t Swap(uint16_t value) const {
206 return swapped_ ? Swap_(value) : value;
a362a82f
JF
207 }
208
fdb119ef
JF
209 uint32_t Swap(uint32_t value) const {
210 return swapped_ ? Swap_(value) : value;
a362a82f
JF
211 }
212
fdb119ef
JF
213 int16_t Swap(int16_t value) const {
214 return Swap(static_cast<uint16_t>(value));
a362a82f
JF
215 }
216
fdb119ef
JF
217 int32_t Swap(int32_t value) const {
218 return Swap(static_cast<uint32_t>(value));
a362a82f
JF
219 }
220
221 Framework(const char *framework_path) :
222 swapped_(false)
223 {
224 base_ = map(framework_path, 0, _not(size_t), &size_, false);
225 fat_header *fat_header = reinterpret_cast<struct fat_header *>(base_);
226
227 if (Swap(fat_header->magic) == FAT_CIGAM) {
228 swapped_ = !swapped_;
229 goto fat;
230 } else if (Swap(fat_header->magic) != FAT_MAGIC)
231 mach_header_ = (mach_header *) base_;
232 else fat: {
233 size_t fat_narch = Swap(fat_header->nfat_arch);
234 fat_arch *fat_arch = reinterpret_cast<struct fat_arch *>(fat_header + 1);
235 size_t arch;
236 for (arch = 0; arch != fat_narch; ++arch) {
237 uint32_t arch_offset = Swap(fat_arch->offset);
238 mach_header_ = (mach_header *) ((uint8_t *) base_ + arch_offset);
239 goto found;
240 ++fat_arch;
241 }
242
243 _assert(false);
244 }
245
246 found:
247 if (Swap(mach_header_->magic) == MH_CIGAM)
248 swapped_ = !swapped_;
249 else _assert(Swap(mach_header_->magic) == MH_MAGIC);
250
251 _assert(
252 Swap(mach_header_->filetype) == MH_EXECUTE ||
253 Swap(mach_header_->filetype) == MH_DYLIB ||
254 Swap(mach_header_->filetype) == MH_BUNDLE
255 );
256 }
257
afbb7c8e
JF
258 struct mach_header *operator ->() const {
259 return mach_header_;
260 }
261
a362a82f
JF
262 void *GetBase() {
263 return base_;
264 }
265
266 size_t GetSize() {
267 return size_;
268 }
269
270 std::vector<struct load_command *> GetLoadCommands() {
271 std::vector<struct load_command *> load_commands;
272
273 struct load_command *load_command = reinterpret_cast<struct load_command *>(mach_header_ + 1);
274 for (uint32_t cmd = 0; cmd != Swap(mach_header_->ncmds); ++cmd) {
275 load_commands.push_back(load_command);
276 load_command = (struct load_command *) ((uint8_t *) load_command + Swap(load_command->cmdsize));
277 }
278
279 return load_commands;
280 }
6e83315b
JF
281
282 std::vector<segment_command *> GetSegments(const char *segment_name) {
283 std::vector<struct segment_command *> segment_commands;
284
285 _foreach (load_command, GetLoadCommands())
286 if (Swap((*load_command)->cmd) == LC_SEGMENT) {
287 segment_command *segment_command = reinterpret_cast<struct segment_command *>(*load_command);
288 if (strncmp(segment_command->segname, segment_name, 16) == 0)
289 segment_commands.push_back(segment_command);
290 }
291
292 return segment_commands;
293 }
294
295 std::vector<section *> GetSections(const char *segment_name, const char *section_name) {
296 std::vector<section *> sections;
297
298 _foreach (segment, GetSegments(segment_name)) {
299 section *section = (struct section *) (*segment + 1);
300
301 uint32_t sect;
302 for (sect = 0; sect != Swap((*segment)->nsects); ++sect) {
303 if (strncmp(section->sectname, section_name, 16) == 0)
304 sections.push_back(section);
305 ++section;
306 }
307 }
308
309 return sections;
310 }
311
312 template <typename Target_>
313 Pointer<Target_> GetPointer(uint32_t address, const char *segment_name = NULL) {
314 load_command *load_command = (struct load_command *) (mach_header_ + 1);
315 uint32_t cmd;
316
317 for (cmd = 0; cmd != Swap(mach_header_->ncmds); ++cmd) {
318 if (Swap(load_command->cmd) == LC_SEGMENT) {
319 segment_command *segment_command = (struct segment_command *) load_command;
320 if (segment_name != NULL && strncmp(segment_command->segname, segment_name, 16) != 0)
321 goto next_command;
322
323 section *sections = (struct section *) (segment_command + 1);
324
325 uint32_t sect;
326 for (sect = 0; sect != Swap(segment_command->nsects); ++sect) {
327 section *section = &sections[sect];
328 //printf("%s %u %p %p %u\n", segment_command->segname, sect, address, section->addr, section->size);
329 if (address >= Swap(section->addr) && address < Swap(section->addr) + Swap(section->size)) {
330 //printf("0x%.8x %s\n", address, segment_command->segname);
331 return Pointer<Target_>(this, reinterpret_cast<Target_ *>(address - Swap(section->addr) + Swap(section->offset) + (char *) mach_header_));
332 }
333 }
334 }
335
336 next_command:
337 load_command = (struct load_command *) ((char *) load_command + Swap(load_command->cmdsize));
338 }
339
340 return Pointer<Target_>(this);
341 }
342
343 template <typename Target_>
344 Pointer<Target_> GetOffset(uint32_t offset) {
345 return Pointer<Target_>(this, reinterpret_cast<Target_ *>(offset + (uint8_t *) mach_header_));
346 }
347};
348
349template <typename Target_>
350class Pointer {
351 private:
352 const Framework *framework_;
353 const Target_ *pointer_;
354
355 public:
356 Pointer(const Framework *framework = NULL, const Target_ *pointer = NULL) :
357 framework_(framework),
358 pointer_(pointer)
359 {
360 }
361
362 operator const Target_ *() const {
363 return pointer_;
364 }
365
366 const Target_ *operator ->() const {
367 return pointer_;
368 }
369
370 Pointer<Target_> &operator ++() {
371 ++pointer_;
372 return *this;
373 }
374
375 template <typename Value_>
376 Value_ Swap(Value_ value) {
377 return framework_->Swap(value);
378 }
a362a82f
JF
379};
380
645f8f12
JF
381#define CSMAGIC_CODEDIRECTORY uint32_t(0xfade0c02)
382#define CSMAGIC_EMBEDDED_SIGNATURE uint32_t(0xfade0cc0)
383#define CSMAGIC_ENTITLEMENTS uint32_t(0xfade7171)
c05d9758 384
645f8f12
JF
385#define CSSLOT_CODEDIRECTORY uint32_t(0)
386#define CSSLOT_REQUIREMENTS uint32_t(2)
387#define CSSLOT_ENTITLEMENTS uint32_t(5)
fdb119ef
JF
388
389struct BlobIndex {
390 uint32_t type;
391 uint32_t offset;
c05d9758 392} _packed;
fdb119ef 393
c05d9758 394struct Blob {
fdb119ef
JF
395 uint32_t magic;
396 uint32_t length;
c05d9758
JF
397} _packed;
398
399struct SuperBlob {
400 struct Blob blob;
fdb119ef
JF
401 uint32_t count;
402 struct BlobIndex index[];
c05d9758 403} _packed;
fdb119ef
JF
404
405struct CodeDirectory {
c05d9758 406 struct Blob blob;
fdb119ef
JF
407 uint32_t version;
408 uint32_t flags;
409 uint32_t hashOffset;
410 uint32_t identOffset;
411 uint32_t nSpecialSlots;
412 uint32_t nCodeSlots;
413 uint32_t codeLimit;
414 uint8_t hashSize;
415 uint8_t hashType;
416 uint8_t spare1;
417 uint8_t pageSize;
418 uint32_t spare2;
c05d9758 419} _packed;
fdb119ef 420
a362a82f
JF
421extern "C" uint32_t hash(uint8_t *k, uint32_t length, uint32_t initval);
422
fdb119ef
JF
423#define CODESIGN_ALLOCATE "arm-apple-darwin9-codesign_allocate"
424
425void sha1(uint8_t *hash, uint8_t *data, size_t size) {
426 SHA1Context context;
427 SHA1Reset(&context);
428 SHA1Input(&context, data, size);
429 SHA1Result(&context, hash);
430}
431
a362a82f
JF
432int main(int argc, const char *argv[]) {
433 bool flag_R(false);
434 bool flag_t(false);
435 bool flag_p(false);
436 bool flag_u(false);
9c83be90 437 bool flag_e(false);
a362a82f
JF
438
439 bool flag_T(false);
20c5f1e8 440
fdb119ef 441 bool flag_S(false);
20c5f1e8 442 bool flag_s(false);
a362a82f
JF
443
444 bool timeh(false);
445 uint32_t timev(0);
446
c05d9758
JF
447 const void *xmld(NULL);
448 size_t xmls(0);
449
6e83315b
JF
450 uintptr_t noffset(_not(uintptr_t));
451 uintptr_t woffset(_not(uintptr_t));
452
a362a82f
JF
453 std::vector<std::string> files;
454
a960f392
JF
455 if (argc == 1) {
456 fprintf(stderr, "usage: %s -S[entitlements.xml] <binary>\n", argv[0]);
9c83be90 457 fprintf(stderr, " %s -e MobileSafari\n", argv[0]);
a960f392
JF
458 fprintf(stderr, " %s -S cat\n", argv[0]);
459 fprintf(stderr, " %s -Stfp.xml gdb\n", argv[0]);
460 exit(0);
461 }
462
a362a82f
JF
463 for (int argi(1); argi != argc; ++argi)
464 if (argv[argi][0] != '-')
465 files.push_back(argv[argi]);
466 else switch (argv[argi][1]) {
467 case 'R': flag_R = true; break;
468 case 't': flag_t = true; break;
469 case 'u': flag_u = true; break;
470 case 'p': flag_p = true; break;
9c83be90 471 case 'e': flag_e = true; break;
c05d9758 472
20c5f1e8
JF
473 case 's':
474 _assert(!flag_S);
475 flag_s = true;
476 break;
477
c05d9758 478 case 'S':
20c5f1e8 479 _assert(!flag_s);
c05d9758
JF
480 flag_S = true;
481 if (argv[argi][2] != '\0') {
482 const char *xml = argv[argi] + 2;
483 xmld = map(xml, 0, _not(size_t), &xmls, true);
484 }
485 break;
a362a82f
JF
486
487 case 'T': {
488 flag_T = true;
489 if (argv[argi][2] == '-')
490 timeh = true;
491 else {
492 char *arge;
493 timev = strtoul(argv[argi] + 2, &arge, 0);
494 _assert(arge == argv[argi] + strlen(argv[argi]));
495 }
496 } break;
497
6e83315b
JF
498 case 'n': {
499 char *arge;
500 noffset = strtoul(argv[argi] + 2, &arge, 0);
501 _assert(arge == argv[argi] + strlen(argv[argi]));
502 } break;
503
504 case 'w': {
505 char *arge;
506 woffset = strtoul(argv[argi] + 2, &arge, 0);
507 _assert(arge == argv[argi] + strlen(argv[argi]));
508 } break;
509
a362a82f
JF
510 default:
511 goto usage;
512 break;
513 }
514
515 if (files.empty()) usage: {
516 exit(0);
517 }
518
519 size_t filei(0), filee(0);
520 _foreach (file, files) try {
fdb119ef
JF
521 const char *path(file->c_str());
522 const char *base = strrchr(path, '/');
523 char *temp(NULL), *dir;
524
525 if (base != NULL)
b8187ac7 526 dir = strndup_(path, base++ - path + 1);
fdb119ef
JF
527 else {
528 dir = strdup("");
529 base = path;
530 }
531
532 if (flag_S) {
533 asprintf(&temp, "%s.%s.cs", dir, base);
534 const char *allocate = getenv("CODESIGN_ALLOCATE");
535 if (allocate == NULL)
536 allocate = "codesign_allocate";
537
afbb7c8e
JF
538 size_t size = _not(size_t);
539 const char *arch; {
fdb119ef 540 Framework framework(path);
82813bde
JF
541 framework->flags |= MH_DYLDLINK;
542
afbb7c8e
JF
543 _foreach (load_command, framework.GetLoadCommands()) {
544 uint32_t cmd(framework.Swap((*load_command)->cmd));
545 if (cmd == LC_CODE_SIGNATURE) {
546 struct linkedit_data_command *signature = reinterpret_cast<struct linkedit_data_command *>(*load_command);
547 size = framework.Swap(signature->dataoff);
548 _assert(size < framework.GetSize());
549 break;
550 }
551 }
552
553 if (size == _not(size_t))
554 size = framework.GetSize();
555
556 switch (framework->cputype) {
557 case 12: switch (framework->cpusubtype) {
558 case 0: arch = "arm"; break;
559 case 6: arch = "armv6"; break;
560 default: arch = NULL; break;
561 } break;
562
563 default: arch = NULL; break;
564 }
fdb119ef
JF
565 }
566
afbb7c8e
JF
567 _assert(arch != NULL);
568
fdb119ef
JF
569 pid_t pid = fork();
570 _syscall(pid);
571 if (pid == 0) {
572 char *ssize;
20c5f1e8
JF
573 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);
574 //printf("%s -i %s -a %s %s -o %s\n", allocate, path, arch, ssize, temp);
afbb7c8e 575 execlp(allocate, allocate, "-i", path, "-a", arch, ssize, "-o", temp, NULL);
fdb119ef
JF
576 _assert(false);
577 }
578
579 int status;
580 _syscall(waitpid(pid, &status, 0));
581 _assert(WIFEXITED(status));
582 _assert(WEXITSTATUS(status) == 0);
583 }
584
585 Framework framework(temp == NULL ? path : temp);
586 struct linkedit_data_command *signature(NULL);
a362a82f
JF
587
588 if (flag_p)
589 printf("path%zu='%s'\n", filei, file->c_str());
590
6e83315b
JF
591 if (woffset != _not(uintptr_t)) {
592 Pointer<uint32_t> wvalue(framework.GetPointer<uint32_t>(woffset));
593 if (wvalue == NULL)
594 printf("(null) %p\n", woffset);
595 else
596 printf("0x%.08x\n", *wvalue);
597 }
598
599 if (noffset != _not(uintptr_t))
600 printf("%s\n", &*framework.GetPointer<char>(noffset));
601
a362a82f
JF
602 _foreach (load_command, framework.GetLoadCommands()) {
603 uint32_t cmd(framework.Swap((*load_command)->cmd));
604
605 if (flag_R && cmd == LC_REEXPORT_DYLIB)
606 (*load_command)->cmd = framework.Swap(LC_LOAD_DYLIB);
fdb119ef
JF
607 else if (cmd == LC_CODE_SIGNATURE)
608 signature = reinterpret_cast<struct linkedit_data_command *>(*load_command);
a362a82f
JF
609 else if (cmd == LC_UUID) {
610 volatile struct uuid_command *uuid_command(reinterpret_cast<struct uuid_command *>(*load_command));
611
612 if (flag_u) {
613 printf("uuid%zu=%.2x%.2x%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x%.2x%.2x%.2x%.2x\n", filei,
614 uuid_command->uuid[ 0], uuid_command->uuid[ 1], uuid_command->uuid[ 2], uuid_command->uuid[ 3],
615 uuid_command->uuid[ 4], uuid_command->uuid[ 5], uuid_command->uuid[ 6], uuid_command->uuid[ 7],
616 uuid_command->uuid[ 8], uuid_command->uuid[ 9], uuid_command->uuid[10], uuid_command->uuid[11],
617 uuid_command->uuid[12], uuid_command->uuid[13], uuid_command->uuid[14], uuid_command->uuid[15]
618 );
619 }
620 } else if (cmd == LC_ID_DYLIB) {
621 volatile struct dylib_command *dylib_command(reinterpret_cast<struct dylib_command *>(*load_command));
622
623 if (flag_t)
624 printf("time%zu=0x%.8x\n", filei, framework.Swap(dylib_command->dylib.timestamp));
625
626 if (flag_T) {
627 uint32_t timed;
628
629 if (!timeh)
630 timed = timev;
631 else {
632 dylib_command->dylib.timestamp = 0;
633 timed = hash(reinterpret_cast<uint8_t *>(framework.GetBase()), framework.GetSize(), timev);
634 }
635
636 dylib_command->dylib.timestamp = framework.Swap(timed);
637 }
638 }
639 }
640
9c83be90
JF
641 if (flag_e) {
642 _assert(signature != NULL);
643
644 uint32_t data = framework.Swap(signature->dataoff);
645 uint32_t size = framework.Swap(signature->datasize);
646
647 uint8_t *top = reinterpret_cast<uint8_t *>(framework.GetBase());
648 uint8_t *blob = top + data;
649 struct SuperBlob *super = reinterpret_cast<struct SuperBlob *>(blob);
650
651 for (size_t index(0); index != Swap(super->count); ++index)
652 if (Swap(super->index[index].type) == CSSLOT_ENTITLEMENTS) {
653 uint32_t begin = Swap(super->index[index].offset);
654 struct Blob *entitlements = reinterpret_cast<struct Blob *>(blob + begin);
655 fwrite(entitlements + 1, 1, Swap(entitlements->length) - sizeof(struct Blob), stdout);
656 }
657 }
658
20c5f1e8
JF
659 if (flag_s) {
660 _assert(signature != NULL);
661
662 uint32_t data = framework.Swap(signature->dataoff);
663 uint32_t size = framework.Swap(signature->datasize);
664
665 uint8_t *top = reinterpret_cast<uint8_t *>(framework.GetBase());
666 uint8_t *blob = top + data;
667 struct SuperBlob *super = reinterpret_cast<struct SuperBlob *>(blob);
668
669 for (size_t index(0); index != Swap(super->count); ++index)
670 if (Swap(super->index[index].type) == CSSLOT_CODEDIRECTORY) {
671 uint32_t begin = Swap(super->index[index].offset);
672 struct CodeDirectory *directory = reinterpret_cast<struct CodeDirectory *>(blob + begin);
673
674 uint8_t (*hashes)[20] = reinterpret_cast<uint8_t (*)[20]>(blob + begin + Swap(directory->hashOffset));
675 uint32_t pages = Swap(directory->nCodeSlots);
676
677 if (pages != 1)
678 for (size_t i = 0; i != pages - 1; ++i)
679 sha1(hashes[i], top + 0x1000 * i, 0x1000);
680 if (pages != 0)
ea6a0421 681 sha1(hashes[pages - 1], top + 0x1000 * (pages - 1), ((data - 1) % 0x1000) + 1);
20c5f1e8
JF
682 }
683 }
684
fdb119ef
JF
685 if (flag_S) {
686 _assert(signature != NULL);
687
688 uint32_t data = framework.Swap(signature->dataoff);
689 uint32_t size = framework.Swap(signature->datasize);
690
691 uint8_t *top = reinterpret_cast<uint8_t *>(framework.GetBase());
692 uint8_t *blob = top + data;
693 struct SuperBlob *super = reinterpret_cast<struct SuperBlob *>(blob);
c05d9758 694 super->blob.magic = Swap(CSMAGIC_EMBEDDED_SIGNATURE);
fdb119ef 695
c05d9758 696 uint32_t count = xmld == NULL ? 2 : 3;
fdb119ef
JF
697 uint32_t offset = sizeof(struct SuperBlob) + count * sizeof(struct BlobIndex);
698
699 super->index[0].type = Swap(CSSLOT_CODEDIRECTORY);
700 super->index[0].offset = Swap(offset);
701
702 uint32_t begin = offset;
703 struct CodeDirectory *directory = reinterpret_cast<struct CodeDirectory *>(blob + begin);
704 offset += sizeof(struct CodeDirectory);
705
c05d9758 706 directory->blob.magic = Swap(CSMAGIC_CODEDIRECTORY);
645f8f12
JF
707 directory->version = Swap(uint32_t(0x00020001));
708 directory->flags = Swap(uint32_t(0));
fdb119ef
JF
709 directory->codeLimit = Swap(data);
710 directory->hashSize = 0x14;
711 directory->hashType = 0x01;
712 directory->spare1 = 0x00;
713 directory->pageSize = 0x0c;
645f8f12 714 directory->spare2 = Swap(uint32_t(0));
fdb119ef
JF
715
716 directory->identOffset = Swap(offset - begin);
717 strcpy(reinterpret_cast<char *>(blob + offset), base);
718 offset += strlen(base) + 1;
719
20c5f1e8
JF
720 uint32_t special = xmld == NULL ? CSSLOT_REQUIREMENTS : CSSLOT_ENTITLEMENTS;
721 directory->nSpecialSlots = Swap(special);
722
fdb119ef 723 uint8_t (*hashes)[20] = reinterpret_cast<uint8_t (*)[20]>(blob + offset);
20c5f1e8
JF
724 memset(hashes, 0, sizeof(*hashes) * special);
725
726 offset += sizeof(*hashes) * special;
727 hashes += special;
fdb119ef
JF
728
729 uint32_t pages = (data + 0x1000 - 1) / 0x1000;
fdb119ef
JF
730 directory->nCodeSlots = Swap(pages);
731
732 if (pages != 1)
733 for (size_t i = 0; i != pages - 1; ++i)
20c5f1e8 734 sha1(hashes[i], top + 0x1000 * i, 0x1000);
fdb119ef 735 if (pages != 0)
ea6a0421 736 sha1(hashes[pages - 1], top + 0x1000 * (pages - 1), ((data - 1) % 0x1000) + 1);
fdb119ef
JF
737
738 directory->hashOffset = Swap(offset - begin);
20c5f1e8 739 offset += sizeof(*hashes) * pages;
c05d9758 740 directory->blob.length = Swap(offset - begin);
fdb119ef 741
afbb7c8e
JF
742 super->index[1].type = Swap(CSSLOT_REQUIREMENTS);
743 super->index[1].offset = Swap(offset);
744
745 memcpy(blob + offset, "\xfa\xde\x0c\x01\x00\x00\x00\x0c\x00\x00\x00\x00", 0xc);
746 offset += 0xc;
747
c05d9758
JF
748 if (xmld != NULL) {
749 super->index[2].type = Swap(CSSLOT_ENTITLEMENTS);
750 super->index[2].offset = Swap(offset);
751
752 uint32_t begin = offset;
753 struct Blob *entitlements = reinterpret_cast<struct Blob *>(blob + begin);
754 offset += sizeof(struct Blob);
755
756 memcpy(blob + offset, xmld, xmls);
757 offset += xmls;
758
759 entitlements->magic = Swap(CSMAGIC_ENTITLEMENTS);
760 entitlements->length = Swap(offset - begin);
761 }
762
20c5f1e8
JF
763 for (size_t index(0); index != count; ++index) {
764 uint32_t type = Swap(super->index[index].type);
765 if (type != 0 && type <= special) {
766 uint32_t offset = Swap(super->index[index].offset);
767 struct Blob *local = (struct Blob *) (blob + offset);
768 sha1((uint8_t *) (hashes - type), (uint8_t *) local, Swap(local->length));
769 }
770 }
771
fdb119ef 772 super->count = Swap(count);
c05d9758
JF
773 super->blob.length = Swap(offset);
774
775 if (offset > size) {
9c83be90 776 fprintf(stderr, "offset (%u) > size (%u)\n", offset, size);
c05d9758
JF
777 _assert(false);
778 } //else fprintf(stderr, "offset (%zu) <= size (%zu)\n", offset, size);
fdb119ef 779
fdb119ef
JF
780 memset(blob + offset, 0, size - offset);
781 }
782
122621c5
JF
783 if (flag_S) {
784 uint8_t *top = reinterpret_cast<uint8_t *>(framework.GetBase());
785 size_t size = framework.GetSize();
786
787 char *copy;
788 asprintf(&copy, "%s.%s.cp", dir, base);
789 FILE *file = fopen(copy, "w+");
790 size_t writ = fwrite(top, 1, size, file);
791 _assert(writ == size);
792 fclose(file);
793
794 _syscall(unlink(temp));
795 free(temp);
796 temp = copy;
797 }
798
fdb119ef 799 if (temp) {
31ad673b
JF
800 struct stat info;
801 _syscall(stat(path, &info));
802 _syscall(chown(temp, info.st_uid, info.st_gid));
803 _syscall(chmod(temp, info.st_mode));
fdb119ef
JF
804 _syscall(unlink(path));
805 _syscall(rename(temp, path));
806 free(temp);
807 }
808
809 free(dir);
a362a82f
JF
810 ++filei;
811 } catch (const char *) {
812 ++filee;
813 ++filei;
814 }
815
816 return filee;
817}