diff --git a/src/p_lx_elf.cpp b/src/p_lx_elf.cpp index 7960d07b..2728a28d 100644 --- a/src/p_lx_elf.cpp +++ b/src/p_lx_elf.cpp @@ -560,6 +560,8 @@ static const static const #include "stub/fold_elf32arm.h" +#include "mem.h" + int PackLinuxElf32armLe::buildLoader(const Filter *ft) { @@ -568,12 +570,52 @@ PackLinuxElf32armLe::buildLoader(const Filter *ft) linux_elf32arm_fold, sizeof(linux_elf32arm_fold), ft ); } +static void brev( + unsigned char *const dst, + unsigned char const *const src, + unsigned len +) +{ + assert(0==(3 & len)); + assert(!((src -4)<=dst && dst < (len + src))); + for (unsigned j = 0; j < len; j += 4) { + dst[0+ j] = src[3+ j]; + dst[1+ j] = src[2+ j]; + dst[2+ j] = src[1+ j]; + dst[3+ j] = src[0+ j]; + } +} + +static void +ehdr_bele(Elf_BE32_Ehdr *const ehdr_be, Elf_LE32_Ehdr const *const ehdr_le) +{ + memcpy(&ehdr_be->e_ident, &ehdr_le->e_ident, sizeof(ehdr_be->e_ident)); + ehdr_be->e_type = ehdr_le->e_type; + ehdr_be->e_machine = ehdr_le->e_machine; + ehdr_be->e_version = ehdr_le->e_version; + ehdr_be->e_entry = ehdr_le->e_entry; + ehdr_be->e_phoff = ehdr_le->e_phoff; + ehdr_be->e_shoff = ehdr_le->e_shoff; + ehdr_be->e_flags = ehdr_le->e_flags; + ehdr_be->e_ehsize = ehdr_le->e_ehsize; + ehdr_be->e_phentsize = ehdr_le->e_phentsize; + ehdr_be->e_phnum = ehdr_le->e_phnum; + ehdr_be->e_shentsize = ehdr_le->e_shentsize; + ehdr_be->e_shnum = ehdr_le->e_shnum; + ehdr_be->e_shstrndx = ehdr_le->e_shstrndx; +} + int PackLinuxElf32armBe::buildLoader(const Filter *ft) // FIXME { - return buildLinuxLoader( - linux_elf32arm_loader, sizeof(linux_elf32arm_loader), - linux_elf32arm_fold, sizeof(linux_elf32arm_fold), ft ); + unsigned const sz_loader = sizeof(linux_elf32arm_loader); + unsigned const sz_fold = sizeof(linux_elf32arm_fold); + MemBuffer brev_loader(sz_loader); + MemBuffer brev_fold (sz_fold); + brev(brev_loader, linux_elf32arm_loader, sz_loader); + brev(brev_fold, linux_elf32arm_fold, sz_fold); + ehdr_bele((Elf_BE32_Ehdr *)&brev_fold, (Elf_LE32_Ehdr const *)linux_elf32arm_fold); + return buildLinuxLoader(brev_loader, sz_loader, brev_fold, sz_fold, ft); } static const @@ -897,7 +939,14 @@ void PackLinuxElf32armLe::pack1(OutputFile *fo, Filter &ft) void PackLinuxElf32armBe::pack1(OutputFile *fo, Filter &ft) // FIXME { super::pack1(fo, ft); - generateElfHdr(fo, linux_elf32arm_fold, getbrk(phdri, ehdri.e_phnum) ); + + cprElfHdr3 h3; + ehdr_bele((Elf_BE32_Ehdr *)&h3.ehdr, (Elf_LE32_Ehdr const *)linux_elf32arm_fold); + brev((unsigned char *)&h3.phdr[0], + (unsigned char const *)(sizeof(Elf32_Ehdr) + &linux_elf32arm_fold), + 3*sizeof(Elf32_Phdr) ); + + generateElfHdr(fo, &h3, getbrk(phdri, ehdri.e_phnum) ); } void PackLinuxElf32ppc::pack1(OutputFile *fo, Filter &ft) @@ -1237,7 +1286,8 @@ void PackLinuxElf32armLe::pack3(OutputFile *fo, Filter &ft) len += lsize; bool const is_big = true; if (is_big) { - elfout.ehdr.e_entry += lo_va_user - lo_va_stub; + set_native32( &elfout.ehdr.e_entry, + get_native32(&elfout.ehdr.e_entry) + lo_va_user - lo_va_stub); set_native32(&elfout.phdr[0].p_vaddr, lo_va_user); set_native32(&elfout.phdr[0].p_paddr, lo_va_user); lo_va_stub = lo_va_user; @@ -1273,6 +1323,67 @@ void PackLinuxElf32armLe::pack3(OutputFile *fo, Filter &ft) super::pack3(fo, ft); } +void PackLinuxElf32armBe::pack3(OutputFile *fo, Filter &ft) +{ + unsigned const hlen = sz_elf_hdrs + sizeof(l_info) + sizeof(p_info); + unsigned const len0 = fo->getBytesWritten(); + unsigned len = len0; + unsigned const zero = 0; + fo->write(&zero, 3& -len); // align to 0 mod 4 + len += (3& -len); + +#define PAGE_MASK (~0u<<12) +#define PAGE_SIZE (-PAGE_MASK) + upx_byte *const p = const_cast(getLoader()); + lsize = getLoaderSize(); + unsigned const lo_va_user = 0x8000; // XXX + unsigned lo_va_stub = get_native32(&elfout.phdr[0].p_vaddr); + unsigned adrc; + unsigned adrm; + unsigned adrx; + unsigned cntc; + unsigned lenm; + + len += lsize; + bool const is_big = true; + if (is_big) { + set_native32( &elfout.ehdr.e_entry, + get_native32(&elfout.ehdr.e_entry) + lo_va_user - lo_va_stub); + set_native32(&elfout.phdr[0].p_vaddr, lo_va_user); + set_native32(&elfout.phdr[0].p_paddr, lo_va_user); + lo_va_stub = lo_va_user; + adrc = lo_va_stub; + adrm = getbrk(phdri, get_native16(&ehdri.e_phnum)); + adrx = hlen + (PAGE_MASK & (~PAGE_MASK + adrm)); // round up to page boundary + lenm = PAGE_SIZE + len; + cntc = len >> 5; + } + else { + adrm = lo_va_stub + len; + adrc = adrm; + adrx = lo_va_stub + hlen; + lenm = PAGE_SIZE; + cntc = 0; + } + adrm = PAGE_MASK & (~PAGE_MASK + adrm); // round up to page boundary + adrc = PAGE_MASK & (~PAGE_MASK + adrc); // round up to page boundary + + // patch in order of descending address + patch_be32(p,lsize,"ADRX", adrx); // compressed input for eXpansion + patch_be32(p,lsize,"LENX", len0 - hlen); + + patch_be32(p,lsize,"CNTC", cntc); // count for copy + patch_be32(p,lsize,"ADRC", adrc); // addr for copy + + patch_be32(p,lsize,"LENM", lenm); // len for map + patch_be32(p,lsize,"ADRM", adrm); // addr for map + +#undef PAGE_SIZE +#undef PAGE_MASK + + super::pack3(fo, ft); +} + void PackLinuxElf::pack4(OutputFile *fo, Filter &ft) { super::pack4(fo, ft); @@ -1836,6 +1947,115 @@ bool PackLinuxElf32armLe::canPack() return true; } +bool PackLinuxElf32armBe::canPack() +{ + unsigned char buf[sizeof(Elf32_Ehdr) + 14*sizeof(Elf32_Phdr)]; + COMPILE_TIME_ASSERT(sizeof(buf) <= 512); + + exetype = 0; + + fi->readx(buf, sizeof(buf)); + fi->seek(0, SEEK_SET); + Elf32_Ehdr const *const ehdr = (Elf32_Ehdr const *)buf; + + // now check the ELF header + if (checkEhdr(ehdr, Elf32_Ehdr::EM_ARM, + Elf32_Ehdr::ELFCLASS32, Elf32_Ehdr::ELFDATA2MSB) != 0) + return false; + + // additional requirements for linux/elfarm + if (get_native16(&ehdr->e_ehsize) != sizeof(*ehdr)) { + throwCantPack("invalid Ehdr e_ehsize; try `--force-execve'"); + return false; + } + if (get_native32(&ehdr->e_phoff) != sizeof(*ehdr)) {// Phdrs not contiguous with Ehdr + throwCantPack("non-contiguous Ehdr/Phdr; try `--force-execve'"); + return false; + } + + // The first PT_LOAD32 must cover the beginning of the file (0==p_offset). + Elf32_Phdr const *phdr = (Elf32_Phdr const *)(buf + get_native32(&ehdr->e_phoff)); + unsigned const e_phnum = get_native16(&ehdr->e_phnum); + for (unsigned j=0; j < e_phnum; ++phdr, ++j) { + if (j >= 14) // 512 bytes holds Elf32_Ehdr + Elf32_Phdr[0..13] + return false; + if (phdr->PT_LOAD32 == get_native32(&phdr->p_type)) { + if (phdr->p_offset != 0) { + throwCantPack("invalid Phdr p_offset; try `--force-execve'"); + return false; + } + + // detect possible conflict upon invocation + //if (ehdr->e_type!=Elf32_Ehdr::ET_DYN + //&& (phdr->p_vaddr < (unsigned)(0x4000 + file_size) + // || phdr->p_paddr < (unsigned)(0x4000 + file_size) ) ) { + // throwAlreadyPackedByUPX(); // not necessarily, but mostly true + // return false; + //} + exetype = 1; + break; + } + } + + // We want to compress position-independent executable (gcc -pie) + // main programs, but compressing a shared library must be avoided + // because the result is no longer usable. In theory, there is no way + // to tell them apart: both are just ET_DYN. Also in theory, + // neither the presence nor the absence of any particular symbol name + // can be used to tell them apart; there are counterexamples. + // However, we will use the following heuristic suggested by + // Peter S. Mazinger September 2005: + // If a ET_DYN has __libc_start_main as a global undefined symbol, + // then the file is a position-independent executable main program + // (that depends on libc.so.6) and is eligible to be compressed. + // Otherwise (no __libc_start_main as global undefined): skip it. + // Also allow __uClibc_main and __uClibc_start_main . + + if (Elf32_Ehdr::ET_DYN==get_native16(&ehdr->e_type)) { + // The DT_STRTAB has no designated length. Read the whole file. + file_image = new char[file_size]; + fi->seek(0, SEEK_SET); + fi->readx(file_image, file_size); + ehdri= *ehdr; + phdri= (Elf32_Phdr *)(get_native32(&ehdr->e_phoff) + file_image); // do not free() !! + + int j= ehdr->e_phnum; + phdr= phdri; + for (; --j>=0; ++phdr) if (Elf32_Phdr::PT_DYNAMIC==get_native32(&phdr->p_type)) { + dynseg= (Elf32_Dyn const *)(get_native32(&phdr->p_offset) + file_image); + break; + } + // elf_find_dynamic() returns 0 if 0==dynseg. + hashtab= (unsigned int const *)elf_find_dynamic(Elf32_Dyn::DT_HASH); + dynstr= (char const *)elf_find_dynamic(Elf32_Dyn::DT_STRTAB); + dynsym= (Elf32_Sym const *)elf_find_dynamic(Elf32_Dyn::DT_SYMTAB); + + char const *const run_start[]= { + "__libc_start_main", "__uClibc_main", "__uClibc_start_main", + }; + for (j=0; j<3; ++j) { + // elf_lookup() returns 0 if any required table is missing. + Elf32_Sym const *const lsm = elf_lookup(run_start[j]); + if (lsm && get_native16(&lsm->st_shndx)==Elf32_Sym::SHN_UNDEF + && get_native16(&lsm->st_info)==lsm->Elf32_Sym::St_info(Elf32_Sym::STB_GLOBAL, Elf32_Sym::STT_FUNC) + && get_native16(&lsm->st_other)==Elf32_Sym::STV_DEFAULT ) { + break; + } + } + phdri = 0; // done "borrowing" this member + if (3<=j) { + return false; + } + } + if (!super::canPack()) + return false; + assert(exetype == 1); + + // set options + opt->o_unix.blocksize = blocksize = file_size; + return true; +} + unsigned PackLinuxElf32::elf_get_offset_from_address(unsigned const addr) const { diff --git a/src/p_lx_elf.h b/src/p_lx_elf.h index 84fc4431..cef0963d 100644 --- a/src/p_lx_elf.h +++ b/src/p_lx_elf.h @@ -336,7 +336,7 @@ public: PackLinuxElf32armLe(InputFile *f); virtual ~PackLinuxElf32armLe(); virtual int getFormat() const { return UPX_F_LINUX_ELF32_ARMLE; } - virtual const char *getName() const { return "linux/ElfArmLE"; } + virtual const char *getName() const { return "linux/armLE"; } virtual const int *getFilters() const; virtual int const *getCompressionMethods(int method, int level) const; @@ -354,7 +354,7 @@ public: PackLinuxElf32armBe(InputFile *f); virtual ~PackLinuxElf32armBe(); virtual int getFormat() const { return UPX_F_LINUX_ELF32_ARMBE; } - virtual const char *getName() const { return "linux/ElfArmBL"; } + virtual const char *getName() const { return "linux/armBE"; } virtual const int *getFilters() const; virtual int const *getCompressionMethods(int method, int level) const; diff --git a/src/packmast.cpp b/src/packmast.cpp index e19e4e75..47965a22 100644 --- a/src/packmast.cpp +++ b/src/packmast.cpp @@ -219,7 +219,9 @@ static Packer* try_packers(InputFile *f, try_function func) return p; if ((p = func(new PackLinuxElf64amd(f),f)) != NULL) return p; - if ((p = func(new PackLinuxElf32arm(f),f)) != NULL) + if ((p = func(new PackLinuxElf32armLe(f),f)) != NULL) + return p; + if ((p = func(new PackLinuxElf32armBe(f),f)) != NULL) return p; if ((p = func(new PackLinuxElf32ppc(f),f)) != NULL) return p;