diff --git a/src/conf.h b/src/conf.h index af6effcc..119d5147 100644 --- a/src/conf.h +++ b/src/conf.h @@ -464,6 +464,7 @@ private: #define UPX_F_MACH_PPC32 131 #define UPX_F_LINUX_ELFPPC32 132 #define UPX_F_LINUX_ELF32_ARMBE 133 +#define UPX_F_MACH_FAT 134 // compression methods diff --git a/src/file.h b/src/file.h index 9910dc35..183bbb4c 100644 --- a/src/file.h +++ b/src/file.h @@ -60,6 +60,7 @@ public: int getFd() const { return _fd; } const char *getName() const { return _name; } virtual off_t st_size() const; // { return _length; } + virtual void set_extent(off_t offset, off_t length); protected: void sopen(); @@ -68,7 +69,6 @@ protected: virtual void write(const void *buf, int len); virtual void seek(off_t off, int whence); virtual off_t tell() const; - virtual void set_extent(off_t offset, off_t length); int _fd; int _flags; diff --git a/src/p_mach.cpp b/src/p_mach.cpp index 5a4cd5c9..361c9035 100644 --- a/src/p_mach.cpp +++ b/src/p_mach.cpp @@ -618,6 +618,128 @@ bool PackMachBase::canPack() template class PackMachBase; template class PackMachBase; + + +PackMachFat::PackMachFat(InputFile *f) : super(f) +{ + bele = &N_BELE_RTP::le_policy; // sham +} + +PackMachFat::~PackMachFat() +{ +} + +const int *PackMachFat::getCompressionMethods(int /*method*/, int /*level*/) const +{ + static const int m_nrv2e[] = { M_NRV2E_LE32, M_END }; + return m_nrv2e; // sham +} + +const int *PackMachFat::getFilters() const +{ + static const int filters[] = { 0x49, FT_END }; + return filters; // sham +} + +void PackMachFat::pack(OutputFile *fo) +{ + fo->write(&fat_head, sizeof(fat_head.fat) + + fat_head.fat.nfat_arch * sizeof(fat_head.arch[0])); + for (unsigned j=0; j < fat_head.fat.nfat_arch; ++j) { + unsigned base = fo->getBytesWritten(); + base += ~(~0u<seek(base, SEEK_SET); + fo->set_extent(base, ~0u); + + fi->set_extent(fat_head.arch[j].offset, fat_head.arch[j].size); + switch (fat_head.arch[j].cputype) { + case PackMachFat::CPU_TYPE_I386: { + PackMachI386 packer(fi); + packer.initPackHeader(); + packer.canPack(); + packer.updatePackHeader(); + packer.pack(fo); + } break; + case PackMachFat::CPU_TYPE_POWERPC: { + PackMachPPC32 packer(fi); + packer.initPackHeader(); + packer.canPack(); + packer.updatePackHeader(); + packer.pack(fo); + } break; + } // switch cputype + fat_head.arch[j].offset = base; + fat_head.arch[j].size = fo->getBytesWritten() - base; + } + fo->set_extent(0, ~0u); + fo->seek(0, SEEK_SET); + fo->write(&fat_head, sizeof(fat_head.fat) + + fat_head.fat.nfat_arch * sizeof(fat_head.arch[0])); +} + +void PackMachFat::unpack(OutputFile */*fo*/) +{ + assert(false); +} + +bool PackMachFat::canPack() +{ + struct Mach_fat_arch *arch = &fat_head.arch[0]; + + fi->readx(&fat_head, sizeof(fat_head)); + if (Mach_fat_header::FAT_MAGIC_SWAB==fat_head.fat.magic) { + unsigned *const p = &fat_head.fat.magic; + for (unsigned j = 0; j < sizeof(fat_head)/sizeof(unsigned); ++j) { + p[j] = acc_swab32(p[j]); + } + } + if (Mach_fat_header::FAT_MAGIC!=fat_head.fat.magic + || N_FAT_ARCH < fat_head.fat.nfat_arch) { + return false; + } + for (unsigned j=0; j < fat_head.fat.nfat_arch; ++j) { + fi->set_extent(fat_head.arch[j].offset, fat_head.arch[j].size); + switch (arch[j].cputype) { + default: return false; + case PackMachFat::CPU_TYPE_I386: { + PackMachI386 packer(fi); + if (!packer.canPack()) + return false; + } break; + case PackMachFat::CPU_TYPE_POWERPC: { + PackMachPPC32 packer(fi); + if (!packer.canPack()) + return false; + } break; + } // switch cputype + } + return true; +} + +int PackMachFat::canUnpack() +{ + return 0; +} + +void PackMachFat::buildLoader(const Filter */*ft*/) +{ + assert(false); +} + +Linker* PackMachFat::newLinker() const +{ + return new ElfLinkerX86; // sham +} + +void PackMachFat::list() +{ + assert(false); +} + +void PackMachFat::fileInfo() +{ + assert(false); +} /* vi:ts=4:et */ diff --git a/src/p_mach.h b/src/p_mach.h index acb02a82..38eb0528 100644 --- a/src/p_mach.h +++ b/src/p_mach.h @@ -33,8 +33,9 @@ // of the machine on which they were created. We must deal with both kinds. struct Mach_fat_header { unsigned magic; - enum e8 { - FAT_MAGIC = 0xcafebabe + enum e8 { // note conflict with java bytecode PackLinuxI386 + FAT_MAGIC = 0xcafebabe, + FAT_MAGIC_SWAB = 0xbebafeca, }; unsigned nfat_arch; // Number of Mach_fat_arch which follow. }; @@ -214,7 +215,7 @@ struct Mach_ppc_thread_state64 Xword r16,r17,r18,r19,r20,r21,r22,r23; Xword r24,r25,r26,r27,r28,r29,r30,r31; - Word cr; /* Condition register */ + Word cr; /* Condition register */ // FIXME: Xword? Xword xer; /* User's integer exception register */ Xword lr; /* Link register */ Xword ctr; /* Count register */ @@ -236,7 +237,7 @@ struct MachClass_32 typedef typename TP::U16 U16; typedef typename TP::U32 U32; typedef typename TP::U64 U64; - typedef N_Mach::MachITypes MachITypes; + typedef N_Mach::MachITypes MachITypes; typedef typename MachITypes::Addr Addr; // Mach types @@ -454,6 +455,53 @@ protected: __attribute_packed; }; +class PackMachFat : public Packer +{ + typedef Packer super; +public: + PackMachFat(InputFile *f); + virtual ~PackMachFat(); + + virtual int getVersion() const { return 13; } + virtual int getFormat() const { return UPX_F_MACH_FAT; } + virtual const char *getName() const { return "Mach/fat"; } + virtual const char *getFullName(const options_t *) const { return "fat-darwin.macho"; } + virtual const int *getCompressionMethods(int method, int level) const; + virtual const int *getFilters() const; + +protected: + // implementation + virtual void pack(OutputFile *fo); + virtual void unpack(OutputFile *fo); + virtual void list(); + virtual void fileInfo(); + +public: + virtual bool canPack(); + virtual int canUnpack(); + +protected: + // loader core + virtual void buildLoader(const Filter *ft); + virtual Linker* newLinker() const; + +protected: + enum { N_FAT_ARCH = 5 }; + struct Fat_head { + struct Mach_fat_header fat; + struct Mach_fat_arch arch[N_FAT_ARCH]; + } fat_head; + + // UI handler + UiPacker *uip; + + // linker + Linker *linker; +#define WANT_MACH_HEADER_ENUM +#include "p_mach_enum.h" +#undef WANT_MACH_HEADER_ENUM +}; + #endif /* already included */ diff --git a/src/packmast.cpp b/src/packmast.cpp index 58341558..9144e14e 100644 --- a/src/packmast.cpp +++ b/src/packmast.cpp @@ -244,7 +244,9 @@ Packer* PackMaster::visitAllPackers(visit_func_t func, InputFile *f, const optio } if ((p = func(new PackBSDI386(f), user)) != NULL) return p; - if ((p = func(new PackLinuxI386(f), user)) != NULL) + if ((p = func(new PackMachFat(f), user)) != NULL) // cafebabe conflict + return p; + if ((p = func(new PackLinuxI386(f), user)) != NULL) // cafebabe conflict return p; //