1
0
mirror of https://github.com/upx/upx synced 2025-09-28 19:06:07 +08:00

PackLinuxElf32armBe (Linux ARM big-endian)

This commit is contained in:
John Reiser 2006-06-13 11:48:54 -07:00
parent 112b10c19d
commit bd8acbde97
3 changed files with 230 additions and 8 deletions

View File

@ -560,6 +560,8 @@ static const
static const static const
#include "stub/fold_elf32arm.h" #include "stub/fold_elf32arm.h"
#include "mem.h"
int int
PackLinuxElf32armLe::buildLoader(const Filter *ft) PackLinuxElf32armLe::buildLoader(const Filter *ft)
{ {
@ -568,12 +570,52 @@ PackLinuxElf32armLe::buildLoader(const Filter *ft)
linux_elf32arm_fold, sizeof(linux_elf32arm_fold), 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 int
PackLinuxElf32armBe::buildLoader(const Filter *ft) // FIXME PackLinuxElf32armBe::buildLoader(const Filter *ft) // FIXME
{ {
return buildLinuxLoader( unsigned const sz_loader = sizeof(linux_elf32arm_loader);
linux_elf32arm_loader, sizeof(linux_elf32arm_loader), unsigned const sz_fold = sizeof(linux_elf32arm_fold);
linux_elf32arm_fold, sizeof(linux_elf32arm_fold), ft ); 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 static const
@ -897,7 +939,14 @@ void PackLinuxElf32armLe::pack1(OutputFile *fo, Filter &ft)
void PackLinuxElf32armBe::pack1(OutputFile *fo, Filter &ft) // FIXME void PackLinuxElf32armBe::pack1(OutputFile *fo, Filter &ft) // FIXME
{ {
super::pack1(fo, ft); 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) void PackLinuxElf32ppc::pack1(OutputFile *fo, Filter &ft)
@ -1237,7 +1286,8 @@ void PackLinuxElf32armLe::pack3(OutputFile *fo, Filter &ft)
len += lsize; len += lsize;
bool const is_big = true; bool const is_big = true;
if (is_big) { 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_vaddr, lo_va_user);
set_native32(&elfout.phdr[0].p_paddr, lo_va_user); set_native32(&elfout.phdr[0].p_paddr, lo_va_user);
lo_va_stub = lo_va_user; lo_va_stub = lo_va_user;
@ -1273,6 +1323,67 @@ void PackLinuxElf32armLe::pack3(OutputFile *fo, Filter &ft)
super::pack3(fo, 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<upx_byte *>(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) void PackLinuxElf::pack4(OutputFile *fo, Filter &ft)
{ {
super::pack4(fo, ft); super::pack4(fo, ft);
@ -1836,6 +1947,115 @@ bool PackLinuxElf32armLe::canPack()
return true; 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 <ps.m@gmx.net> 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 unsigned
PackLinuxElf32::elf_get_offset_from_address(unsigned const addr) const PackLinuxElf32::elf_get_offset_from_address(unsigned const addr) const
{ {

View File

@ -336,7 +336,7 @@ public:
PackLinuxElf32armLe(InputFile *f); PackLinuxElf32armLe(InputFile *f);
virtual ~PackLinuxElf32armLe(); virtual ~PackLinuxElf32armLe();
virtual int getFormat() const { return UPX_F_LINUX_ELF32_ARMLE; } 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 const int *getFilters() const;
virtual int const *getCompressionMethods(int method, int level) const; virtual int const *getCompressionMethods(int method, int level) const;
@ -354,7 +354,7 @@ public:
PackLinuxElf32armBe(InputFile *f); PackLinuxElf32armBe(InputFile *f);
virtual ~PackLinuxElf32armBe(); virtual ~PackLinuxElf32armBe();
virtual int getFormat() const { return UPX_F_LINUX_ELF32_ARMBE; } 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 const int *getFilters() const;
virtual int const *getCompressionMethods(int method, int level) const; virtual int const *getCompressionMethods(int method, int level) const;

View File

@ -219,7 +219,9 @@ static Packer* try_packers(InputFile *f, try_function func)
return p; return p;
if ((p = func(new PackLinuxElf64amd(f),f)) != NULL) if ((p = func(new PackLinuxElf64amd(f),f)) != NULL)
return p; 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; return p;
if ((p = func(new PackLinuxElf32ppc(f),f)) != NULL) if ((p = func(new PackLinuxElf32ppc(f),f)) != NULL)
return p; return p;