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