1 /* p_mach.cpp -- pack Mach Object executable
2
3 This file is part of the UPX executable compressor.
4
5 Copyright (C) 2004-2020 John Reiser
6 All Rights Reserved.
7
8 UPX and the UCL library are free software; you can redistribute them
9 and/or modify them under the terms of the GNU General Public License as
10 published by the Free Software Foundation; either version 2 of
11 the License, or (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; see the file COPYING.
20 If not, write to the Free Software Foundation, Inc.,
21 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22
23 John Reiser
24 <jreiser@users.sourceforge.net>
25 */
26
27
28 #include "conf.h"
29
30 #include "file.h"
31 #include "filter.h"
32 #include "linker.h"
33 #include "packer.h"
34 #include "p_mach.h"
35 #include "ui.h"
36
37 static const
38 #include "stub/i386-darwin.macho-entry.h"
39 static const
40 #include "stub/i386-darwin.macho-fold.h"
41 static const
42 #include "stub/i386-darwin.macho-upxmain.h"
43 static const
44 #include "stub/i386-darwin.dylib-entry.h"
45
46 static const
47 #include "stub/amd64-darwin.macho-entry.h"
48 static const
49 #include "stub/amd64-darwin.macho-fold.h"
50 static const
51 #include "stub/amd64-darwin.macho-upxmain.h"
52 static const
53 #include "stub/amd64-darwin.dylib-entry.h"
54
55 static const
56 #include "stub/arm.v5a-darwin.macho-entry.h"
57 static const
58 #include "stub/arm.v5a-darwin.macho-fold.h"
59
60 static const
61 #include "stub/arm64-darwin.macho-entry.h"
62 static const
63 #include "stub/arm64-darwin.macho-fold.h"
64
65 static const
66 #include "stub/powerpc-darwin.macho-entry.h"
67 static const
68 #include "stub/powerpc-darwin.macho-fold.h"
69 static const
70 #include "stub/powerpc-darwin.macho-upxmain.h"
71 static const
72 #include "stub/powerpc-darwin.dylib-entry.h"
73
74 static const
75 #include "stub/powerpc64le-darwin.macho-entry.h"
76 static const
77 #include "stub/powerpc64le-darwin.macho-fold.h"
78 static const
79 #include "stub/powerpc64le-darwin.dylib-entry.h"
80
81 // Packing a Darwin (Mach-o) Mac OS X dylib (dynamic shared library)
82 // is restricted. UPX gets control as the -init function, at the very
83 // end of processing by dyld. Relocation, loading of dependent libraries,
84 // etc., already have taken place before decompression. So the Mach-o
85 // headers, the __IMPORT segment, the __LINKEDIT segment, anything
86 // that is modifed by relocation, etc., cannot be compressed.
87 // We simplify arbitrarily by compressing only the __TEXT segment,
88 // which must be the first segment.
89
90 static const unsigned lc_segment[2] = {
91 0x1, 0x19
92 //Mach_command::LC_SEGMENT,
93 //Mach_command::LC_SEGMENT_64
94 };
95
96 #if 0 // NOT USED
97 static const unsigned lc_routines[2] = {
98 0x11, 0x1a
99 //Mach_command::LC_ROUTINES,
100 //Mach_command::LC_ROUTINES_64
101 };
102 #endif
103
104 template <class T>
PackMachBase(InputFile * f,unsigned cputype,unsigned filetype,unsigned flavor,unsigned count,unsigned size)105 PackMachBase<T>::PackMachBase(InputFile *f, unsigned cputype, unsigned filetype,
106 unsigned flavor, unsigned count, unsigned size) :
107 super(f), my_cputype(cputype), my_filetype(filetype), my_thread_flavor(flavor),
108 my_thread_state_word_count(count), my_thread_command_size(size),
109 n_segment(0), rawmseg(NULL), msegcmd(NULL), o__mod_init_func(0),
110 prev_mod_init_func(0), pagezero_vmsize(0)
111 {
112 MachClass::compileTimeAssertions();
113 bele = N_BELE_CTP::getRTP((const BeLePolicy*) NULL);
114 memset(&cmdUUID, 0, sizeof(cmdUUID));
115 memset(&cmdSRCVER, 0, sizeof(cmdSRCVER));
116 memset(&cmdVERMIN, 0, sizeof(cmdVERMIN));
117 memset(&linkitem, 0, sizeof(linkitem));
118 }
119
120 template <class T>
~PackMachBase()121 PackMachBase<T>::~PackMachBase()
122 {
123 delete [] rawmseg;
124 delete [] msegcmd;
125 }
126
PackDylibI386(InputFile * f)127 PackDylibI386::PackDylibI386(InputFile *f) : super(f)
128 {
129 my_filetype = Mach_header::MH_DYLIB;
130 }
131
PackDylibAMD64(InputFile * f)132 PackDylibAMD64::PackDylibAMD64(InputFile *f) : super(f)
133 {
134 my_filetype = Mach_header::MH_DYLIB;
135 }
136
PackDylibPPC32(InputFile * f)137 PackDylibPPC32::PackDylibPPC32(InputFile *f) : super(f)
138 {
139 my_filetype = Mach_header::MH_DYLIB;
140 }
PackDylibPPC64LE(InputFile * f)141 PackDylibPPC64LE::PackDylibPPC64LE(InputFile *f) : super(f)
142 {
143 my_filetype = Mach_header::MH_DYLIB;
144 }
145
146 template <class T>
getCompressionMethods(int method,int level) const147 const int *PackMachBase<T>::getCompressionMethods(int method, int level) const
148 {
149 // There really is no LE bias.
150 return Packer::getDefaultCompressionMethods_le32(method, level);
151 }
152
getCompressionMethods(int method,int level) const153 const int *PackMachARMEL::getCompressionMethods(int method, int level) const
154 {
155 // Un-aligned fetch does not work on 32-bit ARM, so use 8-bit methods
156 return Packer::getDefaultCompressionMethods_8(method, level);
157 }
158
PackMachPPC32(InputFile * f)159 PackMachPPC32::PackMachPPC32(InputFile *f) : super(f, Mach_header::CPU_TYPE_POWERPC,
160 Mach_header::MH_EXECUTE, Mach_thread_command::PPC_THREAD_STATE,
161 sizeof(Mach_ppc_thread_state)>>2, sizeof(threado))
162 { }
163
PackMachPPC64LE(InputFile * f)164 PackMachPPC64LE::PackMachPPC64LE(InputFile *f) : super(f, Mach_header::CPU_TYPE_POWERPC64LE,
165 Mach_header::MH_EXECUTE, Mach_thread_command::PPC_THREAD_STATE64,
166 sizeof(Mach_ppcle_thread_state64)>>2, sizeof(threado))
167 { }
168
getFilters() const169 const int *PackMachPPC32::getFilters() const
170 {
171 static const int filters[] = { 0xd0, FT_END };
172 return filters;
173 }
174
getFilters() const175 const int *PackMachPPC64LE::getFilters() const
176 {
177 static const int filters[] = { 0xd0, FT_END };
178 return filters;
179 }
180
PackMachI386(InputFile * f)181 PackMachI386::PackMachI386(InputFile *f) : super(f, Mach_header::CPU_TYPE_I386,
182 Mach_header::MH_EXECUTE, (unsigned)Mach_thread_command::x86_THREAD_STATE32,
183 sizeof(Mach_i386_thread_state)>>2, sizeof(threado))
184 { }
185
getFilters() const186 int const *PackMachI386::getFilters() const
187 {
188 static const int filters[] = { 0x49, FT_END };
189 return filters;
190 }
191
PackMachAMD64(InputFile * f)192 PackMachAMD64::PackMachAMD64(InputFile *f) : super(f, Mach_header::CPU_TYPE_X86_64,
193 Mach_header::MH_EXECUTE, (unsigned)Mach_thread_command::x86_THREAD_STATE64,
194 sizeof(Mach_AMD64_thread_state)>>2, sizeof(threado))
195 { }
196
getFilters() const197 int const *PackMachAMD64::getFilters() const
198 {
199 static const int filters[] = { 0x49, FT_END };
200 return filters;
201 }
202
PackMachARMEL(InputFile * f)203 PackMachARMEL::PackMachARMEL(InputFile *f) : super(f, Mach_header::CPU_TYPE_ARM,
204 Mach_header::MH_EXECUTE, (unsigned)Mach_thread_command::ARM_THREAD_STATE,
205 sizeof(Mach_ARM_thread_state)>>2, sizeof(threado))
206 { }
207
PackMachARM64EL(InputFile * f)208 PackMachARM64EL::PackMachARM64EL(InputFile *f) : super(f, Mach_header::CPU_TYPE_ARM64,
209 Mach_header::MH_EXECUTE, (unsigned)Mach_thread_command::ARM_THREAD_STATE,
210 sizeof(Mach_ARM64_thread_state)>>2, sizeof(threado))
211 { }
212
getFilters() const213 int const *PackMachARMEL::getFilters() const
214 {
215 static const int filters[] = { 0x50, FT_END };
216 return filters;
217 }
218
getFilters() const219 int const *PackMachARM64EL::getFilters() const
220 {
221 static const int filters[] = { 0x52, FT_END };
222 return filters;
223 }
224
newLinker() const225 Linker *PackMachPPC32::newLinker() const
226 {
227 return new ElfLinkerPpc32;
228 }
229
newLinker() const230 Linker *PackMachPPC64LE::newLinker() const
231 {
232 return new ElfLinkerPpc64le;
233 }
234
newLinker() const235 Linker *PackMachI386::newLinker() const
236 {
237 return new ElfLinkerX86;
238 }
239
newLinker() const240 Linker *PackMachAMD64::newLinker() const
241 {
242 return new ElfLinkerAMD64;
243 }
244
newLinker() const245 Linker *PackMachARMEL::newLinker() const
246 {
247 return new ElfLinkerArmLE;
248 }
249
newLinker() const250 Linker *PackMachARM64EL::newLinker() const
251 {
252 return new ElfLinkerArm64LE;
253 }
254
255 template <class T>
256 void
addStubEntrySections(Filter const *)257 PackMachBase<T>::addStubEntrySections(Filter const *)
258 {
259 addLoader("MACOS000", NULL);
260 //addLoader(getDecompressorSections(), NULL);
261 addLoader(
262 ( M_IS_NRV2E(ph.method) ? "NRV_HEAD,NRV2E,NRV_TAIL"
263 : M_IS_NRV2D(ph.method) ? "NRV_HEAD,NRV2D,NRV_TAIL"
264 : M_IS_NRV2B(ph.method) ? "NRV_HEAD,NRV2B,NRV_TAIL"
265 : M_IS_LZMA(ph.method) ? "LZMA_ELF00,LZMA_DEC20,LZMA_DEC30"
266 : NULL), NULL);
267 if (hasLoaderSection("CFLUSH"))
268 addLoader("CFLUSH");
269 addLoader("ELFMAINY,IDENTSTR,+40,ELFMAINZ,FOLDEXEC", NULL);
270 }
271
addStubEntrySections(Filter const *)272 void PackMachI386::addStubEntrySections(Filter const * /*ft*/)
273 {
274 addLoader("MACHMAINX", NULL); // different for MY_DYLIB vs MH_EXECUTE
275 if (my_filetype==Mach_header::MH_EXECUTE) {
276 addLoader("MACH_UNC", NULL);
277 }
278 //addLoader(getDecompressorSections(), NULL);
279 addLoader(
280 ( M_IS_NRV2E(ph.method) ? "NRV_HEAD,NRV2E,NRV_TAIL"
281 : M_IS_NRV2D(ph.method) ? "NRV_HEAD,NRV2D,NRV_TAIL"
282 : M_IS_NRV2B(ph.method) ? "NRV_HEAD,NRV2B,NRV_TAIL"
283 : M_IS_LZMA(ph.method) ? "LZMA_ELF00,LZMA_DEC20,LZMA_DEC30"
284 : NULL), NULL);
285 if (hasLoaderSection("CFLUSH"))
286 addLoader("CFLUSH");
287 addLoader("MACHMAINY,IDENTSTR,+40,MACHMAINZ,FOLDEXEC", NULL);
288 }
289
addStubEntrySections(Filter const *)290 void PackMachAMD64::addStubEntrySections(Filter const * /*ft*/)
291 {
292 addLoader("MACHMAINX", NULL); // different for MY_DYLIB vs MH_EXECUTE
293 if (my_filetype==Mach_header::MH_EXECUTE) {
294 addLoader("MACH_UNC", NULL);
295 }
296 //addLoader(getDecompressorSections(), NULL);
297 addLoader(
298 ( M_IS_NRV2E(ph.method) ? "NRV_HEAD,NRV2E,NRV_TAIL"
299 : M_IS_NRV2D(ph.method) ? "NRV_HEAD,NRV2D,NRV_TAIL"
300 : M_IS_NRV2B(ph.method) ? "NRV_HEAD,NRV2B,NRV_TAIL"
301 : M_IS_LZMA(ph.method) ? "LZMA_ELF00,LZMA_DEC20,LZMA_DEC30"
302 : NULL), NULL);
303 if (hasLoaderSection("CFLUSH"))
304 addLoader("CFLUSH");
305 addLoader("MACHMAINY,IDENTSTR,+40,MACHMAINZ,FOLDEXEC", NULL);
306 }
307
addStubEntrySections(Filter const *)308 void PackMachPPC32::addStubEntrySections(Filter const * /*ft*/)
309 {
310 if (my_filetype!=Mach_header::MH_EXECUTE) {
311 addLoader("MACHMAINX", NULL);
312 }
313 else {
314 addLoader("PPC32BXX", NULL);
315 }
316 addLoader("MACH_UNC", NULL);
317 //addLoader(getDecompressorSections(), NULL);
318 addLoader(
319 ( M_IS_NRV2E(ph.method) ? "NRV_HEAD,NRV2E,NRV_TAIL"
320 : M_IS_NRV2D(ph.method) ? "NRV_HEAD,NRV2D,NRV_TAIL"
321 : M_IS_NRV2B(ph.method) ? "NRV_HEAD,NRV2B,NRV_TAIL"
322 : M_IS_LZMA(ph.method) ? "LZMA_ELF00,LZMA_DEC20,LZMA_DEC30"
323 : NULL), NULL);
324 if (hasLoaderSection("CFLUSH"))
325 addLoader("CFLUSH");
326 addLoader("MACHMAINY,IDENTSTR,+40,MACHMAINZ", NULL);
327 if (my_filetype!=Mach_header::MH_EXECUTE) {
328 addLoader("FOLDEXEC", NULL);
329 }
330 }
331
addStubEntrySections(Filter const *)332 void PackMachARMEL::addStubEntrySections(Filter const * /*ft*/)
333 {
334 addLoader("MACHMAINX", NULL);
335 //addLoader(getDecompressorSections(), NULL);
336 addLoader(
337 ( M_IS_NRV2E(ph.method) ? "NRV_HEAD,NRV2E,NRV_TAIL"
338 : M_IS_NRV2D(ph.method) ? "NRV_HEAD,NRV2D,NRV_TAIL"
339 : M_IS_NRV2B(ph.method) ? "NRV_HEAD,NRV2B,NRV_TAIL"
340 : M_IS_LZMA(ph.method) ? "LZMA_ELF00,LZMA_DEC20,LZMA_DEC30"
341 : NULL), NULL);
342 if (hasLoaderSection("CFLUSH"))
343 addLoader("CFLUSH");
344 addLoader("MACHMAINY,IDENTSTR,+40,MACHMAINZ,FOLDEXEC", NULL);
345 }
346
addStubEntrySections(Filter const *)347 void PackMachARM64EL::addStubEntrySections(Filter const * /*ft*/)
348 {
349 addLoader("MACHMAINX", NULL);
350 //addLoader(getDecompressorSections(), NULL);
351 addLoader(
352 ( M_IS_NRV2E(ph.method) ? "NRV_HEAD,NRV2E,NRV_TAIL"
353 : M_IS_NRV2D(ph.method) ? "NRV_HEAD,NRV2D,NRV_TAIL"
354 : M_IS_NRV2B(ph.method) ? "NRV_HEAD,NRV2B,NRV_TAIL"
355 : M_IS_LZMA(ph.method) ? "LZMA_ELF00,LZMA_DEC20,LZMA_DEC30"
356 : NULL), NULL);
357 if (hasLoaderSection("CFLUSH"))
358 addLoader("CFLUSH");
359 addLoader("MACHMAINY,IDENTSTR,+40,MACHMAINZ,FOLDEXEC", NULL);
360 }
361
362 template <class T>
defineSymbols(Filter const *)363 void PackMachBase<T>::defineSymbols(Filter const *)
364 {
365 // empty
366 }
367
368
369 template <class T>
370 void
buildMachLoader(upx_byte const * const proto,unsigned const szproto,upx_byte const * const fold,unsigned const szfold,Filter const * ft)371 PackMachBase<T>::buildMachLoader(
372 upx_byte const *const proto,
373 unsigned const szproto,
374 upx_byte const *const fold,
375 unsigned const szfold,
376 Filter const *ft
377 )
378 {
379 initLoader(proto, szproto);
380
381 struct b_info h; memset(&h, 0, sizeof(h));
382 unsigned fold_hdrlen = 0;
383 if (0 < szfold) {
384 h.sz_unc = (szfold < fold_hdrlen) ? 0 : (szfold - fold_hdrlen);
385 h.b_method = (unsigned char) ph.method;
386 h.b_ftid = (unsigned char) ph.filter;
387 h.b_cto8 = (unsigned char) ph.filter_cto;
388 }
389 unsigned char const *const uncLoader = fold_hdrlen + fold;
390
391 unsigned char *const cprLoader = New(unsigned char, sizeof(h) + h.sz_unc);
392 if (0 < szfold) {
393 unsigned sz_cpr = 0;
394 int r = upx_compress(uncLoader, h.sz_unc, sizeof(h) + cprLoader, &sz_cpr,
395 NULL, ph.method, 10, NULL, NULL );
396 h.sz_cpr = sz_cpr;
397 if (r != UPX_E_OK || h.sz_cpr >= h.sz_unc)
398 throwInternalError("loader compression failed");
399 }
400 memcpy(cprLoader, &h, sizeof(h));
401
402 // This adds the definition to the "library", to be used later.
403 linker->addSection("FOLDEXEC", cprLoader, sizeof(h) + h.sz_cpr, 0);
404 delete [] cprLoader;
405
406 int const GAP = 128; // must match stub/l_mac_ppc.S
407 int const NO_LAP = 64; // must match stub/src/*darwin*.S
408 segTEXT.vmsize = h.sz_unc - h.sz_cpr + GAP + NO_LAP;
409
410 addStubEntrySections(ft);
411
412 defineSymbols(ft);
413 relocateLoader();
414 }
415
416 template <class T>
417 void
buildLoader(const Filter * ft)418 PackMachBase<T>::buildLoader(const Filter *ft)
419 {
420 buildMachLoader(
421 stub_entry, sz_stub_entry,
422 stub_fold, sz_stub_fold, ft );
423 }
424
425 template <class T>
patchLoader()426 void PackMachBase<T>::patchLoader() { }
427
428 template <class T>
updateLoader(OutputFile *)429 void PackMachBase<T>::updateLoader(OutputFile *) {}
430
431 template <class T>
patchLoaderChecksum()432 void PackMachBase<T>::patchLoaderChecksum()
433 {
434 unsigned char *const ptr = getLoader();
435 l_info *const lp = &linfo;
436 // checksum for loader; also some PackHeader info
437 lp->l_checksum = 0;
438 lp->l_magic = UPX_MAGIC_LE32; // LE32 always
439 set_te16(&lp->l_lsize, (upx_uint16_t) lsize);
440 lp->l_version = (unsigned char) ph.version;
441 lp->l_format = (unsigned char) ph.format;
442 // INFO: lp->l_checksum is currently unused
443 set_te32(&lp->l_checksum, upx_adler32(ptr, lsize));
444 }
445
446 template <class T>
447 int __acc_cdecl_qsort
compare_segment_command(void const * const aa,void const * const bb)448 PackMachBase<T>::compare_segment_command(void const *const aa, void const *const bb)
449 {
450 Mach_segment_command const *const a = (Mach_segment_command const *)aa;
451 Mach_segment_command const *const b = (Mach_segment_command const *)bb;
452 unsigned const lc_seg = lc_segment[sizeof(Addr)>>3];
453 unsigned const xa = a->cmd - lc_seg;
454 unsigned const xb = b->cmd - lc_seg;
455 if (xa < xb) return -1; // LC_SEGMENT first
456 if (xa > xb) return 1;
457 if (0 != xa) return 0; // not LC_SEGMENT
458 // Ascending by .fileoff so that find_SEGMENT_gap works
459 if (a->fileoff < b->fileoff)
460 return -1;
461 if (a->fileoff > b->fileoff)
462 return 1;
463 // Ascending by .vmaddr
464 if (a->vmaddr < b->vmaddr) return -1;
465 if (a->vmaddr > b->vmaddr) return 1;
466 // Descending by .vmsize
467 if (a->vmsize) return -1; // 'a' is first
468 if (b->vmsize) return 1; // 'a' is last
469 // What could remain?
470 return 0;
471 }
472
473 #undef PAGE_MASK
474 #undef PAGE_SIZE
475 #define PAGE_MASK (~0u<<12)
476 #define PAGE_SIZE (0u-PAGE_MASK)
477
478 #undef PAGE_MASK64
479 #undef PAGE_SIZE64
480 #define PAGE_MASK64 (~(upx_uint64_t)0<<16)
481 #define PAGE_SIZE64 ((upx_uint64_t)0-PAGE_MASK64)
482
483 // At 2013-02-03 part of the source for codesign was
484 // http://opensource.apple.com/source/cctools/cctools-836/libstuff/ofile.c
485
486 #undef PAGE_MASK64
487 #undef PAGE_SIZE64
488 #define PAGE_MASK64 (~(upx_uint64_t)0<<12)
489 #define PAGE_SIZE64 ((upx_uint64_t)0-PAGE_MASK64)
490
491 unsigned const blankLINK = 16; // size of our empty __LINK segment
492 // Note: "readelf --segments" ==> "otool -hl" or "otool -hlv" etc. (Xcode on MacOS)
493
494 template <class T>
pack4(OutputFile * fo,Filter & ft)495 void PackMachBase<T>::pack4(OutputFile *fo, Filter &ft) // append PackHeader
496 {
497 // offset of p_info in compressed file
498 overlay_offset = secTEXT.offset + sizeof(linfo);
499 super::pack4(fo, ft);
500
501 if (Mach_header::MH_EXECUTE == my_filetype) {
502 unsigned len = fo->getBytesWritten();
503 char page[~PAGE_MASK]; memset(page, 0, sizeof(page));
504 fo->write(page, ~PAGE_MASK & (0u - len));
505 len += ~PAGE_MASK & (0u - len) ;
506
507 segTEXT.filesize = len;
508 segTEXT.vmsize = len; // FIXME? utilize GAP + NO_LAP + sz_unc - sz_cpr
509 secTEXT.offset = overlay_offset - sizeof(linfo);
510 secTEXT.addr = segTEXT.vmaddr + secTEXT.offset;
511 secTEXT.size = segTEXT.filesize - secTEXT.offset;
512 secXHDR.offset = overlay_offset - sizeof(linfo);
513 if (my_filetype==Mach_header::MH_EXECUTE) {
514 secXHDR.offset -= sizeof(linkitem);
515 }
516 secXHDR.addr += secXHDR.offset;
517 unsigned offLINK = segLINK.fileoff;
518
519
520 segLINK.fileoff = len; // must be in the file
521 segLINK.vmaddr = len + segTEXT.vmaddr;
522 fo->write(page, blankLINK); len += blankLINK;
523 segLINK.vmsize = PAGE_SIZE;
524 segLINK.filesize = blankLINK;
525
526 // Get a writeable copy of the stub to make editing easier.
527 ByteArray(upxstub, sz_stub_main);
528 memcpy(upxstub, stub_main, sz_stub_main);
529
530 Mach_header *const mhp = (Mach_header *)upxstub;
531 mhp->cpusubtype = my_cpusubtype;
532 mhp->flags = mhdro.flags;
533 char *tail = (char *)(1+ mhp);
534 char *const lcp_end = mhdro.sizeofcmds + tail;
535 Mach_command *lcp = (Mach_command *)(1+ mhp);
536 Mach_command *lcp_next;
537 unsigned const ncmds = mhdro.ncmds;
538 //unsigned cmdsize = mhdro.sizeofcmds;
539 unsigned delta = 0;
540
541 for (unsigned j = 0; j < ncmds; ++j) {
542 unsigned skip = 0;
543 unsigned sz_cmd = lcp->cmdsize;
544 lcp_next = (Mach_command *)(sz_cmd + (char *)lcp);
545
546 switch (lcp->cmd) {
547 case Mach_command::LC_SEGMENT: // fall through
548 case Mach_command::LC_SEGMENT_64: {
549 Mach_segment_command *const segptr = (Mach_segment_command *)lcp;
550 if (!strcmp("__PAGEZERO", segptr->segname)) {
551 segptr->vmsize = pagezero_vmsize;
552 }
553 if (!strcmp("__TEXT", segptr->segname)) {
554 sz_cmd = (segTEXT.nsects * sizeof(secTEXT)) + sizeof(segTEXT);
555 mhp->sizeofcmds += sizeof(secTEXT) * (1 - segptr->nsects);
556 memcpy(tail, &segTEXT, sz_cmd); tail += sz_cmd;
557 goto next;
558 }
559 if (!strcmp("__LINKEDIT", segptr->segname)) {
560 segLINK.initprot = Mach_command::VM_PROT_READ;
561 delta = offLINK - segptr->fileoff; // relocation constant
562
563 sz_cmd = sizeof(segLINK);
564 if (Mach_header::CPU_TYPE_I386==mhdri.cputype
565 && Mach_header::MH_EXECUTE==mhdri.filetype) {
566 segLINK.maxprot = 0
567 | Mach_command::VM_PROT_EXECUTE
568 | Mach_command::VM_PROT_WRITE
569 | Mach_command::VM_PROT_READ;
570 segLINK.initprot = 0
571 | Mach_command::VM_PROT_WRITE
572 | Mach_command::VM_PROT_READ;
573 }
574 memcpy(tail, &segLINK, sz_cmd); tail += sz_cmd;
575 goto next;
576 }
577 } break;
578 case Mach_command::LC_DYLD_INFO_ONLY: {
579 Mach_dyld_info_only_command *p = (Mach_dyld_info_only_command *)lcp;
580 if (p->rebase_off) p->rebase_off += delta;
581 if (p->bind_off) p->bind_off += delta;
582 if (p->lazy_bind_off) p->lazy_bind_off += delta;
583 if (p->export_off) p->export_off += delta;
584 // But we don't want any exported symbols.
585 p->export_off = 0;
586 p->export_size = 0;
587 skip = 1;
588 } break;
589 case Mach_command::LC_SYMTAB: {
590 // Apple codesign requires that string table is last in the file.
591 Mach_symtab_command *p = (Mach_symtab_command *)lcp;
592 p->symoff = segLINK.filesize + segLINK.fileoff;
593 p->nsyms = 0;
594 p->stroff = segLINK.fileoff;
595 p->strsize = segLINK.filesize;
596 skip = 1;
597 } break;
598 case Mach_command::LC_DYSYMTAB: {
599 Mach_dysymtab_command *p = (Mach_dysymtab_command *)lcp;
600 if (p->tocoff) p->tocoff += delta;
601 if (p->modtaboff) p->modtaboff += delta;
602 if (p->extrefsymoff) p->extrefsymoff += delta;
603 if (p->indirectsymoff) p->indirectsymoff += delta;
604 if (p->extreloff) p->extreloff += delta;
605 if (p->locreloff) p->locreloff += delta;
606 // But we don't want any symbols.
607 p->ilocalsym = 0;
608 p->nlocalsym = 0;
609 p->iextdefsym = 0;
610 p->nextdefsym = 0;
611 p->iundefsym = 0;
612 p->nundefsym = 0;
613 skip = 1;
614 } break;
615 case Mach_command::LC_MAIN: {
616 // Replace later with LC_UNIXTHREAD.
617 // LC_MAIN requires libSystem.B.dylib to provide the environment for main(), and CALLs the entryoff.
618 // LC_UNIXTHREAD does not need libSystem.B.dylib, and JMPs to the .rip with %rsp/argc and argv= 8+%rsp
619 threado_setPC(segTEXT.vmaddr +
620 (((Mach_main_command const *)lcp)->entryoff - segTEXT.fileoff));
621 skip = 1;
622 } break;
623 case Mach_command::LC_UNIXTHREAD: { // pre-LC_MAIN
624 skip = 1;
625 } break;
626 case Mach_command::LC_LOAD_DYLIB: {
627 skip = 1;
628 } break;
629
630 case Mach_command::LC_FUNCTION_STARTS:
631 case Mach_command::LC_DATA_IN_CODE: {
632 Mach_linkedit_data_command *p = (Mach_linkedit_data_command *)lcp;
633 if (p->dataoff) p->dataoff += delta;
634 skip = 1;
635 } break;
636 case Mach_command::LC_LOAD_DYLINKER: {
637 skip = 1;
638 } break;
639 case Mach_command::LC_SOURCE_VERSION: { // copy from saved original
640 memcpy(lcp, &cmdSRCVER, sizeof(cmdSRCVER));
641 if (Mach_command::LC_SOURCE_VERSION != cmdSRCVER.cmd) {
642 skip = 1; // was not seen
643 }
644 } break;
645 case Mach_command::LC_VERSION_MIN_MACOSX: { // copy from saved original
646 memcpy(lcp, &cmdVERMIN, sizeof(cmdVERMIN));
647 if (Mach_command::LC_VERSION_MIN_MACOSX != cmdVERMIN.cmd) {
648 skip = 1; // was not seen
649 }
650 } break;
651 } // end switch
652
653 if (skip) {
654 mhp->ncmds -= 1;
655 mhp->sizeofcmds -= sz_cmd;
656 }
657 else {
658 if (tail != (char *)lcp) {
659 memmove(tail, lcp, sz_cmd);
660 }
661 tail += sz_cmd;
662 }
663 next:
664 lcp = lcp_next;
665 } // end for each Mach_command
666
667 // Append LC_UNIXTHREAD
668 unsigned const sz_threado = threado_size();
669 mhp->ncmds += 1;
670 mhp->sizeofcmds += sz_threado;
671 fo->seek(0, SEEK_SET);
672 fo->rewrite(mhp, tail - (char *)mhp);
673 threado_rewrite(fo);
674 tail += sz_threado;
675 //
676 // Zero any remaining tail.
677 if (tail < lcp_end) {
678 unsigned sz_cmd = lcp_end - tail;
679 memset(tail, 0, sz_cmd);
680 fo->rewrite(tail, sz_cmd);
681 }
682 // Rewrite linfo in file.
683 fo->seek(sz_mach_headers, SEEK_SET);
684 fo->rewrite(&linfo, sizeof(linfo));
685 fo->seek(0, SEEK_END);
686 }
687 }
688
689 // At 2013-02-03 part of the source for codesign was:
690 // http://opensource.apple.com/source/cctools/cctools-836/libstuff/ofile.c
691
692 template <class T>
pack4dylib(OutputFile * const fo,Filter & ft,Addr init_address)693 void PackMachBase<T>::pack4dylib( // append PackHeader
694 OutputFile *const fo,
695 Filter &ft,
696 Addr init_address
697 )
698 {
699 fo->seek(0, SEEK_SET);
700 fo->rewrite(&mhdro, sizeof(mhdro)); // segTEXT.nsect=1 (only secTEXT)
701 fo->rewrite(&segTEXT, sizeof(segTEXT)); // .vmsize
702 unsigned opos = sizeof(mhdro);
703
704 // Append each non-__TEXT segment, page aligned.
705 int slide = 0;
706 unsigned o_end_txt = 0;
707 unsigned hdrpos = sizeof(mhdro);
708 Mach_segment_command const *seg = rawmseg;
709 Mach_segment_command const *const endseg =
710 (Mach_segment_command const *)(mhdri.sizeofcmds + (char const *)seg);
711 for ( ; seg < endseg; seg = (Mach_segment_command const *)(
712 seg->cmdsize + (char const *)seg )
713 ) switch (seg->cmd & ~Mach_command::LC_REQ_DYLD) {
714 default: // unknown if any file offset field must slide
715 fprintf(stderr, "Unrecognized Macho cmd offset=0x%lx cmd=0x%lx size=0x%lx\n",
716 (unsigned long)((const char *)seg - (const char *)rawmseg),
717 (unsigned long)seg->cmd, (unsigned long)seg->cmdsize);
718 // fall through
719 case Mach_command::LC_VERSION_MIN_MACOSX:
720 case Mach_command::LC_SOURCE_VERSION:
721 case Mach_command::LC_THREAD:
722 case Mach_command::LC_UNIXTHREAD:
723 case Mach_command::LC_LOAD_DYLIB:
724 case Mach_command::LC_ID_DYLIB:
725 case Mach_command::LC_LOAD_DYLINKER:
726 case Mach_command::LC_UUID:
727 case Mach_command::LC_RPATH:
728 case Mach_command::LC_REEXPORT_DYLIB: { // contain no file offset fields
729 fo->seek(hdrpos, SEEK_SET);
730 fo->rewrite(seg, seg->cmdsize);
731 hdrpos += seg->cmdsize;
732 } break;
733
734 case Mach_command::LC_CODE_SIGNATURE:
735 case Mach_command::LC_SEGMENT_SPLIT_INFO:
736 case Mach_command::LC_DYLIB_CODE_SIGN_DRS:
737 case Mach_command::LC_DATA_IN_CODE:
738 case Mach_command::LC_FUNCTION_STARTS: {
739 Mach_linkedit_data_command cmd; memcpy(&cmd, seg, sizeof(cmd));
740 if (o_end_txt <= cmd.dataoff) { cmd.dataoff += slide; }
741 fo->seek(hdrpos, SEEK_SET);
742 fo->rewrite(&cmd, sizeof(cmd));
743 hdrpos += sizeof(cmd);
744 } break;
745 case Mach_command::LC_DYLD_INFO_ONLY & ~Mach_command::LC_REQ_DYLD: {
746 Mach_dyld_info_only_command cmd; memcpy(&cmd, seg, sizeof(cmd));
747 if (o_end_txt <= cmd.rebase_off) { cmd.rebase_off += slide; }
748 if (o_end_txt <= cmd.bind_off) { cmd.bind_off += slide; }
749 if (o_end_txt <= cmd.weak_bind_off) { cmd.weak_bind_off += slide; }
750 if (o_end_txt <= cmd.lazy_bind_off) { cmd.lazy_bind_off += slide; }
751 if (o_end_txt <= cmd.export_off) { cmd.export_off += slide; }
752 fo->seek(hdrpos, SEEK_SET);
753 fo->rewrite(&cmd, sizeof(cmd));
754 hdrpos += sizeof(cmd);
755 } break;
756 case Mach_command::LC_TWOLEVEL_HINTS: {
757 Mach_twolevel_hints_command cmd; memcpy(&cmd, seg, sizeof(cmd));
758 if (o_end_txt <= cmd.offset) { cmd.offset += slide; }
759 fo->seek(hdrpos, SEEK_SET);
760 fo->rewrite(&cmd, sizeof(cmd));
761 hdrpos += sizeof(cmd);
762 } break;
763 case Mach_command::LC_ROUTINES_64:
764 case Mach_command::LC_ROUTINES: {
765 Mach_routines_command cmd; memcpy(&cmd, seg, sizeof(cmd));
766 cmd.reserved1 = cmd.init_address;
767 cmd.init_address = init_address;
768 fo->seek(hdrpos, SEEK_SET);
769 fo->rewrite(&cmd, sizeof(cmd));
770 hdrpos += sizeof(cmd);
771 } break;
772 case Mach_command::LC_SEGMENT_64:
773 case Mach_command::LC_SEGMENT: {
774 // non-__TEXT might be observed and relocated by dyld before us.
775 Mach_segment_command segcmdtmp = *seg;
776 bool const is_text = 0==strncmp(&seg->segname[0], "__TEXT", 1+ 6);
777 {
778 if (is_text) {
779 slide = 0;
780 segTEXT.vmsize = segTEXT.filesize = fo->getBytesWritten();
781 segTEXT.maxprot |= Mach_command::VM_PROT_WRITE;
782 segcmdtmp = segTEXT;
783 opos = o_end_txt = segcmdtmp.filesize + segcmdtmp.fileoff;
784 }
785 else {
786 opos += ~PAGE_MASK & (0u - opos); // advance to PAGE_SIZE boundary
787 slide = opos - segcmdtmp.fileoff;
788 segcmdtmp.fileoff = opos;
789 }
790
791 fo->seek(hdrpos, SEEK_SET);
792 fo->rewrite(&segcmdtmp, sizeof(segcmdtmp));
793 hdrpos += sizeof(segcmdtmp);
794
795 // Update the sections.
796 Mach_section_command const *secp =
797 (Mach_section_command const *)(const void*)(const char*)(1+ seg);
798 if (is_text) {
799 secTEXT.offset = secp->offset;
800 secTEXT.addr = segTEXT.vmaddr + secTEXT.offset;
801 secTEXT.size = segTEXT.filesize - secTEXT.offset;
802 secp = &secTEXT;
803 }
804 unsigned const nsects = (is_text ? 1 : segcmdtmp.nsects);
805 Mach_section_command seccmdtmp;
806 for (unsigned j = 0; j < nsects; ++secp, ++j) {
807 seccmdtmp = *secp;
808 if (o_end_txt <= seccmdtmp.offset) { seccmdtmp.offset += slide; }
809 if (o_end_txt <= seccmdtmp.reloff) { seccmdtmp.reloff += slide; }
810 fo->rewrite(&seccmdtmp, sizeof(seccmdtmp));
811 hdrpos += sizeof(seccmdtmp);
812 }
813
814 if (!is_text) {
815 unsigned const len = seg->filesize;
816 MemBuffer data(len);
817 fi->seek(seg->fileoff, SEEK_SET);
818 fi->readx(data, len);
819 unsigned const pos = o__mod_init_func - seg->fileoff;
820 if (pos < seg->filesize) {
821 if (*(unsigned *)(pos + data) != (unsigned)prev_mod_init_func) {
822 throwCantPack("__mod_init_func inconsistent");
823 }
824 *(unsigned *)(pos + data) = (unsigned)entryVMA;
825 }
826 fo->seek(opos, SEEK_SET);
827 fo->write(data, len);
828 opos += len;
829 }
830 }
831 } break;
832 case Mach_command::LC_SYMTAB: {
833 Mach_symtab_command cmd; memcpy(&cmd, seg, sizeof(cmd));
834 if (o_end_txt <= cmd.symoff) { cmd.symoff += slide; }
835 if (o_end_txt <= cmd.stroff) { cmd.stroff += slide; }
836 fo->seek(hdrpos, SEEK_SET);
837 fo->rewrite(&cmd, sizeof(cmd));
838 hdrpos += sizeof(cmd);
839 } break;
840 case Mach_command::LC_DYSYMTAB: {
841 Mach_dysymtab_command cmd; memcpy(&cmd, seg, sizeof(cmd));
842 if (o_end_txt <= cmd.tocoff) { cmd.tocoff += slide; }
843 if (o_end_txt <= cmd.modtaboff) { cmd.modtaboff += slide; }
844 if (o_end_txt <= cmd.extrefsymoff) { cmd.extrefsymoff += slide; }
845 if (o_end_txt <= cmd.indirectsymoff) { cmd.indirectsymoff += slide; }
846 if (o_end_txt <= cmd.extreloff) { cmd.extreloff += slide; }
847 if (o_end_txt <= cmd.locreloff) { cmd.locreloff += slide; }
848 fo->seek(hdrpos, SEEK_SET);
849 fo->rewrite(&cmd, sizeof(cmd));
850 hdrpos += sizeof(cmd);
851 } break;
852 } // end 'switch'
853 fo->seek(opos, SEEK_SET); // BUG: "fo->seek(0, SEEK_END);" is broken
854
855 PackMachBase<T>::pack4(fo, ft);
856 }
857
pack4(OutputFile * fo,Filter & ft)858 void PackDylibI386::pack4(OutputFile *fo, Filter &ft) // append PackHeader
859 {
860 pack4dylib(fo, ft, threado.state.eip);
861 }
862
pack4(OutputFile * fo,Filter & ft)863 void PackDylibAMD64::pack4(OutputFile *fo, Filter &ft) // append PackHeader
864 {
865 pack4dylib(fo, ft, threado.state.rip);
866 }
867
pack4(OutputFile * fo,Filter & ft)868 void PackDylibPPC32::pack4(OutputFile *fo, Filter &ft) // append PackHeader
869 {
870 pack4dylib(fo, ft, threado.state.srr0);
871 }
872
pack4(OutputFile * fo,Filter & ft)873 void PackDylibPPC64LE::pack4(OutputFile *fo, Filter &ft) // append PackHeader
874 {
875 pack4dylib(fo, ft, threado.state64.srr0);
876 }
877
878 template <class T>
pack3(OutputFile * fo,Filter & ft)879 off_t PackMachBase<T>::pack3(OutputFile *fo, Filter &ft) // append loader
880 {
881 TE32 disp;
882 upx_uint64_t const zero = 0;
883 unsigned len = fo->getBytesWritten();
884 fo->write(&zero, 3& (0u-len));
885 len += (3& (0u-len));
886
887 disp = len; // backward offset to Mach_header
888 fo->write(&disp, sizeof(disp));
889 len += sizeof(disp);
890
891 if (my_filetype!=Mach_header::MH_DYLIB) {
892 disp = len - sz_mach_headers; // backward offset to start of compressed data
893 fo->write(&disp, sizeof(disp));
894 len += sizeof(disp);
895 }
896 segTEXT.vmsize = segTEXT.filesize;
897 threado_setPC(entryVMA= len + segTEXT.vmaddr);
898
899 return super::pack3(fo, ft);
900 }
901
pack3(OutputFile * fo,Filter & ft)902 off_t PackDylibI386::pack3(OutputFile *fo, Filter &ft) // append loader
903 {
904 TE32 disp;
905 upx_uint32_t const zero = 0;
906 off_t len = fo->getBytesWritten();
907 fo->write(&zero, 3& (0u-len));
908 len += (3& (0u-len)) + 4*sizeof(disp);
909
910 disp = prev_mod_init_func;
911 fo->write(&disp, sizeof(disp)); // user .init_address
912
913 disp = secTEXT.offset + sizeof(l_info) + sizeof(p_info);
914 fo->write(&disp, sizeof(disp)); // src offset(compressed __TEXT)
915
916 disp = len - disp - 3*sizeof(disp);
917 fo->write(&disp, sizeof(disp)); // length(compressed __TEXT)
918
919 unsigned const save_sz_mach_headers(sz_mach_headers);
920 sz_mach_headers = 0;
921 len = super::pack3(fo, ft);
922 sz_mach_headers = save_sz_mach_headers;
923 return len;
924 }
925
pack3(OutputFile * fo,Filter & ft)926 off_t PackDylibAMD64::pack3(OutputFile *fo, Filter &ft) // append loader
927 {
928 TE32 disp;
929 upx_uint64_t const zero = 0;
930 off_t len = fo->getBytesWritten();
931 fo->write(&zero, 3& (0u-len));
932 len += (3& (0u-len)) + 3*sizeof(disp);
933
934 disp = prev_mod_init_func;
935 fo->write(&disp, sizeof(disp)); // user .init_address
936
937 disp = secTEXT.offset + sizeof(l_info) + sizeof(p_info);
938 fo->write(&disp, sizeof(disp)); // src offset(b_info)
939
940 disp = rawmseg[0].vmsize;
941 fo->write(&disp, sizeof(disp)); // __TEXT.vmsize when expanded
942
943 unsigned const save_sz_mach_headers(sz_mach_headers);
944 sz_mach_headers = 0;
945 len = super::pack3(fo, ft);
946 sz_mach_headers = save_sz_mach_headers;
947 return len;
948 }
949
pack3(OutputFile * fo,Filter & ft)950 off_t PackDylibPPC32::pack3(OutputFile *fo, Filter &ft) // append loader
951 {
952 TE32 disp;
953 upx_uint32_t const zero = 0;
954 off_t len = fo->getBytesWritten();
955 fo->write(&zero, 3& (0u-len));
956 len += (3& (0u-len)) + 4*sizeof(disp);
957
958 disp = prev_mod_init_func;
959 fo->write(&disp, sizeof(disp)); // user .init_address
960
961 disp = secTEXT.offset + sizeof(l_info) + sizeof(p_info);
962 fo->write(&disp, sizeof(disp)); // src offset(compressed __TEXT)
963
964 disp = len - disp - 3*sizeof(disp);
965 fo->write(&disp, sizeof(disp)); // length(compressed __TEXT)
966
967 unsigned const save_sz_mach_headers(sz_mach_headers);
968 sz_mach_headers = 0;
969 len = super::pack3(fo, ft);
970 sz_mach_headers = save_sz_mach_headers;
971 return len;
972 }
973
pack3(OutputFile * fo,Filter & ft)974 off_t PackDylibPPC64LE::pack3(OutputFile *fo, Filter &ft) // append loader
975 {
976 TE64 disp;
977 upx_uint64_t const zero = 0;
978 off_t len = fo->getBytesWritten();
979 fo->write(&zero, 3& (0u-len));
980 len += (3& (0u-len)) + 4*sizeof(disp);
981
982 disp = prev_mod_init_func;
983 fo->write(&disp, sizeof(disp)); // user .init_address
984
985 disp = secTEXT.offset + sizeof(l_info) + sizeof(p_info);
986 fo->write(&disp, sizeof(disp)); // src offset(compressed __TEXT)
987
988 disp = len - disp - 3*sizeof(disp);
989 fo->write(&disp, sizeof(disp)); // length(compressed __TEXT)
990
991 unsigned const save_sz_mach_headers(sz_mach_headers);
992 sz_mach_headers = 0;
993 len = super::pack3(fo, ft);
994 sz_mach_headers = save_sz_mach_headers;
995 return len;
996 }
997
998 // Determine length of gap between PT_LOAD phdri[k] and closest PT_LOAD
999 // which follows in the file (or end-of-file). Optimize for common case
1000 // where the PT_LOAD are adjacent ascending by .p_offset. Assume no overlap.
1001
1002 template <class T>
find_SEGMENT_gap(unsigned const k,unsigned pos_eof)1003 unsigned PackMachBase<T>::find_SEGMENT_gap(
1004 unsigned const k, unsigned pos_eof
1005 )
1006 {
1007 unsigned const lc_seg = lc_segment[sizeof(Addr)>>3];
1008 if (lc_seg!=msegcmd[k].cmd
1009 || 0==msegcmd[k].filesize ) {
1010 return 0;
1011 }
1012 unsigned const hi = msegcmd[k].fileoff + msegcmd[k].filesize;
1013 unsigned lo = pos_eof;
1014 unsigned j = k;
1015 for (;;) { // circular search, optimize for adjacent ascending
1016 ++j;
1017 if (n_segment==j) {
1018 j = 0;
1019 }
1020 if (k==j) {
1021 break;
1022 }
1023 if (lc_seg==msegcmd[j].cmd
1024 && 0!=msegcmd[j].filesize ) {
1025 unsigned const t = (unsigned) msegcmd[j].fileoff;
1026 if ((t - hi) < (lo - hi)) {
1027 lo = t;
1028 if (hi==lo) {
1029 break;
1030 }
1031 }
1032 }
1033 }
1034 return lo - hi;
1035 }
1036
1037 template <class T>
pack2(OutputFile * fo,Filter & ft)1038 int PackMachBase<T>::pack2(OutputFile *fo, Filter &ft) // append compressed body
1039 {
1040 unsigned const lc_seg = lc_segment[sizeof(Addr)>>3];
1041 Extent x;
1042 unsigned k;
1043
1044 // count passes, set ptload vars
1045 uip->ui_total_passes = 0;
1046 for (k = 0; k < n_segment; ++k) {
1047 if (lc_seg==msegcmd[k].cmd
1048 && 0!=msegcmd[k].filesize ) {
1049 uip->ui_total_passes++;
1050 if (my_filetype==Mach_header::MH_DYLIB) {
1051 break;
1052 }
1053 if (find_SEGMENT_gap(k, fi->st_size())) {
1054 uip->ui_total_passes++;
1055 }
1056 }
1057 }
1058
1059 // compress extents
1060 unsigned total_in = 0;
1061 unsigned total_out = 0;
1062
1063 unsigned hdr_u_len = mhdri.sizeofcmds + sizeof(mhdri);
1064
1065 uip->ui_pass = 0;
1066 ft.addvalue = 0;
1067
1068 // Packer::compressWithFilters chooses a filter for us, and the stubs
1069 // can handle only one filter, and most filters are for executable
1070 // instructions. So filter only the largest executable segment.
1071 unsigned exe_filesize_max = 0;
1072 for (k = 0; k < n_segment; ++k)
1073 if (lc_seg==msegcmd[k].cmd
1074 && 0!=(Mach_command::VM_PROT_EXECUTE & msegcmd[k].initprot)
1075 && exe_filesize_max < msegcmd[k].filesize) {
1076 exe_filesize_max = (unsigned) msegcmd[k].filesize;
1077 }
1078
1079 int nx = 0;
1080 for (k = 0; k < n_segment; ++k)
1081 if (lc_seg==msegcmd[k].cmd
1082 && 0!=msegcmd[k].filesize ) {
1083 x.offset = msegcmd[k].fileoff;
1084 x.size = msegcmd[k].filesize;
1085 if (0 == nx) { // 1st LC_SEGMENT must cover Mach_header at 0==fileoffset
1086 unsigned const delta = mhdri.sizeofcmds + sizeof(mhdri);
1087 x.offset += delta;
1088 x.size -= delta;
1089 }
1090 bool const do_filter = (msegcmd[k].filesize==exe_filesize_max)
1091 && 0!=(Mach_command::VM_PROT_EXECUTE & msegcmd[k].initprot);
1092 packExtent(x, total_in, total_out,
1093 (do_filter ? &ft : 0 ), fo, hdr_u_len );
1094 if (do_filter) {
1095 exe_filesize_max = 0;
1096 }
1097 hdr_u_len = 0;
1098 ++nx;
1099 if (my_filetype==Mach_header::MH_DYLIB) {
1100 break;
1101 }
1102 }
1103 if (my_filetype!=Mach_header::MH_DYLIB)
1104 for (k = 0; k < n_segment; ++k) {
1105 x.size = find_SEGMENT_gap(k, fi->st_size());
1106 if (x.size) {
1107 x.offset = msegcmd[k].fileoff +msegcmd[k].filesize;
1108 packExtent(x, total_in, total_out, 0, fo);
1109 }
1110 }
1111
1112 if (my_filetype!=Mach_header::MH_DYLIB)
1113 if ((off_t)total_in != file_size)
1114 throwEOFException();
1115 segTEXT.filesize = fo->getBytesWritten();
1116 secTEXT.size = segTEXT.filesize - overlay_offset + sizeof(linfo);
1117
1118 return 1;
1119 }
1120
pack1_setup_threado(OutputFile * const fo)1121 void PackMachPPC32::pack1_setup_threado(OutputFile *const fo)
1122 {
1123 threado.cmd = Mach_command::LC_UNIXTHREAD;
1124 threado.cmdsize = sizeof(threado);
1125 threado.flavor = my_thread_flavor;
1126 threado.count = my_thread_state_word_count;
1127 memset(&threado.state, 0, sizeof(threado.state));
1128 fo->write(&threado, sizeof(threado));
1129 }
1130
pack1_setup_threado(OutputFile * const fo)1131 void PackMachPPC64LE::pack1_setup_threado(OutputFile *const fo)
1132 {
1133 threado.cmd = Mach_command::LC_UNIXTHREAD;
1134 threado.cmdsize = sizeof(threado);
1135 threado.flavor = my_thread_flavor;
1136 threado.count = my_thread_state_word_count;
1137 memset(&threado.state64, 0, sizeof(threado.state64));
1138 fo->write(&threado, sizeof(threado));
1139 }
1140
pack1_setup_threado(OutputFile * const fo)1141 void PackMachI386::pack1_setup_threado(OutputFile *const fo)
1142 {
1143 threado.cmd = Mach_command::LC_UNIXTHREAD;
1144 threado.cmdsize = sizeof(threado);
1145 threado.flavor = my_thread_flavor;
1146 threado.count = my_thread_state_word_count;
1147 memset(&threado.state, 0, sizeof(threado.state));
1148 fo->write(&threado, sizeof(threado));
1149 }
1150
pack1_setup_threado(OutputFile * const fo)1151 void PackMachAMD64::pack1_setup_threado(OutputFile *const fo)
1152 {
1153 threado.cmd = Mach_command::LC_UNIXTHREAD;
1154 threado.cmdsize = sizeof(threado);
1155 threado.flavor = my_thread_flavor;
1156 threado.count = my_thread_state_word_count;
1157 memset(&threado.state, 0, sizeof(threado.state));
1158 fo->write(&threado, sizeof(threado));
1159 }
1160
pack1_setup_threado(OutputFile * const fo)1161 void PackMachARMEL::pack1_setup_threado(OutputFile *const fo)
1162 {
1163 threado.cmd = Mach_command::LC_UNIXTHREAD;
1164 threado.cmdsize = sizeof(threado);
1165 threado.flavor = my_thread_flavor;
1166 threado.count = my_thread_state_word_count;
1167 memset(&threado.state, 0, sizeof(threado.state));
1168 fo->write(&threado, sizeof(threado));
1169 }
1170
pack1_setup_threado(OutputFile * const fo)1171 void PackMachARM64EL::pack1_setup_threado(OutputFile *const fo)
1172 {
1173 threado.cmd = Mach_command::LC_UNIXTHREAD;
1174 threado.cmdsize = sizeof(threado);
1175 threado.flavor = my_thread_flavor;
1176 threado.count = my_thread_state_word_count;
1177 memset(&threado.state, 0, sizeof(threado.state));
1178 fo->write(&threado, sizeof(threado));
1179 }
1180
1181 template <class T>
pack1(OutputFile * const fo,Filter &)1182 void PackMachBase<T>::pack1(OutputFile *const fo, Filter &/*ft*/) // generate executable header
1183 {
1184 unsigned const lc_seg = lc_segment[sizeof(Addr)>>3];
1185 mhdro = mhdri;
1186 if (my_filetype==Mach_header::MH_EXECUTE) {
1187 memcpy(&mhdro, stub_main, sizeof(mhdro));
1188 mhdro.flags = mhdri.flags;
1189 COMPILE_TIME_ASSERT(sizeof(mhdro.flags) == sizeof(unsigned))
1190 }
1191 unsigned pos = sizeof(mhdro);
1192 fo->write(&mhdro, sizeof(mhdro));
1193
1194 memset(&segZERO, 0, sizeof(segZERO));
1195 segZERO.cmd = lc_seg;
1196 segZERO.cmdsize = sizeof(segZERO);
1197 strncpy((char *)segZERO.segname, "__PAGEZERO", sizeof(segZERO.segname));
1198 segZERO.vmsize = PAGE_SIZE;
1199 if __acc_cte(sizeof(segZERO.vmsize) == 8
1200 && mhdro.filetype == Mach_header::MH_EXECUTE
1201 && mhdro.cputype == Mach_header::CPU_TYPE_X86_64) {
1202 if (pagezero_vmsize < 0xF0000000ull) {
1203 segZERO.vmsize = pagezero_vmsize;
1204 }
1205 else {
1206 segZERO.vmsize <<= 20; // (1ul<<32)
1207 }
1208 }
1209
1210 segTEXT.cmd = lc_seg;
1211 segTEXT.cmdsize = sizeof(segTEXT) + sizeof(secTEXT);
1212 strncpy((char *)segTEXT.segname, "__TEXT", sizeof(segTEXT.segname));
1213 if (my_filetype==Mach_header::MH_EXECUTE) {
1214 if (Mach_header::MH_PIE & mhdri.flags) {
1215 segTEXT.vmaddr = segZERO.vmsize; // contiguous
1216 }
1217 else { // not MH_PIE
1218 // Start above all eventual mappings.
1219 // Cannot enlarge segZERO.vmsize because MacOS 10.13 (HighSierra)
1220 // won't permit re-map of PAGEZERO.
1221 // Stub will fill with PROT_NONE first.
1222 segTEXT.vmaddr = vma_max;
1223 }
1224 }
1225 if (my_filetype==Mach_header::MH_DYLIB) {
1226 segTEXT.vmaddr = 0;
1227 }
1228 segTEXT.vmsize = 0; // adjust later
1229 segTEXT.fileoff = 0;
1230 segTEXT.filesize = 0; // adjust later
1231 segTEXT.maxprot =
1232 Mach_command::VM_PROT_READ |
1233 Mach_command::VM_PROT_WRITE |
1234 Mach_command::VM_PROT_EXECUTE;
1235 segTEXT.initprot =
1236 Mach_command::VM_PROT_READ |
1237 Mach_command::VM_PROT_EXECUTE;
1238 segTEXT.nsects = 1; // secTEXT
1239 segTEXT.flags = 0;
1240
1241 memset(&secTEXT, 0, sizeof(secTEXT));
1242 strncpy((char *)secTEXT.sectname, "__text", sizeof(secTEXT.sectname));
1243 memcpy(secTEXT.segname, segTEXT.segname, sizeof(secTEXT.segname));
1244 secTEXT.align = 2; // (1<<2) ==> 4
1245 secTEXT.flags = Mach_section_command::S_REGULAR
1246 | Mach_section_command::S_ATTR_SOME_INSTRUCTIONS
1247 | Mach_section_command::S_ATTR_PURE_INSTRUCTIONS;
1248
1249 segXHDR = segTEXT;
1250 segXHDR.cmdsize = sizeof(segXHDR) + sizeof(secXHDR);
1251 segXHDR.vmaddr = segZERO.vmsize;
1252 segXHDR.vmsize = PAGE_SIZE;
1253 segXHDR.filesize = PAGE_SIZE;
1254 segXHDR.nsects = 1;
1255 strncpy((char *)segXHDR.segname, "UPX_DATA", sizeof(segXHDR.segname));
1256
1257 memset(&secXHDR, 0, sizeof(secXHDR));
1258 strncpy((char *)secXHDR.sectname, "upx_data", sizeof(secXHDR.sectname));
1259 memcpy(secXHDR.segname, segXHDR.segname, sizeof(secXHDR.segname));
1260 secXHDR.addr = segXHDR.vmaddr;
1261 secXHDR.size = 0; // empty so far
1262 secXHDR.align = 2; // (1<<2) ==> 4
1263
1264 segLINK = segTEXT;
1265 segLINK.cmdsize = sizeof(segLINK);
1266 strncpy((char *)segLINK.segname, "__LINKEDIT", sizeof(segLINK.segname));
1267 segLINK.initprot = Mach_command::VM_PROT_READ;
1268 segLINK.nsects = 0;
1269 segLINK.vmsize = 0;
1270 // Adjust later: .vmaddr .vmsize .fileoff .filesize
1271
1272 unsigned gap = 0;
1273 if (my_filetype == Mach_header::MH_EXECUTE) {
1274 unsigned cmdsize = mhdro.sizeofcmds;
1275 Mach_header const *const ptr0 = (Mach_header const *)stub_main;
1276 Mach_command const *ptr1 = (Mach_command const *)(1+ ptr0);
1277 for (unsigned j = 0; j < mhdro.ncmds -1; ++j, (cmdsize -= ptr1->cmdsize),
1278 ptr1 = (Mach_command const *)(ptr1->cmdsize + (char const *)ptr1)) {
1279 if (lc_seg == ptr1->cmd) {
1280 Mach_segment_command const *const segptr = (Mach_segment_command const *)ptr1;
1281 Mach_section_command const *const secptr = (Mach_section_command const *)(1+ segptr);
1282 if (!strcmp("__TEXT", segptr->segname)) {
1283 strncpy((char *)secTEXT.segname, "__TEXT", sizeof(secTEXT.segname));
1284 strncpy((char *)secTEXT.sectname, "upxTEXT", sizeof(secTEXT.sectname));
1285 secTEXT.addr = secptr->addr;
1286 secTEXT.size = secptr->size; // update later
1287 secTEXT.offset = secptr->offset;
1288 secTEXT.align = secptr->align;
1289 }
1290 if (!strcmp("__LINKEDIT", segptr->segname)) {
1291 // Mach_command before __LINKEDIT
1292 pos += (char const *)ptr1 - (char const *)(1+ ptr0);
1293 fo->write((1+ ptr0), (char const *)ptr1 - (char const *)(1+ ptr0));
1294
1295 // Mach_command __LINKEDIT and after
1296 pos += cmdsize;
1297 fo->write((char const *)ptr1, cmdsize);
1298
1299 // 400: space for LC_UUID, LC_RPATH, LC_CODE_SIGNATURE, etc.
1300 gap = 400 + threado_size();
1301 secTEXT.offset = gap + pos;
1302 secTEXT.addr = secTEXT.offset + segTEXT.vmaddr;
1303 break;
1304 }
1305 }
1306 }
1307 unsigned const sz_threado = threado_size();
1308 MemBuffer space(sz_threado); memset(space, 0, sz_threado);
1309 fo->write(space, sz_threado);
1310 }
1311 else if (my_filetype == Mach_header::MH_DYLIB) {
1312 Mach_command const *ptr = (Mach_command const *)rawmseg;
1313 unsigned cmdsize = mhdri.sizeofcmds;
1314 for (unsigned j = 0; j < mhdri.ncmds; ++j, (cmdsize -= ptr->cmdsize),
1315 ptr = (Mach_command const *)(ptr->cmdsize + (char const *)ptr)) {
1316 if (lc_seg == ptr->cmd) {
1317 Mach_segment_command const *const segptr = (Mach_segment_command const *)ptr;
1318 Mach_section_command const *const secptr = (Mach_section_command const *)(1+ segptr);
1319 if (!strcmp("__TEXT", segptr->segname)) {
1320 if (!(1 <= segptr->nsects)) {
1321 throwCantPack("TEXT.nsects == 0");
1322 }
1323 strncpy((char *)secTEXT.sectname, "upxTEXT", sizeof(secTEXT.sectname));
1324 secTEXT.addr = secptr->addr;
1325 secTEXT.size = secptr->size; // update later
1326 secTEXT.offset = secptr->offset;
1327 secTEXT.align = secptr->align;
1328 fo->write(&segTEXT, sizeof(segTEXT));
1329 fo->write(&secTEXT, sizeof(secTEXT));
1330 }
1331 else { // not __TEXT
1332 fo->write(ptr, ptr->cmdsize);
1333 }
1334 }
1335 else { // not LC_SEGMENT*
1336 fo->write(ptr, ptr->cmdsize);
1337 }
1338 }
1339 memset(&linkitem, 0, sizeof(linkitem));
1340 fo->write(&linkitem, sizeof(linkitem));
1341 }
1342 sz_mach_headers = fo->getBytesWritten();
1343 gap = secTEXT.offset - sz_mach_headers;
1344 MemBuffer filler(gap); filler.clear();
1345 fo->write(filler, gap);
1346 sz_mach_headers += gap;
1347
1348 memset((char *)&linfo, 0, sizeof(linfo));
1349 fo->write(&linfo, sizeof(linfo));
1350
1351 return;
1352 }
1353
1354 #define WANT_MACH_HEADER_ENUM 1
1355 #include "p_mach_enum.h"
1356
1357 static unsigned
umin(unsigned a,unsigned b)1358 umin(unsigned a, unsigned b)
1359 {
1360 return (a <= b) ? a : b;
1361 }
1362
1363 template <class T>
unpack(OutputFile * fo)1364 void PackMachBase<T>::unpack(OutputFile *fo)
1365 {
1366 unsigned const lc_seg = lc_segment[sizeof(Addr)>>3];
1367 fi->seek(0, SEEK_SET);
1368 fi->readx(&mhdri, sizeof(mhdri));
1369 if ((MH_MAGIC + (sizeof(Addr)>>3)) != mhdri.magic
1370 && Mach_fat_header::FAT_MAGIC != mhdri.magic) {
1371 throwCantUnpack("file header corrupted");
1372 }
1373 unsigned const sz_cmds = mhdri.sizeofcmds;
1374 if ((sizeof(mhdri) + sz_cmds) > (size_t)fi->st_size()) {
1375 throwCantUnpack("file header corrupted");
1376 }
1377 rawmseg = (Mach_segment_command *) New(char, sz_cmds);
1378 fi->readx(rawmseg, mhdri.sizeofcmds);
1379
1380 // FIXME forgot space left for LC_CODE_SIGNATURE;
1381 // but canUnpack() sets overlay_offset anyway.
1382 //overlay_offset = sizeof(mhdri) + mhdri.sizeofcmds + sizeof(linfo);
1383
1384 fi->seek(overlay_offset, SEEK_SET);
1385 p_info hbuf;
1386 fi->readx(&hbuf, sizeof(hbuf));
1387 unsigned const orig_file_size = get_te32(&hbuf.p_filesize);
1388 blocksize = get_te32(&hbuf.p_blocksize); // emacs-21.2.1 was 0x01d47e6c (== 30703212)
1389 if (blocksize > orig_file_size || blocksize > 0x05000000)
1390 throwCantUnpack("file header corrupted");
1391 if (file_size > (off_t)orig_file_size) {
1392 opt->info_mode += !opt->info_mode ? 1 : 0; // make visible
1393 opt->backup = 1;
1394 infoWarning("packed size too big; discarding appended data, keeping backup");
1395 }
1396
1397 ibuf.alloc(blocksize + OVERHEAD);
1398 b_info bhdr; memset(&bhdr, 0, sizeof(bhdr));
1399 fi->readx(&bhdr, sizeof(bhdr));
1400 ph.u_len = get_te32(&bhdr.sz_unc);
1401 ph.c_len = get_te32(&bhdr.sz_cpr);
1402 if ((unsigned)file_size < ph.c_len || ph.c_len == 0 || ph.u_len == 0)
1403 throwCantUnpack("file header corrupted");
1404 ph.method = bhdr.b_method;
1405 ph.filter = bhdr.b_ftid;
1406 ph.filter_cto = bhdr.b_cto8;
1407
1408 // Uncompress Macho headers
1409 fi->readx(ibuf, ph.c_len);
1410 Mach_header *const mhdr = (Mach_header *) New(upx_byte, ph.u_len);
1411 decompress(ibuf, (upx_byte *)mhdr, false);
1412 if (mhdri.magic != mhdr->magic
1413 || mhdri.cputype != mhdr->cputype
1414 || mhdri.cpusubtype != mhdr->cpusubtype
1415 || mhdri.filetype != mhdr->filetype)
1416 throwCantUnpack("file header corrupted");
1417 unsigned const ncmds = mhdr->ncmds;
1418
1419 msegcmd = New(Mach_segment_command, ncmds);
1420 unsigned char const *ptr = (unsigned char const *)(1+mhdr);
1421 for (unsigned j= 0; j < ncmds; ++j) {
1422 memcpy(&msegcmd[j], ptr, umin(sizeof(Mach_segment_command),
1423 ((Mach_command const *)ptr)->cmdsize));
1424 ptr += (unsigned) ((Mach_command const *)ptr)->cmdsize;
1425 if (ptr_udiff(ptr, (1+ mhdr)) > ph.u_len) {
1426 throwCantUnpack("cmdsize");
1427 }
1428 }
1429
1430 // Put LC_SEGMENT together at the beginning
1431 qsort(msegcmd, ncmds, sizeof(*msegcmd), compare_segment_command);
1432 n_segment = 0;
1433 for (unsigned j= 0; j < ncmds; ++j) {
1434 n_segment += (lc_seg==msegcmd[j].cmd);
1435 }
1436
1437 unsigned total_in = 0;
1438 unsigned total_out = 0;
1439 unsigned c_adler = upx_adler32(NULL, 0);
1440 unsigned u_adler = upx_adler32(NULL, 0);
1441
1442 fi->seek(- (off_t)(sizeof(bhdr) + ph.c_len), SEEK_CUR);
1443 for (unsigned k = 0; k < ncmds; ++k) {
1444 if (msegcmd[k].cmd==lc_seg && msegcmd[k].filesize!=0) {
1445 if (!strcmp("__TEXT", msegcmd[k].segname)) {
1446 segTEXT = msegcmd[k];
1447 }
1448 if (fo)
1449 fo->seek(msegcmd[k].fileoff, SEEK_SET);
1450 unpackExtent(msegcmd[k].filesize, fo, total_in, total_out,
1451 c_adler, u_adler, false, sizeof(bhdr));
1452 if (my_filetype==Mach_header::MH_DYLIB) {
1453 break; // only the first lc_seg when MH_DYLIB
1454 }
1455 }
1456 }
1457 Mach_segment_command const *sc = (Mach_segment_command const *)(void *)(1+ mhdr);
1458 if (my_filetype==Mach_header::MH_DYLIB) { // rest of lc_seg are not compressed
1459 upx_uint64_t cpr_mod_init_func(0);
1460 TE32 unc_mod_init_func; *(int *)&unc_mod_init_func = 0;
1461 Mach_segment_command const *rc = rawmseg;
1462 rc = (Mach_segment_command const *)(rc->cmdsize + (char const *)rc);
1463 sc = (Mach_segment_command const *)(sc->cmdsize + (char const *)sc);
1464 for (
1465 unsigned k=1; // skip first lc_seg, which was uncompressed above
1466 k < ncmds;
1467 (++k), (sc = (Mach_segment_command const *)(sc->cmdsize + (char const *)sc)),
1468 (rc = (Mach_segment_command const *)(rc->cmdsize + (char const *)rc))
1469 ) {
1470 if (lc_seg==rc->cmd
1471 && 0!=rc->filesize ) {
1472 if (!strcmp("__DATA", rc->segname)) {
1473 cpr_mod_init_func = get_mod_init_func(rc);
1474 fi->seek(cpr_mod_init_func - 4*sizeof(TE32), SEEK_SET);
1475 fi->readx(&unc_mod_init_func, sizeof(unc_mod_init_func));
1476 }
1477 fi->seek(rc->fileoff, SEEK_SET);
1478 if (fo)
1479 fo->seek(sc->fileoff, SEEK_SET);
1480 unsigned const len = rc->filesize;
1481 MemBuffer data(len);
1482 fi->readx(data, len);
1483 if (!strcmp("__DATA", rc->segname)) {
1484 set_te32(&data[o__mod_init_func - rc->fileoff], unc_mod_init_func);
1485 }
1486 if (fo)
1487 fo->write(data, len);
1488 }
1489 }
1490 }
1491 else
1492 for (unsigned j = 0; j < ncmds; ++j) {
1493 unsigned const size = find_SEGMENT_gap(j, orig_file_size);
1494 if (size) {
1495 unsigned const where = msegcmd[j].fileoff +msegcmd[j].filesize;
1496 if (fo)
1497 fo->seek(where, SEEK_SET);
1498 unpackExtent(size, fo, total_in, total_out,
1499 c_adler, u_adler, false, sizeof(bhdr));
1500 }
1501 }
1502 delete [] mhdr;
1503 }
1504
1505 // The prize is the value of overlay_offset: the offset of compressed data
1506 template <class T>
canUnpack()1507 int PackMachBase<T>::canUnpack()
1508 {
1509 unsigned const lc_seg = lc_segment[sizeof(Addr)>>3];
1510 fi->seek(0, SEEK_SET);
1511 fi->readx(&mhdri, sizeof(mhdri));
1512
1513 if (((unsigned) Mach_header::MH_MAGIC + (sizeof(Addr)>>3)) !=mhdri.magic
1514 || my_cputype !=mhdri.cputype
1515 || my_filetype !=mhdri.filetype
1516 )
1517 return false;
1518 my_cpusubtype = mhdri.cpusubtype;
1519
1520 int headway = (int)mhdri.sizeofcmds;
1521 if (headway < (int)(3 * sizeof(Mach_segment_command)
1522 + sizeof(Mach_main_command))) {
1523 infoWarning("Mach_header.sizeofcmds = %d too small", headway);
1524 throwCantUnpack("file corrupted");
1525 }
1526 sz_mach_headers = headway + sizeof(mhdri);
1527 if (2048 < headway) {
1528 infoWarning("Mach_header.sizeofcmds(%d) > 1024", headway);
1529 }
1530 rawmseg = (Mach_segment_command *) New(char, mhdri.sizeofcmds);
1531 fi->readx(rawmseg, mhdri.sizeofcmds);
1532
1533 Mach_segment_command const *ptrTEXT = 0;
1534 upx_uint64_t rip = 0;
1535 unsigned style = 0;
1536 off_t offLINK = 0;
1537 unsigned pos_next = 0;
1538 unsigned nseg = 0;
1539 unsigned const ncmds = mhdri.ncmds;
1540 Mach_command const *ptr = (Mach_command const *)rawmseg;
1541 for (unsigned j= 0; j < ncmds;
1542 ptr = (Mach_command const *)(ptr->cmdsize + (char const *)ptr), ++j) {
1543 if ((unsigned)headway < ptr->cmdsize) {
1544 infoWarning("bad Mach_command[%u]{@0x%lx,+0x%x}: file_size=0x%lx cmdsize=0x%lx",
1545 j, (unsigned long) (sizeof(mhdri) + ((char const *)ptr - (char const *)rawmseg)), headway,
1546 (unsigned long) file_size, (unsigned long)ptr->cmdsize);
1547 throwCantUnpack("file corrupted");
1548 }
1549 if (lc_seg == ptr->cmd) {
1550 Mach_segment_command const *const segptr = (Mach_segment_command const *)ptr;
1551 if ((unsigned long)file_size < segptr->filesize
1552 || (unsigned long)file_size < segptr->fileoff
1553 || (unsigned long)file_size < (segptr->filesize + segptr->fileoff)) {
1554 infoWarning("bad Mach_segment_command[%u]{@0x%lx,+0x%x}: file_size=0x%lx cmdsize=0x%lx"
1555 " filesize=0x%lx fileoff=0x%lx",
1556 j, (unsigned long) (sizeof(mhdri) + ((char const *)ptr - (char const *)rawmseg)), headway,
1557 (unsigned long) file_size, (unsigned long)ptr->cmdsize,
1558 (unsigned long)segptr->filesize, (unsigned long)segptr->fileoff);
1559 throwCantUnpack("file corrupted");
1560 }
1561 ++nseg;
1562 if (!strcmp("__XHDR", segptr->segname)) {
1563 // PackHeader precedes __LINKEDIT (pre-Sierra MacOS 10.12)
1564 style = 391; // UPX 3.91
1565 }
1566 if (!strcmp("__TEXT", segptr->segname)) {
1567 ptrTEXT = segptr;
1568 style = 391; // UPX 3.91
1569 }
1570 if (!strcmp("UPX_DATA", segptr->segname)) {
1571 // PackHeader follows loader at __LINKEDIT (Sierra MacOS 10.12)
1572 style = 392; // UPX 3.92
1573 }
1574 if (!strcmp("__LINKEDIT", segptr->segname)) {
1575 offLINK = segptr->fileoff;
1576 if (segptr->filesize == blankLINK) {
1577 style = 395;
1578 }
1579 if (offLINK < (off_t) pos_next) {
1580 offLINK = pos_next;
1581 }
1582 }
1583 pos_next = segptr->filesize + segptr->fileoff;
1584 if ((headway -= ptr->cmdsize) < 0) {
1585 infoWarning("Mach_command[%u]{@%lu}.cmdsize = %u", j,
1586 (unsigned long) (sizeof(mhdri) + mhdri.sizeofcmds - (headway + ptr->cmdsize)),
1587 (unsigned)ptr->cmdsize);
1588 throwCantUnpack("sum(.cmdsize) exceeds .sizeofcmds");
1589 }
1590 }
1591 else if (Mach_command::LC_UNIXTHREAD==ptr->cmd) {
1592 rip = entryVMA = threadc_getPC(ptr);
1593 }
1594 }
1595 if (3==nseg && 395 != style) { // __PAGEZERO, __TEXT, __LINKEDIT; no __XHDR, no UPX_DATA
1596 style = 392;
1597 }
1598 if (391==style && 0==offLINK && 2==ncmds) { // pre-3.91 ?
1599 offLINK = ptrTEXT->fileoff + ptrTEXT->filesize; // fake __LINKEDIT at EOF
1600 }
1601 if (0 == style || 0 == offLINK) {
1602 return false;
1603 }
1604
1605 int const small = 32 + sizeof(overlay_offset);
1606 unsigned bufsize = 4096;
1607 if (391 == style) { // PackHeader precedes __LINKEDIT
1608 fi->seek(offLINK - bufsize, SEEK_SET);
1609 } else
1610 if (392 == style) {
1611 if (MH_DYLIB == my_filetype) {
1612 fi->seek(fi->st_size() - bufsize, SEEK_SET);
1613 }
1614 else { // PackHeader follows loader at __LINKEDIT
1615 if ((off_t)bufsize > (fi->st_size() - offLINK)) {
1616 bufsize = fi->st_size() - offLINK;
1617 }
1618 fi->seek(offLINK, SEEK_SET);
1619 }
1620 } else
1621 if (395 == style) {
1622 fi->seek(offLINK - bufsize - sizeof(PackHeader), SEEK_SET);
1623 }
1624 MemBuffer buf(bufsize);
1625
1626 fi->readx(buf, bufsize);
1627 int i = bufsize;
1628 while (i > small && 0 == buf[--i]) { }
1629 i -= small;
1630 // allow incompressible extents
1631 if (i < 1 || !getPackHeader(buf + i, bufsize - i, true)) {
1632 // Breadcrumbs failed.
1633 // Pirates might overwrite the UPX! marker. Try harder.
1634 upx_uint64_t const rip_off = ptrTEXT ? (rip - ptrTEXT->vmaddr) : 0;
1635 if (ptrTEXT && rip && rip_off < ptrTEXT->vmsize) {
1636 fi->seek(ptrTEXT->fileoff + rip_off, SEEK_SET);
1637 fi->readx(buf, bufsize);
1638 unsigned char const *b = &buf[0];
1639 unsigned disp = *(TE32 const *)&b[1];
1640 // Emulate the code
1641 if (0xe8==b[0] && disp < bufsize
1642 && 0x5d==b[5+disp] && 0xe8==b[6+disp]) {
1643 unsigned disp2 = 0u - *(TE32 const *)&b[7+disp];
1644 if (disp2 < (12+disp) && 0x5b==b[11+disp-disp2]) {
1645 struct b_info const *bptr = (struct b_info const *)&b[11+disp];
1646 // This is the folded stub.
1647 // FIXME: check b_method?
1648 if (bptr->sz_cpr < bptr->sz_unc && bptr->sz_unc < 0x1000) {
1649 b = bptr->sz_cpr + (unsigned char const *)(1+ bptr);
1650 // FIXME: check PackHeader::putPackHeader(), packhead.cpp
1651 overlay_offset = *(TE32 const *)(32 + b);
1652 if (overlay_offset < 0x1000) {
1653 return true; // success
1654 }
1655 overlay_offset = 0;
1656 }
1657 }
1658 }
1659 }
1660 if (391==style) {
1661 TE32 const *uptr = (TE32 const *)&buf[bufsize];
1662 while (0==*--uptr) /*empty*/ ;
1663 overlay_offset = *uptr;
1664 if (mhdri.sizeofcmds <= overlay_offset && overlay_offset < 0x1000) {
1665 return true; // success
1666 }
1667 overlay_offset = 0;
1668 return false;
1669 }
1670 if (392==style) {
1671 overlay_offset = 0x100c; // (l_info precedes;) p_info; b_info; cpr_data
1672 // p_info isn't used for execution, so it has less value for checking:
1673 // 0== .p_progid
1674 // .p_filesize == .p_blocksize
1675 fi->seek(overlay_offset, SEEK_SET);
1676 fi->readx(buf, bufsize);
1677 struct p_info const *const p_ptr = (struct p_info const *)&buf[0];
1678 struct b_info const *const b_ptr = (struct b_info const *)(1+ p_ptr);
1679 TE32 const *uptr = (TE32 const *)(1+ b_ptr);
1680 if (b_ptr->sz_unc < 0x4000
1681 && b_ptr->sz_cpr < b_ptr->sz_unc ) {
1682 unsigned const method = b_ptr->b_method;
1683 if ((M_NRV2B_LE32 == method || M_NRV2E_LE32 == method)
1684 && (0xff>>2)==(uptr[0] >> (2+ 24)) // 1st 6 bytes are unique literals
1685 && (Mach_header::MH_MAGIC + (sizeof(Addr)>>3)) == uptr[1]) {
1686 return true;
1687 }
1688 unsigned const magic = get_te32(1+ (char const *)uptr);
1689 if ((M_NRV2B_8 == method || M_NRV2E_8 == method)
1690 && 0xfc==(0xfc & uptr[0])
1691 && (Mach_header::MH_MAGIC + (sizeof(Addr)>>3)) == magic) {
1692 return true;
1693 }
1694 // FIXME: M_LZMA
1695 }
1696
1697 overlay_offset = 0;
1698 // The first non-zero word scanning backwards from __LINKEDIT.fileoff
1699 // is the total length of compressed data which precedes it
1700 //(distance to l_info), so that's another method.
1701 fi->seek(offLINK - 0x1000, SEEK_SET);
1702 fi->readx(buf, 0x1000);
1703 unsigned const *const lo = (unsigned const *)&buf[0];
1704 unsigned const *p;
1705 for (p = (unsigned const *)&buf[0x1000]; p > lo; ) if (*--p) {
1706 overlay_offset = *(TE32 const *)p;
1707 if ((off_t)overlay_offset < offLINK) {
1708 overlay_offset = ((char const *)p - (char const *)lo) +
1709 (offLINK - 0x1000) - overlay_offset + sizeof(l_info);
1710 fi->seek(overlay_offset, SEEK_SET);
1711 fi->readx(buf, bufsize);
1712 if (b_ptr->sz_unc < 0x4000
1713 && b_ptr->sz_cpr < b_ptr->sz_unc ) {
1714 return true;
1715 }
1716 }
1717 }
1718 }
1719 }
1720
1721 overlay_offset = 0; // impossible value
1722 int l = ph.buf_offset + ph.getPackHeaderSize();
1723 if (0 <= l && (unsigned)(l + sizeof(TE32)) <=bufsize) {
1724 overlay_offset = get_te32(buf + i + l);
1725 }
1726 if ( overlay_offset < sz_mach_headers
1727 || (off_t)overlay_offset >= file_size) {
1728 infoWarning("file corrupted");
1729 MemBuffer buf2(umin(1<<14, file_size));
1730 fi->seek(sz_mach_headers, SEEK_SET);
1731 fi->readx(buf2, buf2.getSize());
1732 unsigned const *p = (unsigned const *)&buf2[0];
1733 unsigned const *const e_buf2 = (unsigned const *)&buf2[buf2.getSize() - 4*sizeof(*p)];
1734 for (; p <= e_buf2; ++p)
1735 if ( 0==p[0] // p_info.p_progid
1736 && 0!=p[1] // p_info.p_filesize
1737 && p[2]==p[1] // p_info.p_blocksize == p_info.p_filesize
1738 && (unsigned)file_size < get_te32(&p[1]) // compression was worthwhile
1739 && sz_mach_headers==get_te32(&p[3]) // b_info.sz_unc
1740 ) {
1741 overlay_offset = ((char const *)p - (char const *)&buf2[0]) + sz_mach_headers;
1742 if (!(3&overlay_offset // not word aligned
1743 || overlay_offset < sz_mach_headers
1744 || (off_t)overlay_offset >= file_size)) {
1745 infoWarning("attempting recovery, overlay_offset = %#x", overlay_offset);
1746 return true;
1747 }
1748 }
1749 throwCantUnpack("file corrupted");
1750 }
1751 return true;
1752 }
1753 #define WANT_MACH_SEGMENT_ENUM
1754 #define WANT_MACH_SECTION_ENUM
1755 #include "p_mach_enum.h"
1756
1757 template <class T>
get_mod_init_func(Mach_segment_command const * segptr)1758 upx_uint64_t PackMachBase<T>::get_mod_init_func(Mach_segment_command const *segptr)
1759 {
1760 for (Mach_section_command const *secptr = (Mach_section_command const *)(1+ segptr);
1761 ptr_udiff(secptr, segptr) < segptr->cmdsize;
1762 ++secptr
1763 ) {
1764 if (sizeof(Addr) == secptr->size
1765 && !strcmp("__mod_init_func", secptr->sectname)) {
1766 o__mod_init_func = secptr->offset;
1767 fi->seek(o__mod_init_func, SEEK_SET);
1768 Addr tmp;
1769 fi->readx(&tmp, sizeof(Addr));
1770 return tmp;
1771 }
1772 }
1773 return 0;
1774 }
1775
1776 template <class T>
canPack()1777 bool PackMachBase<T>::canPack()
1778 {
1779 unsigned const lc_seg = lc_segment[sizeof(Addr)>>3];
1780 fi->seek(0, SEEK_SET);
1781 fi->readx(&mhdri, sizeof(mhdri));
1782
1783 if (((unsigned) Mach_header::MH_MAGIC + (sizeof(Addr)>>3)) !=mhdri.magic
1784 || my_cputype !=mhdri.cputype
1785 || my_filetype !=mhdri.filetype
1786 )
1787 return false;
1788 my_cpusubtype = mhdri.cpusubtype;
1789
1790 unsigned const sz_mhcmds = (unsigned)mhdri.sizeofcmds;
1791 unsigned headway = file_size - sizeof(mhdri);
1792 if (headway < sz_mhcmds) {
1793 char buf[32]; snprintf(buf, sizeof(buf), "bad sizeofcmds %d", sz_mhcmds);
1794 throwCantPack(buf);
1795 }
1796 if (16384 < sz_mhcmds) { // somewhat arbitrary, but amd64-darwin.macho-upxmain.c
1797 throwCantPack("16384 < Mach_header.sizeofcmds");
1798 }
1799 rawmseg = (Mach_segment_command *) New(char, sz_mhcmds);
1800 fi->readx(rawmseg, mhdri.sizeofcmds);
1801
1802 unsigned const ncmds = mhdri.ncmds;
1803 if (256 < ncmds) { // arbitrary, but guard against garbage
1804 throwCantPack("256 < Mach_header.ncmds");
1805 }
1806 msegcmd = New(Mach_segment_command, ncmds);
1807 unsigned char const *ptr = (unsigned char const *)rawmseg;
1808 for (unsigned j= 0; j < ncmds; ++j) {
1809 Mach_segment_command const *segptr = (Mach_segment_command const *)ptr;
1810 if (headway < ((Mach_command const *)ptr)->cmdsize) {
1811 char buf[64]; snprintf(buf, sizeof(buf),
1812 "bad Mach_command[%d]{%#x, %#x}", j,
1813 (unsigned)segptr->cmd, (unsigned)((Mach_command const *)ptr)->cmdsize);
1814 throwCantPack(buf);
1815 }
1816 headway -= ((Mach_command const *)ptr)->cmdsize;
1817 if (lc_seg == segptr->cmd) {
1818 msegcmd[j] = *segptr;
1819 if (!strcmp("__DATA", segptr->segname)) {
1820 prev_mod_init_func = get_mod_init_func(segptr);
1821 }
1822 }
1823 else {
1824 memcpy(&msegcmd[j], ptr, 2*sizeof(unsigned)); // cmd and cmdsize
1825 }
1826 switch (((Mach_uuid_command const *)ptr)->cmd) {
1827 default: break;
1828 case Mach_command::LC_UUID: {
1829 memcpy(&cmdUUID, ptr, sizeof(cmdUUID)); // remember the UUID
1830 // Set output UUID to be 1 more than the input UUID.
1831 for (unsigned k = 0; k < sizeof(cmdUUID.uuid); ++k) {
1832 if (0 != ++cmdUUID.uuid[k]) { // no Carry
1833 break;
1834 }
1835 }
1836 } break;
1837 case Mach_command::LC_VERSION_MIN_MACOSX: {
1838 memcpy(&cmdVERMIN, ptr, sizeof(cmdVERMIN));
1839 } break;
1840 case Mach_command::LC_SOURCE_VERSION: {
1841 memcpy(&cmdSRCVER, ptr, sizeof(cmdSRCVER));
1842 } break;
1843 }
1844 ptr += (unsigned) ((Mach_command const *)ptr)->cmdsize;
1845 }
1846 if (Mach_header::MH_DYLIB==my_filetype && 0==o__mod_init_func) {
1847 infoWarning("missing -init function");
1848 return false;
1849 }
1850
1851 // Put LC_SEGMENT together at the beginning
1852 qsort(msegcmd, ncmds, sizeof(*msegcmd), compare_segment_command);
1853
1854 if (lc_seg==msegcmd[0].cmd && 0==msegcmd[0].vmaddr
1855 && !strcmp("__PAGEZERO", msegcmd[0].segname)) {
1856 pagezero_vmsize = msegcmd[0].vmsize;
1857 }
1858
1859 // Check alignment of non-null LC_SEGMENT.
1860 vma_max = 0;
1861 for (unsigned j= 0; j < ncmds; ++j) {
1862 if (lc_seg==msegcmd[j].cmd) {
1863 ++n_segment;
1864 if (~PAGE_MASK & (msegcmd[j].fileoff | msegcmd[j].vmaddr)) {
1865 return false;
1866 }
1867 upx_uint64_t t = msegcmd[j].vmsize + msegcmd[j].vmaddr;
1868 if (vma_max < t) {
1869 vma_max = t;
1870 }
1871 // Segments need not be contigous {esp. "rust")
1872 sz_segment = msegcmd[j].filesize + msegcmd[j].fileoff - msegcmd[0].fileoff;
1873 }
1874 }
1875 vma_max = PAGE_MASK & (~PAGE_MASK + vma_max);
1876
1877 // info: currently the header is 36 (32+4) bytes before EOF
1878 unsigned char buf[256];
1879 fi->seek(-(off_t)sizeof(buf), SEEK_END);
1880 fi->readx(buf, sizeof(buf));
1881 checkAlreadyPacked(buf, sizeof(buf));
1882
1883 // set options
1884 opt->o_unix.blocksize = file_size;
1885 if (!n_segment) {
1886 return false;
1887 }
1888 struct {
1889 unsigned cputype;
1890 unsigned short filetype;
1891 unsigned short sz_stub_entry;
1892 unsigned short sz_stub_fold;
1893 unsigned short sz_stub_main;
1894 upx_byte const *stub_entry;
1895 upx_byte const *stub_fold;
1896 upx_byte const *stub_main;
1897 } const stub_list[] = {
1898 {CPU_TYPE_I386, MH_EXECUTE,
1899 sizeof(stub_i386_darwin_macho_entry),
1900 sizeof(stub_i386_darwin_macho_fold),
1901 sizeof(stub_i386_darwin_macho_upxmain_exe),
1902 stub_i386_darwin_macho_entry,
1903 stub_i386_darwin_macho_fold,
1904 stub_i386_darwin_macho_upxmain_exe
1905 },
1906 {CPU_TYPE_I386, MH_DYLIB,
1907 sizeof(stub_i386_darwin_dylib_entry), 0, 0,
1908 stub_i386_darwin_dylib_entry, 0, 0
1909 },
1910 {CPU_TYPE_X86_64, MH_EXECUTE,
1911 sizeof(stub_amd64_darwin_macho_entry),
1912 sizeof(stub_amd64_darwin_macho_fold),
1913 0, //sizeof(stub_amd64_darwin_macho_upxmain_exe),
1914 stub_amd64_darwin_macho_entry,
1915 stub_amd64_darwin_macho_fold,
1916 0 // stub_amd64_darwin_macho_upxmain_exe
1917 },
1918 {CPU_TYPE_X86_64, MH_DYLIB,
1919 sizeof(stub_amd64_darwin_dylib_entry), 0, 0,
1920 stub_amd64_darwin_dylib_entry, 0, 0
1921 },
1922 {CPU_TYPE_ARM, MH_EXECUTE,
1923 sizeof(stub_arm_v5a_darwin_macho_entry),
1924 sizeof(stub_arm_v5a_darwin_macho_fold),
1925 0,
1926 stub_arm_v5a_darwin_macho_entry,
1927 stub_arm_v5a_darwin_macho_fold,
1928 0
1929 },
1930 {CPU_TYPE_ARM64, MH_EXECUTE,
1931 sizeof(stub_arm64_darwin_macho_entry),
1932 sizeof(stub_arm64_darwin_macho_fold),
1933 0,
1934 stub_arm64_darwin_macho_entry,
1935 stub_arm64_darwin_macho_fold,
1936 0
1937 },
1938 {CPU_TYPE_POWERPC, MH_EXECUTE,
1939 sizeof(stub_powerpc_darwin_macho_entry),
1940 sizeof(stub_powerpc_darwin_macho_fold),
1941 sizeof(stub_powerpc_darwin_macho_upxmain_exe),
1942 stub_powerpc_darwin_macho_entry,
1943 stub_powerpc_darwin_macho_fold,
1944 stub_powerpc_darwin_macho_upxmain_exe
1945 },
1946 {CPU_TYPE_POWERPC, MH_DYLIB,
1947 sizeof(stub_powerpc_darwin_dylib_entry), 0, 0,
1948 stub_powerpc_darwin_dylib_entry, 0, 0
1949 },
1950 {CPU_TYPE_POWERPC64LE, MH_EXECUTE,
1951 sizeof(stub_powerpc64le_darwin_macho_entry),
1952 sizeof(stub_powerpc64le_darwin_macho_fold),
1953 0,
1954 stub_powerpc64le_darwin_macho_entry,
1955 stub_powerpc64le_darwin_macho_fold,
1956 0
1957 },
1958 {CPU_TYPE_POWERPC64LE, MH_DYLIB,
1959 sizeof(stub_powerpc64le_darwin_dylib_entry), 0, 0,
1960 stub_powerpc64le_darwin_dylib_entry, 0, 0
1961 },
1962 {0,0, 0,0,0, 0,0,0}
1963 };
1964 for (unsigned j = 0; stub_list[j].cputype; ++j) {
1965 if (stub_list[j].cputype == my_cputype
1966 && stub_list[j].filetype == my_filetype) {
1967 sz_stub_entry = stub_list[j].sz_stub_entry;
1968 stub_entry = stub_list[j].stub_entry;
1969 sz_stub_fold = stub_list[j].sz_stub_fold;
1970 stub_fold = stub_list[j].stub_fold;
1971 sz_stub_main = stub_list[j].sz_stub_main;
1972 stub_main = stub_list[j].stub_main;
1973 if (!stub_main) { // development stub
1974 static struct {
1975 Mach_header mhdri;
1976 Mach_segment_command segZERO;
1977 Mach_segment_command segTEXT;
1978 Mach_section_command secTEXT;
1979 Mach_segment_command segLINK;
1980 Mach_version_min_command cmdVERMIN;
1981 Mach_source_version_command cmdSRCVER;
1982 } fsm; // fake_stub_main
1983 fsm.mhdri = mhdri;
1984 fsm.mhdri.ncmds = 5;
1985 fsm.mhdri.sizeofcmds = sizeof(fsm) - sizeof(fsm.mhdri);
1986 fsm.mhdri.flags = MH_NOUNDEFS | MH_PIE;
1987
1988 fsm.segZERO.cmd = LC_SEGMENT + (fsm.mhdri.cputype >> 24)
1989 * (LC_SEGMENT_64 - LC_SEGMENT);
1990 fsm.segZERO.cmdsize = sizeof(Mach_segment_command);
1991 strncpy(fsm.segZERO.segname, "__PAGEZERO", sizeof(fsm.segZERO.segname));
1992 fsm.segZERO.vmaddr = 0;
1993 fsm.segZERO.vmsize = (4<<16);
1994 if __acc_cte(8==sizeof(void *)) fsm.segZERO.vmsize <<= (32 - 18);
1995 fsm.segZERO.fileoff = 0;
1996 fsm.segZERO.filesize = 0;
1997 fsm.segZERO.maxprot = 0;
1998 fsm.segZERO.initprot = 0;
1999 fsm.segZERO.nsects = 0;
2000 fsm.segZERO.flags = 0;
2001
2002 unsigned const slop = 400;
2003 fsm.segTEXT.cmd = fsm.segZERO.cmd;
2004 fsm.segTEXT.cmdsize = sizeof(Mach_segment_command)
2005 + sizeof(Mach_section_command);
2006 strncpy(fsm.segTEXT.segname, "__TEXT", sizeof(fsm.segTEXT.segname));
2007 fsm.segTEXT.vmaddr = fsm.segZERO.vmsize;
2008 fsm.segTEXT.vmsize = slop + threado_size() + sizeof(fsm); // dummy
2009 fsm.segTEXT.fileoff = 0;
2010 fsm.segTEXT.filesize = fsm.segTEXT.vmsize; // dummy
2011 fsm.segTEXT.maxprot = VM_PROT_EXECUTE | VM_PROT_READ;
2012 fsm.segTEXT.initprot = VM_PROT_EXECUTE | VM_PROT_READ;
2013 fsm.segTEXT.nsects = 1;
2014 fsm.segTEXT.flags = 0;
2015
2016 strncpy(fsm.secTEXT.sectname, "__text", sizeof(fsm.secTEXT.sectname));
2017 memcpy(fsm.secTEXT.segname, fsm.segTEXT.segname, sizeof(fsm.secTEXT.segname));
2018 unsigned const d = slop + fsm.mhdri.sizeofcmds;
2019 fsm.secTEXT.addr = fsm.segTEXT.vmaddr + d; // dummy
2020 fsm.secTEXT.size = fsm.segTEXT.vmsize - d; // dummy
2021 fsm.secTEXT.offset = d; // dummy
2022 fsm.secTEXT.align = 3; // (1<<2)
2023 fsm.secTEXT.reloff = 0;
2024 fsm.secTEXT.nreloc = 0;
2025 fsm.secTEXT.flags = S_REGULAR | S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SOME_INSTRUCTIONS;
2026 fsm.secTEXT.reserved1 = 0;
2027 fsm.secTEXT.reserved2 = 0;
2028
2029 fsm.segLINK = fsm.segTEXT;
2030 fsm.segLINK.cmdsize = sizeof(Mach_segment_command);
2031 strncpy(fsm.segLINK.segname, "__LINKEDIT", sizeof(fsm.segLINK.segname));
2032 fsm.segLINK.vmaddr = fsm.segTEXT.vmaddr + fsm.segTEXT.vmsize; // dummy
2033 fsm.segLINK.vmsize = 0x1000; // dummy
2034 fsm.segLINK.fileoff = fsm.segTEXT.fileoff + fsm.segTEXT.filesize;
2035 fsm.segLINK.filesize = fsm.segLINK.vmsize;
2036 fsm.segLINK.maxprot = VM_PROT_READ;
2037 fsm.segLINK.initprot = VM_PROT_READ;
2038 fsm.segLINK.nsects = 0;
2039
2040 fsm.cmdVERMIN.cmd = LC_VERSION_MIN_MACOSX; // LC_VERSION_MIN_IPHONEOS
2041 fsm.cmdVERMIN.cmdsize = 4*4;
2042 fsm.cmdVERMIN.version = (10<<16)|(12<<8);
2043 fsm.cmdVERMIN.sdk = fsm.cmdVERMIN.version;
2044
2045 fsm.cmdSRCVER.cmd = LC_SOURCE_VERSION;
2046 fsm.cmdSRCVER.cmdsize = 4*4;
2047 fsm.cmdSRCVER.version = 0;
2048 fsm.cmdSRCVER.__pad = 0;
2049
2050 sz_stub_main = sizeof(fsm);
2051 stub_main = (unsigned char const *)&fsm;
2052 }
2053 break;
2054 }
2055 }
2056 return true;
2057 }
2058
2059 template class PackMachBase<MachClass_BE32>;
2060 template class PackMachBase<MachClass_LE32>;
2061 template class PackMachBase<MachClass_LE64>;
2062
2063
PackMachFat(InputFile * f)2064 PackMachFat::PackMachFat(InputFile *f) : super(f)
2065 {
2066 bele = &N_BELE_RTP::le_policy; // sham
2067 }
2068
~PackMachFat()2069 PackMachFat::~PackMachFat()
2070 {
2071 }
2072
check_fat_head()2073 unsigned PackMachFat::check_fat_head()
2074 {
2075 struct Mach_fat_arch const *const arch = &fat_head.arch[0];
2076 unsigned nfat = fat_head.fat.nfat_arch;
2077 if (Mach_fat_header::FAT_MAGIC!=fat_head.fat.magic
2078 || N_FAT_ARCH < nfat) {
2079 return 0;
2080 }
2081 for (unsigned j=0; j < nfat; ++j) {
2082 unsigned const align = arch[j].align;
2083 unsigned const mask = ~(~0u<<align);
2084 unsigned const size = arch[j].size;
2085 unsigned const offset = arch[j].offset;
2086 if (align < 12 || align > 24) { // heuristic
2087 throwUnknownExecutableFormat("align", 0);
2088 }
2089 if (mask > size) {
2090 throwUnknownExecutableFormat("size", 0);
2091 }
2092 if (mask & offset
2093 || (unsigned)fi->st_size_orig() < size + offset
2094 || (unsigned)fi->st_size_orig() <= offset) { // redundant unless overflow
2095 throwUnknownExecutableFormat("offset", 0);
2096 }
2097 }
2098 return nfat;
2099 }
2100
getCompressionMethods(int,int) const2101 const int *PackMachFat::getCompressionMethods(int /*method*/, int /*level*/) const
2102 {
2103 static const int m_nrv2e[] = { M_NRV2E_LE32, M_END };
2104 return m_nrv2e; // sham
2105 }
2106
getFilters() const2107 const int *PackMachFat::getFilters() const
2108 {
2109 static const int filters[] = { 0x49, FT_END };
2110 return filters; // sham
2111 }
2112
pack(OutputFile * fo)2113 void PackMachFat::pack(OutputFile *fo)
2114 {
2115 unsigned const in_size = this->file_size;
2116 fo->write(&fat_head, sizeof(fat_head.fat) +
2117 fat_head.fat.nfat_arch * sizeof(fat_head.arch[0]));
2118 unsigned length = 0;
2119 for (unsigned j=0; j < fat_head.fat.nfat_arch; ++j) {
2120 unsigned base = fo->unset_extent(); // actual length
2121 base += ~(~0u<<fat_head.arch[j].align) & (0-base); // align up
2122 fo->seek(base, SEEK_SET);
2123 fo->set_extent(base, ~0u);
2124
2125 ph.u_file_size = fat_head.arch[j].size;
2126 fi->set_extent(fat_head.arch[j].offset, fat_head.arch[j].size);
2127 fi->seek(0, SEEK_SET);
2128 switch (fat_head.arch[j].cputype) {
2129 case PackMachFat::CPU_TYPE_I386: {
2130 typedef N_Mach::Mach_header<MachClass_LE32::MachITypes> Mach_header;
2131 Mach_header hdr;
2132 fi->readx(&hdr, sizeof(hdr));
2133 if (hdr.filetype==Mach_header::MH_EXECUTE) {
2134 PackMachI386 packer(fi);
2135 packer.initPackHeader();
2136 packer.canPack();
2137 packer.updatePackHeader();
2138 packer.pack(fo);
2139 }
2140 else if (hdr.filetype==Mach_header::MH_DYLIB) {
2141 PackDylibI386 packer(fi);
2142 packer.initPackHeader();
2143 packer.canPack();
2144 packer.updatePackHeader();
2145 packer.pack(fo);
2146 }
2147 } break;
2148 case PackMachFat::CPU_TYPE_X86_64: {
2149 typedef N_Mach::Mach_header<MachClass_LE64::MachITypes> Mach_header;
2150 Mach_header hdr;
2151 fi->readx(&hdr, sizeof(hdr));
2152 if (hdr.filetype==Mach_header::MH_EXECUTE) {
2153 PackMachAMD64 packer(fi);
2154 packer.initPackHeader();
2155 packer.canPack();
2156 packer.updatePackHeader();
2157 packer.pack(fo);
2158 }
2159 else if (hdr.filetype==Mach_header::MH_DYLIB) {
2160 PackDylibAMD64 packer(fi);
2161 packer.initPackHeader();
2162 packer.canPack();
2163 packer.updatePackHeader();
2164 packer.pack(fo);
2165 }
2166 } break;
2167 case PackMachFat::CPU_TYPE_POWERPC: {
2168 typedef N_Mach::Mach_header<MachClass_BE32::MachITypes> Mach_header;
2169 Mach_header hdr;
2170 fi->readx(&hdr, sizeof(hdr));
2171 if (hdr.filetype==Mach_header::MH_EXECUTE) {
2172 PackMachPPC32 packer(fi);
2173 packer.initPackHeader();
2174 packer.canPack();
2175 packer.updatePackHeader();
2176 packer.pack(fo);
2177 }
2178 else if (hdr.filetype==Mach_header::MH_DYLIB) {
2179 PackDylibPPC32 packer(fi);
2180 packer.initPackHeader();
2181 packer.canPack();
2182 packer.updatePackHeader();
2183 packer.pack(fo);
2184 }
2185 } break;
2186 case PackMachFat::CPU_TYPE_POWERPC64LE: {
2187 typedef N_Mach::Mach_header<MachClass_LE64::MachITypes> Mach_header;
2188 Mach_header hdr;
2189 fi->readx(&hdr, sizeof(hdr));
2190 if (hdr.filetype==Mach_header::MH_EXECUTE) {
2191 PackMachPPC64LE packer(fi);
2192 packer.initPackHeader();
2193 packer.canPack();
2194 packer.updatePackHeader();
2195 packer.pack(fo);
2196 }
2197 else if (hdr.filetype==Mach_header::MH_DYLIB) {
2198 PackDylibPPC64LE packer(fi);
2199 packer.initPackHeader();
2200 packer.canPack();
2201 packer.updatePackHeader();
2202 packer.pack(fo);
2203 }
2204 } break;
2205 } // switch cputype
2206 fat_head.arch[j].offset = base;
2207 length = fo->unset_extent();
2208 fat_head.arch[j].size = length - base;
2209 }
2210 ph.u_file_size = in_size;
2211 fi->set_extent(0, in_size);
2212
2213 fo->seek(0, SEEK_SET);
2214 fo->rewrite(&fat_head, sizeof(fat_head.fat) +
2215 fat_head.fat.nfat_arch * sizeof(fat_head.arch[0]));
2216 fo->set_extent(0, length);
2217 }
2218
unpack(OutputFile * fo)2219 void PackMachFat::unpack(OutputFile *fo)
2220 {
2221 if (fo) { // test mode ("-t") sets fo = NULL
2222 fo->seek(0, SEEK_SET);
2223 fo->write(&fat_head, sizeof(fat_head.fat) +
2224 fat_head.fat.nfat_arch * sizeof(fat_head.arch[0]));
2225 }
2226 unsigned const nfat = check_fat_head();
2227 unsigned length;
2228 for (unsigned j=0; j < nfat; ++j) {
2229 unsigned base = (fo ? fo->unset_extent() : 0); // actual length
2230 base += ~(~0u<<fat_head.arch[j].align) & (0-base); // align up
2231 if (fo) {
2232 fo->seek(base, SEEK_SET);
2233 fo->set_extent(base, ~0u);
2234 }
2235
2236 ph.u_file_size = fat_head.arch[j].size;
2237 fi->set_extent(fat_head.arch[j].offset, fat_head.arch[j].size);
2238 fi->seek(0, SEEK_SET);
2239 switch (fat_head.arch[j].cputype) {
2240 case PackMachFat::CPU_TYPE_I386: {
2241 N_Mach::Mach_header<MachClass_LE32::MachITypes> hdr;
2242 typedef N_Mach::Mach_header<MachClass_LE32::MachITypes> Mach_header;
2243 fi->readx(&hdr, sizeof(hdr));
2244 if (hdr.filetype==Mach_header::MH_EXECUTE) {
2245 PackMachI386 packer(fi);
2246 packer.initPackHeader();
2247 packer.canUnpack();
2248 packer.unpack(fo);
2249 }
2250 else if (hdr.filetype==Mach_header::MH_DYLIB) {
2251 PackDylibI386 packer(fi);
2252 packer.initPackHeader();
2253 packer.canUnpack();
2254 packer.unpack(fo);
2255 }
2256 } break;
2257 case PackMachFat::CPU_TYPE_X86_64: {
2258 N_Mach::Mach_header<MachClass_LE64::MachITypes> hdr;
2259 typedef N_Mach::Mach_header<MachClass_LE64::MachITypes> Mach_header;
2260 fi->readx(&hdr, sizeof(hdr));
2261 if (hdr.filetype==Mach_header::MH_EXECUTE) {
2262 PackMachAMD64 packer(fi);
2263 packer.initPackHeader();
2264 packer.canUnpack();
2265 packer.unpack(fo);
2266 }
2267 else if (hdr.filetype==Mach_header::MH_DYLIB) {
2268 PackDylibAMD64 packer(fi);
2269 packer.initPackHeader();
2270 packer.canUnpack();
2271 packer.unpack(fo);
2272 }
2273 } break;
2274 case PackMachFat::CPU_TYPE_POWERPC: {
2275 N_Mach::Mach_header<MachClass_BE32::MachITypes> hdr;
2276 typedef N_Mach::Mach_header<MachClass_BE32::MachITypes> Mach_header;
2277 fi->readx(&hdr, sizeof(hdr));
2278 if (hdr.filetype==Mach_header::MH_EXECUTE) {
2279 PackMachPPC32 packer(fi);
2280 packer.initPackHeader();
2281 packer.canUnpack();
2282 packer.unpack(fo);
2283 }
2284 else if (hdr.filetype==Mach_header::MH_DYLIB) {
2285 PackDylibPPC32 packer(fi);
2286 packer.initPackHeader();
2287 packer.canUnpack();
2288 packer.unpack(fo);
2289 }
2290 } break;
2291 case PackMachFat::CPU_TYPE_POWERPC64LE: {
2292 N_Mach::Mach_header<MachClass_LE64::MachITypes> hdr;
2293 typedef N_Mach::Mach_header<MachClass_LE64::MachITypes> Mach_header;
2294 fi->readx(&hdr, sizeof(hdr));
2295 if (hdr.filetype==Mach_header::MH_EXECUTE) {
2296 PackMachPPC64LE packer(fi);
2297 packer.initPackHeader();
2298 packer.canUnpack();
2299 packer.unpack(fo);
2300 }
2301 else if (hdr.filetype==Mach_header::MH_DYLIB) {
2302 PackDylibPPC64LE packer(fi);
2303 packer.initPackHeader();
2304 packer.canUnpack();
2305 packer.unpack(fo);
2306 }
2307 } break;
2308 } // switch cputype
2309 fat_head.arch[j].offset = base;
2310 length = (fo ? fo->unset_extent() : 0);
2311 fat_head.arch[j].size = length - base;
2312 }
2313 if (fo) {
2314 fo->unset_extent();
2315 fo->seek(0, SEEK_SET);
2316 fo->rewrite(&fat_head, sizeof(fat_head.fat) +
2317 fat_head.fat.nfat_arch * sizeof(fat_head.arch[0]));
2318 }
2319 }
2320
canPack()2321 bool PackMachFat::canPack()
2322 {
2323 struct Mach_fat_arch const *const arch = &fat_head.arch[0];
2324
2325 fi->readx(&fat_head, sizeof(fat_head));
2326 unsigned const nfat = check_fat_head();
2327 if (0==nfat)
2328 return false;
2329 for (unsigned j=0; j < nfat; ++j) {
2330 fi->set_extent(arch[j].offset, arch[j].size);
2331 fi->seek(0, SEEK_SET);
2332 switch (arch[j].cputype) {
2333 default:
2334 infoWarning("unknown cputype 0x%x: %s",
2335 (unsigned)arch[j].cputype, fi->getName());
2336 return false;
2337 case PackMachFat::CPU_TYPE_I386: {
2338 PackMachI386 packer(fi);
2339 if (!packer.canPack()) {
2340 PackDylibI386 pack2r(fi);
2341 if (!pack2r.canPack())
2342 return false;
2343 }
2344 } break;
2345 case PackMachFat::CPU_TYPE_X86_64: {
2346 PackMachAMD64 packer(fi);
2347 if (!packer.canPack()) {
2348 PackDylibI386 pack2r(fi);
2349 if (!pack2r.canPack())
2350 return false;
2351 }
2352 } break;
2353 case PackMachFat::CPU_TYPE_POWERPC: {
2354 PackMachPPC32 packer(fi);
2355 if (!packer.canPack()) {
2356 PackDylibPPC32 pack2r(fi);
2357 if (!pack2r.canPack())
2358 return false;
2359 }
2360 } break;
2361 case PackMachFat::CPU_TYPE_POWERPC64LE: {
2362 PackMachPPC64LE packer(fi);
2363 if (!packer.canPack()) {
2364 PackDylibPPC64LE pack2r(fi);
2365 if (!pack2r.canPack())
2366 return false;
2367 }
2368 } break;
2369 } // switch cputype
2370 }
2371
2372 // info: currently the header is 36 (32+4) bytes before EOF
2373 unsigned char buf[256];
2374 fi->seek(-(off_t)sizeof(buf), SEEK_END);
2375 fi->readx(buf, sizeof(buf));
2376 checkAlreadyPacked(buf, sizeof(buf));
2377
2378 return true;
2379 }
2380
canUnpack()2381 int PackMachFat::canUnpack()
2382 {
2383 struct Mach_fat_arch const *const arch = &fat_head.arch[0];
2384
2385 fi->readx(&fat_head, sizeof(fat_head));
2386 unsigned const nfat = check_fat_head();
2387 if (0 == nfat) {
2388 return false;
2389 }
2390 for (unsigned j=0; j < nfat; ++j) {
2391 fi->set_extent(arch[j].offset, arch[j].size);
2392 fi->seek(0, SEEK_SET);
2393 switch (arch[j].cputype) {
2394 default: return false;
2395 case PackMachFat::CPU_TYPE_I386: {
2396 PackMachI386 packer(fi);
2397 if (!packer.canUnpack()) {
2398 PackDylibI386 pack2r(fi);
2399 if (!pack2r.canUnpack())
2400 return 0;
2401 else
2402 ph.format = pack2r.getFormat(); // FIXME: copy entire PackHeader
2403 }
2404 else
2405 ph.format = packer.getFormat(); // FIXME: copy entire PackHeader
2406 } break;
2407 case PackMachFat::CPU_TYPE_X86_64: {
2408 PackMachAMD64 packer(fi);
2409 if (!packer.canUnpack()) {
2410 PackDylibAMD64 pack2r(fi);
2411 if (!pack2r.canUnpack())
2412 return 0;
2413 else
2414 ph.format = pack2r.getFormat(); // FIXME: copy entire PackHeader
2415 }
2416 else
2417 ph.format = packer.getFormat(); // FIXME: copy entire PackHeader
2418 } break;
2419 case PackMachFat::CPU_TYPE_POWERPC: {
2420 PackMachPPC32 packer(fi);
2421 if (!packer.canUnpack()) {
2422 PackDylibPPC32 pack2r(fi);
2423 if (!pack2r.canUnpack())
2424 return 0;
2425 else
2426 ph.format = pack2r.getFormat(); // FIXME: copy entire PackHeader
2427 }
2428 else
2429 ph.format = packer.getFormat(); // FIXME: copy entire PackHeader
2430 } break;
2431 case PackMachFat::CPU_TYPE_POWERPC64LE: {
2432 PackMachPPC64LE packer(fi);
2433 if (!packer.canUnpack()) {
2434 PackDylibPPC64LE pack2r(fi);
2435 if (!pack2r.canUnpack())
2436 return 0;
2437 else
2438 ph.format = pack2r.getFormat(); // FIXME: copy entire PackHeader
2439 }
2440 else
2441 ph.format = packer.getFormat(); // FIXME: copy entire PackHeader
2442 } break;
2443 } // switch cputype
2444 }
2445 return 1;
2446 }
2447
buildLoader(const Filter *)2448 void PackMachFat::buildLoader(const Filter * /*ft*/)
2449 {
2450 assert(false);
2451 }
2452
newLinker() const2453 Linker* PackMachFat::newLinker() const
2454 {
2455 return new ElfLinkerX86; // sham
2456 }
2457
list()2458 void PackMachFat::list()
2459 {
2460 assert(false);
2461 }
2462
2463 /* vim:set ts=4 sw=4 et: */
2464