]> git.saurik.com Git - ldid.git/blob - ldid.cpp
bcad71e4b947bf18db98c975130d793ba21b2a55
[ldid.git] / ldid.cpp
1 /* ldid - (Mach-O) Link-Loader Identity Editor
2 * Copyright (C) 2007-2012 Jay Freeman (saurik)
3 */
4
5 /* GNU Lesser General Public License, Version 3 {{{ */
6 /* This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 **/
19 /* }}} */
20
21 #include "minimal/stdlib.h"
22 #include "minimal/string.h"
23 #include "minimal/mapping.h"
24
25 #include "sha1.h"
26
27 #include <cstring>
28 #include <string>
29 #include <vector>
30
31 #include <sys/wait.h>
32 #include <sys/types.h>
33 #include <sys/stat.h>
34
35 struct fat_header {
36 uint32_t magic;
37 uint32_t nfat_arch;
38 } _packed;
39
40 #define FAT_MAGIC 0xcafebabe
41 #define FAT_CIGAM 0xbebafeca
42
43 struct fat_arch {
44 uint32_t cputype;
45 uint32_t cpusubtype;
46 uint32_t offset;
47 uint32_t size;
48 uint32_t align;
49 } _packed;
50
51 struct mach_header {
52 uint32_t magic;
53 uint32_t cputype;
54 uint32_t cpusubtype;
55 uint32_t filetype;
56 uint32_t ncmds;
57 uint32_t sizeofcmds;
58 uint32_t flags;
59 } _packed;
60
61 #define MH_MAGIC 0xfeedface
62 #define MH_CIGAM 0xcefaedfe
63
64 #define MH_MAGIC_64 0xfeedfacf
65 #define MH_CIGAM_64 0xcffaedfe
66
67 #define MH_DYLDLINK 0x4
68
69 #define MH_EXECUTE 0x2
70 #define MH_DYLIB 0x6
71 #define MH_BUNDLE 0x8
72 #define MH_DYLIB_STUB 0x9
73
74 struct load_command {
75 uint32_t cmd;
76 uint32_t cmdsize;
77 } _packed;
78
79 #define LC_REQ_DYLD uint32_t(0x80000000)
80
81 #define LC_SEGMENT uint32_t(0x01)
82 #define LC_SYMTAB uint32_t(0x02)
83 #define LC_DYSYMTAB uint32_t(0x0b)
84 #define LC_LOAD_DYLIB uint32_t(0x0c)
85 #define LC_ID_DYLIB uint32_t(0x0d)
86 #define LC_SEGMENT_64 uint32_t(0x19)
87 #define LC_UUID uint32_t(0x1b)
88 #define LC_CODE_SIGNATURE uint32_t(0x1d)
89 #define LC_SEGMENT_SPLIT_INFO uint32_t(0x1e)
90 #define LC_REEXPORT_DYLIB uint32_t(0x1f | LC_REQ_DYLD)
91 #define LC_DYLD_INFO uint32_t(0x22)
92 #define LC_DYLD_INFO_ONLY uint32_t(0x22 | LC_REQ_DYLD)
93
94 struct dylib {
95 uint32_t name;
96 uint32_t timestamp;
97 uint32_t current_version;
98 uint32_t compatibility_version;
99 } _packed;
100
101 struct dylib_command {
102 uint32_t cmd;
103 uint32_t cmdsize;
104 struct dylib dylib;
105 } _packed;
106
107 struct uuid_command {
108 uint32_t cmd;
109 uint32_t cmdsize;
110 uint8_t uuid[16];
111 } _packed;
112
113 struct symtab_command {
114 uint32_t cmd;
115 uint32_t cmdsize;
116 uint32_t symoff;
117 uint32_t nsyms;
118 uint32_t stroff;
119 uint32_t strsize;
120 } _packed;
121
122 struct dyld_info_command {
123 uint32_t cmd;
124 uint32_t cmdsize;
125 uint32_t rebase_off;
126 uint32_t rebase_size;
127 uint32_t bind_off;
128 uint32_t bind_size;
129 uint32_t weak_bind_off;
130 uint32_t weak_bind_size;
131 uint32_t lazy_bind_off;
132 uint32_t lazy_bind_size;
133 uint32_t export_off;
134 uint32_t export_size;
135 } _packed;
136
137 struct dysymtab_command {
138 uint32_t cmd;
139 uint32_t cmdsize;
140 uint32_t ilocalsym;
141 uint32_t nlocalsym;
142 uint32_t iextdefsym;
143 uint32_t nextdefsym;
144 uint32_t iundefsym;
145 uint32_t nundefsym;
146 uint32_t tocoff;
147 uint32_t ntoc;
148 uint32_t modtaboff;
149 uint32_t nmodtab;
150 uint32_t extrefsymoff;
151 uint32_t nextrefsyms;
152 uint32_t indirectsymoff;
153 uint32_t nindirectsyms;
154 uint32_t extreloff;
155 uint32_t nextrel;
156 uint32_t locreloff;
157 uint32_t nlocrel;
158 } _packed;
159
160 struct dylib_table_of_contents {
161 uint32_t symbol_index;
162 uint32_t module_index;
163 } _packed;
164
165 struct dylib_module {
166 uint32_t module_name;
167 uint32_t iextdefsym;
168 uint32_t nextdefsym;
169 uint32_t irefsym;
170 uint32_t nrefsym;
171 uint32_t ilocalsym;
172 uint32_t nlocalsym;
173 uint32_t iextrel;
174 uint32_t nextrel;
175 uint32_t iinit_iterm;
176 uint32_t ninit_nterm;
177 uint32_t objc_module_info_addr;
178 uint32_t objc_module_info_size;
179 } _packed;
180
181 struct dylib_reference {
182 uint32_t isym:24;
183 uint32_t flags:8;
184 } _packed;
185
186 struct relocation_info {
187 int32_t r_address;
188 uint32_t r_symbolnum:24;
189 uint32_t r_pcrel:1;
190 uint32_t r_length:2;
191 uint32_t r_extern:1;
192 uint32_t r_type:4;
193 } _packed;
194
195 struct nlist {
196 union {
197 char *n_name;
198 int32_t n_strx;
199 } n_un;
200
201 uint8_t n_type;
202 uint8_t n_sect;
203 uint8_t n_desc;
204 uint32_t n_value;
205 } _packed;
206
207 struct segment_command {
208 uint32_t cmd;
209 uint32_t cmdsize;
210 char segname[16];
211 uint32_t vmaddr;
212 uint32_t vmsize;
213 uint32_t fileoff;
214 uint32_t filesize;
215 uint32_t maxprot;
216 uint32_t initprot;
217 uint32_t nsects;
218 uint32_t flags;
219 } _packed;
220
221 struct segment_command_64 {
222 uint32_t cmd;
223 uint32_t cmdsize;
224 char segname[16];
225 uint64_t vmaddr;
226 uint64_t vmsize;
227 uint64_t fileoff;
228 uint64_t filesize;
229 uint32_t maxprot;
230 uint32_t initprot;
231 uint32_t nsects;
232 uint32_t flags;
233 } _packed;
234
235 struct section {
236 char sectname[16];
237 char segname[16];
238 uint32_t addr;
239 uint32_t size;
240 uint32_t offset;
241 uint32_t align;
242 uint32_t reloff;
243 uint32_t nreloc;
244 uint32_t flags;
245 uint32_t reserved1;
246 uint32_t reserved2;
247 } _packed;
248
249 struct section_64 {
250 char sectname[16];
251 char segname[16];
252 uint64_t addr;
253 uint64_t size;
254 uint32_t offset;
255 uint32_t align;
256 uint32_t reloff;
257 uint32_t nreloc;
258 uint32_t flags;
259 uint32_t reserved1;
260 uint32_t reserved2;
261 } _packed;
262
263 struct linkedit_data_command {
264 uint32_t cmd;
265 uint32_t cmdsize;
266 uint32_t dataoff;
267 uint32_t datasize;
268 } _packed;
269
270 uint16_t Swap_(uint16_t value) {
271 return
272 ((value >> 8) & 0x00ff) |
273 ((value << 8) & 0xff00);
274 }
275
276 uint32_t Swap_(uint32_t value) {
277 value = ((value >> 8) & 0x00ff00ff) |
278 ((value << 8) & 0xff00ff00);
279 value = ((value >> 16) & 0x0000ffff) |
280 ((value << 16) & 0xffff0000);
281 return value;
282 }
283
284 int16_t Swap_(int16_t value) {
285 return Swap_(static_cast<uint16_t>(value));
286 }
287
288 int32_t Swap_(int32_t value) {
289 return Swap_(static_cast<uint32_t>(value));
290 }
291
292 bool little_(true);
293
294 uint16_t Swap(uint16_t value) {
295 return little_ ? Swap_(value) : value;
296 }
297
298 uint32_t Swap(uint32_t value) {
299 return little_ ? Swap_(value) : value;
300 }
301
302 int16_t Swap(int16_t value) {
303 return Swap(static_cast<uint16_t>(value));
304 }
305
306 int32_t Swap(int32_t value) {
307 return Swap(static_cast<uint32_t>(value));
308 }
309
310 template <typename Target_>
311 class Pointer;
312
313 class Data {
314 private:
315 void *base_;
316 size_t size_;
317
318 protected:
319 bool swapped_;
320
321 public:
322 Data(void *base, size_t size) :
323 base_(base),
324 size_(size),
325 swapped_(false)
326 {
327 }
328
329 uint16_t Swap(uint16_t value) const {
330 return swapped_ ? Swap_(value) : value;
331 }
332
333 uint32_t Swap(uint32_t value) const {
334 return swapped_ ? Swap_(value) : value;
335 }
336
337 int16_t Swap(int16_t value) const {
338 return Swap(static_cast<uint16_t>(value));
339 }
340
341 int32_t Swap(int32_t value) const {
342 return Swap(static_cast<uint32_t>(value));
343 }
344
345 void *GetBase() const {
346 return base_;
347 }
348
349 size_t GetSize() const {
350 return size_;
351 }
352 };
353
354 class MachHeader :
355 public Data
356 {
357 private:
358 bool bits64_;
359
360 struct mach_header *mach_header_;
361 struct load_command *load_command_;
362
363 public:
364 MachHeader(void *base, size_t size) :
365 Data(base, size)
366 {
367 mach_header_ = (mach_header *) base;
368
369 switch (Swap(mach_header_->magic)) {
370 case MH_CIGAM:
371 swapped_ = !swapped_;
372 case MH_MAGIC:
373 bits64_ = false;
374 break;
375
376 case MH_CIGAM_64:
377 swapped_ = !swapped_;
378 case MH_MAGIC_64:
379 bits64_ = true;
380 break;
381
382 default:
383 _assert(false);
384 }
385
386 void *post = mach_header_ + 1;
387 if (bits64_)
388 post = (uint32_t *) post + 1;
389 load_command_ = (struct load_command *) post;
390
391 _assert(
392 Swap(mach_header_->filetype) == MH_EXECUTE ||
393 Swap(mach_header_->filetype) == MH_DYLIB ||
394 Swap(mach_header_->filetype) == MH_BUNDLE
395 );
396 }
397
398 struct mach_header *operator ->() const {
399 return mach_header_;
400 }
401
402 uint32_t GetCPUType() const {
403 return Swap(mach_header_->cputype);
404 }
405
406 uint16_t GetCPUSubtype() const {
407 return Swap(mach_header_->cpusubtype) & 0xff;
408 }
409
410 std::vector<struct load_command *> GetLoadCommands() const {
411 std::vector<struct load_command *> load_commands;
412
413 struct load_command *load_command = load_command_;
414 for (uint32_t cmd = 0; cmd != Swap(mach_header_->ncmds); ++cmd) {
415 load_commands.push_back(load_command);
416 load_command = (struct load_command *) ((uint8_t *) load_command + Swap(load_command->cmdsize));
417 }
418
419 return load_commands;
420 }
421
422 std::vector<segment_command *> GetSegments(const char *segment_name) const {
423 std::vector<struct segment_command *> segment_commands;
424
425 _foreach (load_command, GetLoadCommands()) {
426 if (Swap(load_command->cmd) == LC_SEGMENT) {
427 segment_command *segment_command = reinterpret_cast<struct segment_command *>(load_command);
428 if (strncmp(segment_command->segname, segment_name, 16) == 0)
429 segment_commands.push_back(segment_command);
430 }
431 }
432
433 return segment_commands;
434 }
435
436 std::vector<segment_command_64 *> GetSegments64(const char *segment_name) {
437 std::vector<struct segment_command_64 *> segment_commands;
438
439 _foreach (load_command, GetLoadCommands()) {
440 if (Swap(load_command->cmd) == LC_SEGMENT_64) {
441 segment_command_64 *segment_command = reinterpret_cast<struct segment_command_64 *>(load_command);
442 if (strncmp(segment_command->segname, segment_name, 16) == 0)
443 segment_commands.push_back(segment_command);
444 }
445 }
446
447 return segment_commands;
448 }
449
450 std::vector<section *> GetSections(const char *segment_name, const char *section_name) const {
451 std::vector<section *> sections;
452
453 _foreach (segment, GetSegments(segment_name)) {
454 section *section = (struct section *) (segment + 1);
455
456 uint32_t sect;
457 for (sect = 0; sect != Swap(segment->nsects); ++sect) {
458 if (strncmp(section->sectname, section_name, 16) == 0)
459 sections.push_back(section);
460 ++section;
461 }
462 }
463
464 return sections;
465 }
466
467 template <typename Target_>
468 Pointer<Target_> GetPointer(uint32_t address, const char *segment_name = NULL) const {
469 load_command *load_command = (struct load_command *) (mach_header_ + 1);
470 uint32_t cmd;
471
472 for (cmd = 0; cmd != Swap(mach_header_->ncmds); ++cmd) {
473 if (Swap(load_command->cmd) == LC_SEGMENT) {
474 segment_command *segment_command = (struct segment_command *) load_command;
475 if (segment_name != NULL && strncmp(segment_command->segname, segment_name, 16) != 0)
476 goto next_command;
477
478 section *sections = (struct section *) (segment_command + 1);
479
480 uint32_t sect;
481 for (sect = 0; sect != Swap(segment_command->nsects); ++sect) {
482 section *section = &sections[sect];
483 //printf("%s %u %p %p %u\n", segment_command->segname, sect, address, section->addr, section->size);
484 if (address >= Swap(section->addr) && address < Swap(section->addr) + Swap(section->size)) {
485 //printf("0x%.8x %s\n", address, segment_command->segname);
486 return Pointer<Target_>(this, reinterpret_cast<Target_ *>(address - Swap(section->addr) + Swap(section->offset) + (char *) mach_header_));
487 }
488 }
489 }
490
491 next_command:
492 load_command = (struct load_command *) ((char *) load_command + Swap(load_command->cmdsize));
493 }
494
495 return Pointer<Target_>(this);
496 }
497
498 template <typename Target_>
499 Pointer<Target_> GetOffset(uint32_t offset) {
500 return Pointer<Target_>(this, reinterpret_cast<Target_ *>(offset + (uint8_t *) mach_header_));
501 }
502 };
503
504 class FatMachHeader :
505 public MachHeader
506 {
507 private:
508 fat_arch *fat_arch_;
509
510 public:
511 FatMachHeader(void *base, size_t size, fat_arch *fat_arch) :
512 MachHeader(base, size),
513 fat_arch_(fat_arch)
514 {
515 }
516
517 fat_arch *GetFatArch() const {
518 return fat_arch_;
519 }
520 };
521
522 class FatHeader :
523 public Data
524 {
525 private:
526 fat_header *fat_header_;
527 std::vector<FatMachHeader> mach_headers_;
528
529 public:
530 FatHeader(void *base, size_t size) :
531 Data(base, size)
532 {
533 fat_header_ = reinterpret_cast<struct fat_header *>(base);
534
535 if (Swap(fat_header_->magic) == FAT_CIGAM) {
536 swapped_ = !swapped_;
537 goto fat;
538 } else if (Swap(fat_header_->magic) != FAT_MAGIC) {
539 fat_header_ = NULL;
540 mach_headers_.push_back(FatMachHeader(base, size, NULL));
541 } else fat: {
542 size_t fat_narch = Swap(fat_header_->nfat_arch);
543 fat_arch *fat_arch = reinterpret_cast<struct fat_arch *>(fat_header_ + 1);
544 size_t arch;
545 for (arch = 0; arch != fat_narch; ++arch) {
546 uint32_t arch_offset = Swap(fat_arch->offset);
547 uint32_t arch_size = Swap(fat_arch->size);
548 mach_headers_.push_back(FatMachHeader((uint8_t *) base + arch_offset, arch_size, fat_arch));
549 ++fat_arch;
550 }
551 }
552 }
553
554 std::vector<FatMachHeader> &GetMachHeaders() {
555 return mach_headers_;
556 }
557
558 bool IsFat() const {
559 return fat_header_ != NULL;
560 }
561
562 struct fat_header *operator ->() const {
563 return fat_header_;
564 }
565 };
566
567 FatHeader Map(const char *path, bool ro = false) {
568 size_t size;
569 void *base(map(path, 0, _not(size_t), &size, ro));
570 return FatHeader(base, size);
571 }
572
573 template <typename Target_>
574 class Pointer {
575 private:
576 const MachHeader *framework_;
577 const Target_ *pointer_;
578
579 public:
580 Pointer(const MachHeader *framework = NULL, const Target_ *pointer = NULL) :
581 framework_(framework),
582 pointer_(pointer)
583 {
584 }
585
586 operator const Target_ *() const {
587 return pointer_;
588 }
589
590 const Target_ *operator ->() const {
591 return pointer_;
592 }
593
594 Pointer<Target_> &operator ++() {
595 ++pointer_;
596 return *this;
597 }
598
599 template <typename Value_>
600 Value_ Swap(Value_ value) {
601 return framework_->Swap(value);
602 }
603 };
604
605 #define CSMAGIC_CODEDIRECTORY uint32_t(0xfade0c02)
606 #define CSMAGIC_EMBEDDED_SIGNATURE uint32_t(0xfade0cc0)
607 #define CSMAGIC_ENTITLEMENTS uint32_t(0xfade7171)
608
609 #define CSSLOT_CODEDIRECTORY uint32_t(0)
610 #define CSSLOT_REQUIREMENTS uint32_t(2)
611 #define CSSLOT_ENTITLEMENTS uint32_t(5)
612
613 struct BlobIndex {
614 uint32_t type;
615 uint32_t offset;
616 } _packed;
617
618 struct Blob {
619 uint32_t magic;
620 uint32_t length;
621 } _packed;
622
623 struct SuperBlob {
624 struct Blob blob;
625 uint32_t count;
626 struct BlobIndex index[];
627 } _packed;
628
629 struct CodeDirectory {
630 struct Blob blob;
631 uint32_t version;
632 uint32_t flags;
633 uint32_t hashOffset;
634 uint32_t identOffset;
635 uint32_t nSpecialSlots;
636 uint32_t nCodeSlots;
637 uint32_t codeLimit;
638 uint8_t hashSize;
639 uint8_t hashType;
640 uint8_t spare1;
641 uint8_t pageSize;
642 uint32_t spare2;
643 } _packed;
644
645 extern "C" uint32_t hash(uint8_t *k, uint32_t length, uint32_t initval);
646
647 void sha1(uint8_t *hash, uint8_t *data, size_t size) {
648 SHA1Context context;
649 SHA1Reset(&context);
650 SHA1Input(&context, data, size);
651 SHA1Result(&context, hash);
652 }
653
654 struct CodesignAllocation {
655 uint32_t type_;
656 uint16_t subtype_;
657 size_t size_;
658
659 CodesignAllocation(uint32_t type, uint16_t subtype, size_t size) :
660 type_(type),
661 subtype_(subtype),
662 size_(size)
663 {
664 }
665 };
666
667 int main(int argc, const char *argv[]) {
668 union {
669 uint16_t word;
670 uint8_t byte[2];
671 } endian = {1};
672
673 little_ = endian.byte[0];
674
675 bool flag_R(false);
676 bool flag_r(false);
677
678 bool flag_t(false);
679 bool flag_p(false);
680 bool flag_u(false);
681 bool flag_e(false);
682
683 bool flag_T(false);
684
685 bool flag_S(false);
686 bool flag_s(false);
687
688 bool flag_O(false);
689
690 bool timeh(false);
691 uint32_t timev(0);
692
693 const void *xmld(NULL);
694 size_t xmls(0);
695
696 uintptr_t noffset(_not(uintptr_t));
697 uintptr_t woffset(_not(uintptr_t));
698
699 std::vector<std::string> files;
700
701 if (argc == 1) {
702 fprintf(stderr, "usage: %s -S[entitlements.xml] <binary>\n", argv[0]);
703 fprintf(stderr, " %s -e MobileSafari\n", argv[0]);
704 fprintf(stderr, " %s -S cat\n", argv[0]);
705 fprintf(stderr, " %s -Stfp.xml gdb\n", argv[0]);
706 exit(0);
707 }
708
709 for (int argi(1); argi != argc; ++argi)
710 if (argv[argi][0] != '-')
711 files.push_back(argv[argi]);
712 else switch (argv[argi][1]) {
713 case 'R': flag_R = true; break;
714 case 'r': flag_r = true; break;
715
716 case 't': flag_t = true; break;
717 case 'u': flag_u = true; break;
718 case 'p': flag_p = true; break;
719 case 'e': flag_e = true; break;
720 case 'O': flag_O = true; break;
721
722 case 's':
723 _assert(!flag_S);
724 flag_s = true;
725 break;
726
727 case 'S':
728 _assert(!flag_s);
729 flag_S = true;
730 if (argv[argi][2] != '\0') {
731 const char *xml = argv[argi] + 2;
732 xmld = map(xml, 0, _not(size_t), &xmls, true);
733 }
734 break;
735
736 case 'T': {
737 flag_T = true;
738 if (argv[argi][2] == '-')
739 timeh = true;
740 else {
741 char *arge;
742 timev = strtoul(argv[argi] + 2, &arge, 0);
743 _assert(arge == argv[argi] + strlen(argv[argi]));
744 }
745 } break;
746
747 case 'n': {
748 char *arge;
749 noffset = strtoul(argv[argi] + 2, &arge, 0);
750 _assert(arge == argv[argi] + strlen(argv[argi]));
751 } break;
752
753 case 'w': {
754 char *arge;
755 woffset = strtoul(argv[argi] + 2, &arge, 0);
756 _assert(arge == argv[argi] + strlen(argv[argi]));
757 } break;
758
759 default:
760 goto usage;
761 break;
762 }
763
764 if (files.empty()) usage: {
765 exit(0);
766 }
767
768 size_t filei(0), filee(0);
769 _foreach (file, files) try {
770 const char *path(file.c_str());
771 const char *base = strrchr(path, '/');
772 char *temp(NULL), *dir;
773
774 if (base != NULL)
775 dir = strndup_(path, base++ - path + 1);
776 else {
777 dir = strdup("");
778 base = path;
779 }
780
781 if (flag_r) {
782 uint32_t clip(0); {
783 FatHeader fat_header(Map(path));
784 _foreach (mach_header, fat_header.GetMachHeaders()) {
785 mach_header->flags = mach_header.Swap(mach_header.Swap(mach_header->flags) | MH_DYLDLINK);
786
787 uint32_t size(_not(uint32_t)); {
788 _foreach (load_command, mach_header.GetLoadCommands()) {
789 switch (mach_header.Swap(load_command->cmd)) {
790 case LC_CODE_SIGNATURE: {
791 struct linkedit_data_command *signature = reinterpret_cast<struct linkedit_data_command *>(load_command);
792 memset(reinterpret_cast<uint8_t *>(mach_header.GetBase()) + mach_header.Swap(signature->dataoff), 0, mach_header.Swap(signature->datasize));
793 memset(signature, 0, sizeof(struct linkedit_data_command));
794
795 mach_header->ncmds = mach_header.Swap(mach_header.Swap(mach_header->ncmds) - 1);
796 mach_header->sizeofcmds = mach_header.Swap(uint32_t(mach_header.Swap(mach_header->sizeofcmds) - sizeof(struct linkedit_data_command)));
797 } break;
798
799 case LC_SYMTAB: {
800 struct symtab_command *symtab = reinterpret_cast<struct symtab_command *>(load_command);
801 size = mach_header.Swap(symtab->stroff) + mach_header.Swap(symtab->strsize);
802 } break;
803 }
804 }
805 }
806
807 _assert(size != _not(uint32_t));
808
809 _foreach (segment, const_cast<FatMachHeader &>(mach_header).GetSegments("__LINKEDIT")) {
810 segment->filesize -= mach_header.GetSize() - size;
811
812 if (fat_arch *fat_arch = mach_header.GetFatArch()) {
813 fat_arch->size = fat_header.Swap(size);
814 clip = std::max(clip, fat_header.Swap(fat_arch->offset) + size);
815 } else
816 clip = std::max(clip, size);
817 }
818
819 _foreach (segment, const_cast<FatMachHeader &>(mach_header).GetSegments64("__LINKEDIT")) {
820 segment->filesize -= mach_header.GetSize() - size;
821
822 if (fat_arch *fat_arch = mach_header.GetFatArch()) {
823 fat_arch->size = fat_header.Swap(size);
824 clip = std::max(clip, fat_header.Swap(fat_arch->offset) + size);
825 } else
826 clip = std::max(clip, size);
827 }
828 }
829 }
830
831 _assert(clip != 0);
832 _syscall(truncate(path, clip));
833 }
834
835 if (flag_S) {
836 asprintf(&temp, "%s.%s.cs", dir, base);
837 const char *allocate = getenv("CODESIGN_ALLOCATE");
838 if (allocate == NULL)
839 allocate = "codesign_allocate";
840
841 std::vector<CodesignAllocation> allocations; {
842 FatHeader fat_header(Map(path));
843 _foreach (mach_header, fat_header.GetMachHeaders()) {
844 mach_header->flags = mach_header.Swap(mach_header.Swap(mach_header->flags) | MH_DYLDLINK);
845
846 size_t size(_not(size_t)); {
847 _foreach (load_command, mach_header.GetLoadCommands()) {
848 uint32_t cmd(mach_header.Swap(load_command->cmd));
849 if (cmd == LC_CODE_SIGNATURE) {
850 struct linkedit_data_command *signature = reinterpret_cast<struct linkedit_data_command *>(load_command);
851 size = mach_header.Swap(signature->dataoff);
852 _assert(size < mach_header.GetSize());
853 break;
854 }
855 }
856
857 if (size == _not(size_t))
858 size = mach_header.GetSize();
859 }
860
861 allocations.push_back(CodesignAllocation(mach_header.GetCPUType(), mach_header.GetCPUSubtype(), size));
862 }
863 }
864
865 pid_t pid = fork();
866 _syscall(pid);
867 if (pid == 0) {
868 // XXX: this leaks memory, but it doesn't really matter
869 std::vector<const char *> args;
870 char *arg;
871
872 args.push_back(allocate);
873
874 args.push_back("-i");
875 args.push_back(path);
876
877 _foreach (allocation, allocations) {
878 args.push_back("-A");
879
880 asprintf(&arg, "%u", allocation.type_);
881 args.push_back(arg);
882
883 asprintf(&arg, "%u", allocation.subtype_);
884 args.push_back(arg);
885
886 size_t alloc(0);
887 alloc += sizeof(struct SuperBlob);
888 uint32_t special(0);
889
890 special = std::max(special, CSSLOT_CODEDIRECTORY);
891 alloc += sizeof(struct BlobIndex);
892 alloc += sizeof(struct CodeDirectory);
893 alloc += strlen(base) + 1;
894
895 special = std::max(special, CSSLOT_REQUIREMENTS);
896 alloc += sizeof(struct BlobIndex);
897 alloc += 0xc;
898
899 if (xmld != NULL) {
900 special = std::max(special, CSSLOT_ENTITLEMENTS);
901 alloc += sizeof(struct BlobIndex);
902 alloc += sizeof(struct Blob);
903 alloc += xmls;
904 }
905
906 size_t normal((allocation.size_ + 0x1000 - 1) / 0x1000);
907 alloc += (special + normal) * 0x14;
908
909 alloc += 15;
910 alloc /= 16;
911 alloc *= 16;
912
913 asprintf(&arg, "%zu", alloc);
914 args.push_back(arg);
915 }
916
917 args.push_back("-o");
918 args.push_back(temp);
919
920 args.push_back(NULL);
921
922 if (false) {
923 printf("run:");
924 _foreach (arg, args)
925 printf(" %s", arg);
926 printf("\n");
927 }
928
929 execvp(allocate, (char **) &args[0]);
930 _assert(false);
931 }
932
933 int status;
934 _syscall(waitpid(pid, &status, 0));
935 _assert(WIFEXITED(status));
936 _assert(WEXITSTATUS(status) == 0);
937 }
938
939 if (flag_p)
940 printf("path%zu='%s'\n", filei, file.c_str());
941
942 FatHeader fat_header(Map(temp == NULL ? path : temp, !(flag_R | flag_T | flag_s | flag_S | flag_O)));
943 struct linkedit_data_command *signature(NULL);
944
945 _foreach (mach_header, fat_header.GetMachHeaders()) {
946 if (woffset != _not(uintptr_t)) {
947 Pointer<uint32_t> wvalue(mach_header.GetPointer<uint32_t>(woffset));
948 if (wvalue == NULL)
949 printf("(null) %p\n", reinterpret_cast<void *>(woffset));
950 else
951 printf("0x%.08x\n", *wvalue);
952 }
953
954 if (noffset != _not(uintptr_t))
955 printf("%s\n", &*mach_header.GetPointer<char>(noffset));
956
957 if (flag_O) {
958 _foreach(section, mach_header.GetSections("__TEXT", "__text"))
959 section->addr = mach_header.Swap(0);
960 }
961
962 _foreach (load_command, mach_header.GetLoadCommands()) {
963 uint32_t cmd(mach_header.Swap(load_command->cmd));
964
965 if (flag_R && cmd == LC_REEXPORT_DYLIB)
966 load_command->cmd = mach_header.Swap(LC_LOAD_DYLIB);
967 else if (cmd == LC_CODE_SIGNATURE)
968 signature = reinterpret_cast<struct linkedit_data_command *>(load_command);
969 else if (cmd == LC_UUID) {
970 volatile struct uuid_command *uuid_command(reinterpret_cast<struct uuid_command *>(load_command));
971
972 if (flag_u) {
973 printf("uuid%zu=%.2x%.2x%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x%.2x%.2x%.2x%.2x\n", filei,
974 uuid_command->uuid[ 0], uuid_command->uuid[ 1], uuid_command->uuid[ 2], uuid_command->uuid[ 3],
975 uuid_command->uuid[ 4], uuid_command->uuid[ 5], uuid_command->uuid[ 6], uuid_command->uuid[ 7],
976 uuid_command->uuid[ 8], uuid_command->uuid[ 9], uuid_command->uuid[10], uuid_command->uuid[11],
977 uuid_command->uuid[12], uuid_command->uuid[13], uuid_command->uuid[14], uuid_command->uuid[15]
978 );
979 }
980 } else if (cmd == LC_ID_DYLIB) {
981 volatile struct dylib_command *dylib_command(reinterpret_cast<struct dylib_command *>(load_command));
982
983 if (flag_t)
984 printf("time%zu=0x%.8x\n", filei, mach_header.Swap(dylib_command->dylib.timestamp));
985
986 if (flag_T) {
987 uint32_t timed;
988
989 if (!timeh)
990 timed = timev;
991 else {
992 dylib_command->dylib.timestamp = 0;
993 timed = hash(reinterpret_cast<uint8_t *>(mach_header.GetBase()), mach_header.GetSize(), timev);
994 }
995
996 dylib_command->dylib.timestamp = mach_header.Swap(timed);
997 }
998 }
999 }
1000
1001 if (flag_e) {
1002 _assert(signature != NULL);
1003
1004 uint32_t data = mach_header.Swap(signature->dataoff);
1005
1006 uint8_t *top = reinterpret_cast<uint8_t *>(mach_header.GetBase());
1007 uint8_t *blob = top + data;
1008 struct SuperBlob *super = reinterpret_cast<struct SuperBlob *>(blob);
1009
1010 for (size_t index(0); index != Swap(super->count); ++index)
1011 if (Swap(super->index[index].type) == CSSLOT_ENTITLEMENTS) {
1012 uint32_t begin = Swap(super->index[index].offset);
1013 struct Blob *entitlements = reinterpret_cast<struct Blob *>(blob + begin);
1014 fwrite(entitlements + 1, 1, Swap(entitlements->length) - sizeof(struct Blob), stdout);
1015 }
1016 }
1017
1018 if (flag_s) {
1019 _assert(signature != NULL);
1020
1021 uint32_t data = mach_header.Swap(signature->dataoff);
1022
1023 uint8_t *top = reinterpret_cast<uint8_t *>(mach_header.GetBase());
1024 uint8_t *blob = top + data;
1025 struct SuperBlob *super = reinterpret_cast<struct SuperBlob *>(blob);
1026
1027 for (size_t index(0); index != Swap(super->count); ++index)
1028 if (Swap(super->index[index].type) == CSSLOT_CODEDIRECTORY) {
1029 uint32_t begin = Swap(super->index[index].offset);
1030 struct CodeDirectory *directory = reinterpret_cast<struct CodeDirectory *>(blob + begin);
1031
1032 uint8_t (*hashes)[20] = reinterpret_cast<uint8_t (*)[20]>(blob + begin + Swap(directory->hashOffset));
1033 uint32_t pages = Swap(directory->nCodeSlots);
1034
1035 if (pages != 1)
1036 for (size_t i = 0; i != pages - 1; ++i)
1037 sha1(hashes[i], top + 0x1000 * i, 0x1000);
1038 if (pages != 0)
1039 sha1(hashes[pages - 1], top + 0x1000 * (pages - 1), ((data - 1) % 0x1000) + 1);
1040 }
1041 }
1042
1043 if (flag_S) {
1044 _assert(signature != NULL);
1045
1046 uint32_t data = mach_header.Swap(signature->dataoff);
1047 uint32_t size = mach_header.Swap(signature->datasize);
1048
1049 uint8_t *top = reinterpret_cast<uint8_t *>(mach_header.GetBase());
1050 uint8_t *blob = top + data;
1051 struct SuperBlob *super = reinterpret_cast<struct SuperBlob *>(blob);
1052 super->blob.magic = Swap(CSMAGIC_EMBEDDED_SIGNATURE);
1053
1054 uint32_t count = xmld == NULL ? 2 : 3;
1055 uint32_t offset = sizeof(struct SuperBlob) + count * sizeof(struct BlobIndex);
1056
1057 super->index[0].type = Swap(CSSLOT_CODEDIRECTORY);
1058 super->index[0].offset = Swap(offset);
1059
1060 uint32_t begin = offset;
1061 struct CodeDirectory *directory = reinterpret_cast<struct CodeDirectory *>(blob + begin);
1062 offset += sizeof(struct CodeDirectory);
1063
1064 directory->blob.magic = Swap(CSMAGIC_CODEDIRECTORY);
1065 directory->version = Swap(uint32_t(0x00020001));
1066 directory->flags = Swap(uint32_t(0));
1067 directory->codeLimit = Swap(data);
1068 directory->hashSize = 0x14;
1069 directory->hashType = 0x01;
1070 directory->spare1 = 0x00;
1071 directory->pageSize = 0x0c;
1072 directory->spare2 = Swap(uint32_t(0));
1073
1074 directory->identOffset = Swap(offset - begin);
1075 strcpy(reinterpret_cast<char *>(blob + offset), base);
1076 offset += strlen(base) + 1;
1077
1078 uint32_t special = xmld == NULL ? CSSLOT_REQUIREMENTS : CSSLOT_ENTITLEMENTS;
1079 directory->nSpecialSlots = Swap(special);
1080
1081 uint8_t (*hashes)[20] = reinterpret_cast<uint8_t (*)[20]>(blob + offset);
1082 memset(hashes, 0, sizeof(*hashes) * special);
1083
1084 offset += sizeof(*hashes) * special;
1085 hashes += special;
1086
1087 uint32_t pages = (data + 0x1000 - 1) / 0x1000;
1088 directory->nCodeSlots = Swap(pages);
1089
1090 if (pages != 1)
1091 for (size_t i = 0; i != pages - 1; ++i)
1092 sha1(hashes[i], top + 0x1000 * i, 0x1000);
1093 if (pages != 0)
1094 sha1(hashes[pages - 1], top + 0x1000 * (pages - 1), ((data - 1) % 0x1000) + 1);
1095
1096 directory->hashOffset = Swap(offset - begin);
1097 offset += sizeof(*hashes) * pages;
1098 directory->blob.length = Swap(offset - begin);
1099
1100 super->index[1].type = Swap(CSSLOT_REQUIREMENTS);
1101 super->index[1].offset = Swap(offset);
1102
1103 memcpy(blob + offset, "\xfa\xde\x0c\x01\x00\x00\x00\x0c\x00\x00\x00\x00", 0xc);
1104 offset += 0xc;
1105
1106 if (xmld != NULL) {
1107 super->index[2].type = Swap(CSSLOT_ENTITLEMENTS);
1108 super->index[2].offset = Swap(offset);
1109
1110 uint32_t begin = offset;
1111 struct Blob *entitlements = reinterpret_cast<struct Blob *>(blob + begin);
1112 offset += sizeof(struct Blob);
1113
1114 memcpy(blob + offset, xmld, xmls);
1115 offset += xmls;
1116
1117 entitlements->magic = Swap(CSMAGIC_ENTITLEMENTS);
1118 entitlements->length = Swap(offset - begin);
1119 }
1120
1121 for (size_t index(0); index != count; ++index) {
1122 uint32_t type = Swap(super->index[index].type);
1123 if (type != 0 && type <= special) {
1124 uint32_t offset = Swap(super->index[index].offset);
1125 struct Blob *local = (struct Blob *) (blob + offset);
1126 sha1((uint8_t *) (hashes - type), (uint8_t *) local, Swap(local->length));
1127 }
1128 }
1129
1130 super->count = Swap(count);
1131 super->blob.length = Swap(offset);
1132
1133 if (offset > size) {
1134 fprintf(stderr, "offset (%u) > size (%u)\n", offset, size);
1135 _assert(false);
1136 } //else fprintf(stderr, "offset (%zu) <= size (%zu)\n", offset, size);
1137
1138 memset(blob + offset, 0, size - offset);
1139 }
1140 }
1141
1142 if (flag_S) {
1143 uint8_t *top = reinterpret_cast<uint8_t *>(fat_header.GetBase());
1144 size_t size = fat_header.GetSize();
1145
1146 char *copy;
1147 asprintf(&copy, "%s.%s.cp", dir, base);
1148 FILE *file = fopen(copy, "w+");
1149 size_t writ = fwrite(top, 1, size, file);
1150 _assert(writ == size);
1151 fclose(file);
1152
1153 _syscall(unlink(temp));
1154 free(temp);
1155 temp = copy;
1156 }
1157
1158 if (temp != NULL) {
1159 struct stat info;
1160 _syscall(stat(path, &info));
1161 _syscall(chown(temp, info.st_uid, info.st_gid));
1162 _syscall(chmod(temp, info.st_mode));
1163 _syscall(unlink(path));
1164 _syscall(rename(temp, path));
1165 free(temp);
1166 }
1167
1168 free(dir);
1169 ++filei;
1170 } catch (const char *) {
1171 ++filee;
1172 ++filei;
1173 }
1174
1175 return filee;
1176 }