From 00b1ff1ff6ea91e37daacac2db881ea03eb65a4c Mon Sep 17 00:00:00 2001 From: John Reiser Date: Sat, 1 Oct 2016 17:40:32 -0700 Subject: [PATCH] Apple codesign now works. modified: p_mach.cpp --- src/p_mach.cpp | 229 +++++++++++++++++++++++-------------------------- 1 file changed, 105 insertions(+), 124 deletions(-) diff --git a/src/p_mach.cpp b/src/p_mach.cpp index e4302aa1..5f103b91 100644 --- a/src/p_mach.cpp +++ b/src/p_mach.cpp @@ -805,48 +805,38 @@ void PackMachAMD64::pack4(OutputFile *fo, Filter &ft) // append PackHeader unsigned char upxstub[sizeof(stub_amd64_darwin_macho_upxmain_exe)]; memcpy(upxstub, stub_amd64_darwin_macho_upxmain_exe, sizeof(upxstub)); - Mach_header *const ptr0 = (Mach_header *)upxstub; - Mach_command *ptr1 = (Mach_command *)(1+ ptr0); - unsigned cmdsize = mhdro.sizeofcmds - sizeof(segXHDR); + Mach_header *const mhp = (Mach_header *)upxstub; + char *tail = (char *)(1+ mhp); + char *const lcp_end = mhdro.sizeofcmds + tail; + Mach_command *lcp = (Mach_command *)(1+ mhp); + Mach_command *lcp_next; unsigned const ncmds = mhdro.ncmds; + //unsigned cmdsize = mhdro.sizeofcmds; unsigned delta = 0; - for (unsigned j = 0; j < ncmds -1; ++j, - (cmdsize -= ptr1->cmdsize), - ptr1 = (Mach_command *)(ptr1->cmdsize + (char *)ptr1)) -next: - switch (ptr1->cmd) { + + for (unsigned j = 0; j < ncmds; ++j) { + unsigned skip = 0; + unsigned sz_cmd = lcp->cmdsize; + lcp_next = (Mach_command *)(sz_cmd + (char *)lcp); + + switch (lcp->cmd) { case Mach_segment_command::LC_SEGMENT_64: { - Mach_segment_command const *const segptr = (Mach_segment_command const *)ptr1; + Mach_segment_command *const segptr = (Mach_segment_command *)lcp; if (!strcmp("__TEXT", segptr->segname)) { + if (0) { // Why is codesign unhappy with this? + int const d = (-1+ segptr->nsects) * sizeof(secTEXT); + if (0 < d) { + segptr->nsects = 1; + segptr->cmdsize -= d; + sz_cmd -= d; + } + } memcpy(&segTEXT, segptr, sizeof(segTEXT)); Mach_section_command const *const secptr = (Mach_section_command const *)(1+ segptr); memcpy(&secTEXT, secptr, sizeof(secTEXT)); - // // Put f_unf and f_exp before compiled C code: - // // steal space from -Wl,-headerpadsize - //secTEXT.align = 0; - //unsigned const d = getLoaderSize(); - //secTEXT.addr -= d; - //secTEXT.size += d; - //secTEXT.offset -= d; - fo->seek((char const *)secptr - (char const *)ptr0, SEEK_SET); - fo->rewrite(&secTEXT, sizeof(secTEXT)); - //fo->seek(secTEXT.offset, SEEK_SET); - //fo->rewrite(getLoader(), d); - fo->seek(0, SEEK_END); + break; } if (!strcmp("__DATA", segptr->segname) && !segptr->vmsize) { - goto omit; - } - if (!strcmp("__LINKEDIT", segptr->segname)) { - segLINK.initprot = Mach_segment_command::VM_PROT_READ - | Mach_segment_command::VM_PROT_EXECUTE; - delta = offLINK - segptr->fileoff; // relocation constant - - //// The contents for __LINKEDIT remain the same, - //// but move to a different offset in the file - //fo->seek(offLINK, SEEK_SET); - //fo->write(&stub_amd64_darwin_macho_upxmain_exe[segLINK.fileoff], segLINK.filesize); - // Mach_segment_command for new segXHDR segXHDR.cmdsize = sizeof(segXHDR); // no need for sections segXHDR.vmaddr = segTEXT.vmsize + segTEXT.vmaddr; // XXX FIXME @@ -855,62 +845,66 @@ next: segXHDR.filesize = offLINK - segTEXT.filesize; // XXX FIXME: assumes no __DATA in stub; segXHDR.maxprot = Mach_segment_command::VM_PROT_READ; segXHDR.nsects = 0; - fo->seek((char const *)ptr1 - (char const *)ptr0, SEEK_SET); - fo->rewrite(&segXHDR, sizeof(segXHDR)); + memcpy(tail, &segXHDR, sizeof(segXHDR)); + tail += sizeof(segXHDR); + goto next; + } + if (!strcmp("__LINKEDIT", segptr->segname)) { + segLINK.initprot = Mach_segment_command::VM_PROT_READ + | Mach_segment_command::VM_PROT_EXECUTE; + delta = offLINK - segptr->fileoff; // relocation constant // Update the __LINKEDIT header segLINK.filesize = eofcmpr - offLINK; segLINK.vmsize = PAGE_MASK64 & (~PAGE_MASK64 + eofcmpr - offLINK); segLINK.fileoff = segXHDR.filesize + segXHDR.fileoff; segLINK.vmaddr = segXHDR.vmsize + segXHDR.vmaddr; - fo->rewrite(&segLINK, sizeof(segLINK)); + memcpy(tail, &segLINK, sizeof(segLINK)); + tail += sizeof(segLINK); + goto next; } } break; case Mach_segment_command::LC_DYLD_INFO_ONLY: { - N_Mach::Mach_dyld_info_only_command blk; memcpy(&blk, ptr1, sizeof(blk)); - if (blk.rebase_off) blk.rebase_off += delta; - if (blk.bind_off) blk.bind_off += delta; - if (blk.lazy_bind_off) blk.lazy_bind_off += delta; - if (blk.export_off) blk.export_off += delta; + N_Mach::Mach_dyld_info_only_command *p = (N_Mach::Mach_dyld_info_only_command *)lcp; + if (p->rebase_off) p->rebase_off += delta; + if (p->bind_off) p->bind_off += delta; + if (p->lazy_bind_off) p->lazy_bind_off += delta; + if (p->export_off) p->export_off += delta; // But we don't want any exported symbols. - blk.export_off = 0; - blk.export_size = 0; - fo->seek(sizeof(segXHDR) + ((char const *)ptr1 - (char const *)ptr0), SEEK_SET); - fo->rewrite(&blk, sizeof(blk)); - goto omit; // try omitting this + p->export_off = 0; + p->export_size = 0; + skip = 1; } break; case Mach_segment_command::LC_SYMTAB: { - Mach_symtab_command blk; memcpy(&blk, ptr1, sizeof(blk)); - if (blk.symoff) blk.symoff += delta; - if (blk.stroff) blk.stroff += delta; - fo->seek(sizeof(segXHDR) + ((char const *)ptr1 - (char const *)ptr0), SEEK_SET); - fo->rewrite(&blk, sizeof(blk)); - goto omit; // try omitting this + // Apple codesign requires that string table is last in the file. + Mach_symtab_command *p = (Mach_symtab_command *)lcp; + p->symoff = segLINK.filesize + segLINK.fileoff; + p->nsyms = 0; + p->stroff = segLINK.fileoff; + p->strsize = segLINK.filesize; + skip = 1; } break; case Mach_segment_command::LC_DYSYMTAB: { - Mach_dysymtab_command blk; memcpy(&blk, ptr1, sizeof(blk)); - if (blk.tocoff) blk.tocoff += delta; - if (blk.modtaboff) blk.modtaboff += delta; - if (blk.extrefsymoff) blk.extrefsymoff += delta; - if (blk.indirectsymoff) blk.indirectsymoff += delta; - if (blk.extreloff) blk.extreloff += delta; - if (blk.locreloff) blk.locreloff += delta; + Mach_dysymtab_command *p = (Mach_dysymtab_command *)lcp; + if (p->tocoff) p->tocoff += delta; + if (p->modtaboff) p->modtaboff += delta; + if (p->extrefsymoff) p->extrefsymoff += delta; + if (p->indirectsymoff) p->indirectsymoff += delta; + if (p->extreloff) p->extreloff += delta; + if (p->locreloff) p->locreloff += delta; // But we don't want any symbols. - blk.ilocalsym = 0; - blk.nlocalsym = 0; - blk.iextdefsym = 0; - blk.nextdefsym = 0; - blk.iundefsym = 0; - blk.nundefsym = 0; - fo->seek(sizeof(segXHDR) + ((char const *)ptr1 - (char const *)ptr0), SEEK_SET); - fo->rewrite(&blk, sizeof(blk)); - goto omit; // adds full path as another agrument? + p->ilocalsym = 0; + p->nlocalsym = 0; + p->iextdefsym = 0; + p->nextdefsym = 0; + p->iundefsym = 0; + p->nundefsym = 0; + skip = 1; } break; case Mach_segment_command::LC_FUNCTION_STARTS: { - N_Mach::Mach_function_starts_command blk; memcpy(&blk, ptr1, sizeof(blk)); - if (blk.dataoff) blk.dataoff += delta; - fo->seek(sizeof(segXHDR) + ((char const *)ptr1 - (char const *)ptr0), SEEK_SET); - fo->rewrite(&blk, sizeof(blk)); + N_Mach::Mach_function_starts_command *p = (N_Mach::Mach_function_starts_command *)lcp; + if (p->dataoff) p->dataoff += delta; + skip = 1; } break; case Mach_segment_command::LC_MAIN: { // Change to LC_UNIX_THREAD; known to be contiguous with last @@ -921,69 +915,56 @@ next: threado.flavor = my_thread_flavor; threado.count = my_thread_state_word_count; memset(&threado.state, 0, sizeof(threado.state)); - threado.state.rip = ((N_Mach::Mach_main_command const *)ptr1)->entryoff + segTEXT.vmaddr; - fo->seek(sizeof(segXHDR) + ((char const *)ptr1 - (char const *)ptr0), SEEK_SET); - fo->rewrite(&threado, sizeof(threado)); - mhdro.sizeofcmds += sizeof(threado) - ((Mach_command const *)ptr1)->cmdsize; - fo->seek(0, SEEK_SET); - fo->rewrite(&mhdro, sizeof(mhdro)); + threado.state.rip = ((N_Mach::Mach_main_command const *)lcp)->entryoff + segTEXT.vmaddr; + skip = 1; } break; case Mach_segment_command::LC_LOAD_DYLIB: { - // Remove this command; known to be contiguous with last - N_Mach::Mach_load_dylib_command blk; memset(&blk, 0, sizeof(blk)); - fo->seek(sizeof(segXHDR) + ((char const *)ptr1 - (char const *)ptr0), SEEK_SET); - fo->rewrite(&blk, sizeof(blk)); - mhdro.ncmds -= 1; - mhdro.sizeofcmds -= ((Mach_command const *)ptr1)->cmdsize; - fo->seek(0, SEEK_SET); - fo->rewrite(&mhdro, sizeof(mhdro)); + skip = 1; } break; case Mach_segment_command::LC_DATA_IN_CODE: { - N_Mach::Mach_data_in_code_command blk; memcpy(&blk, ptr1, sizeof(blk)); - if (blk.dataoff) blk.dataoff += delta; - memset(&blk, 0, sizeof(blk)); - fo->seek(sizeof(segXHDR) + ((char const *)ptr1 - (char const *)ptr0), SEEK_SET); - fo->rewrite(&blk, sizeof(blk)); - // Temporary test: remove this command; known to be last - mhdro.ncmds -= 1; - mhdro.sizeofcmds -= ((Mach_command const *)ptr1)->cmdsize; - fo->seek(0, SEEK_SET); - fo->rewrite(&mhdro, sizeof(mhdro)); + N_Mach::Mach_data_in_code_command *p = (N_Mach::Mach_data_in_code_command *)lcp; + if (p->dataoff) p->dataoff += delta; + skip = 1; } break; case Mach_segment_command::LC_LOAD_DYLINKER: { - // Try omitting this -omit: - fo->seek(sizeof(mhdro) + mhdro.sizeofcmds - cmdsize, SEEK_SET); - Mach_command *ptr2 = ptr1; - unsigned const sz_omit = ptr1->cmdsize; - ptr1 = (Mach_command *)(sz_omit + (char *)ptr1); - cmdsize -= sz_omit; - - fo->rewrite(ptr1, cmdsize); // slide in file TODO: clear the garbage - memmove(ptr2, ptr1, cmdsize); // overlapping slide lower - ptr1 = ptr2; - - mhdro.ncmds -= 1; - mhdro.sizeofcmds -= sz_omit; - fo->seek(0, SEEK_SET); - fo->rewrite(&mhdro, sizeof(mhdro)); - if (++j < (ncmds -1)) - goto next; - goto done; + skip = 1; } break; case Mach_segment_command::LC_SOURCE_VERSION: { // copy from saved original - fo->seek(sizeof(segXHDR) + ((char const *)ptr1 - (char const *)ptr0), SEEK_SET); - fo->rewrite(&cmdSRCVER, sizeof(cmdSRCVER)); - memcpy(ptr1, &cmdSRCVER, sizeof(cmdSRCVER)); - goto omit; + memcpy(lcp, &cmdSRCVER, sizeof(cmdSRCVER)); } break; case Mach_segment_command::LC_VERSION_MIN_MACOSX: { // copy from saved original - fo->seek(sizeof(segXHDR) + ((char const *)ptr1 - (char const *)ptr0), SEEK_SET); - fo->rewrite(&cmdVERMIN, sizeof(cmdVERMIN)); - memcpy(ptr1, &cmdVERMIN, sizeof(cmdVERMIN)); + memcpy(lcp, &cmdVERMIN, sizeof(cmdVERMIN)); } break; } // end switch -done: + + if (skip) { + mhp->ncmds -= 1; + mhp->sizeofcmds -= sz_cmd; + } + else { + if (tail != (char *)lcp) { + memmove(tail, lcp, sz_cmd); + } + tail += sz_cmd; + } +next: + lcp = lcp_next; + } // end for + + // Add LC_UNIX_THREAD + mhp->ncmds += 1; + mhp->sizeofcmds += sizeof(threado); + fo->seek(0, SEEK_SET); + fo->rewrite(mhp, tail - (char *)mhp); + fo->rewrite(&threado, sizeof(threado)); + tail += sizeof(threado); + // + // Zero any remaining tail. + if (tail < lcp_end) { + unsigned sz_cmd = lcp_end - tail; + memset(tail, 0, sz_cmd); + fo->rewrite(tail, sz_cmd); + } fo->seek(0, SEEK_END); } } @@ -2022,7 +2003,7 @@ int PackMachBase::canUnpack() if (i < 1 || !getPackHeader(buf + i, bufsize - i, true)) { // Breadcrumbs failed. // Pirates might overwrite the UPX! marker. Try harder. - upx_uint64_t const rip_off = rip - ptrTEXT->vmaddr; + upx_uint64_t const rip_off = ptrTEXT ? (rip - ptrTEXT->vmaddr) : 0; if (ptrTEXT && rip && rip_off < ptrTEXT->vmsize) { fi->seek(ptrTEXT->fileoff + rip_off, SEEK_SET); fi->readx(buf, bufsize);