]> git.saurik.com Git - ldid.git/blob - ldid.cpp
Added a few _packed modifiers that were missing.
[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 timeh(false);
689 uint32_t timev(0);
690
691 const void *xmld(NULL);
692 size_t xmls(0);
693
694 uintptr_t noffset(_not(uintptr_t));
695 uintptr_t woffset(_not(uintptr_t));
696
697 std::vector<std::string> files;
698
699 if (argc == 1) {
700 fprintf(stderr, "usage: %s -S[entitlements.xml] <binary>\n", argv[0]);
701 fprintf(stderr, " %s -e MobileSafari\n", argv[0]);
702 fprintf(stderr, " %s -S cat\n", argv[0]);
703 fprintf(stderr, " %s -Stfp.xml gdb\n", argv[0]);
704 exit(0);
705 }
706
707 for (int argi(1); argi != argc; ++argi)
708 if (argv[argi][0] != '-')
709 files.push_back(argv[argi]);
710 else switch (argv[argi][1]) {
711 case 'R': flag_R = true; break;
712 case 'r': flag_r = true; break;
713
714 case 't': flag_t = true; break;
715 case 'u': flag_u = true; break;
716 case 'p': flag_p = true; break;
717 case 'e': flag_e = true; break;
718
719 case 's':
720 _assert(!flag_S);
721 flag_s = true;
722 break;
723
724 case 'S':
725 _assert(!flag_s);
726 flag_S = true;
727 if (argv[argi][2] != '\0') {
728 const char *xml = argv[argi] + 2;
729 xmld = map(xml, 0, _not(size_t), &xmls, true);
730 }
731 break;
732
733 case 'T': {
734 flag_T = true;
735 if (argv[argi][2] == '-')
736 timeh = true;
737 else {
738 char *arge;
739 timev = strtoul(argv[argi] + 2, &arge, 0);
740 _assert(arge == argv[argi] + strlen(argv[argi]));
741 }
742 } break;
743
744 case 'n': {
745 char *arge;
746 noffset = strtoul(argv[argi] + 2, &arge, 0);
747 _assert(arge == argv[argi] + strlen(argv[argi]));
748 } break;
749
750 case 'w': {
751 char *arge;
752 woffset = strtoul(argv[argi] + 2, &arge, 0);
753 _assert(arge == argv[argi] + strlen(argv[argi]));
754 } break;
755
756 default:
757 goto usage;
758 break;
759 }
760
761 if (files.empty()) usage: {
762 exit(0);
763 }
764
765 size_t filei(0), filee(0);
766 _foreach (file, files) try {
767 const char *path(file.c_str());
768 const char *base = strrchr(path, '/');
769 char *temp(NULL), *dir;
770
771 if (base != NULL)
772 dir = strndup_(path, base++ - path + 1);
773 else {
774 dir = strdup("");
775 base = path;
776 }
777
778 if (flag_r) {
779 uint32_t clip(0); {
780 FatHeader fat_header(Map(path));
781 _foreach (mach_header, fat_header.GetMachHeaders()) {
782 mach_header->flags = mach_header.Swap(mach_header.Swap(mach_header->flags) | MH_DYLDLINK);
783
784 uint32_t size(_not(uint32_t)); {
785 _foreach (load_command, mach_header.GetLoadCommands()) {
786 switch (mach_header.Swap(load_command->cmd)) {
787 case LC_CODE_SIGNATURE: {
788 struct linkedit_data_command *signature = reinterpret_cast<struct linkedit_data_command *>(load_command);
789 memset(reinterpret_cast<uint8_t *>(mach_header.GetBase()) + mach_header.Swap(signature->dataoff), 0, mach_header.Swap(signature->datasize));
790 memset(signature, 0, sizeof(struct linkedit_data_command));
791
792 mach_header->ncmds = mach_header.Swap(mach_header.Swap(mach_header->ncmds) - 1);
793 mach_header->sizeofcmds = mach_header.Swap(uint32_t(mach_header.Swap(mach_header->sizeofcmds) - sizeof(struct linkedit_data_command)));
794 } break;
795
796 case LC_SYMTAB: {
797 struct symtab_command *symtab = reinterpret_cast<struct symtab_command *>(load_command);
798 size = mach_header.Swap(symtab->stroff) + mach_header.Swap(symtab->strsize);
799 } break;
800 }
801 }
802 }
803
804 _assert(size != _not(uint32_t));
805
806 _foreach (segment, const_cast<FatMachHeader &>(mach_header).GetSegments("__LINKEDIT")) {
807 segment->filesize -= mach_header.GetSize() - size;
808
809 if (fat_arch *fat_arch = mach_header.GetFatArch()) {
810 fat_arch->size = fat_header.Swap(size);
811 clip = std::max(clip, fat_header.Swap(fat_arch->offset) + size);
812 } else
813 clip = std::max(clip, size);
814 }
815
816 _foreach (segment, const_cast<FatMachHeader &>(mach_header).GetSegments64("__LINKEDIT")) {
817 segment->filesize -= mach_header.GetSize() - size;
818
819 if (fat_arch *fat_arch = mach_header.GetFatArch()) {
820 fat_arch->size = fat_header.Swap(size);
821 clip = std::max(clip, fat_header.Swap(fat_arch->offset) + size);
822 } else
823 clip = std::max(clip, size);
824 }
825 }
826 }
827
828 _assert(clip != 0);
829 _syscall(truncate(path, clip));
830 }
831
832 if (flag_S) {
833 asprintf(&temp, "%s.%s.cs", dir, base);
834 const char *allocate = getenv("CODESIGN_ALLOCATE");
835 if (allocate == NULL)
836 allocate = "codesign_allocate";
837
838 std::vector<CodesignAllocation> allocations; {
839 FatHeader fat_header(Map(path));
840 _foreach (mach_header, fat_header.GetMachHeaders()) {
841 mach_header->flags = mach_header.Swap(mach_header.Swap(mach_header->flags) | MH_DYLDLINK);
842
843 size_t size(_not(size_t)); {
844 _foreach (load_command, mach_header.GetLoadCommands()) {
845 uint32_t cmd(mach_header.Swap(load_command->cmd));
846 if (cmd == LC_CODE_SIGNATURE) {
847 struct linkedit_data_command *signature = reinterpret_cast<struct linkedit_data_command *>(load_command);
848 size = mach_header.Swap(signature->dataoff);
849 _assert(size < mach_header.GetSize());
850 break;
851 }
852 }
853
854 if (size == _not(size_t))
855 size = mach_header.GetSize();
856 }
857
858 allocations.push_back(CodesignAllocation(mach_header.GetCPUType(), mach_header.GetCPUSubtype(), size));
859 }
860 }
861
862 pid_t pid = fork();
863 _syscall(pid);
864 if (pid == 0) {
865 // XXX: this leaks memory, but it doesn't really matter
866 std::vector<const char *> args;
867 char *arg;
868
869 args.push_back(allocate);
870
871 args.push_back("-i");
872 args.push_back(path);
873
874 _foreach (allocation, allocations) {
875 args.push_back("-A");
876
877 asprintf(&arg, "%u", allocation.type_);
878 args.push_back(arg);
879
880 asprintf(&arg, "%u", allocation.subtype_);
881 args.push_back(arg);
882
883 size_t alloc(0);
884 alloc += sizeof(struct SuperBlob);
885 uint32_t special(0);
886
887 special = std::max(special, CSSLOT_CODEDIRECTORY);
888 alloc += sizeof(struct BlobIndex);
889 alloc += sizeof(struct CodeDirectory);
890 alloc += strlen(base) + 1;
891
892 special = std::max(special, CSSLOT_REQUIREMENTS);
893 alloc += sizeof(struct BlobIndex);
894 alloc += 0xc;
895
896 if (xmld != NULL) {
897 special = std::max(special, CSSLOT_ENTITLEMENTS);
898 alloc += sizeof(struct BlobIndex);
899 alloc += sizeof(struct Blob);
900 alloc += xmls;
901 }
902
903 size_t normal((allocation.size_ + 0x1000 - 1) / 0x1000);
904 alloc += (special + normal) * 0x14;
905
906 alloc += 15;
907 alloc /= 16;
908 alloc *= 16;
909
910 asprintf(&arg, "%zu", alloc);
911 args.push_back(arg);
912 }
913
914 args.push_back("-o");
915 args.push_back(temp);
916
917 args.push_back(NULL);
918
919 if (false) {
920 printf("run:");
921 _foreach (arg, args)
922 printf(" %s", arg);
923 printf("\n");
924 }
925
926 execvp(allocate, (char **) &args[0]);
927 _assert(false);
928 }
929
930 int status;
931 _syscall(waitpid(pid, &status, 0));
932 _assert(WIFEXITED(status));
933 _assert(WEXITSTATUS(status) == 0);
934 }
935
936 if (flag_p)
937 printf("path%zu='%s'\n", filei, file.c_str());
938
939 FatHeader fat_header(Map(temp == NULL ? path : temp, !(flag_R | flag_T | flag_s | flag_S)));
940 struct linkedit_data_command *signature(NULL);
941
942 _foreach (mach_header, fat_header.GetMachHeaders()) {
943 if (woffset != _not(uintptr_t)) {
944 Pointer<uint32_t> wvalue(mach_header.GetPointer<uint32_t>(woffset));
945 if (wvalue == NULL)
946 printf("(null) %p\n", reinterpret_cast<void *>(woffset));
947 else
948 printf("0x%.08x\n", *wvalue);
949 }
950
951 if (noffset != _not(uintptr_t))
952 printf("%s\n", &*mach_header.GetPointer<char>(noffset));
953
954 _foreach (load_command, mach_header.GetLoadCommands()) {
955 uint32_t cmd(mach_header.Swap(load_command->cmd));
956
957 if (flag_R && cmd == LC_REEXPORT_DYLIB)
958 load_command->cmd = mach_header.Swap(LC_LOAD_DYLIB);
959 else if (cmd == LC_CODE_SIGNATURE)
960 signature = reinterpret_cast<struct linkedit_data_command *>(load_command);
961 else if (cmd == LC_UUID) {
962 volatile struct uuid_command *uuid_command(reinterpret_cast<struct uuid_command *>(load_command));
963
964 if (flag_u) {
965 printf("uuid%zu=%.2x%.2x%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x%.2x%.2x%.2x%.2x\n", filei,
966 uuid_command->uuid[ 0], uuid_command->uuid[ 1], uuid_command->uuid[ 2], uuid_command->uuid[ 3],
967 uuid_command->uuid[ 4], uuid_command->uuid[ 5], uuid_command->uuid[ 6], uuid_command->uuid[ 7],
968 uuid_command->uuid[ 8], uuid_command->uuid[ 9], uuid_command->uuid[10], uuid_command->uuid[11],
969 uuid_command->uuid[12], uuid_command->uuid[13], uuid_command->uuid[14], uuid_command->uuid[15]
970 );
971 }
972 } else if (cmd == LC_ID_DYLIB) {
973 volatile struct dylib_command *dylib_command(reinterpret_cast<struct dylib_command *>(load_command));
974
975 if (flag_t)
976 printf("time%zu=0x%.8x\n", filei, mach_header.Swap(dylib_command->dylib.timestamp));
977
978 if (flag_T) {
979 uint32_t timed;
980
981 if (!timeh)
982 timed = timev;
983 else {
984 dylib_command->dylib.timestamp = 0;
985 timed = hash(reinterpret_cast<uint8_t *>(mach_header.GetBase()), mach_header.GetSize(), timev);
986 }
987
988 dylib_command->dylib.timestamp = mach_header.Swap(timed);
989 }
990 }
991 }
992
993 if (flag_e) {
994 _assert(signature != NULL);
995
996 uint32_t data = mach_header.Swap(signature->dataoff);
997
998 uint8_t *top = reinterpret_cast<uint8_t *>(mach_header.GetBase());
999 uint8_t *blob = top + data;
1000 struct SuperBlob *super = reinterpret_cast<struct SuperBlob *>(blob);
1001
1002 for (size_t index(0); index != Swap(super->count); ++index)
1003 if (Swap(super->index[index].type) == CSSLOT_ENTITLEMENTS) {
1004 uint32_t begin = Swap(super->index[index].offset);
1005 struct Blob *entitlements = reinterpret_cast<struct Blob *>(blob + begin);
1006 fwrite(entitlements + 1, 1, Swap(entitlements->length) - sizeof(struct Blob), stdout);
1007 }
1008 }
1009
1010 if (flag_s) {
1011 _assert(signature != NULL);
1012
1013 uint32_t data = mach_header.Swap(signature->dataoff);
1014
1015 uint8_t *top = reinterpret_cast<uint8_t *>(mach_header.GetBase());
1016 uint8_t *blob = top + data;
1017 struct SuperBlob *super = reinterpret_cast<struct SuperBlob *>(blob);
1018
1019 for (size_t index(0); index != Swap(super->count); ++index)
1020 if (Swap(super->index[index].type) == CSSLOT_CODEDIRECTORY) {
1021 uint32_t begin = Swap(super->index[index].offset);
1022 struct CodeDirectory *directory = reinterpret_cast<struct CodeDirectory *>(blob + begin);
1023
1024 uint8_t (*hashes)[20] = reinterpret_cast<uint8_t (*)[20]>(blob + begin + Swap(directory->hashOffset));
1025 uint32_t pages = Swap(directory->nCodeSlots);
1026
1027 if (pages != 1)
1028 for (size_t i = 0; i != pages - 1; ++i)
1029 sha1(hashes[i], top + 0x1000 * i, 0x1000);
1030 if (pages != 0)
1031 sha1(hashes[pages - 1], top + 0x1000 * (pages - 1), ((data - 1) % 0x1000) + 1);
1032 }
1033 }
1034
1035 if (flag_S) {
1036 _assert(signature != NULL);
1037
1038 uint32_t data = mach_header.Swap(signature->dataoff);
1039 uint32_t size = mach_header.Swap(signature->datasize);
1040
1041 uint8_t *top = reinterpret_cast<uint8_t *>(mach_header.GetBase());
1042 uint8_t *blob = top + data;
1043 struct SuperBlob *super = reinterpret_cast<struct SuperBlob *>(blob);
1044 super->blob.magic = Swap(CSMAGIC_EMBEDDED_SIGNATURE);
1045
1046 uint32_t count = xmld == NULL ? 2 : 3;
1047 uint32_t offset = sizeof(struct SuperBlob) + count * sizeof(struct BlobIndex);
1048
1049 super->index[0].type = Swap(CSSLOT_CODEDIRECTORY);
1050 super->index[0].offset = Swap(offset);
1051
1052 uint32_t begin = offset;
1053 struct CodeDirectory *directory = reinterpret_cast<struct CodeDirectory *>(blob + begin);
1054 offset += sizeof(struct CodeDirectory);
1055
1056 directory->blob.magic = Swap(CSMAGIC_CODEDIRECTORY);
1057 directory->version = Swap(uint32_t(0x00020001));
1058 directory->flags = Swap(uint32_t(0));
1059 directory->codeLimit = Swap(data);
1060 directory->hashSize = 0x14;
1061 directory->hashType = 0x01;
1062 directory->spare1 = 0x00;
1063 directory->pageSize = 0x0c;
1064 directory->spare2 = Swap(uint32_t(0));
1065
1066 directory->identOffset = Swap(offset - begin);
1067 strcpy(reinterpret_cast<char *>(blob + offset), base);
1068 offset += strlen(base) + 1;
1069
1070 uint32_t special = xmld == NULL ? CSSLOT_REQUIREMENTS : CSSLOT_ENTITLEMENTS;
1071 directory->nSpecialSlots = Swap(special);
1072
1073 uint8_t (*hashes)[20] = reinterpret_cast<uint8_t (*)[20]>(blob + offset);
1074 memset(hashes, 0, sizeof(*hashes) * special);
1075
1076 offset += sizeof(*hashes) * special;
1077 hashes += special;
1078
1079 uint32_t pages = (data + 0x1000 - 1) / 0x1000;
1080 directory->nCodeSlots = Swap(pages);
1081
1082 if (pages != 1)
1083 for (size_t i = 0; i != pages - 1; ++i)
1084 sha1(hashes[i], top + 0x1000 * i, 0x1000);
1085 if (pages != 0)
1086 sha1(hashes[pages - 1], top + 0x1000 * (pages - 1), ((data - 1) % 0x1000) + 1);
1087
1088 directory->hashOffset = Swap(offset - begin);
1089 offset += sizeof(*hashes) * pages;
1090 directory->blob.length = Swap(offset - begin);
1091
1092 super->index[1].type = Swap(CSSLOT_REQUIREMENTS);
1093 super->index[1].offset = Swap(offset);
1094
1095 memcpy(blob + offset, "\xfa\xde\x0c\x01\x00\x00\x00\x0c\x00\x00\x00\x00", 0xc);
1096 offset += 0xc;
1097
1098 if (xmld != NULL) {
1099 super->index[2].type = Swap(CSSLOT_ENTITLEMENTS);
1100 super->index[2].offset = Swap(offset);
1101
1102 uint32_t begin = offset;
1103 struct Blob *entitlements = reinterpret_cast<struct Blob *>(blob + begin);
1104 offset += sizeof(struct Blob);
1105
1106 memcpy(blob + offset, xmld, xmls);
1107 offset += xmls;
1108
1109 entitlements->magic = Swap(CSMAGIC_ENTITLEMENTS);
1110 entitlements->length = Swap(offset - begin);
1111 }
1112
1113 for (size_t index(0); index != count; ++index) {
1114 uint32_t type = Swap(super->index[index].type);
1115 if (type != 0 && type <= special) {
1116 uint32_t offset = Swap(super->index[index].offset);
1117 struct Blob *local = (struct Blob *) (blob + offset);
1118 sha1((uint8_t *) (hashes - type), (uint8_t *) local, Swap(local->length));
1119 }
1120 }
1121
1122 super->count = Swap(count);
1123 super->blob.length = Swap(offset);
1124
1125 if (offset > size) {
1126 fprintf(stderr, "offset (%u) > size (%u)\n", offset, size);
1127 _assert(false);
1128 } //else fprintf(stderr, "offset (%zu) <= size (%zu)\n", offset, size);
1129
1130 memset(blob + offset, 0, size - offset);
1131 }
1132 }
1133
1134 if (flag_S) {
1135 uint8_t *top = reinterpret_cast<uint8_t *>(fat_header.GetBase());
1136 size_t size = fat_header.GetSize();
1137
1138 char *copy;
1139 asprintf(&copy, "%s.%s.cp", dir, base);
1140 FILE *file = fopen(copy, "w+");
1141 size_t writ = fwrite(top, 1, size, file);
1142 _assert(writ == size);
1143 fclose(file);
1144
1145 _syscall(unlink(temp));
1146 free(temp);
1147 temp = copy;
1148 }
1149
1150 if (temp != NULL) {
1151 struct stat info;
1152 _syscall(stat(path, &info));
1153 _syscall(chown(temp, info.st_uid, info.st_gid));
1154 _syscall(chmod(temp, info.st_mode));
1155 _syscall(unlink(path));
1156 _syscall(rename(temp, path));
1157 free(temp);
1158 }
1159
1160 free(dir);
1161 ++filei;
1162 } catch (const char *) {
1163 ++filee;
1164 ++filei;
1165 }
1166
1167 return filee;
1168 }