Skip to content

Commit

Permalink
DF_1_PIE and calls_crt1() to handle part of -pie,-fPIE
Browse files Browse the repository at this point in the history
#106  [partial]
	modified:   p_elf_enum.h
	modified:   p_lx_elf.cpp
	modified:   p_lx_elf.h
  • Loading branch information
jreiser committed May 31, 2017
1 parent a67aed2 commit ee18fe9
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 118 deletions.
1 change: 1 addition & 0 deletions src/p_elf_enum.h
Expand Up @@ -154,6 +154,7 @@
DT_RELAENT = 9, /* Size of one RELA relocation */
DT_INIT = 12, /* Address of init function */
DT_REL = 17, /* Relocations which contain no addend */
DT_RELSZ = 18, /* Total size of Rel relocs */
DT_RELENT = 19, /* Size of one Rel relocation */
DT_STRSZ = 10, /* Sizeof string table */
DT_PLTREL = 20, /* Type of reloc in PLT */
Expand Down
178 changes: 60 additions & 118 deletions src/p_lx_elf.cpp
Expand Up @@ -1481,6 +1481,34 @@ Elf64_Shdr const *PackLinuxElf64::elf_find_section_type(
return 0;
}

bool PackLinuxElf64::calls_crt1(Elf64_Rela const *rela, int sz)
{
for (; 0 < sz; (sz -= sizeof(Elf64_Rela)), ++rela) {
unsigned const symnum = get_te64(&rela->r_info) >> 32;
char const *const symnam = get_te32(&dynsym[symnum].st_name) + dynstr;
if (0==strcmp(symnam, "__libc_start_main") // glibc
|| 0==strcmp(symnam, "__libc_init") // Android
|| 0==strcmp(symnam, "__uClibc_main")
|| 0==strcmp(symnam, "__uClibc_start_main"))
return true;
}
return false;
}

bool PackLinuxElf32::calls_crt1(Elf32_Rel const *rel, int sz)
{
for (; 0 < sz; (sz -= sizeof(Elf32_Rel)), ++rel) {
unsigned const symnum = get_te32(&rel->r_info) >> 8;
char const *const symnam = get_te32(&dynsym[symnum].st_name) + dynstr;
if (0==strcmp(symnam, "__libc_start_main") // glibc
|| 0==strcmp(symnam, "__libc_init") // Android
|| 0==strcmp(symnam, "__uClibc_main")
|| 0==strcmp(symnam, "__uClibc_start_main"))
return true;
}
return false;
}

bool PackLinuxElf32::canPack()
{
union {
Expand Down Expand Up @@ -1600,23 +1628,14 @@ bool PackLinuxElf32::canPack()
if (Elf32_Ehdr::ET_DYN==get_te16(&ehdr->e_type)) {
memcpy(&ehdri, ehdr, sizeof(Elf32_Ehdr));

// 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.

Elf32_Rel const *
jmprel= (Elf32_Rel const *)elf_find_dynamic(Elf32_Dyn::DT_JMPREL);
for ( int sz = elf_unsigned_dynamic(Elf32_Dyn::DT_PLTRELSZ);
0 < sz;
(sz -= sizeof(Elf32_Rel)), ++jmprel
) {
unsigned const symnum = get_te32(&jmprel->r_info) >> 8;
char const *const symnam = get_te32(&dynsym[symnum].st_name) + dynstr;
if (0==strcmp(symnam, "__libc_start_main") // glibc
|| 0==strcmp(symnam, "__libc_init") // Android
|| 0==strcmp(symnam, "__uClibc_main")
|| 0==strcmp(symnam, "__uClibc_start_main"))
goto proceed;
if (Elf32_Dyn::DF_1_PIE & elf_unsigned_dynamic(Elf32_Dyn::DT_FLAGS_1)) {
goto proceed; // marked as main program
}
if (calls_crt1((Elf32_Rel const *)elf_find_dynamic(Elf32_Dyn::DT_REL),
(int)elf_unsigned_dynamic(Elf32_Dyn::DT_RELSZ))
|| calls_crt1((Elf32_Rel const *)elf_find_dynamic(Elf32_Dyn::DT_JMPREL),
(int)elf_unsigned_dynamic(Elf32_Dyn::DT_PLTRELSZ))) {
goto proceed; // calls C library init for main program
}

// Heuristic HACK for shared libraries (compare Darwin (MacOS) Dylib.)
Expand Down Expand Up @@ -1763,7 +1782,7 @@ PackLinuxElf64ppcle::canPack()
// Otherwise (no __libc_start_main as global undefined): skip it.
// Also allow __uClibc_main and __uClibc_start_main .

if (Elf32_Ehdr::ET_DYN==get_te16(&ehdr->e_type)) {
if (Elf64_Ehdr::ET_DYN==get_te16(&ehdr->e_type)) {
// The DT_SYMTAB has no designated length. Read the whole file.
alloc_file_image(file_image, file_size);
fi->seek(0, SEEK_SET);
Expand Down Expand Up @@ -1793,37 +1812,16 @@ PackLinuxElf64ppcle::canPack()
// which references the symbol, because DT_GNU_HASH contains only
// defined symbols, and there might be no DT_HASH.

Elf64_Rela const *
rela= (Elf64_Rela const *)elf_find_dynamic(Elf64_Dyn::DT_RELA);
Elf64_Rela const *
jmprela= (Elf64_Rela const *)elf_find_dynamic(Elf64_Dyn::DT_JMPREL);
for ( int sz = elf_unsigned_dynamic(Elf64_Dyn::DT_PLTRELSZ);
0 < sz;
(sz -= sizeof(Elf64_Rela)), ++jmprela
) {
unsigned const symnum = get_te64(&jmprela->r_info) >> 32;
char const *const symnam = get_te32(&dynsym[symnum].st_name) + dynstr;
if (0==strcmp(symnam, "__libc_start_main") // glibc
|| 0==strcmp(symnam, "__libc_init") // Android
|| 0==strcmp(symnam, "__uClibc_main")
|| 0==strcmp(symnam, "__uClibc_start_main"))
goto proceed;
}

// 2016-10-09 DT_JMPREL is no more (binutils-2.26.1)?
// Check the general case, too.
for ( int sz = elf_unsigned_dynamic(Elf64_Dyn::DT_RELASZ);
0 < sz;
(sz -= sizeof(Elf64_Rela)), ++rela
) {
unsigned const symnum = get_te64(&rela->r_info) >> 32;
char const *const symnam = get_te32(&dynsym[symnum].st_name) + dynstr;
if (0==strcmp(symnam, "__libc_start_main") // glibc
|| 0==strcmp(symnam, "__libc_init") // Android
|| 0==strcmp(symnam, "__uClibc_main")
|| 0==strcmp(symnam, "__uClibc_start_main"))
goto proceed;
if (Elf64_Dyn::DF_1_PIE & elf_unsigned_dynamic(Elf64_Dyn::DT_FLAGS_1)) {
goto proceed; // marked as main program
}
if (calls_crt1((Elf64_Rela const *)elf_find_dynamic(Elf64_Dyn::DT_RELA),
(int)elf_unsigned_dynamic(Elf64_Dyn::DT_RELASZ))
|| calls_crt1((Elf64_Rela const *)elf_find_dynamic(Elf64_Dyn::DT_JMPREL),
(int)elf_unsigned_dynamic(Elf64_Dyn::DT_PLTRELSZ))) {
goto proceed; // calls C library init for main program
}

// Heuristic HACK for shared libraries (compare Darwin (MacOS) Dylib.)
// If there is an existing DT_INIT, and if everything that the dynamic
// linker ld-linux needs to perform relocations before calling DT_INIT
Expand Down Expand Up @@ -1985,44 +1983,14 @@ PackLinuxElf64amd::canPack()
dynstr= (char const *)elf_find_dynamic(Elf64_Dyn::DT_STRTAB);
dynsym= (Elf64_Sym const *)elf_find_dynamic(Elf64_Dyn::DT_SYMTAB);

// 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.

Elf64_Rela const *
rela= (Elf64_Rela const *)elf_find_dynamic(Elf64_Dyn::DT_RELA);
Elf64_Rela const *
jmprela= (Elf64_Rela const *)elf_find_dynamic(Elf64_Dyn::DT_JMPREL);

if (Elf64_Dyn::DF_1_PIE & elf_unsigned_dynamic(Elf64_Dyn::DT_FLAGS_1)) {
goto proceed; // marked as main program
}
for ( int sz = elf_unsigned_dynamic(Elf64_Dyn::DT_PLTRELSZ);
0 < sz;
(sz -= sizeof(Elf64_Rela)), ++jmprela
) {
unsigned const symnum = get_te64(&jmprela->r_info) >> 32;
char const *const symnam = get_te32(&dynsym[symnum].st_name) + dynstr;
if (0==strcmp(symnam, "__libc_start_main") // glibc
|| 0==strcmp(symnam, "__libc_init") // Android
|| 0==strcmp(symnam, "__uClibc_main")
|| 0==strcmp(symnam, "__uClibc_start_main"))
goto proceed;
}

// 2016-10-09 DT_JMPREL is no more (binutils-2.26.1)?
// Check the general case, too.
for ( int sz = elf_unsigned_dynamic(Elf64_Dyn::DT_RELASZ);
0 < sz;
(sz -= sizeof(Elf64_Rela)), ++rela
) {
unsigned const symnum = get_te64(&rela->r_info) >> 32;
char const *const symnam = get_te32(&dynsym[symnum].st_name) + dynstr;
if (0==strcmp(symnam, "__libc_start_main") // glibc
|| 0==strcmp(symnam, "__libc_init") // Android
|| 0==strcmp(symnam, "__uClibc_main")
|| 0==strcmp(symnam, "__uClibc_start_main"))
goto proceed;
if (calls_crt1((Elf64_Rela const *)elf_find_dynamic(Elf64_Dyn::DT_RELA),
(int)elf_unsigned_dynamic(Elf64_Dyn::DT_RELASZ))
|| calls_crt1((Elf64_Rela const *)elf_find_dynamic(Elf64_Dyn::DT_JMPREL),
(int)elf_unsigned_dynamic(Elf64_Dyn::DT_PLTRELSZ))) {
goto proceed; // calls C library init for main program
}

// Heuristic HACK for shared libraries (compare Darwin (MacOS) Dylib.)
Expand Down Expand Up @@ -2160,7 +2128,7 @@ PackLinuxElf64arm::canPack()
// Otherwise (no __libc_start_main as global undefined): skip it.
// Also allow __uClibc_main and __uClibc_start_main .

if (Elf32_Ehdr::ET_DYN==get_te16(&ehdr->e_type)) {
if (Elf64_Ehdr::ET_DYN==get_te16(&ehdr->e_type)) {
// The DT_SYMTAB has no designated length. Read the whole file.
alloc_file_image(file_image, file_size);
fi->seek(0, SEEK_SET);
Expand All @@ -2186,40 +2154,14 @@ PackLinuxElf64arm::canPack()
dynstr= (char const *)elf_find_dynamic(Elf64_Dyn::DT_STRTAB);
dynsym= (Elf64_Sym const *)elf_find_dynamic(Elf64_Dyn::DT_SYMTAB);

// 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.

Elf64_Rela const *
rela= (Elf64_Rela const *)elf_find_dynamic(Elf64_Dyn::DT_RELA);
Elf64_Rela const *
jmprela= (Elf64_Rela const *)elf_find_dynamic(Elf64_Dyn::DT_JMPREL);
for ( int sz = elf_unsigned_dynamic(Elf64_Dyn::DT_PLTRELSZ);
0 < sz;
(sz -= sizeof(Elf64_Rela)), ++jmprela
) {
unsigned const symnum = get_te64(&jmprela->r_info) >> 32;
char const *const symnam = get_te32(&dynsym[symnum].st_name) + dynstr;
if (0==strcmp(symnam, "__libc_start_main") // glibc
|| 0==strcmp(symnam, "__libc_init") // Android
|| 0==strcmp(symnam, "__uClibc_main")
|| 0==strcmp(symnam, "__uClibc_start_main"))
goto proceed;
}

// 2016-10-09 DT_JMPREL is no more (binutils-2.26.1)?
// Check the general case, too.
for ( int sz = elf_unsigned_dynamic(Elf64_Dyn::DT_RELASZ);
0 < sz;
(sz -= sizeof(Elf64_Rela)), ++rela
) {
unsigned const symnum = get_te64(&rela->r_info) >> 32;
char const *const symnam = get_te32(&dynsym[symnum].st_name) + dynstr;
if (0==strcmp(symnam, "__libc_start_main") // glibc
|| 0==strcmp(symnam, "__libc_init") // Android
|| 0==strcmp(symnam, "__uClibc_main")
|| 0==strcmp(symnam, "__uClibc_start_main"))
goto proceed;
if (Elf64_Dyn::DF_1_PIE & elf_unsigned_dynamic(Elf64_Dyn::DT_FLAGS_1)) {
goto proceed; // marked as main program
}
if (calls_crt1((Elf64_Rela const *)elf_find_dynamic(Elf64_Dyn::DT_RELA),
(int)elf_unsigned_dynamic(Elf64_Dyn::DT_RELASZ))
|| calls_crt1((Elf64_Rela const *)elf_find_dynamic(Elf64_Dyn::DT_JMPREL),
(int)elf_unsigned_dynamic(Elf64_Dyn::DT_PLTRELSZ))) {
goto proceed; // calls C library init for main program
}

// Heuristic HACK for shared libraries (compare Darwin (MacOS) Dylib.)
Expand Down
2 changes: 2 additions & 0 deletions src/p_lx_elf.h
Expand Up @@ -139,6 +139,7 @@ class PackLinuxElf32 : public PackLinuxElf
virtual unsigned find_LOAD_gap(Elf32_Phdr const *const phdri, unsigned const k,
unsigned const e_phnum);
virtual off_t getbase(const Elf32_Phdr *phdr, int e_phnum) const;
bool calls_crt1(Elf32_Rel const *rel, int sz);

virtual Elf32_Sym const *elf_lookup(char const *) const;
virtual unsigned elf_get_offset_from_address(unsigned) const;
Expand Down Expand Up @@ -259,6 +260,7 @@ class PackLinuxElf64 : public PackLinuxElf
virtual void updateLoader(OutputFile *fo);
virtual unsigned find_LOAD_gap(Elf64_Phdr const *const phdri, unsigned const k,
unsigned const e_phnum);
bool calls_crt1(Elf64_Rela const *rela, int sz);

virtual Elf64_Sym const *elf_lookup(char const *) const;
virtual upx_uint64_t elf_get_offset_from_address(upx_uint64_t) const;
Expand Down

0 comments on commit ee18fe9

Please sign in to comment.