📄 p_mach.cpp
字号:
/* p_mach.cpp -- pack Mach Object executable This file is part of the UPX executable compressor. Copyright (C) 2004-2007 John Reiser All Rights Reserved. UPX and the UCL library are free software; you can redistribute them and/or modify them under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. John Reiser jreiser@users.sourceforge.net */#include "conf.h"#include "file.h"#include "filter.h"#include "linker.h"#include "packer.h"#include "p_mach.h"#include "ui.h"static const#include "stub/powerpc-darwin.macho-entry.h"static const#include "stub/powerpc-darwin.macho-fold.h"static const#include "stub/i386-darwin.macho-entry.h"static const#include "stub/i386-darwin.macho-fold.h"template <class T>PackMachBase<T>::PackMachBase(InputFile *f, unsigned cputype, unsigned flavor, unsigned count, unsigned size) : super(f), my_cputype(cputype), my_thread_flavor(flavor), my_thread_state_word_count(count), my_thread_command_size(size), n_segment(0), rawmseg(NULL), msegcmd(NULL){ MachClass::compileTimeAssertions(); bele = N_BELE_CTP::getRTP<BeLePolicy>();}template <class T>PackMachBase<T>::~PackMachBase(){ delete [] rawmseg; delete [] msegcmd;}template <class T>const int *PackMachBase<T>::getCompressionMethods(int method, int level) const{ // There really is no LE bias. return Packer::getDefaultCompressionMethods_le32(method, level);}const int *PackMachPPC32::getFilters() const{ static const int filters[] = { 0xd0, FT_END }; return filters;}int const *PackMachI386::getFilters() const{ static const int filters[] = { 0x49, FT_END }; return filters;}Linker *PackMachPPC32::newLinker() const{ return new ElfLinkerPpc32;}Linker *PackMachI386::newLinker() const{ return new ElfLinkerX86;}template <class T>voidPackMachBase<T>::addStubEntrySections(Filter const *){ addLoader("MACOS000", NULL); //addLoader(getDecompressorSections(), NULL); addLoader( ( M_IS_NRV2E(ph.method) ? "NRV_HEAD,NRV2E,NRV_TAIL" : M_IS_NRV2D(ph.method) ? "NRV_HEAD,NRV2D,NRV_TAIL" : M_IS_NRV2B(ph.method) ? "NRV_HEAD,NRV2B,NRV_TAIL" : M_IS_LZMA(ph.method) ? "LZMA_ELF00,LZMA_DEC20,LZMA_DEC30" : NULL), NULL); addLoader("ELFMAINY,IDENTSTR,+40,ELFMAINZ,FOLDEXEC", NULL);}void PackMachI386::addStubEntrySections(Filter const *ft){ int const n_mru = ft->n_mru; // FIXME: belongs to filter? packerf? // entry to stub addLoader("LEXEC000", NULL); if (ft->id) { { // decompr, unfilter are separate addLoader("LXUNF000", NULL); addLoader("LXUNF002", NULL); if (0x80==(ft->id & 0xF0)) { if (256==n_mru) { addLoader("MRUBYTE0", NULL); } else if (n_mru) { addLoader("LXMRU005", NULL); } if (n_mru) { addLoader("LXMRU006", NULL); } else { addLoader("LXMRU007", NULL); } } else if (0x40==(ft->id & 0xF0)) { addLoader("LXUNF008", NULL); } addLoader("LXUNF010", NULL); } if (n_mru) { addLoader("LEXEC009", NULL); } } addLoader("LEXEC010", NULL); addLoader(getDecompressorSections(), NULL); addLoader("LEXEC015", NULL); if (ft->id) { { // decompr, unfilter are separate if (0x80!=(ft->id & 0xF0)) { addLoader("LXUNF042", NULL); } } addFilter32(ft->id); { // decompr, unfilter are separate if (0x80==(ft->id & 0xF0)) { if (0==n_mru) { addLoader("LXMRU058", NULL); } } addLoader("LXUNF035", NULL); } } else { addLoader("LEXEC017", NULL); } addLoader("IDENTSTR", NULL); addLoader("LEXEC020", NULL); addLoader("FOLDEXEC", NULL);}template <class T>void PackMachBase<T>::defineSymbols(Filter const *){ // empty}template <class T>voidPackMachBase<T>::buildMachLoader( upx_byte const *const proto, unsigned const szproto, upx_byte const *const fold, unsigned const szfold, Filter const *ft){ initLoader(proto, szproto); struct b_info h; memset(&h, 0, sizeof(h)); unsigned fold_hdrlen = 0; if (0 < szfold) { h.sz_unc = (szfold < fold_hdrlen) ? 0 : (szfold - fold_hdrlen); h.b_method = (unsigned char) ph.method; h.b_ftid = (unsigned char) ph.filter; h.b_cto8 = (unsigned char) ph.filter_cto; } unsigned char const *const uncLoader = fold_hdrlen + fold; unsigned char *const cprLoader = new unsigned char[sizeof(h) + h.sz_unc]; if (0 < szfold) { unsigned sz_cpr = 0; int r = upx_compress(uncLoader, h.sz_unc, sizeof(h) + cprLoader, &sz_cpr, NULL, ph.method, 10, NULL, NULL ); h.sz_cpr = sz_cpr; if (r != UPX_E_OK || h.sz_cpr >= h.sz_unc) throwInternalError("loader compression failed"); } memcpy(cprLoader, &h, sizeof(h)); // This adds the definition to the "library", to be used later. linker->addSection("FOLDEXEC", cprLoader, sizeof(h) + h.sz_cpr, 0); delete [] cprLoader; int const GAP = 128; // must match stub/l_mac_ppc.S segcmdo.vmsize += h.sz_unc - h.sz_cpr + GAP + 64; addStubEntrySections(ft); defineSymbols(ft); relocateLoader();}voidPackMachPPC32::buildLoader(const Filter *ft){ buildMachLoader( stub_powerpc_darwin_macho_entry, sizeof(stub_powerpc_darwin_macho_entry), stub_powerpc_darwin_macho_fold, sizeof(stub_powerpc_darwin_macho_fold), ft );}voidPackMachI386::buildLoader(const Filter *ft){ buildMachLoader( stub_i386_darwin_macho_entry, sizeof(stub_i386_darwin_macho_entry), stub_i386_darwin_macho_fold, sizeof(stub_i386_darwin_macho_fold), ft );}template <class T>void PackMachBase<T>::patchLoader() { }template <class T>void PackMachBase<T>::updateLoader(OutputFile *) {}template <class T>void PackMachBase<T>::patchLoaderChecksum(){ unsigned char *const ptr = getLoader(); l_info *const lp = &linfo; // checksum for loader; also some PackHeader info lp->l_checksum = 0; lp->l_magic = UPX_MAGIC_LE32; // LE32 always lp->l_lsize = (unsigned short) lsize; lp->l_version = (unsigned char) ph.version; lp->l_format = (unsigned char) ph.format; // INFO: lp->l_checksum is currently unused lp->l_checksum = upx_adler32(ptr, lsize);}template <class T>int __acc_cdecl_qsortPackMachBase<T>::compare_segment_command(void const *const aa, void const *const bb){ Mach_segment_command const *const a = (Mach_segment_command const *)aa; Mach_segment_command const *const b = (Mach_segment_command const *)bb; unsigned const xa = a->cmd - Mach_segment_command::LC_SEGMENT; unsigned const xb = b->cmd - Mach_segment_command::LC_SEGMENT; if (xa < xb) return -1; // LC_SEGMENT first if (xa > xb) return 1; if (a->vmaddr < b->vmaddr) return -1; // ascending by .vmaddr if (a->vmaddr > b->vmaddr) return 1; return 0;}void PackMachPPC32::pack4(OutputFile *fo, Filter &ft) // append PackHeader{ // offset of p_info in compressed file overlay_offset = sizeof(mhdro) + sizeof(segcmdo) + sizeof(threado) + sizeof(linfo); super::pack4(fo, ft); segcmdo.filesize = fo->getBytesWritten(); segcmdo.vmsize += segcmdo.filesize; fo->seek(sizeof(mhdro), SEEK_SET); fo->rewrite(&segcmdo, sizeof(segcmdo)); fo->rewrite(&threado, sizeof(threado)); fo->rewrite(&linfo, sizeof(linfo));}void PackMachI386::pack4(OutputFile *fo, Filter &ft) // append PackHeader{ // offset of p_info in compressed file overlay_offset = sizeof(mhdro) + sizeof(segcmdo) + sizeof(threado) + sizeof(linfo); super::pack4(fo, ft); segcmdo.filesize = fo->getBytesWritten(); segcmdo.vmsize += segcmdo.filesize; fo->seek(sizeof(mhdro), SEEK_SET); fo->rewrite(&segcmdo, sizeof(segcmdo)); fo->rewrite(&threado, sizeof(threado)); fo->rewrite(&linfo, sizeof(linfo));}void PackMachPPC32::pack3(OutputFile *fo, Filter &ft) // append loader{ BE32 disp; unsigned const zero = 0; unsigned len = fo->getBytesWritten(); fo->write(&zero, 3& (0u-len)); len += (3& (0u-len)) + sizeof(disp); disp = 4+ len - sz_mach_headers; // 4: sizeof(instruction) fo->write(&disp, sizeof(disp)); threado.state.srr0 = len + segcmdo.vmaddr; /* entry address */ super::pack3(fo, ft);}void PackMachI386::pack3(OutputFile *fo, Filter &ft) // append loader{ LE32 disp; unsigned const zero = 0; unsigned len = fo->getBytesWritten(); fo->write(&zero, 3& (0u-len)); len += (3& (0u-len)); disp = len - sz_mach_headers; fo->write(&disp, sizeof(disp)); threado.state.eip = len + sizeof(disp) + segcmdo.vmaddr; /* entry address */ super::pack3(fo, ft);}// Determine length of gap between PT_LOAD phdri[k] and closest PT_LOAD// which follows in the file (or end-of-file). Optimize for common case// where the PT_LOAD are adjacent ascending by .p_offset. Assume no overlap.template <class T>unsigned PackMachBase<T>::find_SEGMENT_gap( unsigned const k){ if (Mach_segment_command::LC_SEGMENT!=msegcmd[k].cmd || 0==msegcmd[k].filesize ) { return 0; } unsigned const hi = msegcmd[k].fileoff + msegcmd[k].filesize; unsigned lo = ph.u_file_size; unsigned j = k; for (;;) { // circular search, optimize for adjacent ascending ++j; if (n_segment==j) { j = 0; } if (k==j) { break; } if (Mach_segment_command::LC_SEGMENT==msegcmd[j].cmd && 0!=msegcmd[j].filesize ) { unsigned const t = msegcmd[j].fileoff; if ((t - hi) < (lo - hi)) { lo = t; if (hi==lo) { break; } } } } return lo - hi;}template <class T>void PackMachBase<T>::pack4(OutputFile *fo, Filter &ft){ PackUnix::pack4(fo, ft); // FIXME super() does not work?}template <class T>void PackMachBase<T>::pack3(OutputFile *fo, Filter &ft){ PackUnix::pack3(fo, ft); // FIXME super() does not work?}template <class T>void PackMachBase<T>::pack2(OutputFile *fo, Filter &ft) // append compressed body{ Extent x; unsigned k; // count passes, set ptload vars uip->ui_total_passes = 0; for (k = 0; k < n_segment; ++k) { if (Mach_segment_command::LC_SEGMENT==msegcmd[k].cmd && 0!=msegcmd[k].filesize ) { uip->ui_total_passes++; if (find_SEGMENT_gap(k)) { uip->ui_total_passes++; } } } // compress extents unsigned total_in = 0; unsigned total_out = 0; unsigned hdr_u_len = mhdri.sizeofcmds; uip->ui_pass = 0; ft.addvalue = 0; // Packer::compressWithFilters chooses a filter for us, and the stubs // can handle only one filter, and most filters are for executable // instructions. So filter only the largest executable segment. unsigned exe_filesize_max = 0; for (k = 0; k < n_segment; ++k) if (Mach_segment_command::LC_SEGMENT==msegcmd[k].cmd && 0!=(Mach_segment_command::VM_PROT_EXECUTE & msegcmd[k].initprot)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -