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