]> git.saurik.com Git - ldid.git/blame - ldid.cpp
Added a few _packed modifiers that were missing.
[ldid.git] / ldid.cpp
CommitLineData
ab113d22 1/* ldid - (Mach-O) Link-Loader Identity Editor
e0524446 2 * Copyright (C) 2007-2012 Jay Freeman (saurik)
a362a82f
JF
3*/
4
e0524446
JF
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.
a362a82f 10 *
e0524446
JF
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.
a362a82f 15 *
e0524446
JF
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/* }}} */
a362a82f
JF
20
21#include "minimal/stdlib.h"
b8187ac7 22#include "minimal/string.h"
a362a82f
JF
23#include "minimal/mapping.h"
24
fdb119ef
JF
25#include "sha1.h"
26
a362a82f
JF
27#include <cstring>
28#include <string>
29#include <vector>
30
fdb119ef 31#include <sys/wait.h>
31ad673b
JF
32#include <sys/types.h>
33#include <sys/stat.h>
fdb119ef 34
a362a82f
JF
35struct fat_header {
36 uint32_t magic;
37 uint32_t nfat_arch;
c05d9758 38} _packed;
a362a82f
JF
39
40#define FAT_MAGIC 0xcafebabe
41#define FAT_CIGAM 0xbebafeca
42
43struct fat_arch {
44 uint32_t cputype;
45 uint32_t cpusubtype;
46 uint32_t offset;
47 uint32_t size;
48 uint32_t align;
c05d9758 49} _packed;
a362a82f
JF
50
51struct mach_header {
52 uint32_t magic;
53 uint32_t cputype;
04802ab1 54 uint32_t cpusubtype;
a362a82f
JF
55 uint32_t filetype;
56 uint32_t ncmds;
57 uint32_t sizeofcmds;
58 uint32_t flags;
c05d9758 59} _packed;
a362a82f 60
fdb119ef 61#define MH_MAGIC 0xfeedface
a362a82f
JF
62#define MH_CIGAM 0xcefaedfe
63
3cbc6463
JF
64#define MH_MAGIC_64 0xfeedfacf
65#define MH_CIGAM_64 0xcffaedfe
66
82813bde
JF
67#define MH_DYLDLINK 0x4
68
efd6cd4a
JF
69#define MH_EXECUTE 0x2
70#define MH_DYLIB 0x6
71#define MH_BUNDLE 0x8
72#define MH_DYLIB_STUB 0x9
a362a82f
JF
73
74struct load_command {
75 uint32_t cmd;
76 uint32_t cmdsize;
c05d9758 77} _packed;
a362a82f 78
4a57e66c
JF
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)
289ccbbc 86#define LC_SEGMENT_64 uint32_t(0x19)
4a57e66c
JF
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)
a362a82f
JF
93
94struct dylib {
95 uint32_t name;
96 uint32_t timestamp;
97 uint32_t current_version;
98 uint32_t compatibility_version;
c05d9758 99} _packed;
a362a82f
JF
100
101struct dylib_command {
102 uint32_t cmd;
103 uint32_t cmdsize;
104 struct dylib dylib;
c05d9758 105} _packed;
a362a82f
JF
106
107struct uuid_command {
108 uint32_t cmd;
109 uint32_t cmdsize;
110 uint8_t uuid[16];
c05d9758 111} _packed;
a362a82f 112
20e7eb29
JF
113struct 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
4a57e66c
JF
122struct 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
137struct 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
160struct dylib_table_of_contents {
161 uint32_t symbol_index;
162 uint32_t module_index;
163} _packed;
164
165struct 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
181struct dylib_reference {
182 uint32_t isym:24;
183 uint32_t flags:8;
184} _packed;
185
186struct 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
195struct 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
6e83315b
JF
207struct 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;
429e34a5 219} _packed;
6e83315b 220
289ccbbc
JF
221struct 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;
429e34a5 233} _packed;
289ccbbc 234
6e83315b
JF
235struct 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;
429e34a5 247} _packed;
6e83315b 248
289ccbbc
JF
249struct 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;
429e34a5 261} _packed;
289ccbbc 262
fdb119ef
JF
263struct linkedit_data_command {
264 uint32_t cmd;
265 uint32_t cmdsize;
266 uint32_t dataoff;
267 uint32_t datasize;
c05d9758 268} _packed;
fdb119ef
JF
269
270uint16_t Swap_(uint16_t value) {
271 return
272 ((value >> 8) & 0x00ff) |
273 ((value << 8) & 0xff00);
274}
275
276uint32_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
284int16_t Swap_(int16_t value) {
285 return Swap_(static_cast<uint16_t>(value));
286}
287
288int32_t Swap_(int32_t value) {
289 return Swap_(static_cast<uint32_t>(value));
290}
291
5525a5a7
JF
292bool little_(true);
293
fdb119ef 294uint16_t Swap(uint16_t value) {
5525a5a7 295 return little_ ? Swap_(value) : value;
fdb119ef
JF
296}
297
298uint32_t Swap(uint32_t value) {
5525a5a7 299 return little_ ? Swap_(value) : value;
fdb119ef
JF
300}
301
302int16_t Swap(int16_t value) {
303 return Swap(static_cast<uint16_t>(value));
304}
305
306int32_t Swap(int32_t value) {
307 return Swap(static_cast<uint32_t>(value));
308}
309
6e83315b
JF
310template <typename Target_>
311class Pointer;
312
0a033524 313class Data {
a362a82f
JF
314 private:
315 void *base_;
316 size_t size_;
3cbc6463 317
0a033524 318 protected:
a362a82f
JF
319 bool swapped_;
320
321 public:
0a033524
JF
322 Data(void *base, size_t size) :
323 base_(base),
324 size_(size),
325 swapped_(false)
326 {
327 }
328
fdb119ef
JF
329 uint16_t Swap(uint16_t value) const {
330 return swapped_ ? Swap_(value) : value;
a362a82f
JF
331 }
332
fdb119ef
JF
333 uint32_t Swap(uint32_t value) const {
334 return swapped_ ? Swap_(value) : value;
a362a82f
JF
335 }
336
fdb119ef
JF
337 int16_t Swap(int16_t value) const {
338 return Swap(static_cast<uint16_t>(value));
a362a82f
JF
339 }
340
fdb119ef
JF
341 int32_t Swap(int32_t value) const {
342 return Swap(static_cast<uint32_t>(value));
a362a82f
JF
343 }
344
0a033524
JF
345 void *GetBase() const {
346 return base_;
347 }
a362a82f 348
0a033524
JF
349 size_t GetSize() const {
350 return size_;
351 }
352};
a362a82f 353
0a033524
JF
354class 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;
a362a82f 368
3cbc6463
JF
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;
a362a82f
JF
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
afbb7c8e
JF
398 struct mach_header *operator ->() const {
399 return mach_header_;
400 }
401
04802ab1
JF
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
0a033524 410 std::vector<struct load_command *> GetLoadCommands() const {
a362a82f
JF
411 std::vector<struct load_command *> load_commands;
412
3cbc6463 413 struct load_command *load_command = load_command_;
a362a82f
JF
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 }
6e83315b 421
6f340f51 422 std::vector<segment_command *> GetSegments(const char *segment_name) const {
6e83315b
JF
423 std::vector<struct segment_command *> segment_commands;
424
289ccbbc 425 _foreach (load_command, GetLoadCommands()) {
0a033524
JF
426 if (Swap(load_command->cmd) == LC_SEGMENT) {
427 segment_command *segment_command = reinterpret_cast<struct segment_command *>(load_command);
6e83315b
JF
428 if (strncmp(segment_command->segname, segment_name, 16) == 0)
429 segment_commands.push_back(segment_command);
430 }
289ccbbc
JF
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 }
6e83315b
JF
446
447 return segment_commands;
448 }
449
6f340f51 450 std::vector<section *> GetSections(const char *segment_name, const char *section_name) const {
6e83315b
JF
451 std::vector<section *> sections;
452
453 _foreach (segment, GetSegments(segment_name)) {
0a033524 454 section *section = (struct section *) (segment + 1);
6e83315b
JF
455
456 uint32_t sect;
0a033524 457 for (sect = 0; sect != Swap(segment->nsects); ++sect) {
6e83315b
JF
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_>
0a033524 468 Pointer<Target_> GetPointer(uint32_t address, const char *segment_name = NULL) const {
6e83315b
JF
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
289ccbbc
JF
504class 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
0a033524
JF
522class FatHeader :
523 public Data
524{
525 private:
526 fat_header *fat_header_;
289ccbbc 527 std::vector<FatMachHeader> mach_headers_;
0a033524
JF
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;
289ccbbc 540 mach_headers_.push_back(FatMachHeader(base, size, NULL));
0a033524
JF
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);
289ccbbc 548 mach_headers_.push_back(FatMachHeader((uint8_t *) base + arch_offset, arch_size, fat_arch));
0a033524
JF
549 ++fat_arch;
550 }
551 }
552 }
553
289ccbbc 554 std::vector<FatMachHeader> &GetMachHeaders() {
0a033524
JF
555 return mach_headers_;
556 }
20e7eb29
JF
557
558 bool IsFat() const {
559 return fat_header_ != NULL;
560 }
6b38c173
JF
561
562 struct fat_header *operator ->() const {
563 return fat_header_;
564 }
0a033524
JF
565};
566
80fb9fad 567FatHeader Map(const char *path, bool ro = false) {
0a033524 568 size_t size;
80fb9fad 569 void *base(map(path, 0, _not(size_t), &size, ro));
0a033524
JF
570 return FatHeader(base, size);
571}
572
6e83315b
JF
573template <typename Target_>
574class Pointer {
575 private:
0a033524 576 const MachHeader *framework_;
6e83315b
JF
577 const Target_ *pointer_;
578
579 public:
0a033524 580 Pointer(const MachHeader *framework = NULL, const Target_ *pointer = NULL) :
6e83315b
JF
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 }
a362a82f
JF
603};
604
645f8f12
JF
605#define CSMAGIC_CODEDIRECTORY uint32_t(0xfade0c02)
606#define CSMAGIC_EMBEDDED_SIGNATURE uint32_t(0xfade0cc0)
607#define CSMAGIC_ENTITLEMENTS uint32_t(0xfade7171)
c05d9758 608
645f8f12
JF
609#define CSSLOT_CODEDIRECTORY uint32_t(0)
610#define CSSLOT_REQUIREMENTS uint32_t(2)
611#define CSSLOT_ENTITLEMENTS uint32_t(5)
fdb119ef
JF
612
613struct BlobIndex {
614 uint32_t type;
615 uint32_t offset;
c05d9758 616} _packed;
fdb119ef 617
c05d9758 618struct Blob {
fdb119ef
JF
619 uint32_t magic;
620 uint32_t length;
c05d9758
JF
621} _packed;
622
623struct SuperBlob {
624 struct Blob blob;
fdb119ef
JF
625 uint32_t count;
626 struct BlobIndex index[];
c05d9758 627} _packed;
fdb119ef
JF
628
629struct CodeDirectory {
c05d9758 630 struct Blob blob;
fdb119ef
JF
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;
c05d9758 643} _packed;
fdb119ef 644
a362a82f
JF
645extern "C" uint32_t hash(uint8_t *k, uint32_t length, uint32_t initval);
646
fdb119ef
JF
647void 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
0a033524
JF
654struct 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
a362a82f 667int main(int argc, const char *argv[]) {
5525a5a7
JF
668 union {
669 uint16_t word;
670 uint8_t byte[2];
671 } endian = {1};
672
673 little_ = endian.byte[0];
674
a362a82f 675 bool flag_R(false);
20e7eb29
JF
676 bool flag_r(false);
677
a362a82f
JF
678 bool flag_t(false);
679 bool flag_p(false);
680 bool flag_u(false);
9c83be90 681 bool flag_e(false);
a362a82f
JF
682
683 bool flag_T(false);
20c5f1e8 684
fdb119ef 685 bool flag_S(false);
20c5f1e8 686 bool flag_s(false);
a362a82f
JF
687
688 bool timeh(false);
689 uint32_t timev(0);
690
c05d9758
JF
691 const void *xmld(NULL);
692 size_t xmls(0);
693
6e83315b
JF
694 uintptr_t noffset(_not(uintptr_t));
695 uintptr_t woffset(_not(uintptr_t));
696
a362a82f
JF
697 std::vector<std::string> files;
698
a960f392
JF
699 if (argc == 1) {
700 fprintf(stderr, "usage: %s -S[entitlements.xml] <binary>\n", argv[0]);
9c83be90 701 fprintf(stderr, " %s -e MobileSafari\n", argv[0]);
a960f392
JF
702 fprintf(stderr, " %s -S cat\n", argv[0]);
703 fprintf(stderr, " %s -Stfp.xml gdb\n", argv[0]);
704 exit(0);
705 }
706
a362a82f
JF
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;
20e7eb29
JF
712 case 'r': flag_r = true; break;
713
a362a82f
JF
714 case 't': flag_t = true; break;
715 case 'u': flag_u = true; break;
716 case 'p': flag_p = true; break;
9c83be90 717 case 'e': flag_e = true; break;
c05d9758 718
20c5f1e8
JF
719 case 's':
720 _assert(!flag_S);
721 flag_s = true;
722 break;
723
c05d9758 724 case 'S':
20c5f1e8 725 _assert(!flag_s);
c05d9758
JF
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;
a362a82f
JF
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
6e83315b
JF
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
a362a82f
JF
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 {
0a033524 767 const char *path(file.c_str());
fdb119ef
JF
768 const char *base = strrchr(path, '/');
769 char *temp(NULL), *dir;
770
771 if (base != NULL)
b8187ac7 772 dir = strndup_(path, base++ - path + 1);
fdb119ef
JF
773 else {
774 dir = strdup("");
775 base = path;
776 }
777
20e7eb29 778 if (flag_r) {
289ccbbc 779 uint32_t clip(0); {
20e7eb29
JF
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
289ccbbc 784 uint32_t size(_not(uint32_t)); {
20e7eb29
JF
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);
289ccbbc 789 memset(reinterpret_cast<uint8_t *>(mach_header.GetBase()) + mach_header.Swap(signature->dataoff), 0, mach_header.Swap(signature->datasize));
20e7eb29
JF
790 memset(signature, 0, sizeof(struct linkedit_data_command));
791
289ccbbc
JF
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)));
20e7eb29
JF
794 } break;
795
796 case LC_SYMTAB: {
797 struct symtab_command *symtab = reinterpret_cast<struct symtab_command *>(load_command);
289ccbbc 798 size = mach_header.Swap(symtab->stroff) + mach_header.Swap(symtab->strsize);
20e7eb29
JF
799 } break;
800 }
801 }
289ccbbc 802 }
20e7eb29 803
289ccbbc 804 _assert(size != _not(uint32_t));
20e7eb29 805
289ccbbc
JF
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);
20e7eb29
JF
824 }
825 }
826 }
827
289ccbbc
JF
828 _assert(clip != 0);
829 _syscall(truncate(path, clip));
20e7eb29
JF
830 }
831
fdb119ef
JF
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
0a033524
JF
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();
afbb7c8e 856 }
afbb7c8e 857
0a033524 858 allocations.push_back(CodesignAllocation(mach_header.GetCPUType(), mach_header.GetCPUSubtype(), size));
afbb7c8e 859 }
fdb119ef
JF
860 }
861
862 pid_t pid = fork();
863 _syscall(pid);
864 if (pid == 0) {
0a033524
JF
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
6f340f51 910 asprintf(&arg, "%zu", alloc);
0a033524
JF
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]);
fdb119ef
JF
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
0a033524
JF
936 if (flag_p)
937 printf("path%zu='%s'\n", filei, file.c_str());
938
80fb9fad 939 FatHeader fat_header(Map(temp == NULL ? path : temp, !(flag_R | flag_T | flag_s | flag_S)));
fdb119ef 940 struct linkedit_data_command *signature(NULL);
a362a82f 941
0a033524
JF
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 }
6e83315b 950
0a033524
JF
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));
a362a82f 974
0a033524
JF
975 if (flag_t)
976 printf("time%zu=0x%.8x\n", filei, mach_header.Swap(dylib_command->dylib.timestamp));
a362a82f 977
0a033524
JF
978 if (flag_T) {
979 uint32_t timed;
a362a82f 980
0a033524
JF
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 }
a362a82f 987
0a033524
JF
988 dylib_command->dylib.timestamp = mach_header.Swap(timed);
989 }
a362a82f
JF
990 }
991 }
a362a82f 992
0a033524
JF
993 if (flag_e) {
994 _assert(signature != NULL);
9c83be90 995
0a033524 996 uint32_t data = mach_header.Swap(signature->dataoff);
9c83be90 997
0a033524
JF
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);
9c83be90 1001
0a033524
JF
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 }
9c83be90 1009
0a033524
JF
1010 if (flag_s) {
1011 _assert(signature != NULL);
20c5f1e8 1012
0a033524 1013 uint32_t data = mach_header.Swap(signature->dataoff);
20c5f1e8 1014
0a033524
JF
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);
20c5f1e8 1018
0a033524
JF
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);
20c5f1e8 1023
0a033524
JF
1024 uint8_t (*hashes)[20] = reinterpret_cast<uint8_t (*)[20]>(blob + begin + Swap(directory->hashOffset));
1025 uint32_t pages = Swap(directory->nCodeSlots);
20c5f1e8 1026
0a033524
JF
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 }
20c5f1e8 1034
0a033524
JF
1035 if (flag_S) {
1036 _assert(signature != NULL);
fdb119ef 1037
0a033524
JF
1038 uint32_t data = mach_header.Swap(signature->dataoff);
1039 uint32_t size = mach_header.Swap(signature->datasize);
fdb119ef 1040
0a033524
JF
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);
fdb119ef 1045
0a033524
JF
1046 uint32_t count = xmld == NULL ? 2 : 3;
1047 uint32_t offset = sizeof(struct SuperBlob) + count * sizeof(struct BlobIndex);
fdb119ef 1048
0a033524
JF
1049 super->index[0].type = Swap(CSSLOT_CODEDIRECTORY);
1050 super->index[0].offset = Swap(offset);
fdb119ef 1051
0a033524
JF
1052 uint32_t begin = offset;
1053 struct CodeDirectory *directory = reinterpret_cast<struct CodeDirectory *>(blob + begin);
1054 offset += sizeof(struct CodeDirectory);
fdb119ef 1055
0a033524
JF
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));
fdb119ef 1065
0a033524
JF
1066 directory->identOffset = Swap(offset - begin);
1067 strcpy(reinterpret_cast<char *>(blob + offset), base);
1068 offset += strlen(base) + 1;
fdb119ef 1069
0a033524
JF
1070 uint32_t special = xmld == NULL ? CSSLOT_REQUIREMENTS : CSSLOT_ENTITLEMENTS;
1071 directory->nSpecialSlots = Swap(special);
20c5f1e8 1072
0a033524
JF
1073 uint8_t (*hashes)[20] = reinterpret_cast<uint8_t (*)[20]>(blob + offset);
1074 memset(hashes, 0, sizeof(*hashes) * special);
20c5f1e8 1075
0a033524
JF
1076 offset += sizeof(*hashes) * special;
1077 hashes += special;
fdb119ef 1078
0a033524
JF
1079 uint32_t pages = (data + 0x1000 - 1) / 0x1000;
1080 directory->nCodeSlots = Swap(pages);
fdb119ef 1081
0a033524
JF
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);
fdb119ef 1087
0a033524
JF
1088 directory->hashOffset = Swap(offset - begin);
1089 offset += sizeof(*hashes) * pages;
1090 directory->blob.length = Swap(offset - begin);
fdb119ef 1091
0a033524
JF
1092 super->index[1].type = Swap(CSSLOT_REQUIREMENTS);
1093 super->index[1].offset = Swap(offset);
afbb7c8e 1094
0a033524
JF
1095 memcpy(blob + offset, "\xfa\xde\x0c\x01\x00\x00\x00\x0c\x00\x00\x00\x00", 0xc);
1096 offset += 0xc;
afbb7c8e 1097
0a033524
JF
1098 if (xmld != NULL) {
1099 super->index[2].type = Swap(CSSLOT_ENTITLEMENTS);
1100 super->index[2].offset = Swap(offset);
c05d9758 1101
0a033524
JF
1102 uint32_t begin = offset;
1103 struct Blob *entitlements = reinterpret_cast<struct Blob *>(blob + begin);
1104 offset += sizeof(struct Blob);
c05d9758 1105
0a033524
JF
1106 memcpy(blob + offset, xmld, xmls);
1107 offset += xmls;
c05d9758 1108
0a033524
JF
1109 entitlements->magic = Swap(CSMAGIC_ENTITLEMENTS);
1110 entitlements->length = Swap(offset - begin);
1111 }
c05d9758 1112
0a033524
JF
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 }
20c5f1e8 1120 }
20c5f1e8 1121
0a033524
JF
1122 super->count = Swap(count);
1123 super->blob.length = Swap(offset);
c05d9758 1124
0a033524
JF
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);
fdb119ef 1129
0a033524
JF
1130 memset(blob + offset, 0, size - offset);
1131 }
fdb119ef
JF
1132 }
1133
122621c5 1134 if (flag_S) {
0a033524
JF
1135 uint8_t *top = reinterpret_cast<uint8_t *>(fat_header.GetBase());
1136 size_t size = fat_header.GetSize();
122621c5
JF
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
0a033524 1150 if (temp != NULL) {
31ad673b
JF
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));
fdb119ef
JF
1155 _syscall(unlink(path));
1156 _syscall(rename(temp, path));
1157 free(temp);
1158 }
1159
1160 free(dir);
a362a82f
JF
1161 ++filei;
1162 } catch (const char *) {
1163 ++filee;
1164 ++filei;
1165 }
1166
1167 return filee;
1168}