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

Better detection of Position Independent main Executables (gcc -pie -FPIC).

This commit is contained in:
John Reiser 2009-10-10 14:50:30 -07:00
parent e0c11956a6
commit 0a485eafcb
2 changed files with 38 additions and 30 deletions

View File

@ -955,40 +955,35 @@ bool PackLinuxElf32::canPack()
break;
}
// elf_find_dynamic() returns 0 if 0==dynseg.
gashtab= (unsigned int const *)elf_find_dynamic(Elf32_Dyn::DT_GNU_HASH);
hashtab= (unsigned int const *)elf_find_dynamic(Elf32_Dyn::DT_HASH);
//gashtab= (unsigned int const *)elf_find_dynamic(Elf32_Dyn::DT_GNU_HASH);
//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);
Elf32_Rel const *
jmprel= (Elf32_Rel const *)elf_find_dynamic(Elf32_Dyn::DT_JMPREL);
//unsigned const sz_1pltrel =
// (Elf32_Dyn::DT_REL==elf_unsigned_dynamic(Elf32_Dyn::DT_PLTREL))
// ? elf_unsigned_dynamic(Elf32_Dyn::DT_RELENT)
// : elf_unsigned_dynamic(Elf32_Dyn::DT_RELAENT);
// FIXME 2007-09-10 It seems that DT_GNU_HASH does not have undefined
// symbols. So if no DT_HASH, then we would have to look in .dynsym.
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_te16(&lsm->st_shndx)==Elf32_Sym::SHN_UNDEF
&& get_te16(&lsm->st_info)==lsm->Elf32_Sym::make_st_info(Elf32_Sym::STB_GLOBAL, Elf32_Sym::STT_FUNC)
&& get_te16(&lsm->st_other)==Elf32_Sym::STV_DEFAULT ) {
break;
}
if (sec_dynsym) {
Elf32_Sym const *symp = (Elf32_Sym const *)(get_te32(&sec_dynsym->sh_offset) + file_image);
Elf32_Sym const *const symlwa = (Elf32_Sym const *)(
get_te32(&sec_dynsym->sh_size) +
get_te32(&sec_dynsym->sh_offset) + file_image);
for (; symp < symlwa; ++symp)
if (0==strcmp(run_start[j], get_te32(&symp->st_name) + dynstr)) {
goto found;
}
}
}
found:
phdri = 0; // done "borrowing" this member
if (3<=j) {
return false;
// Modified 2009-10-10 to detect a ProgramLinkageTable relocation
// which references the symbol, because DT_GNU_HASH contains only
// defined symbols, and there might be no DT_HASH.
for ( int sz = elf_unsigned_dynamic(Elf32_Dyn::DT_PLTRELSZ);
0 < sz;
(sz -= sizeof(Elf32_Rel)), ++jmprel) {
unsigned const symnum = jmprel->r_info >> 8;
char const *const symnam = get_te32(&dynsym[symnum].st_name) + dynstr;
if (0==strcmp(symnam, "__libc_start_main")
|| 0==strcmp(symnam, "__uClibc_main")
|| 0==strcmp(symnam, "__uClibc_start_main"))
goto main_found;
}
phdri = 0;
return false;
main_found:
phdri = 0;
}
// XXX Theoretically the following test should be first,
// but PackUnix::canPack() wants 0!=exetype ?
@ -1113,6 +1108,7 @@ PackLinuxElf32::generateElfHdr(
cprElfHdr2 *const h2 = (cprElfHdr2 *)(void *)&elfout;
cprElfHdr3 *const h3 = (cprElfHdr3 *)(void *)&elfout;
memcpy(h3, proto, sizeof(*h3)); // reads beyond, but OK
h3->ehdr.e_type = ehdri.e_type; // ET_EXEC vs ET_DYN (gcc -pie -fPIC)
h3->ehdr.e_ident[Elf32_Ehdr::EI_OSABI] = ei_osabi;
if (Elf32_Ehdr::EM_MIPS==e_machine) { // MIPS R3000 FIXME
h3->ehdr.e_ident[Elf32_Ehdr::EI_OSABI] = Elf32_Ehdr::ELFOSABI_NONE;
@ -2289,6 +2285,17 @@ PackLinuxElf32::elf_find_dynamic(unsigned int const key) const
return 0;
}
unsigned
PackLinuxElf32::elf_unsigned_dynamic(unsigned int const key) const
{
Elf32_Dyn const *dynp= dynseg;
if (dynp)
for (; Elf32_Dyn::DT_NULL!=dynp->d_tag; ++dynp) if (get_te32(&dynp->d_tag)==key) {
return get_te32(&dynp->d_val);
}
return 0;
}
unsigned PackLinuxElf32::gnu_hash(char const *q)
{
unsigned char const *p = (unsigned char const *)q;

View File

@ -123,6 +123,7 @@ protected:
static unsigned elf_hash(char const *) /*const*/;
static unsigned gnu_hash(char const *) /*const*/;
virtual void const *elf_find_dynamic(unsigned) const;
virtual unsigned elf_unsigned_dynamic(unsigned) const;
virtual Elf32_Sym const *elf_lookup(char const *) const;
virtual unsigned elf_get_offset_from_address(unsigned) const;
Elf32_Shdr const *elf_find_section_name(char const *) const;